[ forwarded from https://launchpad.net/bugs/663294 ] seen with the 2.21 branch and trunk, not seen when using gold (2.21 branch) as the linker. The original issue was seen with a firefox build. Report from Chris Coulson: The information that is wrong in the final executable isn't coming from the compiler, but is added by the linker (although the relocations in the .rel.text section are coming from the compiler). So, I did two builds of Firefox again - 1 with gcc-4.5 and 1 with gcc-4.4 to compare the jemalloc.o objects. There is one obvious difference - gcc-4.4 outputs an object using global-dynamic TLS (I see lots of R_386_TLS_GD relocations .rel.text where arenas_map is accessed), and gcc-4.5 seems to be outputting an object with local-dynamic TLS access model (I see lots of R_386_TLS_LDM and R_386_TLS_LDO_32 relocations). So, I've managed to write a small reproducer now: #include <stdlib.h> #include <stdio.h> static __thread int a; static int *c; int main(int argc, char *argv[]) { a = 2; c = &a; printf("c=%d\n", *c); } You can save this as test.c and compile in various ways: - "gcc -o test -fPIC test.c" - This generates an intermediate object with global-dynamic TLS (you can verify this if you split the compile/link steps and inspect the resulting object with readelf) which is passed to the linker, and works properly - "gcc -o test -fPIC -pie test.c" - This generates a pie which works correctly - "gcc -o test -ftls-model=local-dynamic -fPIC test.c" - This generates an intermediate object with local-dynamic TLS (again, verified by splitting the compile/link steps and inspecting the object with readelf), and the linker generates a working binary - "gcc -o test -ftls-model=local-dynamic -fPIC -pie test.c" - The resulting binary crashes, and inspecting the resulting binary shows the same issue we have with Firefox (it's accessing the wrong location where it should be accessing the TLS variable) Disassembling main from the broken binary shows: 000005ac <main>: 5ac: 55 push %ebp 5ad: 89 e5 mov %esp,%ebp 5af: 83 e4 f0 and $0xfffffff0,%esp 5b2: 56 push %esi 5b3: 53 push %ebx 5b4: 83 ec 18 sub $0x18,%esp 5b7: e8 eb ff ff ff call 5a7 <__i686.get_pc_thunk.bx> 5bc: 81 c3 38 1a 00 00 add $0x1a38,%ebx 5c2: 65 a1 00 00 00 00 mov %gs:0x0,%eax 5c8: 90 nop 5c9: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi 5cd: 89 c6 mov %eax,%esi 5cf: 8d 05 00 00 00 00 lea 0x0,%eax 5d5: 8d 04 06 lea (%esi,%eax,1),%eax 5d8: c7 00 02 00 00 00 movl $0x2,(%eax) 5de: 65 a1 00 00 00 00 mov %gs:0x0,%eax 5e4: 90 nop 5e5: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi 5e9: 89 c6 mov %eax,%esi 5eb: 8d 05 00 00 00 00 lea 0x0,%eax 5f1: 8d 04 06 lea (%esi,%eax,1),%eax 5f4: 89 83 30 00 00 00 mov %eax,0x30(%ebx) 5fa: 8b 83 30 00 00 00 mov 0x30(%ebx),%eax 600: 8b 10 mov (%eax),%edx 602: 8d 83 f8 e6 ff ff lea -0x1908(%ebx),%eax 608: 89 54 24 04 mov %edx,0x4(%esp) 60c: 89 04 24 mov %eax,(%esp) 60f: e8 70 fe ff ff call 484 <printf@plt> 614: 83 c4 18 add $0x18,%esp 617: 5b pop %ebx 618: 5e pop %esi 619: 89 ec mov %ebp,%esp 61b: 5d pop %ebp 61c: c3 ret 61d: 90 nop 61e: 90 nop 61f: 90 nop And from the working binary: 08048454 <main>: 8048454: 55 push %ebp 8048455: 89 e5 mov %esp,%ebp 8048457: 83 e4 f0 and $0xfffffff0,%esp 804845a: 56 push %esi 804845b: 53 push %ebx 804845c: 83 ec 18 sub $0x18,%esp 804845f: e8 61 00 00 00 call 80484c5 <__i686.get_pc_thunk.bx> 8048464: 81 c3 90 1b 00 00 add $0x1b90,%ebx 804846a: 65 a1 00 00 00 00 mov %gs:0x0,%eax 8048470: 90 nop 8048471: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi 8048475: 89 c6 mov %eax,%esi 8048477: 8d 05 fc ff ff ff lea 0xfffffffc,%eax 804847d: 8d 04 06 lea (%esi,%eax,1),%eax 8048480: c7 00 02 00 00 00 movl $0x2,(%eax) 8048486: 65 a1 00 00 00 00 mov %gs:0x0,%eax 804848c: 90 nop 804848d: 8d 74 26 00 lea 0x0(%esi,%eiz,1),%esi 8048491: 89 c6 mov %eax,%esi 8048493: 8d 05 fc ff ff ff lea 0xfffffffc,%eax 8048499: 8d 04 06 lea (%esi,%eax,1),%eax 804849c: 89 83 2c 00 00 00 mov %eax,0x2c(%ebx) 80484a2: 8b 83 2c 00 00 00 mov 0x2c(%ebx),%eax 80484a8: 8b 10 mov (%eax),%edx 80484aa: 8d 83 9c e5 ff ff lea -0x1a64(%ebx),%eax 80484b0: 89 54 24 04 mov %edx,0x4(%esp) 80484b4: 89 04 24 mov %eax,(%esp) 80484b7: e8 c8 fe ff ff call 8048384 <printf@plt> 80484bc: 83 c4 18 add $0x18,%esp 80484bf: 5b pop %ebx 80484c0: 5e pop %esi 80484c1: 89 ec mov %ebp,%esp 80484c3: 5d pop %ebp 80484c4: c3 ret Note, the broken (pie) binary shows: 5eb: 8d 05 00 00 00 00 lea 0x0,%eax ...where, the working (non pie) binary shows: 8048493: 8d 05 fc ff ff ff lea 0xfffffffc,%eax Note, I just hacked the intermediate test.o object and inserted 4 bytes of garbage from offset 0x25 from the start of the .text section (which is where the linker applies a R_386_TLS_LDO_32 relocation, and seems to be the one which isn't applied correctly). Then I ran the linker on it, and confirmed that the relocation is actually applied incorrectly (rather than not being applied at all), as the garbage i inserted in to the intermediate object was overwritten. So, it just seems to be that R_386_TLS_LDO_32 relocations aren't handled properly with -pie
The code in elf_i386_relocate_section for R_386_TLS_LDO_32 checks info->shared where it should probably check !info->executable.
(In reply to comment #1) > The code in elf_i386_relocate_section for R_386_TLS_LDO_32 checks info->shared > where it should probably check !info->executable. Thanks, Ian. I will check in a fix soon.
CVSROOT: /cvs/src Module name: src Changes by: hjl@sourceware.org 2011-04-08 16:14:49 Modified files: bfd : ChangeLog elf32-i386.c ld/testsuite : ChangeLog ld/testsuite/ld-i386: i386.exp Added files: ld/testsuite/ld-i386: tlspie2.d tlspie2.s Log message: Properly handle R_386_TLS_LDO_32 for PIE. bfd/ 2011-04-08 H.J. Lu <hongjiu.lu@intel.com> PR ld/12654 * elf32-i386.c (elf_i386_relocate_section): Check !executable instead of shared for R_386_TLS_LDO_32. ld/testsuite/ 2011-04-08 H.J. Lu <hongjiu.lu@intel.com> PR ld/12654 * ld-i386/i386.exp: Run tlspie2. * ld-i386/tlspie2.d: New. * ld-i386/tlspie2.s: Likewise. Patches: http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/ChangeLog.diff?cvsroot=src&r1=1.5293&r2=1.5294 http://sourceware.org/cgi-bin/cvsweb.cgi/src/bfd/elf32-i386.c.diff?cvsroot=src&r1=1.243&r2=1.244 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ChangeLog.diff?cvsroot=src&r1=1.1382&r2=1.1383 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-i386/tlspie2.d.diff?cvsroot=src&r1=NONE&r2=1.1 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-i386/tlspie2.s.diff?cvsroot=src&r1=NONE&r2=1.1 http://sourceware.org/cgi-bin/cvsweb.cgi/src/ld/testsuite/ld-i386/i386.exp.diff?cvsroot=src&r1=1.36&r2=1.37
Fixed.
Thanks! That does the trick, and I have a working -pie build of firefox now too