GCC: include math.h function in bare-metal software on ARM (arm-none-eabi-gcc) - gcc

I am working on a bare-metal free standing software on a STM32H753. I'm not using neither the libc nor the crt.
Here is the link command line:
arm-none-eabi-gcc -T"xxx.ld" -mfpu=fpv5-d16 -mfloat-abi=hard -mthumb -ffreestanding -nostdlib -nostartfiles --specs=nosys.specs -Wl,--start-group -lc -lm -Wl,--end-group -Wl,-Map=xxx.map -o xxx.elf <list of .o>
Now I need to include math library since I am using sqrt function. i thought the link command line would be sufficient but I get a "sqrt undefined" error.
I tried to add the path to the libm.a: (also tried without -Wl)
arm-none-eabi-gcc -T"xxx.ld" -Wl,-L/opt/gcc-arm-none-eabi-10-2020-q4-major/arm-none-eabi/lib/ -mfpu=fpv5-d16 -mfloat-abi=hard -mthumb -ffreestanding -nostdlib -nostartfiles --specs=nosys.specs -Wl,--start-group -lc -lm -Wl,--end-group -Wl,-Map=build_uP1/base_gen_uP1.map -o build_uP1/base_gen_uP1.elf <list of .o>
But I still get the same error.
I don't understand what options to choose to link with the correct library

Sorry for this self answer but I think I 've found the solution.
my first mistake is that the library must be put at the end of the command line. the order of arguments does matter.
then there are many versions of libm.a in the gcc install so I had to pick the right one
The following line is working:
arm-none-eabi-gcc -T"xxx.ld" -L/opt/gcc-arm-none-eabi-10-2020-q4-major/arm-none-eabi/lib/thumb/v7+fp/hard/ -mfpu=fpv5-d16 -mfloat-abi=hard -mthumb -ffreestanding -nostdlib -nostartfiles --specs=nosys.specs -Wl,-Map=xxx.map -o xxx.elf <list of .o> -lm -lc
I've noticed that one symbol and some data from libc.a are needed: __errno, and impure_data

Related

Understanding error from ld "archive member is not mach-o or llvm bitcode file"

I'm getting the following error when trying to link a code on a Mac (Montery). First let me say that up until a recent upgrade to Xcode the code built fine. GCC is 10, OpenMPI and it's a Fortran code. Now there are multiple executables which build and one libaray. The library compiles fine and is archived via ar (ar -ruvs). For example, here's a compile and build line for a code.
mpif90 -O2 -g -fexternal-blas -fbacktrace -fcheck=all,no-array-temps -fallow-argument-mismatch -I../../LIBSTELL/Release -I/opt/local/include -I. -c ../Sources/boozer_coords.f
mpif90 -shared -Wl,-no_compact_unwind -O2 -g -fexternal-blas -fbacktrace -fcheck=all,no-array-temps -fallow-argument-mismatch -I../../LIBSTELL/Release -I/opt/local/include -o xbooz_xform booz_jac.o read_wout_booz.o foranl.o allocate_boozer.o transpmn.o boozer_xform.o setup_booz.o write_boozmn.o harfun.o trigfunc.o booz_params.o vcoords.o boozer.o free_mem_boozer.o boozer_coords.o booz_persistent.o ../../LIBSTELL/Release/libstell.a -L/usr/lib -L/opt/local/lib -lopenblas -lscalapack -L/opt/local/lib -lnetcdf -lnetcdff -L/opt/local/lib -lfftw3 -L/opt/local/lib -lhdf5hl_fortran -lhdf5_hl -lhdf5_fortran -lhdf5 -lz -ldl -lm
This works fine and produces an executable. However, there is another code which links to this code. For that reason archives are made of the compiled code.
mpif90 -ffree-form -ffree-line-length-none -ffixed-line-length-none -O2 -g -fexternal-blas -fbacktrace -fcheck=all,no-array-temps -fallow-argument-mismatch -I../../LIBSTELL/Release -I../../BOOTSJ/Release -I/opt/local/include -I/opt/local/include -I. -c ../Sources/thrift_main.f90
mpif90 -shared -Wl,-no_compact_unwind -O2 -g -fexternal-blas -fbacktrace -fcheck=all,no-array-temps -fallow-argument-mismatch -I../../LIBSTELL/Release -I/opt/local/include -o xthrift thrift_interface_mod.o thrift_runtime.o thrift_main.o ../../BOOTSJ/Release/libbootsj.a ../../LIBSTELL/Release/libstell.a -L/usr/lib -L/opt/local/lib -lopenblas -lscalapack -L/opt/local/lib -lnetcdf -lnetcdff -L/opt/local/lib -lfftw3 -L/opt/local/lib -lhdf5hl_fortran -lhdf5_hl -lhdf5_fortran -lhdf5 -lz -ldl -lm
ld: in ../../BOOTSJ/Release/libbootsj.a(parambs.mod), archive member 'parambs.mod' with length 2800 is not mach-o or llvm bitcode file '../../BOOTSJ/Release/libbootsj.a' for architecture x86_64
collect2: error: ld returned 1 exit status
I've had limited success trying to understand the source of this error. Here's what the table for the archive looks like.
ar -t ../BOOTSJ/Release/libbootsj.a
__.SYMDEF SORTED
SIMPUN.o
al31.o
allocate_angles.o
allocate_radial.o
bongrid.o
bootsj.o
caprsh2.o
datain.o
deallocate_all.o
denmf.o
do_fft.o
driver.o
fraction.o
grad.o
othersums.o
output.o
parambs.o
positiv.o
read_boozer.o
reorganz.o
smooth1.o
sumit.o
temp.o
tok_fraction.o
trig.o
vmec0.o
woflam.o
parambs.mod
trig.mod
vmec0.mod
OK so I was adding the module files (.mod) to the archive. This was incorrect. Only the Object (.o) files should be in the archive.
If I understand correctly the compiler will use the -I <path> command to look for (.mod) files. So the archive only needs the object files.

Selecting correct multilib version for linker automatically

I am using GCC to compile a program for an Atmel Cortex M4 SAM4S Processor. I need to link the standard libraries libgcc.a and libc.a, and to do so I am currently using the following makefile commands
LIBDIR1=C:/Program\ Files\ \(x86\)/GNU\ Arm\ Embedded\ Toolchain/10\ 2020-q4-major/arm-none-eabi/lib/thumb/v7e-m/nofp
LIBDIR2=C:/Program\ Files\ \(x86\)/GNU\ Arm\ Embedded\ Toolchain/10\ 2020-q4-major/lib/gcc/arm-none-eabi/10.2.1/thumb/v7e-m/nofp
ld_input=linker.ld startup.o main.o syscalls.o
ld_flags=-L$(LIBDIR1) -L$(LIBDIR2) -lm -lc -lgcc
out.elf: $(ld_input)
arm-none-eabi-ld -o out.elf -T $(ld_input) $(ld_flags)
However, to link to the correct multilib, I need to specify the subdirectories /thumb/v7e-m/nofp explicitly, which I determined via
arm-none-eabi-gcc -mcpu=cortex-m4 --print-multi-dir
Is there a way to link to the correct subdirectories automatically, based on the -mcpu=cortex-m4 option?
It seems everything works by using gcc instead of ld for linking. gcc then calls the linker with all the correct options, including all the standard librarier automatically.
The code shown in the question can be replaced by
ld_input=linker.ld startup.o main.o syscalls.o
out.elf: $(ld_input)
arm-none-eabi-gcc -mcpu=cortex-m4 -o out.elf -T $(ld_input)

CMake w/ARM tools _start symbol undefined

I build an executable file thru CMake. The executable is linked to various static libraries, also built thru CMake in the same project. However, linking is not happening properly.
I run arm-none-eabi objdump -tT executable and see that symbols _start and many of the other functions that I define are undefined.
This is the main CMakeLists.txt file:
set(CMAKE_BUILD_TYPE DEBUG)
# Set C/C++ compile and linking flags
set(GCC_COVERAGE_COMPILE_FLAGS "-march=armv7e-m -mthumb \
-mfloat-abi=softfp -mfpu=fpv4-sp-d16 -Og -fmessage-length=0 \
-fsigned-char -ffunction-sections -fdata-sections -ffreestanding \
-fno-move-loop-invariants -Wall -Wextra -g3")
set(GCC_COVERAGE_LINK_FLAGS
"-T \"${PROJECT_SOURCE_DIR}/ldscripts/mem.ld\" \
-T \"${PROJECT_SOURCE_DIR}/ldscripts/libs.ld\" \
-T \"${PROJECT_SOURCE_DIR}/ldscripts/sections.ld\" \
-nostartfiles -Xlinker --gc-sections -Wl,-Map,\"elka.map\" \
--specs=nano.specs")
#--specs=nano.specs -o \"elka.elf\"")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${GCC_COVERAGE_COMPILE_FLAGS}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER__FLAGS} ${GCC_COVERAGE_LINK_FLAGS}")
set(ELKA_LINK_LIBS "")
add_definitions(-DUSE_STDPERIPH_DRIVER)
# Add libraries, subdirectories, etc to include all source and header files
include_directories(${PROJECT_SOURCE_DIR}/inc
${PROJECT_SOURCE_DIR}/inc/CMSIS
${PROJECT_SOURCE_DIR}/inc/Device/STM32F4xx
${PROJECT_SOURCE_DIR}/inc/drivers
${PROJECT_SOURCE_DIR}/inc/elka_hal
${PROJECT_SOURCE_DIR}/inc/FreeRTOS
${PROJECT_SOURCE_DIR}/inc/FreeRTOS/GCC/ARM_CM4F
${PROJECT_SOURCE_DIR}/inc/modules
${PROJECT_SOURCE_DIR}/inc/nvicconf
${PROJECT_SOURCE_DIR}/inc/STM32F4xx_StdPeriph_Driver
${PROJECT_SOURCE_DIR}/inc/utils
)
add_subdirectory(src)
#FIXME make sure that this will create elka executable file
#TODO link against libraries
add_executable(elka
src/main.c
src/_write.c
)
add_dependencies(elka
${ELKA_LINK_LIBS}
)
There are other CMakeLists.txt files in subdirectories. They serve to build the static libraries and add them to the ELKA_LINK_LIBS variable. The main CMakeLists.txt file generates the following command in CMake. to perform linking, followed by the warning:
/usr/bin/arm-none-eabi-gcc -march=armv7e-m -mthumb -mfloat-abi=softfp -mfpu=fpv4-sp-d16 -Og -fmessage-length=0 -fsigned-char -ffunction-sections -fdata-sections -ffreestanding -fno-move-loop-invariants -Wall -Wextra -g3 -g -T /Programs/elka/elka_firmware/elka_firmware/ldscripts/mem.ld -T /Programs/elka/elka_firmware/elka_firmware/ldscripts/libs.ld -T /Programs/elka/elka_firmware/elka_firmware/ldscripts/sections.ld -nostartfiles -Xlinker --gc-sections -Wl,-Map,elka.map --specs=nano.specs CMakeFiles/elka.dir/src/main.c.obj CMakeFiles/elka.dir/src/_write.c.obj -o elka src/drivers/libelka_drivers.a src/elka_hal/libelka_hal.a src/FreeRTOS/libFreeRTOS.a src/modules/libelka_modules.a src/STM32F4xx_StdPeriph_Driver/libSTM32F4xx_StdPeriph_Driver.a src/utils/libelka_utils.a
/usr/bin/../lib/gcc/arm-none-eabi/4.9.3/../../../../arm-none-eabi/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000008000028
Why is _start undefined, first of all? If that is a trivial answer, then why are the other symbols in this executable undefined? I can post the objdump or other files if pertinent.
In a final note, I have found that the symbols for functions that I have defined in other libraries are undefined in those other static libraries. Below is a sample CMakeLists.txt for one library:
# src/elka_hal
include_directories(
${CMAKE_CURRENT_BINARY_DIR}
${PROJECT_SOURCE_DIR}/inc/elka_hal
)
add_library(elka_hal STATIC
imu.c
)
set(ELKA_LINK_LIBS
${ELKA_LINK_LIBS} elka_hal
PARENT_SCOPE
)
Edit: It seems to link symbols correctly if I take away the -nostartfiles flag from GCC_COVERAGE_LINK_FLAGS and change --specs=nano.specs to --specs=nosys.specs

About -ffunction-sections -fdata-sections and --gc-sections options

In my ARM project, I use following to build os-less application binary:
arm-linux-gcc -Os -ffunction-sections -fdata-sections -o boot.o boot.S
arm-linux-gcc -Os -ffunction-sections -fdata-sections -o main.o main.c
arm-linux-ld -T link.lds --gc-sections -o target.bin boot.o main.o
These works fine. Because If I remove "-ffunction-sections", "-fdata-sections" and "--gc-sections" options, the target.bin file size will increase nearly twice..
But on the x86 platform, same method, I found that:
If I don't use those gcc and ld options, the output is normal, but the output file will be 0 byte if I use those options as arm platform.
-Os -ffunction-sections -fdata-sections and --gc-sections should work on x86 system. Are you sure your program and your linker script are suitable for x86 ? As your program is meant for bare-metal ARM, it probably does not have entry points for your x86 OS, and if there is no entry point, everything is garbaged by --gc-sections option.
BTW, your "question" actually enclose no question.

gcc linker issue

I am trying to make a library that wraps libpurple (you shouldn't need to know anything about libpurple to help here). Libpurple in turn loads "plugins" which are just .so's accessed via something like dlopen. Those plugins in turn call back to functions in libpurple.
I can build my library just fine, but when it calls the appropriate libpurple init function, and libpurple tries to load a plugin, I get an error like the following:
symbol lookup error: /usr/local/lib/purple-2/autoaccept.so: undefined
symbol: purple_user_dir
purple_user_dir is a function defined in libpurple. When I build a program (not a library) that links to libpurple there are no problems. I have tried using -export-dynamic and that did not seem to help. Here is my build command:
gcc -export-dynamic -I/usr/local/include/libpurple -I/usr/include/python2.5 -DH\
AVE_CONFIG_H -I. -DSTANDALONE -DBR_PTHREADS=0 -DDATADIR=\"/usr/local/share\" -D\
LIBDIR=\"/usr/local/lib/purple-2/\" -DLOCALEDIR=\"/usr/local/share/locale\" -DS\
YSCONFDIR=\"/usr/local/etc\" -Wall -Waggregate-return -Wcast-align -Wdeclarati\
on-after-statement -Wendif-labels -Werror-implicit-function-declaration -Wextra\
-Wno-sign-compare -Wno-unused-parameter -Winit-self -Wmissing-declarations -Wm\
issing-noreturn -Wmissing-prototypes -Wpointer-arith -Wundef -Wp,-D_FORTIFY_SOU\
RCE=2 -pthread -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -I/usr/inc\
lude/dbus-1.0 -I/usr/lib/dbus-1.0/include -I/usr/include/glib-2.0 -I/usr/lib/gl\
ib-2.0/include -I/usr/include/libxml2 -g -g -O2 -c -o spurple.o spurple.c
gcc -shared -g -O2 -Wl,--export-dynamic -pthread
../../libpurple/.libs/libpurple.so -o spurple.so spurple.o
-Wl,--export-dynamic /usr/local/lib/libpurple.so
-ldbus-glib-1 -ldbus-1 /usr/lib/libgobject-2.0.so /usr/lib/libgmodule-2.0.so
-ldl /usr/lib/libgthread-2.0.so -lrt /usr/lib/libglib-2.0.so
/usr/lib/libxml2.so -lm -lpython2.5 -lutil -lpthread -lnsl -lresolv
Thanks.
I would try to use the ldd and nm unix commands to look for the symbols in the wrapper and wrapped libraries.
Just a shot in the dark, but do you have a different LD_LIBRARY_PATH environment variable when you build the app than when you run it?

Resources