I'm building a kernel for a Rapsberry Pi 2 with -flto. Most of the code will be linked to 0x8000xxxx. The kernel image will be loaded to 0x8000 and I have set up LMA and VMA in my linker script accordingly. But I have some bootstrap code (boot.S and early.cc) that needs to at the physical address. So I put the following in my linker script: ENTRY(_start) PHYS_TO_VIRT = 0x80000000; SECTIONS { . = 0x8000; .early : { boot.o(.*) early.o(.*) } /* rest of the code runs in higher half virtual address */ . = . + PHYS_TO_VIRT; .text : AT(ADDR(.text) - PHYS_TO_VIRT) { ... Using objdump -d I see the boot.o contents show up at 0x8000 exactly as it should. But all the code from early.o only appears later in the .text section and at the virtual adress. If I drop the -flto then everything works as expected. It would be nice if -flto could preserve which file each function and variable comes from so the linker can place them properly.
You could use -fno-lto when compiling early.cc.
As long as it's only one C/C++ file that works. But if one has multiple files then -fno-lto would optimize less. I was thinking of a more general case than mine.
LTO doesn't know about linker scripts and their effects (see other related bugreports). For your case LTO partitioning might simply tear boot.o and early.o apart and put parts in differen LTRANS units. I don't see any way to fix this but to teach WPA to parse linker scripts and guide partitioning. That means basically a WONTFIX with the known workaround to compile boot.o and early.o without -flto. Another workaround that might work is to use -flto-partition=1to1 (but the filenames will still get wrong I think).