2016-04-01 3 views
5

Я пытаюсь сделать мир привет в архитектуре руки с помощью CMake с this toolchainрука-ни-EABI-НКУ с CMake не имеет точку входа с флагом -nostdlib

Мой main.c

int main() 
{ 
    char *str = "Hello World"; 
    return 0; 
} 

И мой CMakeLists.txt

cmake_minimum_required(VERSION 3.4) 
SET(PROJ_NAME arm-hello-world-nostdlib) 
PROJECT(${PROJ_NAME}) 

# Include directories with headers 
#---------------------------------------------------# 
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) 

# Source 
#---------------------------------------------------# 
FILE(GLOB ${PROJ_NAME}_SRC 
    "src/*.c" 
) 
FILE(GLOB ${PROJ_NAME}_HEADERS 
    "include/*.h" 
) 

# Create Exe 
#---------------------------------------------------# 
ADD_EXECUTABLE(${PROJ_NAME} ${${PROJ_NAME}_SRC} ${${PROJ_NAME}_HEADERS}) 

# Specify libraries or flags to use when linking a given target. 
#---------------------------------------------------# 
TARGET_LINK_LIBRARIES(${PROJ_NAME} -nostdlib --specs=rdimon.specs -lm -lrdimon) 

Этот запуск конфигурации предупреждение:

[100%] Linking C executable arm-hello-world-nostdlib 
/usr/lib/gcc/arm-none-eabi/5.2.0/../../../../arm-none-eabi/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000008000 

и выполнения бинарного с QEMU врезаться выполнение:

qemu-arm arm-hello-world-nostdlib 
qemu: uncaught target signal 4 (Illegal instruction) - core dumped 
Illegal instruction (core dumped) 

Без флага --nostdlib работает отлично, и команда

arm-none-eabi-objdump -s arm-hello-world-nostdlib 

Показать много информации в двоичной, компиляции с флагом только шоу:

samples/helloworld-nostdlib/arm-hello-world-nostdlib:  file format elf32-littlearm 

Contents of section .text: 
8000 80b483b0 00af044b 7b600023 18460c37 .......K{`.#.F.7 
8010 bd465df8 047b7047 1c800000   .F]..{pG....  
Contents of section .rodata: 
801c 48656c6c 6f20576f 726c6400   Hello World.  
Contents of section .comment: 
0000 4743433a 20284665 646f7261 20352e32 GCC: (Fedora 5.2 
0010 2e302d33 2e666332 33292035 2e322e30 .0-3.fc23) 5.2.0 
0020 00         .    
Contents of section .ARM.attributes: 
0000 41380000 00616561 62690001 2e000000 A8...aeabi...... 
0010 05436f72 7465782d 4d340006 0d074d09 .Cortex-M4....M. 
0020 020a0612 04140115 01170318 0119011a ................ 
0030 011b011c 011e0622 01     .......".  

Я не хочу СТЛ библиотеки в моем двоичном, но я предполагаю, что отсутствует код сборки, чтобы найти запись р oint. Как добавить его вручную?

Update: По GNU Linker doc для -nostdlib:

Не использовать стандартные файлы запуска или библиотеки при ссылок. Нет файлов запуска и только указанные вами библиотеки будут , переданные компоновщику, а опции, определяющие связь систем , такие библиотеки, как -static-libgcc или -shared-libgcc, игнорируются.

В качестве альтернативы, если кто-то не хочет использовать стандартную библиотеку пользователя, они могут использовать флаг -nodefaultlibs.

Не используйте стандартные системные библиотеки при связывании. Только указанные библиотеки передаются компоновщику, а параметры, указывающие , связаны с системными библиотеками, такими как -static-libgcc или -shared-libgcc, игнорируются. Обычно стандартные файлы запуска используются, если не используются файлы -nostartfiles.

Компилятор может генерировать вызовы memcmp, memset, memcpy и memmove. Эти записи обычно разрешаются записями в libc. Эти позиции должны быть предоставлены через какой-либо другой механизм, если указан параметр .

Кстати, я хочу способ создать и добавить файлы запуска, возможный путь в this tutorial, но я добавляю Баунти, чтобы получить ответ на мой вопрос, и есть общее решение для всех. Я считаю это удобным для людей, которые хотят настроить и узнать о файлах перекрестной компиляции, руки и запуска.

Update 2

Используя старт.S код сборки:

.text 
.align 4 

.global _start 
.global _exit 

_start: 
     mov  fp, #0    /* frame pointer */ 
     ldr  a1, [sp]    /* 1st arg = argc */ 
     add  a2, sp, #4   /* 2nd arg = argv */ 

     bl  main 

_exit: 
     mov  r7, #1    /* __NR_exit */ 
     swi  0 

.type _start,function 
.size _start,_exit-_start 

.type _exit,function 
.size _exit,.-_exit 

указать точку входа, представленную arsv и компилирование с помощью команды:

arm-none-eabi-gcc -nostdlib -o main main.c start.S 

, кажется, работает propertly. Обновление CMakeLists.txt:

#Directly works: 
#arm-none-eabi-gcc -nostdlib -o main main.c start.S 

cmake_minimum_required(VERSION 3.4) 
SET(PROJ_NAME arm-hello-world-nostdlib) 

# Assembler files (.S) in the source list are ignored completely by CMake unless we 
# “enable” the assembler by telling CMake in the project definition that we’re using assembly 
# files. When we enable assembler, CMake detects gcc as the assembler rather than as – this 
# is good for us because we then only need one set of compilation flags. 
PROJECT(${PROJ_NAME} C ASM) 

# Include directories with headers 
#---------------------------------------------------# 
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/include) 

# Source 
#---------------------------------------------------# 
FILE(GLOB ${PROJ_NAME}_SRC 
    "src/start.S" 
    "src/*.c" 
) 
FILE(GLOB ${PROJ_NAME}_HEADERS 
    "include/*.h" 
) 

# Create Exe 
#---------------------------------------------------# 
ADD_EXECUTABLE(${PROJ_NAME} ${${PROJ_NAME}_SRC} ${${PROJ_NAME}_HEADERS}) 

# Specify libraries or flags to use when linking a given target. 
#---------------------------------------------------# 
TARGET_LINK_LIBRARIES(${PROJ_NAME} -nostdlib --specs=rdimon.specs -lm -lrdimon) 

Если вы связывая проблемы, такие как:

arm-none-eabi/bin/ld: error: CMakeFiles/arm-hello-world-nostdlib.dir/src/main.c.obj: Conflicting CPU architectures 1/13 

Сво проблема набора инструментов для Cortex-A9, работает с помощью:

set(CMAKE_C_FLAGS 
    "${CMAKE_C_FLAGS}" 
    "-mcpu=cortex-a9 -march=armv7-a -mthumb" 
    "-mfloat-abi=softfp -mfpu=fpv4-sp-d16" 
) 
+3

STL - это C++, почему бы вам это сделать в вашей программе на C? Технически вы можете установить точку входа на главную в команде компоновщика, но это пропустит материал инициализации libc и поэтому не рекомендуется. – Jester

+0

Без кросс-компиляции, следуя этому руководству: https://blogs.oracle.com/ksplice/entry/hello_from_a_libc_free, отлично работает, потому что использует собственный файл сборки stub _start, который работает в x86. Я предполагаю, что мне нужно что-то подобное в ARM, но я не знаю, что использовать, тот же файл сборки не работает, потому что архитектура отличается. – vgonisanz

+0

Обратите внимание, что связанная статья специально не использует библиотеку C. Это работает. То, что не гарантируется, заключается в смешивании '-nostdlib' с' -lc'.Вы должны решить, нужен ли вам libc, в этом случае не используйте '-nostdlib', или если вам это не нужно, тогда не используйте' -lc' и установите точку входа через опцию компоновщика. – Jester

ответ

3

Вот _start . Я использую небольшой проект.
Это должно быть достаточно, чтобы связать и запустить основные() с помощью QEmu-руки:

.text 
.align 4 

.global _start 
.global _exit 

_start: 
     mov  fp, #0    /* frame pointer */ 
     ldr  a1, [sp]    /* 1st arg = argc */ 
     add  a2, sp, #4   /* 2nd arg = argv */ 

     bl  main 

_exit: 
     mov  r7, #1    /* __NR_exit */ 
     swi  0 

.type _start,function 
.size _start,_exit-_start 

.type _exit,function 
.size _exit,.-_exit 

Примечания это код запуска для общего Linux двоичного на пользовательском пространство ARM. Это то, что вы, вероятно, хотите для qemu-arm (qemu linux-user mode или syscall proxy). В других случаях, например, в бинарных файлах с открытым железом в связанной записи или в не-Linux-пространстве или в других архитектурах, код запуска будет другим.

В Linux вновь загруженный двоичный файл вызывается с помощью argc в верхней части стека, за которым следует argv [], за которым следует envp [], за которым следует auxv []. Код запуска должен превратить это в правильный главный (argc, argv) вызов в соответствии с соглашением о вызове arch. Для ARM это первый аргумент в регистре a1, 2-й в a2.

«Вызывается» выше означает переход к адресу e_entry из заголовка ELF, который устанавливается в ld, чтобы указать на символ _start, если он найден. Если нигде не указано _start, ld установил e_entry в 0x8000, и все, что было в 0x8000, когда был сделан переход, по-видимому, не выглядел как действительная инструкция ARM. Это не совсем неожиданно.

Чтение кода из меньших/чистых реализаций libc, таких как musl или dietlibc, помогает в понимании таких вещей. Вышеприведенный код, кстати, происходит от dietlibc.

https://github.com/ensc/dietlibc/blob/master/arm/start.S
http://git.musl-libc.org/cgit/musl/tree/arch/arm/crt_arch.h

Для справки, минималистичный CMakeLists.txt для создания проекта:
(предполагается, что файлы с именем main.c и _start.s)

project(arm-hello-world-nostdlib) 
cmake_minimum_required(VERSION 3.4) 

enable_language(ASM) 
set(CMAKE_C_COMPILER arm-none-gnueabi-gcc) 
set(CMAKE_ASM_COMPILER arm-none-gnueabi-gcc) 
set(CMAKE_ASM_FLAGS -c) 
set(CMAKE_VERBOSE_MAKEFILE on) 

add_executable(main _start.s main.c) 
target_link_libraries(main -nostdlib) 

Run результирующая исполняемый файл: qemu-arm ./main

+0

Хорошо. Ваш код сборки работает вручную. «arm-none-eabi-gcc -nostdlib start.S -o main.c» и «qemu-arm main» работают с минимальной информацией в «arm-none-eabi-objdump main». Чтобы завершить ответ, мне нужно знать, как заставить его работать с CMakeLists.txt, потому что я не могу добавить файл start.S в код или флаг ссылки, чтобы он работал с CMake. – vgonisanz

+0

Не большой поклонник cmake, отчасти из-за таких вещей. Очевидно, вам нужно включить язык ASM, иначе он просто молча игнорирует файлы сборки. Добавлен пример CMakeLists.txt, похоже, работает для меня – arsv

+0

Ну, спасибо, похоже, решение для вашего предложения действительно. Я пытаюсь сделать то же самое, но у меня есть неизвестная проблема с компоновщиком, но это действующее решение, 15 часов, чтобы присудить награду: -p – vgonisanz