Bug 81342 - LTO: lto1: internal compiler error: Segmentation fault
Summary: LTO: lto1: internal compiler error: Segmentation fault
Status: RESOLVED INVALID
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 7.1.0
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: lto
Depends on:
Blocks:
 
Reported: 2017-07-06 16:58 UTC by Anatol
Modified: 2017-07-17 09:07 UTC (History)
1 user (show)

See Also:
Host: x86_64
Target: x86_64
Build:
Known to work:
Known to fail:
Last reconfirmed: 2017-07-11 00:00:00


Attachments
Reproduce lto crash with LD (471 bytes, application/x-tar)
2017-07-11 21:35 UTC, Anatol
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Anatol 2017-07-06 16:58:44 UTC
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
Comment 1 Martin Liška 2017-07-11 10:24:35 UTC
Can you please provide info which project is affected (I guess Linux kernel). Can you help me how to reproduce that?
Comment 2 Anatol 2017-07-11 21:35:26 UTC
Created attachment 41724 [details]
Reproduce lto crash with LD
Comment 3 Anatol 2017-07-11 21:35:51 UTC
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.
Comment 4 Martin Liška 2017-07-13 08:25:15 UTC
(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.
Comment 5 Anatol 2017-07-13 13:28:12 UTC
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.
Comment 6 Richard Biener 2017-07-17 09:07:49 UTC
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