[PATCH] D13566: [ELF2] PPC64 needs to delay local-call relocations until after the function-descriptor values are known

hfinkel@anl.gov via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 8 10:35:03 PDT 2015


hfinkel created this revision.
hfinkel added reviewers: ruiu, rafael.
hfinkel added a subscriber: llvm-commits.
hfinkel added a project: lld.

I've separated this into a separate patch because it brings up a design question (which we might wish to solve as I've done here, or we might wish to solve in a completely different way).

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.

We don't process relocations for the .opd section until after we process the code sections, and so when we're processing the relocation for a local call, we don't yet know the address of that call. We know the address of its function descriptor, but won't know the value in the descriptor until after we process relocations for the .opd section.

Here we store a vector of lambda function for each function descriptor, allowing us to go back and process the call relocations for local functions once the function-descriptor values are known.

Obviously still missing test cases, but feedback is certainly appreciated.

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


http://reviews.llvm.org/D13566

Files:
  ELF/Target.cpp

Index: ELF/Target.cpp
===================================================================
--- ELF/Target.cpp
+++ ELF/Target.cpp
@@ -13,6 +13,7 @@
 #include "Symbols.h"
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseMap.h"
 #include "llvm/Object/ELF.h"
 #include "llvm/Support/Endian.h"
 #include "llvm/Support/ELF.h"
@@ -319,6 +320,8 @@
                                   const void *RelP, uint32_t Type,
                                   uint64_t BaseAddr, uint64_t SymVA,
                                   uint64_t GotVA, bool ForPltEntry) const {
+  static DenseMap<uint64_t, std::vector<std::function<void(uint64_t)>>> DelayedRelocs;
+
   typedef ELFFile<ELF64BE>::Elf_Rela Elf_Rela;
   auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
   int64_t Addend = Rel.r_addend;
@@ -428,16 +431,29 @@
     write32be(Loc, Result);
   } break;
   case R_PPC64_REL24: {
-    uint64_t FinalAddress = (BaseAddr + Offset);
-    int32_t delta = static_cast<int32_t>(SymVA - FinalAddress + Addend);
-    uint32_t Mask = 0x03FFFFFC;
-    if (SignExtend32<24>(delta) != delta)
-      error("Relocation R_PPC64_REL24 overflow");
-    write32be(Loc, (read32be(Loc) & ~Mask) | (delta & Mask));
-
-    if (ForPltEntry && Loc + 8 < BufEnd &&
-        read32be(Loc + 4) == 0x60000000 /* nop */)
-      write32be(Loc + 4, 0xe8410028); // ld r2,40(r1)
+    auto ApplyReloc = [=](uint64_t SymVAPlusAddend) {
+      uint64_t FinalAddress = (BaseAddr + Offset);
+      int32_t delta = static_cast<int32_t>(SymVAPlusAddend - FinalAddress);
+      uint32_t Mask = 0x03FFFFFC;
+      if (SignExtend32<24>(delta) != delta)
+        error("Relocation R_PPC64_REL24 overflow");
+      write32be(Loc, (read32be(Loc) & ~Mask) | (delta & Mask));
+
+      if (ForPltEntry && Loc + 8 < BufEnd &&
+          read32be(Loc + 4) == 0x60000000 /* nop */)
+        write32be(Loc + 4, 0xe8410028); // ld r2,40(r1)
+    };
+
+    if (ForPltEntry) {
+      ApplyReloc(SymVA + Addend);
+    } else {
+      // This is a branch to a local symbol, but we cannot yet resolve it. The
+      // address provided here is that of the function's descriptor in the .opd
+      // section. We need to branch, however, to the address that will appear in
+      // the .opd section, but we won't know what that is until we process
+      // relocations in that section.
+      DelayedRelocs[SymVA + Addend].push_back(ApplyReloc);
+    }
   } break;
   case R_PPC64_REL32: {
     uint64_t FinalAddress = (BaseAddr + Offset);
@@ -451,9 +467,17 @@
     uint64_t Delta = SymVA - FinalAddress + Addend;
     write64be(Loc, Delta);
   } break;
-  case R_PPC64_ADDR64:
+  case R_PPC64_ADDR64: {
     write64be(Loc, SymVA + Addend);
-    break;
+
+    // We might be processing the relocation for a function descriptor, and if
+    // so, we can now go back and fill in this value for local call sites as
+    // well.
+    auto DRI = DelayedRelocs.find(BaseAddr + Offset);
+    if (DRI != DelayedRelocs.end())
+      for (auto &DR : DRI->second)
+        DR(SymVA + Addend);
+  } break;
   default:
     error(Twine("unrecognized reloc ") + Twine(Type));
     break;


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D13566.36875.patch
Type: text/x-patch
Size: 3121 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20151008/98e724c4/attachment.bin>


More information about the llvm-commits mailing list