Arm-none-eabi-gcc with Cmake does not have an entry point with the -nostdlib flag

I'm trying to create a hello world in weapon architecture using CMake with this toolchain

My main.c

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

And my 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) 

In this configuration, run the warning:

 [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 

And after executing the binary with qemu, crash:

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

Without the --nostdlib flag works fine, and the command

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

Show a lot of information in binary format, compilation with a flag shows only:

 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 .......". 

I do not want the stl libraries in my binary format, but I think I am missing the build code to find the entry point. How to add it manually?

Update: According to the GNU Linker doc for -nostdlib:

Do not use standard system boot files or libraries unless stitching. There are no startup files and only the libraries you specify will be passed to the linker, and options defining the library system connection, such as -static-libgcc or -shared-libgcc, are ignored.

Alternatively, if someone does not want to use the standard user library, they can use the -nodefaultlibs flag.

Do not use standard system libraries when linking. Only the libraries you specify are passed to the linker, and parameters indicating the link of system libraries, such as -static-libgcc or -shared-libgcc, are ignored. Standard startup files are used normally if the -nostartfiles file is not used.

The compiler can generate memcmp, memset, memcpy, and memmove calls. These entries are usually resolved by entries in libc. These record items should be provided through some other mechanism when this parameter is specified.

By the way, I want to create and add startup files, a possible way to this tutorial , but I add generosity to get an answer to my question and give a general solution for everyone. I find this convenient for people who want to tweak and learn about cross-compilation, hand and launch files.

Update 2

Using start.S assembly code:

 .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 

to specify the entry point provided by arsv and compile with the command:

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

seems to be working properly. Update 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) 

If you have binding problems, for example:

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

The problem with the toolchain for cortex-a9 works using:

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

Here _start.s I use in my small project.
Just bind and run main () with qemu-arm:

 .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 

Please note that this is the startup code for regular Linux user space in ARM. This is what you probably want for qemu-arm (qemu linux-user mode or syscall proxy). In other cases, for example, in open-iron binaries in a connected message or in non-Linux space or in other architectures, the startup code will be different.

On Linux, a newly loaded binary is called with argc at the top of the stack, followed by argv [], followed by envp [], followed by auxv []. The startup code should turn this into the correct main (argc, argv) call in accordance with the arch calling convention. For ARM, this 1st argument in register a1, 2nd in a2.

β€œCalled” above means going to the e_entry address from the ELF header, which is set by ld to indicate the _start character, if found. Unless _start is specified anywhere, ld set e_entry to 0x8000, and everything that was at 0x8000 when the transition was made did not seem to look like a valid ARM instruction. Which is not entirely unexpected.

Reading code from small / clean libc implementations like musl or dietlibc helps in understanding such things. The code above comes from dietlibc, by the way.

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

For reference, a minimalist CMakeLists.txt for creating a project:
(assuming the files are called main.c and _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 the resulting executable file as follows: qemu-arm ./main

+3
source

Source: https://habr.com/ru/post/1246231/


All Articles