ld segfaults with LTO, static library, and memcpy
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
GNU Arm Embedded Toolchain |
New
|
Undecided
|
Unassigned |
Bug Description
Dear maintainers,
I have discovered that LD from the ARM toolchain version 7-2017-q4-major segfaults when a specific set of conditions coincide:
- A startup code that calls main() is compiled into a static library (.a)
- A main() function calls memcpy with a variable as 3rd parameter
- LTO is enabled
- A custom but trivial linker script is used
The output is:
$ make
arm-none-eabi-gcc -flto -c -o main.o main.c
arm-none-eabi-gcc -flto -c -o startup.o startup.c
arm-none-
/home/erlkoenig
arm-none-eabi-gcc -flto -o app.elf main.o startup.a -T ldscript.ld -nostartfiles
collect2: fatal error: ld terminated with signal 11 [Segmentation fault]
compilation terminated.
makefile:6: recipe for target 'app.elf' failed
make: *** [app.elf] Error 1
The problem occurs on both Windows and Linux and on different machines (Core-i3 i4010U, Xeon E5520), using both the prebuilt binary packages and a self-compiled one (see bug #1742188 ).
Attempting to compile the attached testcase (run "make") triggers the problem. The code is of course rather stupid and would not work when compiled, and is the result of reducing actually useful code to a compact example.
Thanks for looking into this!
I built debuggable toolchain, obtained a core dump and ran gdb on it:
Core was generated by `.../arm- none-eabi- ld'. 0x1545370, in_arg=0x77f540 <link_info>) at .../binutils/ bfd/elf32- arm.c:4731 >target_ section- >output_ section- >vma); 0x1545370, in_arg=0x77f540 <link_info>) at .../binutils/ bfd/elf32- arm.c:4731 one_stub> , info=0x77f540 <link_info>) at .../binutils/ bfd/hash. c:656 build_stubs (info=0x77f540 <link_info>) at ./binutils/ bfd/elf32- arm.c:6722 ld/ldemul. c:94 ld/ldlang. c:7402 b3b8) at .../binutils/ ld/ldmain. c:432 >target_ section- >output_ section
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00000000004527a3 in arm_build_one_stub (gen_entry=
4731 + stub_entry-
(gdb) bt
#0 0x00000000004527a3 in arm_build_one_stub (gen_entry=
#1 0x000000000043b7dc in bfd_hash_traverse (table=0x153c440, func=0x4525f6 <arm_build_
#2 0x0000000000456c7d in elf32_arm_
#3 0x000000000042b260 in gldarmelf_finish () at earmelf.c:517
#4 0x00000000004237ee in ldemul_finish () at .../binutils/
#5 0x00000000004193e5 in lang_process () at .../binutils/
#6 0x000000000041d52e in main (argc=23, argv=0x7ffd7f69
(gdb) print stub_entry-
$1 = (struct bfd_section *) 0x0
The code in question is:
/* This is the address of the stub destination. */ >target_ value >target_ section- >output_ offset >target_ section- >output_ section- >vma);
sym_value = (stub_entry-
+ stub_entry-
+ stub_entry-
Since stub_entry- >target_ section- >output_ section is 0, this is a classic null-pointer dereferencing bug.