我试图使用CMake与this toolchain
建立一个手臂架构的hello世界我的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 .......".
我不想在我的二进制文件中使用stl库,但我想我错过了汇编代码来找到入口点。如何手动添加?
更新 根据{{3}} for -nostdlib:
请勿在使用标准系统启动文件或库时使用 链接。没有启动文件,只有您指定的库 传递给链接器,以及指定系统链接的选项 库,例如-static-libgcc或-shared-libgcc,将被忽略。
或者,如果有人不想使用标准库,他们可以使用标志-nodefaultlibs。
链接时不要使用标准系统库。只有 您指定的库将传递给链接器,并指定选项 系统库的链接,例如-static-libgcc或 -shared-libgcc,被忽略。除非使用-nostartfiles,否则标准启动文件将正常使用。
编译器可能会生成对memcmp,memset,memcpy和memmove的调用。 这些条目通常由libc中的条目解析。这些条目 这个点应该通过其他机制提供 选项已指定。
顺便说一句,我想要一种方法来创建和添加启动文件,这是GNU Linker doc中的一种可能方式,但我添加了赏金以获得我的问题的答案并为每个人提供一般解决方案。我认为这对于想要定制和了解交叉编译,arm和启动文件的人来说非常有用。
更新2
使用start.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
似乎有效。更新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"
)
答案 0 :(得分:3)
这是_start.s我在我的一个小项目中使用。
使用qemu-arm链接和运行main()应该足够了:
.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
请注意,这是ARM上常见Linux用户空间二进制文件的启动代码。这是你可能想要的qemu-arm(qemu linux-user模式或系统调用代理)。对于其他情况,如链接帖子中的裸铁二进制文件,或非Linux用户空间或其他体系结构,启动代码将有所不同。
在Linux中,一个新加载的二进制文件在堆栈顶部用argc调用,然后是argv [],然后是envp [],然后是auxv []。启动代码必须根据arch调用约定将其转换为正确的main(argc,argv)调用。对于ARM来说,它是寄存器a1中的第一个参数,是a2中的第二个参数。
“获取调用”上面的意思是从ELF标题跳转到e_entry地址,如果找到一个,则由ld设置指向_start符号。由于没有在任何地方定义_start,ld将e_entry设置为0x8000,并且当跳转显然看起来不像有效的ARM指令时,碰巧发生在0x8000。这并非完全出乎意料。
从较小/更清洁的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)
运行生成的可执行文件,如下所示:qemu-arm ./main