带有Cmake的arm-none-eabi-gcc没有带有标志-nostdlib的入口点

vgo*_*anz 5 c assembly arm entry-point

我正试图用这个工具链使用CMake在arm架构中建立一个hello world

我的主要

int main()
{
  char *str = "Hello World";
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

还有我的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)
Run Code Online (Sandbox Code Playgroud)

此配置启动警告:

[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
Run Code Online (Sandbox Code Playgroud)

使用qemu执行二进制文件会导致执行崩溃:

qemu-arm arm-hello-world-nostdlib 
qemu: uncaught target signal 4 (Illegal instruction) - core dumped
Illegal instruction (core dumped)
Run Code Online (Sandbox Code Playgroud)

没有标志--nostdlib完美地工作,并命令

arm-none-eabi-objdump -s arm-hello-world-nostdlib
Run Code Online (Sandbox Code Playgroud)

以二进制显示大量信息,仅使用标志显示进行编译:

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                 .......".    
Run Code Online (Sandbox Code Playgroud)

我不想在我的二进制文件中使用stl库,但我想我错过了汇编代码来找到入口点.如何手动添加?

更新: 根据GNU Linker doc for -nostdlib:

链接时请勿使用标准系统启动文件或库.没有启动文件,只有您指定的库将传递给链接器,并且将忽略指定系统库链接的选项,例如-static-libgcc或-shared-libgcc.

或者,如果有人不想使用标准库,则可以使用标志-nodefaultlibs.

链接时请勿使用标准系统库.只有您指定的库才会传递给链接器,并且会忽略指定系统库链接的选项,例如-static-libgcc或-shared-libgcc.除非使用-nostartfiles,否则标准启动文件将正常使用.

编译器可能会生成对memcmp,memset,memcpy和memmove的调用.这些条目通常由libc中的条目解析.指定此选项时,应通过其他机制提供这些入口点.

顺便说一句,我想要一种方法来创建和添加启动文件,这是本教程中可能的方法,但我添加赏金以获得我的问题的答案,并为每个人提供一般解决方案.我认为这对于想要定制和了解交叉编译,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
Run Code Online (Sandbox Code Playgroud)

指示arsv提供的入口点,并使用命令进行编译:

arm-none-eabi-gcc -nostdlib -o main main.c start.S
Run Code Online (Sandbox Code Playgroud)

似乎工作性质.更新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)
Run Code Online (Sandbox Code Playgroud)

如果您遇到以下链接问题:

arm-none-eabi/bin/ld: error: CMakeFiles/arm-hello-world-nostdlib.dir/src/main.c.obj: Conflicting CPU architectures 1/13
Run Code Online (Sandbox Code Playgroud)

对于cortex-a9,它的工具链存在问题,可以使用:

  set(CMAKE_C_FLAGS
    "${CMAKE_C_FLAGS}"
    "-mcpu=cortex-a9 -march=armv7-a -mthumb"
    "-mfloat-abi=softfp -mfpu=fpv4-sp-d16"
  )
Run Code Online (Sandbox Code Playgroud)

ars*_*rsv 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
Run Code Online (Sandbox Code Playgroud)

请注意,这是 ARM 上常见 Linux 用户空间二进制文件的启动代码。这就是您可能想要的 qemu-arm (qemu linux 用户模式或系统调用代理)。对于其他情况,例如链接帖子中的裸铁二进制文件、非 Linux 用户空间或其他体系结构,启动代码将会有所不同。

在 Linux 中,新加载的二进制文件通过位于堆栈顶部的 argc、argv[]、envp[]、auxv[] 进行调用。启动代码必须根据 arch 调用约定将其转换为正确的 main(argc, argv) 调用。对于 ARM,这是寄存器 a1 中的第一个参数,a2 中的第二个参数。

上面的“被调用”意味着从ELF头跳转到e_entry地址,如果找到的话,由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 Code Online (Sandbox Code Playgroud)

像这样运行生成的可执行文件:qemu-arm ./main