0

I implement a retarget.c to retarget the printf output to serial port for debugging, it can be linked and works very well, if my link command likes this:

arm-none-eabi-gcc --specs=nano.specs --specs=nosys.specs -g -mcpu=cortex-m4 -mthumb -fmessage-length=0 -std=c99 -fno-builtin -Wl,--gc-sections -Wl,-Map=main.map -T"$(LINKERFILE)" -o main.elf main.o retarget.o $(BUILDDIR)/libs.a -Wl,--start-group -lgcc -lc -lnosys -Wl,--end-group

but when I archive retarget.o into the archive file $(BUILDDIR)/libs.a, and the link command likes this one:

arm-none-eabi-gcc --specs=nano.specs --specs=nosys.specs -g -mcpu=cortex-m4 -mthumb -fmessage-length=0 -std=c99 -fno-builtin -Wl,--gc-sections -Wl,-Map=main.map -T"$(LINKERFILE)" -o main.elf main.o $(BUILDDIR)/libs.a -Wl,--start-group -lgcc -lc -lnosys -Wl,--end-group

it can be linked successfully, but the function printf doesn't output anything to the serial port, it seems that the my own version functions, such as _write in the retarget.c are not used in the final compiled program.

xingkong
  • 1
  • 3
  • What is `$(LIBSFILE)`? I guess you must convert your compiled code to a static lib or dynamic lib to do what you want to do. – LPs Jan 25 '16 at 07:14
  • Try linking your static library before or after libc and see if that changes things. I don't remember the rules for which objects and symbols get picked, but the order of the command line arguments to gcc (which you seem to be using) definitely matters. – Art Jan 25 '16 at 08:05
  • @LPs @Art Thank you for your replies, I updated my questions and replaced some macros with actual arguments. @Art, later on I removed `-Wl,--start-group -lgcc -lc -lnosys -Wl,--end-group` in the command line, then the link command like this: `arm-none-eabi-gcc --specs=nano.specs --specs=nosys.specs -g -mcpu=cortex-m4 -mthumb -fmessage-length=0 -std=c99 -fno-builtin -Wl,--gc-sections -Wl,-map=main.map -T"$(LINKERFILE)" -o main.elf main.o $(BUILDDIR)/libs.a`, but the result still the same, the function printf doesn't output anything to the serial port – xingkong Jan 26 '16 at 22:05
  • Did you try to link your lib with -l option? – LPs Jan 27 '16 at 07:24
  • @LPs, yes, anyway, I believe the `nosys.specs` forced another library was linked firstly. I believe I found the answer somewhere else, here is the link: https://sourceware.org/ml/newlib/2006/msg00036.html – xingkong Jan 30 '16 at 22:12

1 Answers1

0

Because _write is already defined in libnosys.a, included via --specs=nosys.specs

Note: The following investigation was done with ARM toolchain 9-2019-q4-major, downloaded from here.

This requires a rudimentary knowledge of spec files (About spec files)

The compiler's builtin specs can be seen with arm-none-eabi-gcc -dumpspecs (gcc -dumpspecs)

Passing --specs=nosys.specs at the beginning of the command line inserts a -lnosys in the call to ld. (What are “nosys”, “nano”, “rdimon” terms when using ARM GCC?)

arm-none-eabi-objdump -t arm-none-eabi/lib/libnosys.a | grep _write locates the _write(...) that is likely overriding the one you defined in $(BUILDDIR)/libs.a

I too am curious why .a files are treated differently from .o files in the invocation of gcc. The why seems to reside in the design of gcc and ld and still escapes me.

To use the _write symbol defined in the static library libs.a

invoke gcc with -Wl,--undefined=_write during the final linking.
(via this answer). From man ld, --undefined=symbol forces the symbol to be entered in the output file as an undefined symbol.

See also, the Makani firmware repository, in which a static library implementing syscalls marks them as --undefined (Generation of linker options)