简体   繁体   中英

How to include syscalls.c from a separate library file?

My code includes indirect calls to functions like _write() and _sbrk() . Within the project I have a file called syscalls.c that defines my custom implementations of these functions, and the compiler/linker finds this file, and links to the functions correctly when I run make. The compile line make creates looks something like this:

arm-none-eabi-gcc -nostartfiles -mcpu=arm7tdmi -Wl,--gc-sections -Wl,--cref  -L../hardware_drivers/lib -L../framework/lib -T../linker-script.lds -Wl,-Map,./build/bin/Mapfile.map -o build/bin/Elffile.elf ./build/obj/Main.o ./build/obj/SomeCode.o ./build/obj/syscalls.o -Wl,--start-group -lhardware_drivers -lframework -Wl,--end-group

This works perfectly. However, I want to move syscalls.c to the hardware_drivers project that I have, so they should be included in the libharware_drivers.a file that gets created when I compile hardware_drivers, and included by the gcc line above. Moving the file and recompiling all my projects does include my syscalls.c in the .a file (shown using arm-none-eabi-ar ). However, when it comes to compile my top level project, I get this error:

../../arm-none-eabi/lib/libc.a(lib_a-fstatr.o): In function `_fstat_r':
fstatr.c:(.text._fstat_r+0x1c): undefined reference to `_fstat'

I'm using arm-none-eabi-gcc v4.8 from code sourcery and I'm compiling it for a AT91SAM7A1 chip, if that has any relevance.

Is there something special you need to do to point the linker to syscalls when it's in a separate library file?

You use,

  1. -nostartfiles
  2. You create a file with _fstat in libhardware_drivers.a
  3. You use some code with _fstat_r calling ../../arm-none-eabi/lib/libc.a(lib_a-fstatr.o)

Here is the error message,

../../arm-none-eabi/lib/libc.a(lib_a-fstatr.o): In function '_fstat_r': fstatr.c:(.text._fstat_r+0x1c): undefined reference to '_fstat'

You can try to find the code which uses the _fstat_r from a map file or with -nodefaultlibs or -nostdlibs . The issue is that libraries are resolved in a first to last order. You have an implicit -lc at the end of your linker list. If you intend to use the the 'C' library, then you must alter your linker command to position libhardware_drivers.a later in the link.

For example,

arm-none-eabi-gcc -nostartfiles -mcpu=arm7tdmi -Wl,--gc-sections -Wl,--cref\
 -L../hardware_drivers/lib -L../framework/lib -T../linker-script.lds \
 -Wl,-Map,./build/bin/Mapfile.map -o build/bin/Elffile.elf ./build/obj/Main.o\
 ./build/obj/SomeCode.o ./build/obj/syscalls.o \
 -Wl,--start-group -lc -lhardware_drivers -lframework -Wl,--end-group

Here, a -lc is placed before -lhardware_drivers . This will let the linker resolve the lib_a-fstatr.o reference to _fstat in your syscall.o . Another way is to force some synthetic reference earlier in another object file (like Main.o ). A macro can force the link,

#define FORCE_LINK(x) void* __ ## x ## _force_link =(void*)&x
FORCE_LINK(fstat);

Most likely you have circular references in your static libraries. Ie, hardware_drivers refers to framework refers to libc (and libc refers back to hardware_drivers to make things work). Methods to overcome this are to list the libraries multiple times on the command line or restructure your code which is probably better long term.

The restructure is as simple as a separate libsyscall.a , which is listed after -lc .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM