Symbol resolution differs when building with LTO compared to building without

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

I've come across some unexpected behavior and I'd appreciate your input on
the issue. I have an example project below that reproduces the issue. In
short, when building the project without LTO, a function will resolve to my
expected version, but when building with LTO, the symbol is resolved to a
different definition that I do not want.

Specifically, when building without LTO (which results in the behavior I
want), the final binary will pull in the definition of `_write` from my
custom static library that is listed first in the library list. With LTO
enabled (the bad case), the final binary will pull in the definition of
`_write` from libnosys, which comes later in the list of static libraries.

The output of my test project is pasted below. `make` builds without LTO
and dumping the resulting binary shows that `_write` is my stub
implementation. `LTO=1 make` builds with LTO enabled, and dumping the
resulting binary shows the implementation comes from libnosys.

How can I enable LTO in my build while providing custom definitions for
library calls (like _write)?

~/D/lto_test ❯❯❯ make

Final binary:
00008ae0 <_write>:
    8ae0: 4610       mov r0, r2
    8ae2: 4770       bx lr

~/D/lto_test ❯❯❯ make clean
~/D/lto_test ❯❯❯ LTO=1 make

Final binary:
00008b50 <_write>:
    8b50: 4b02       ldr r3, [pc, #8] ; (8b5c <_write+0xc>)
    8b52: 2258       movs r2, #88 ; 0x58
    8b54: 601a       str r2, [r3, #0]
    8b56: f04f 30ff mov.w r0, #4294967295 ; 0xffffffff
    8b5a: 4770       bx lr
    8b5c: 00018c84 .word 0x00018c84

------------------------------------------------

Toolchain version:
ARM 9-2020-q2-update (based on the 9 series)

Repro steps:
make
make clean
LTO=1 make

Repro project:

main.c
```
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[]) {
    printf("Hello.\n");
    return 0;
}
```

write.c
```
#include  <unistd.h>

ssize_t  _write (int      fd,
                 void    *p_buf,
                 size_t   cnt)
{
    return cnt;
}
```

Makefile
Note: You'll have to change the path to point to your local installation of
the ARM 2020 Q2 toolchain.
```
TOOLCHAIN=<YOUR_PATH_TO_TOOLCHAIN>
LTO_PLUGIN=$(TOOLCHAIN)/lib/gcc/arm-none-eabi/9.3.1/liblto_plugin.so

CC=$(TOOLCHAIN)/bin/arm-none-eabi-gcc
AR=$(TOOLCHAIN)/bin/arm-none-eabi-ar
DUMP=$(TOOLCHAIN)/bin/arm-none-eabi-objdump
NM=$(TOOLCHAIN)/bin/arm-none-eabi-gcc-nm

FLAGS=-g -Os -mthumb -mcpu=cortex-m4 -ffunction-sections -fdata-sections
--specs=nano.specs --specs=nosys.specs
ifeq ($(LTO),1)
FLAGS+=-flto -ffat-lto-objects
endif


.PHONY: dump
dump: main.elf _my_write.o
@echo "\n======================== Dump ========================"
@$(NM) -nS _my_write.o
@echo "\n==================== Final binary ===================="
@$(DUMP) -d $< | grep "<_write>:" -A 6
@echo "\n====================== _my_write.o ======================"
@$(DUMP) -d $(word 2,$^) | grep "<_write>:" -A 6
@echo "\n======================= libnosys ========================"
@$(DUMP) -d $(TOOLCHAIN)/arm-none-eabi/lib/thumb/v7e-m/nofp/libnosys.a |
grep "<_write>:" -A 6

main.elf: main.a _my_write.a
@$(CC) $(FLAGS)  -fuse-linker-plugin -fno-common -Wl,-Map=output.map
-Wl,--gc-sections -o $@ -Wl,--start-group $^ -lc -Wl,--end-group

%.a: %.o
@$(AR) --plugin $(LTO_PLUGIN) -rcs $@ $<

_my_write.o: ./write.c Makefile
@$(CC) $(FLAGS) -c $< -o $@

main.o: main.c Makefile
@$(CC) $(FLAGS) -c $< -o $@

.PHONY: clean
clean:
@rm -rf _write.a main.a main.elf *.res *.out *.o *.s *.map *.dump *.a
```

Once again, any insight would be greatly appreciated. My goal is to enable
LTO in my project while being able to provide custom definitions of
specific standard library calls.

Thanks in advance.

From,
AW




[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux