[llvm-bugs] [Bug 31716] New: FreeBSD's 3.9.1 lld: Powerpc64: code in .plt expects function descriptor layout but .got.plt space it uses does not have such

via llvm-bugs llvm-bugs at lists.llvm.org
Sat Jan 21 11:56:39 PST 2017


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

            Bug ID: 31716
           Summary: FreeBSD's 3.9.1 lld: Powerpc64: code in .plt expects
                    function descriptor layout but .got.plt space it uses
                    does not have such
           Product: lld
           Version: unspecified
          Hardware: Macintosh
                OS: FreeBSD
            Status: NEW
          Severity: normal
          Priority: P
         Component: ELF
          Assignee: unassignedbugs at nondot.org
          Reporter: markmi at dsl-only.net
                CC: llvm-bugs at lists.llvm.org
    Classification: Unclassified

powerpc64 context for:

# more main.c
static volatile char big_area[67001] = "This is a test";

int main ()
{
    big_area[67000] = '9';
}

via:

clang -fuse-ld=lld -g main.c

The code that is put in the .plt that does not
match the .got.plt layout used (expecting function
descriptors when there are only single addresses per
function as a .got.plt entry) is:

void PPC64TargetInfo::writePlt(uint8_t *Buf, uint64_t GotEntryAddr,
                             uint64_t PltEntryAddr, int32_t Index,
                             unsigned RelOff) const {
uint64_t Off = GotEntryAddr - getPPC64TocBase();

// FIXME: What we should do, in theory, is get the offset of the function
// descriptor in the .opd section, and use that as the offset from %r2 (the
// TOC-base pointer). Instead, we have the GOT-entry offset, and that will
// be a pointer to the function descriptor in the .opd section. Using
// this scheme is simpler, but requires an extra indirection per PLT dispatch.

write32be(Buf,      0xf8410028);                   // std %r2, 40(%r1)
write32be(Buf + 4,  0x3d620000 | applyPPCHa(Off)); // addis %r11, %r2, X at ha
write32be(Buf + 8,  0xe98b0000 | applyPPCLo(Off)); // ld %r12, X at l(%r11)
write32be(Buf + 12, 0xe96c0000);                   // ld %r11,0(%r12)
write32be(Buf + 16, 0x7d6903a6);                   // mtctr %r11
write32be(Buf + 20, 0xe84c0008);                   // ld %r2,8(%r12)
write32be(Buf + 24, 0xe96c0010);                   // ld %r11,16(%r12)
write32be(Buf + 28, 0x4e800420);                   // bctr
}

But what ld.lld generated for relocation was:

Relocation section with addend (.rela.plt):
r_offset     r_info       r_type              st_value         st_name +
r_addend
000010030038 000300000015 R_PPC64_JMP_SLOT    0000000000000000 atexit + 0
000010030040 000200000015 R_PPC64_JMP_SLOT    0000000000000000 _init_tls + 0
000010030048 000500000015 R_PPC64_JMP_SLOT    0000000000000000 exit + 0

These r_offset's are in the .got.plt area, not in the .plt area:

    0x0000000010030020 - 0x0000000010030050 is .got.plt

The increment is 0x8 between entries, not 0x18 (or more) that
would be needed for function descriptors: There is no
function descriptor space here.

It looks like the other side of this that is not establishing
space for function descriptors is in the code in:

/usr/src/contrib/llvm/tools/lld/ELF/Relocations.cpp

in its scanRelocs :

   // At this point we are done with the relocated position. Some relocations
   // also require us to create a got or plt entry.

   // If a relocation needs PLT, we create a PLT and a GOT slot for the symbol.
   if (needsPlt(Expr)) {
     if (Body.isInPlt())
       continue;
     Out<ELFT>::Plt->addEntry(Body);

     uint32_t Rel;
     if (Body.isGnuIFunc() && !Preemptible)
       Rel = Target->IRelativeRel;
     else
       Rel = Target->PltRel;

     Out<ELFT>::GotPlt->addEntry(Body);
     Out<ELFT>::RelaPlt->addReloc({Rel, Out<ELFT>::GotPlt,
                                   Body.getGotPltOffset<ELFT>(), !Preemptible,
                                   &Body, 0});
     continue;
   }

The code is explicitly targeting creating GotPlt space, not
.opd space, as well., not matching the earlier comment in
PPC64TargetInfo::writePlt .

The effect of such code and the wrtPlt code need to be
correctly matching but currently are not.

For ld.lld's a.out its .plt (not .got.plt) is code,
unlike in the ld.bfd generated a.out:

Disassembly of section .plt:
0000000010010550 <.plt> std     r2,40(r1)
0000000010010554 <.plt+0x4> addis   r11,r2,0
0000000010010558 <.plt+0x8> ld      r12,32512(r11) Note: r12==0x000010030038
results
000000001001055c <.plt+0xc> ld      r11,0(r12)
0000000010010560 <.plt+0x10> mtctr   r11
0000000010010564 <.plt+0x14> ld      r2,8(r12)     Note: accesses
0x000010030040 see .plt+0x28
0000000010010568 <.plt+0x18> ld      r11,16(r12)   Note: accesses
0x000010030048 see .plt+0x48
000000001001056c <.plt+0x1c> bctr

Note: The code expects 0(12), 8(12), and 16(r12) storage
but not such structure is present: 8(r12) above is
equivalent to 0(r12) below as an example.

0000000010010570 <.plt+0x20> std     r2,40(r1)
0000000010010574 <.plt+0x24> addis   r11,r2,0
0000000010010578 <.plt+0x28> ld      r12,32520(r11) Note: r12==0x000010030040
results
000000001001057c <.plt+0x2c> ld      r11,0(r12)
0000000010010580 <.plt+0x30> mtctr   r11
0000000010010584 <.plt+0x34> ld      r2,8(r12)      Note: accesses
0x000010030048 see .plt+0x48
0000000010010588 <.plt+0x38> ld      r11,16(r12)    Note: accesses
0x000010030050
000000001001058c <.plt+0x3c> bctr

Note: 0x000010030050 is from:

    0x0000000010030050 - 0x00000000100300a0 is .toc

0000000010010590 <.plt+0x40> std     r2,40(r1)
0000000010010594 <.plt+0x44> addis   r11,r2,0
0000000010010598 <.plt+0x48> ld      r12,32528(r11) Note: r12==0x000010030048
results
000000001001059c <.plt+0x4c> ld      r11,0(r12)
00000000100105a0 <.plt+0x50> mtctr   r11
00000000100105a4 <.plt+0x54> ld      r2,8(r12)      Note: accesses
0x000010030050
00000000100105a8 <.plt+0x58> ld      r11,16(r12)    Note: accesses
0x000010030058
00000000100105ac <.plt+0x5c> bctr

Note: 0x000010030050 and 0x000010030058 are from:

    0x0000000010030050 - 0x00000000100300a0 is .toc

Either the .got.plt entry layout changes to have room
for 8(r12) and 16(r12) positions (size change to 0x18
Bytes per entry) or this code (and possibly other
code) changes --presuming .got.plt style is used at
all. (I've not found any powerpc family documentation
for .got.plt use: No such powerpc64 ABI yet?)

By contrast the -fuse-ld=bfd ends up with:

Relocation section with addend (.rela.plt):
r_offset     r_info       r_type              st_value         st_name +
r_addend
0000100218b0 000300000015 R_PPC64_JMP_SLOT    0000000000000000 atexit + 0
0000100218c8 000400000015 R_PPC64_JMP_SLOT    0000000000000000 _init_tls + 0
0000100218e0 000600000015 R_PPC64_JMP_SLOT    0000000000000000 exit + 0

is an increment of 0x18 between entries (room for the
function descriptors). The r_offset's are from the
ld.bfd generated .plt section:

    0x0000000010021898 - 0x00000000100218f8 is .plt

NOTE: For the FreeBSD ld.bfd context the .plt does not have
blocks of code for such, just the function descriptors.

-- 
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/20170121/e88e4c91/attachment.html>


More information about the llvm-bugs mailing list