[llvm-bugs] [Bug 31332] New: x86_32 call through PLT for PIE and PIC results in segfault

via llvm-bugs llvm-bugs at lists.llvm.org
Fri Dec 9 08:11:45 PST 2016


https://llvm.org/bugs/show_bug.cgi?id=31332

            Bug ID: 31332
           Summary: x86_32 call through PLT for PIE and PIC results in
                    segfault
           Product: lld
           Version: unspecified
          Hardware: All
                OS: Linux
            Status: NEW
          Severity: normal
          Priority: P
         Component: ELF
          Assignee: unassignedbugs at nondot.org
          Reporter: peter.smith at linaro.org
                CC: llvm-bugs at lists.llvm.org
    Classification: Unclassified

I've spotted a couple of problems with calling through PLTs on x86_32.

The simplest way to reproduce is the canonical hello world with pie.
#include <stdio.h>
int main(void) {
  printf("hello world\n");
  return 0; 
}
With ld as the linker gcc -m32 -fpie --pie hello.c -o hello.exe
./hello.exe
Segmentation fault (core dumped)
I tested with gcc 4.9.4

I've tracked this down to two unrelated problems, the first is pie specific the
second also affects shared libraries.

The pie specific problem is simple, X86TargetInfo::writePlt() uses
Config->Shared in  write32le(Buf + 2, Config->Shared ? GotEntryAddr - Got :
GotEntryAddr); rather than Config->Pic.

The second problem is a bit more difficult. From what I can work out (I'm no
x86 expert) is that with the current implementation .got.plt must immediately
follow the .got. This is because the .got.plt slots are accessed as an offset
from the EBX register. This is set up in _start.S as 
#ifdef SHARED
    /* Load PIC register.  */
    call 1f
    addl $_GLOBAL_OFFSET_TABLE_, %ebx
        ...
#ifdef SHARED
1:    movl    (%esp), %ebx
    ret
#endif

The addl results in a R_386_GOTPC32 relocation which resolves in lld to the end
of the .got section. The assumption being that the .got can be accessed with
negative offsets from EBX and the .got.plt with positive offsets.

If the .got.plt immediately follows the .got then everything works as the
offsets in the .plt entries are from the base of .got.plt.

If the .got.plt does not immediately follow the .got then the .plt entries will
have the wrong offsets, which will likely lead to a segfault. Unfortunately lld
does not guarantee that .got.plt will immediately follow .got. In my example I
see (objdump -s)
Contents of section .got:
 20d4 6c110000 00000000 00000000 00000000  l...............
 20e4 00000000 00000000                    ........        
Contents of section .data:
 3000 00000000 04300000                    .....0..        
Contents of section .got.plt:
 3008 0c200000 00000000 00000000 86120000  . ..............
 3018 96120000 a6120000

The .data has been sorted in between the .got and .got.plt.

When I look at the .plt (I locally fixed the first problem):
00001280 <__libc_start_main at plt>:
    1280:    ff a3 0c 00 00 00        jmp    *0xc(%ebx)
    1286:    68 00 00 00 00           push   $0x0
    128b:    e9 e0 ff ff ff           jmp    1270 <_fini+0x24>

The 0xc offset would be correct if %ebx was set to the equivalent of 3008,
unfortunately .data has broken the offset so we jump to the wrong location.

It looks like it is the compareSectionsNonScript() that puts the .data in
between .got and .got.slot. As .got is RelRo and .got.plt is not we need .got
to be last of the RelRo sections and .got.plt to be first in the non RelRo
sections. 

I thought I could fix this with something by following the
getPPC64SectionRank() convention.
static int getX86SectionRank(StringRef SectionName) {
  if (!Config->ZRelro || Config->ZNow)
    return StringSwitch<int>(SectionName)
      .Case(".got", 0)
      .Case(".got.plt", 1)
      .Default(2);
  else
    return StringSwitch<int>(SectionName)
      .Case(".got", 2)
      .Case(".got.plt", 0)
      .Default(1);
}

This works as far as .got.plt follows .got, but when relro is on there is a
large alignment boundary put between .got and .got.plt. If I enable -znow the
ordering is preserved and I don't get a gap and the example works.

As far as I can tell only x86_32 is affected by this problem.

-- 
You are receiving this mail because:
You are on the CC list for the bug.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-bugs/attachments/20161209/43f69420/attachment-0001.html>


More information about the llvm-bugs mailing list