[lld] r250122 - [ELF2/PPC64] Resolve local-call relocations using the correct function-descriptor values

Hal Finkel via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 12 16:16:53 PDT 2015


Author: hfinkel
Date: Mon Oct 12 18:16:53 2015
New Revision: 250122

URL: http://llvm.org/viewvc/llvm-project?rev=250122&view=rev
Log:
[ELF2/PPC64] Resolve local-call relocations using the correct function-descriptor values

Under PPC64 ELF v1 ABI, the symbols associated with each function name don't
point directly to the code in the .text section (or similar), but rather to a
function descriptor structure in a special data section named .opd. The
elements in the .opd structure include a pointer to the actual code, and a the
relevant TOC base value. Both of these are themselves set by relocations.

When we have a local call, we need the relevant relocation to refer directly to
the target code, not to the function-descriptor in the .opd section. Only when
we have a .plt stub do we care about the address of the .opd function
descriptor itself.

So we make a few changes here:

 1. Always write .opd first, so that its relocated data values are available
    for later use when writing the text sections. Record a pointer to the .opd
    structure, and its corresponding buffer.

 2. When processing a relative branch relocation under ppc64, if the
    destination points into the .opd section, read the code pointer out of the
    function descriptor structure and use that instead.

This this, I can link, and run, a dynamically-compiled "hello world"
application on big-Endian PPC64/Linux (ELF v1 ABI) using lld.

Added:
    lld/trunk/test/elf2/ppc64-rel-calls.s
Modified:
    lld/trunk/ELF/OutputSections.h
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/OutputSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/OutputSections.h?rev=250122&r1=250121&r2=250122&view=diff
==============================================================================
--- lld/trunk/ELF/OutputSections.h (original)
+++ lld/trunk/ELF/OutputSections.h Mon Oct 12 18:16:53 2015
@@ -288,6 +288,8 @@ template <class ELFT> struct Out {
   static HashTableSection<ELFT> *HashTab;
   static InterpSection<ELFT::Is64Bits> *Interp;
   static OutputSection<ELFT> *Bss;
+  static OutputSection<ELFT> *Opd;
+  static uint8_t *OpdBuf;
   static PltSection<ELFT> *Plt;
   static RelocationSection<ELFT> *RelaDyn;
   static StringTableSection<ELFT::Is64Bits> *DynStrTab;
@@ -301,6 +303,8 @@ template <class ELFT> GotSection<ELFT> *
 template <class ELFT> HashTableSection<ELFT> *Out<ELFT>::HashTab;
 template <class ELFT> InterpSection<ELFT::Is64Bits> *Out<ELFT>::Interp;
 template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Bss;
+template <class ELFT> OutputSection<ELFT> *Out<ELFT>::Opd;
+template <class ELFT> uint8_t *Out<ELFT>::OpdBuf;
 template <class ELFT> PltSection<ELFT> *Out<ELFT>::Plt;
 template <class ELFT> RelocationSection<ELFT> *Out<ELFT>::RelaDyn;
 template <class ELFT> StringTableSection<ELFT::Is64Bits> *Out<ELFT>::DynStrTab;

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=250122&r1=250121&r2=250122&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Mon Oct 12 18:16:53 2015
@@ -395,15 +395,26 @@ void PPC64TargetInfo::relocateOne(uint8_
     write32be(L, R);
     break;
   case R_PPC64_REL24: {
+    uint64_t PltStart = Out<ELF64BE>::Plt->getVA();
+    uint64_t PltEnd = PltStart + Out<ELF64BE>::Plt->getSize();
+    bool InPlt = PltStart <= S + A && S + A < PltEnd;
+
+    if (!InPlt && Out<ELF64BE>::Opd) {
+      // If this is a local call, and we currently have the address of a
+      // function-descriptor, get the underlying code address instead.
+      uint64_t OpdStart = Out<ELF64BE>::Opd->getVA();
+      uint64_t OpdEnd = OpdStart + Out<ELF64BE>::Opd->getSize();
+      bool InOpd = OpdStart <= S + A && S + A < OpdEnd;
+
+      if (InOpd)
+        R = read64be(&Out<ELF64BE>::OpdBuf[S + A - OpdStart]);
+    }
+
     uint32_t Mask = 0x03FFFFFC;
     if (!isInt<24>(R - P))
       error("Relocation R_PPC64_REL24 overflow");
     write32be(L, (read32be(L) & ~Mask) | ((R - P) & Mask));
 
-    uint64_t PltStart = Out<ELF64BE>::Plt->getVA();
-    uint64_t PltEnd = PltStart + Out<ELF64BE>::Plt->getSize();
-    bool InPlt = PltStart <= S + A && S + A < PltEnd;
-
     if (InPlt && L + 8 < BufEnd &&
         read32be(L + 4) == 0x60000000 /* nop */)
       write32be(L + 4, 0xe8410028); // ld %r2, 40(%r1)

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=250122&r1=250121&r2=250122&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Mon Oct 12 18:16:53 2015
@@ -472,6 +472,11 @@ template <class ELFT> void Writer<ELFT>:
     Out<ELFT>::StrTab->add(Sec->getName());
     Sec->finalize();
   }
+
+  // If we have a .opd section (used under PPC64 for function descriptors),
+  // store a pointer to it here so that we can use it later when processing
+  // relocations.
+  Out<ELFT>::Opd = Map.lookup({".opd", SHT_PROGBITS, SHF_WRITE | SHF_ALLOC});
 }
 
 template <class ELFT>
@@ -644,8 +649,18 @@ template <class ELFT> void Writer<ELFT>:
 // Write section contents to a mmap'ed file.
 template <class ELFT> void Writer<ELFT>::writeSections() {
   uint8_t *Buf = Buffer->getBufferStart();
+
+  // PPC64 needs to process relocations in the .opd section before processing
+  // relocations in code-containing sections.
+  for (OutputSectionBase<ELFT::Is64Bits> *&Sec : OutputSections)
+    if (Sec->getName() == ".opd") {
+      Out<ELFT>::OpdBuf = Buf + Sec->getFileOff();
+      Sec->writeTo(Buf + Sec->getFileOff());
+    }
+
   for (OutputSectionBase<ELFT::Is64Bits> *Sec : OutputSections)
-    Sec->writeTo(Buf + Sec->getFileOff());
+    if (Sec->getName() != ".opd")
+      Sec->writeTo(Buf + Sec->getFileOff());
 }
 
 template <class ELFT>

Added: lld/trunk/test/elf2/ppc64-rel-calls.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/ppc64-rel-calls.s?rev=250122&view=auto
==============================================================================
--- lld/trunk/test/elf2/ppc64-rel-calls.s (added)
+++ lld/trunk/test/elf2/ppc64-rel-calls.s Mon Oct 12 18:16:53 2015
@@ -0,0 +1,42 @@
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t
+# RUN: ld.lld2 %t -o %t2
+# RUN: llvm-objdump -d %t2 | FileCheck %s
+# REQUIRES: ppc
+
+# CHECK: Disassembly of section .text:
+
+.section        ".opd","aw"
+.global _start
+_start:
+.quad   .Lfoo,.TOC. at tocbase,0
+
+.text
+.Lfoo:
+  li      0,1
+  li      3,42
+  sc
+
+# CHECK: 10010000:       38 00 00 01     li 0, 1
+# CHECK: 10010004:       38 60 00 2a     li 3, 42
+# CHECK: 10010008:       44 00 00 02     sc
+
+.section        ".opd","aw"
+.global bar
+bar:
+.quad   .Lbar,.TOC. at tocbase,0
+
+.text
+.Lbar:
+  bl _start
+  nop
+  bl .Lfoo
+  nop
+  blr
+
+# FIXME: The printing here is misleading, the branch offset here is negative.
+# CHECK: 1001000c:       4b ff ff f5     bl .+67108852
+# CHECK: 10010010:       60 00 00 00     nop
+# CHECK: 10010014:       4b ff ff ed     bl .+67108844
+# CHECK: 10010018:       60 00 00 00     nop
+# CHECK: 1001001c:       4e 80 00 20     blr
+




More information about the llvm-commits mailing list