I am using the latest version of gcc (7.1.0 built using https://github.com/travisg/toolchains on Ubuntu 14.04) and I have following crash if I try to use LTO with my project. The crash happens when I run liner stage: /home/anatol/sources/toolchains/x86_64-elf-7.1.0-Linux-x86_64/bin/x86_64-elf-gcc arch/x86/apic.o arch/x86/interrupt.o arch/x86/interrupt_handler.o arch/x86/mmu.o arch/x86/multiboot1.o arch/x86/pit.o arch/x86/start.o arch/x86/start_64.o arch/x86/vga_console.o core/mem.o core/printf.o core/string.o core/app.o -o out/app.elf -g -ggdb -flto -nostdlib -ffreestanding -std=c11 -fno-stack-protector -mno-red-zone -fno-common -W -Wall -Wextra -O3 -I./include -Wl,-n -Wl,--gc-sections -Wl,-Tarch/x86/linker.ld Here is the message from gcc: lto1: internal compiler error: Segmentation fault 0x994e8f crash_signal ../../gcc-7.1.0/gcc/toplev.c:337 0xb4205d streamer_get_pickled_tree(lto_input_block*, data_in*) ../../gcc-7.1.0/gcc/tree-streamer-in.c:1111 0x8785b4 lto_input_tree_1(lto_input_block*, data_in*, LTO_tags, unsigned int) ../../gcc-7.1.0/gcc/lto-streamer-in.c:1452 0x87880a lto_input_tree(lto_input_block*, data_in*) ../../gcc-7.1.0/gcc/lto-streamer-in.c:1492 0xb41e97 lto_input_ts_decl_minimal_tree_pointers ../../gcc-7.1.0/gcc/tree-streamer-in.c:695 0xb41e97 streamer_read_tree_body(lto_input_block*, data_in*, tree_node*) ../../gcc-7.1.0/gcc/tree-streamer-in.c:1051 0x877edf lto_read_tree_1 ../../gcc-7.1.0/gcc/lto-streamer-in.c:1333 0x878498 lto_read_tree ../../gcc-7.1.0/gcc/lto-streamer-in.c:1363 0x878498 lto_input_tree_1(lto_input_block*, data_in*, LTO_tags, unsigned int) ../../gcc-7.1.0/gcc/lto-streamer-in.c:1475 0x878779 lto_input_scc(lto_input_block*, data_in*, unsigned int*, unsigned int*) ../../gcc-7.1.0/gcc/lto-streamer-in.c:1387 0x5eaa3e lto_read_decls ../../gcc-7.1.0/gcc/lto/lto.c:1696 0x5ec41e lto_file_finalize ../../gcc-7.1.0/gcc/lto/lto.c:2040 0x5ec41e lto_create_files_from_ids ../../gcc-7.1.0/gcc/lto/lto.c:2050 0x5ec41e lto_file_read ../../gcc-7.1.0/gcc/lto/lto.c:2091 0x5ec41e read_cgraph_and_symbols ../../gcc-7.1.0/gcc/lto/lto.c:2803 0x5ec41e lto_main() ../../gcc-7.1.0/gcc/lto/lto.c:3308 Please submit a full bug report, with preprocessed source if appropriate. Please include the complete backtrace with any bug report. See <https://gcc.gnu.org/bugs/> for instructions. lto-wrapper: fatal error: /usr/local/google/home/anatol/sources/toolchains/x86_64-elf-7.1.0-Linux-x86_64/bin/x86_64-elf-gcc returned 1 exit status compilation terminated. /mnt/cold/sources/toolchains/x86_64-elf-7.1.0-Linux-x86_64/bin/../lib/gcc/x86_64-elf/7.1.0/../../../../x86_64-elf/bin/ld: error: lto-wrapper failed collect2: error: ld returned 1 exit status
Can you please provide info which project is affected (I guess Linux kernel). Can you help me how to reproduce that?
Created attachment 41724 [details] Reproduce lto crash with LD
Hi I indeed observe the issue in a kernel project. It is a custom x86 kernel that is not published yet. I tried to narrow down use case and I think I found how to reproduce the issue easily. It looks like a trigger pattern is: 1) compile one file as 32bit code (-m32) 2) convert it to 64bit elf object using objcopy 3) link the object above with regular 64bit elf If "-flto" is not used then linking works fine otherwise I have the crash above. Here is an attached repo case for your convenience.
(In reply to Anatol from comment #3) > Hi > > I indeed observe the issue in a kernel project. It is a custom x86 kernel > that is not published yet. > > I tried to narrow down use case and I think I found how to reproduce the > issue easily. It looks like a trigger pattern is: > > 1) compile one file as 32bit code (-m32) > 2) convert it to 64bit elf object using objcopy > 3) link the object above with regular 64bit elf > > If "-flto" is not used then linking works fine otherwise I have the crash > above. > > Here is an attached repo case for your convenience. Well how does it make sense to combine -m32 and -m64 in a single binary? Without -flto having a cross-reference: $ cat code32.c int hello(int a) { return a * a; } $ cat code64.c void main(void) { return hello(1); } One gets: $ gcc -g -ggdb -nostdlib -ffreestanding -std=c11 -fno-stack-protector -mno-red-zone -fno-common -W -Wall -Wextra -O3 code32.o code64.o -o code_bin /usr/bin/ld: warning: cannot find entry symbol _start; defaulting to 00000000004000f0 Thus without LTO it does not work.
Having 32bit preamble in 64bit code is a standard situation in x86 OS development. Bootloader (such as GRUB multiboot) leaves the system in 32bit protected mode. It is responsibility of the OS to finish 32bit initialization (where only i386 instructions can be used) and switch to 64bit code. Once 32bit initialization is done switching to 64code happens with "far jump with selector" instruction "jmp $CODE_SELECTOR, $START64" You cannot link 32bit and 64bit together (and least LD linker does not allow it). Thus one have to use a trick, either: 1) objcopy code32.o from elf32 to elf64 format 2) if code32 was an ASM code then use ".code32" GAS directive and compile file with 64bit flags. Here is an example of #2 from LK operation system https://github.com/littlekernel/lk/blob/master/arch/x86/64/start.S#L210 I tried both solution and they both work with GCC and CLANG. GCC crashes if I enable LTO for #1.
Well, if you do gcc -m32 -flto -c x.c you can't simply "objcopy" that x.o file to 64bits as objcopy doesn't know how to handle LTO bytecode. I suppose lto-wrapper could diagnose mismatched -m32/-m64 (but those are target flags). The solution is to _not_ use -flto for the 32bit bootloader part. Thus ${PREFIX}gcc -c $CFLAGS -m32 code32.c -o code32.o32 -fno-lto ${PREFIX}objcopy -O elf64-x86-64 code32.o32 code32.o