[lld] r204503 - [Mips] Emit LA25 MIPS stubs to call pic code from non-pic routines.

Simon Atanasyan simon at atanasyan.com
Fri Mar 21 12:08:02 PDT 2014


Author: atanasyan
Date: Fri Mar 21 14:08:02 2014
New Revision: 204503

URL: http://llvm.org/viewvc/llvm-project?rev=204503&view=rev
Log:
[Mips] Emit LA25 MIPS stubs to call pic code from non-pic routines.

Added:
    lld/trunk/test/elf/Mips/Inputs/ext1.s
    lld/trunk/test/elf/Mips/la25-stub.test
Modified:
    lld/trunk/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
    lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
    lld/trunk/test/elf/Mips/r26-1.test

Modified: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsELFFile.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/MipsELFFile.h?rev=204503&r1=204502&r2=204503&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsELFFile.h (original)
+++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsELFFile.h Fri Mar 21 14:08:02 2014
@@ -15,6 +15,28 @@
 namespace lld {
 namespace elf {
 
+template <class ELFT> class MipsELFFile;
+
+template <class ELFT>
+class MipsELFDefinedAtom : public ELFDefinedAtom<ELFT> {
+  typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+  typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
+
+public:
+  MipsELFDefinedAtom(const MipsELFFile<ELFT> &file, StringRef symbolName,
+                     StringRef sectionName, const Elf_Sym *symbol,
+                     const Elf_Shdr *section, ArrayRef<uint8_t> contentData,
+                     unsigned int referenceStart, unsigned int referenceEnd,
+                     std::vector<ELFReference<ELFT> *> &referenceList)
+      : ELFDefinedAtom<ELFT>(file, symbolName, sectionName, symbol, section,
+                             contentData, referenceStart, referenceEnd,
+                             referenceList) {}
+
+  const MipsELFFile<ELFT>& file() const override {
+    return static_cast<const MipsELFFile<ELFT> &>(this->_owningFile);
+  }
+};
+
 template <class ELFT> class MipsELFFile : public ELFFile<ELFT> {
 public:
   MipsELFFile(StringRef name, bool atomizeStrings)
@@ -57,10 +79,25 @@ public:
     return std::move(file);
   }
 
+  bool isPIC() const {
+    return this->_objFile->getHeader()->e_flags & llvm::ELF::EF_MIPS_PIC;
+  }
+
 private:
   typedef llvm::object::Elf_Sym_Impl<ELFT> Elf_Sym;
+  typedef llvm::object::Elf_Shdr_Impl<ELFT> Elf_Shdr;
   typedef llvm::object::Elf_Rel_Impl<ELFT, false> Elf_Rel;
 
+  ErrorOr<ELFDefinedAtom<ELFT> *> handleDefinedSymbol(
+      StringRef symName, StringRef sectionName, const Elf_Sym *sym,
+      const Elf_Shdr *sectionHdr, ArrayRef<uint8_t> contentData,
+      unsigned int referenceStart, unsigned int referenceEnd,
+      std::vector<ELFReference<ELFT> *> &referenceList) override {
+    return new (this->_readerStorage) MipsELFDefinedAtom<ELFT>(
+        *this, symName, sectionName, sym, sectionHdr, contentData,
+        referenceStart, referenceEnd, referenceList);
+  }
+
   ELFReference<ELFT> *
   createRelocationReference(const Elf_Sym &symbol, const Elf_Rel &ri,
                             ArrayRef<uint8_t> content) override {
@@ -70,15 +107,15 @@ private:
                            ri.getType(isMips64EL), ri.getSymbol(isMips64EL));
     const uint8_t *ap = content.data() + ri.r_offset - symbol.st_value;
     switch (ri.getType(isMips64EL)) {
-    case R_MIPS_32:
+      case llvm::ELF::R_MIPS_32:
       ref->setAddend(*(int32_t *)ap);
       break;
-    case R_MIPS_26:
+    case llvm::ELF::R_MIPS_26:
       ref->setAddend(*(int32_t *)ap & 0x3ffffff);
       break;
-    case R_MIPS_HI16:
-    case R_MIPS_LO16:
-    case R_MIPS_GOT16:
+    case llvm::ELF::R_MIPS_HI16:
+    case llvm::ELF::R_MIPS_LO16:
+    case llvm::ELF::R_MIPS_GOT16:
       ref->setAddend(*(int16_t *)ap);
       break;
     }

Modified: lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp?rev=204503&r1=204502&r2=204503&view=diff
==============================================================================
--- lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp (original)
+++ lld/trunk/lib/ReaderWriter/ELF/Mips/MipsRelocationPass.cpp Fri Mar 21 14:08:02 2014
@@ -11,6 +11,7 @@
 #include "MipsRelocationPass.h"
 
 #include "Atoms.h"
+#include "MipsELFFile.h"
 
 namespace {
 
@@ -44,6 +45,14 @@ const uint8_t mipsPltAAtomContent[] = {
   0x00, 0x00, 0xf8, 0x25  // addiu $24, $15, %lo(.got.plt entry)
 };
 
+// LA25 stub entry
+const uint8_t mipsLA25AtomContent[] = {
+  0x00, 0x00, 0x19, 0x3c, // lui   $25, %hi(func)
+  0x00, 0x00, 0x00, 0x08, // j     func
+  0x00, 0x00, 0x39, 0x27, // addiu $25, $25, %lo(func)
+  0x00, 0x00, 0x00, 0x00  // nop
+};
+
 /// \brief Abstract base class represent MIPS GOT entries.
 class MipsGOTAtom : public GOTAtom {
 public:
@@ -102,6 +111,16 @@ public:
   }
 };
 
+/// \brief LA25 stub atom
+class LA25Atom : public PLTAtom {
+public:
+  LA25Atom(const File &f) : PLTAtom(f, ".text") {}
+
+  ArrayRef<uint8_t> rawContent() const override {
+    return llvm::makeArrayRef(mipsLA25AtomContent);
+  }
+};
+
 class RelocationPassFile : public SimpleFile {
 public:
   RelocationPassFile(const ELFLinkingContext &ctx)
@@ -112,7 +131,7 @@ public:
   llvm::BumpPtrAllocator _alloc;
 };
 
-class RelocationPass : public Pass {
+template <typename ELFT> class RelocationPass : public Pass {
 public:
   RelocationPass(MipsLinkingContext &context);
 
@@ -144,6 +163,9 @@ private:
   /// \brief Map Atoms to their Object entries.
   llvm::DenseMap<const Atom *, ObjectAtom *> _objectMap;
 
+  /// \brief Map Atoms to their LA25 entries.
+  llvm::DenseMap<const Atom *, LA25Atom *> _la25Map;
+
   /// \brief the list of PLT atoms.
   std::vector<PLTAtom *> _pltVector;
 
@@ -153,6 +175,9 @@ private:
   /// \brief the list of Object entries.
   std::vector<ObjectAtom *> _objectVector;
 
+  /// \brief the list of LA25 entries.
+  std::vector<LA25Atom *> _la25Vector;
+
   /// \brief Handle a specific reference.
   void handleReference(Reference &ref);
 
@@ -166,20 +191,24 @@ private:
   const GOTAtom *getLocalGOTEntry(const Reference &ref);
   const GOTAtom *getGlobalGOTEntry(const Atom *a);
   const PLTAtom *getPLTEntry(const Atom *a);
+  const LA25Atom *getLA25Entry(const Atom *a);
   const ObjectAtom *getObjectEntry(const SharedLibraryAtom *a);
 
   bool isLocal(const Atom *a) const;
   bool requireLocalGOT(const Atom *a);
+  bool requireLA25Stub(const Atom *a);
   void createPLTHeader();
 };
 
-RelocationPass::RelocationPass(MipsLinkingContext &context)
+template <typename ELFT>
+RelocationPass<ELFT>::RelocationPass(MipsLinkingContext &context)
     : _context(context), _file(context) {
   _localGotVector.push_back(new (_file._alloc) GOT0Atom(_file));
   _localGotVector.push_back(new (_file._alloc) GOTModulePointerAtom(_file));
 }
 
-void RelocationPass::perform(std::unique_ptr<MutableFile> &mf) {
+template <typename ELFT>
+void RelocationPass<ELFT>::perform(std::unique_ptr<MutableFile> &mf) {
   // Process all references.
   for (const auto &atom : mf->defined()) {
     calculateAHLs(*atom);
@@ -221,6 +250,11 @@ void RelocationPass::perform(std::unique
     obj->setOrdinal(ordinal++);
     mf->addAtom(*obj);
   }
+
+  for (auto la25 : _la25Vector) {
+    la25->setOrdinal(ordinal++);
+    mf->addAtom(*la25);
+  }
 }
 
 /// \brief Calculate AHL value combines addends from 'hi' and 'lo' relocations.
@@ -230,7 +264,8 @@ inline int64_t calcAHL(int64_t AHI, int6
   return (AHI << 16) + (int16_t)ALO;
 }
 
-void RelocationPass::calculateAHLs(const DefinedAtom &atom) {
+template <typename ELFT>
+void RelocationPass<ELFT>::calculateAHLs(const DefinedAtom &atom) {
   std::vector<Reference *> references;
   for (const auto &ref : atom) {
     if (ref->kindNamespace() != lld::Reference::KindNamespace::ELF)
@@ -254,7 +289,8 @@ void RelocationPass::calculateAHLs(const
   assert(references.empty());
 }
 
-void RelocationPass::handleReference(Reference &ref) {
+template <typename ELFT>
+void RelocationPass<ELFT>::handleReference(Reference &ref) {
   if (ref.kindNamespace() != lld::Reference::KindNamespace::ELF)
     return;
   assert(ref.kindArch() == Reference::KindArch::Mips);
@@ -275,13 +311,15 @@ void RelocationPass::handleReference(Ref
   }
 }
 
-bool RelocationPass::isLocal(const Atom *a) const {
+template <typename ELFT>
+bool RelocationPass<ELFT>::isLocal(const Atom *a) const {
   if (auto *da = dyn_cast<DefinedAtom>(a))
     return da->scope() == Atom::scopeTranslationUnit;
   return false;
 }
 
-void RelocationPass::handlePlain(Reference &ref) {
+template <typename ELFT>
+void RelocationPass<ELFT>::handlePlain(Reference &ref) {
   if (!ref.target())
     return;
   auto sla = dyn_cast<SharedLibraryAtom>(ref.target());
@@ -289,22 +327,27 @@ void RelocationPass::handlePlain(Referen
     ref.setTarget(getObjectEntry(sla));
 }
 
-void RelocationPass::handlePLT(Reference &ref) {
-  if (ref.kindValue() == R_MIPS_26 && !isLocal(ref.target()))
+template <typename ELFT> void RelocationPass<ELFT>::handlePLT(Reference &ref) {
+  if (ref.kindValue() == R_MIPS_26 && !isLocal(ref.target())) {
     ref.setKindValue(LLD_R_MIPS_GLOBAL_26);
 
+    if (requireLA25Stub(ref.target()))
+      const_cast<Reference &>(ref).setTarget(getLA25Entry(ref.target()));
+  }
+
   if (isa<SharedLibraryAtom>(ref.target()))
     ref.setTarget(getPLTEntry(ref.target()));
 }
 
-void RelocationPass::handleGOT(Reference &ref) {
+template <typename ELFT> void RelocationPass<ELFT>::handleGOT(Reference &ref) {
   if (requireLocalGOT(ref.target()))
     ref.setTarget(getLocalGOTEntry(ref));
   else
     ref.setTarget(getGlobalGOTEntry(ref.target()));
 }
 
-bool RelocationPass::requireLocalGOT(const Atom *a) {
+template <typename ELFT>
+bool RelocationPass<ELFT>::requireLocalGOT(const Atom *a) {
   Atom::Scope scope;
   if (auto *da = dyn_cast<DefinedAtom>(a))
     scope = da->scope();
@@ -324,7 +367,15 @@ bool RelocationPass::requireLocalGOT(con
   return false;
 }
 
-const GOTAtom *RelocationPass::getLocalGOTEntry(const Reference &ref) {
+template <typename ELFT>
+bool RelocationPass<ELFT>::requireLA25Stub(const Atom *a) {
+  if (auto *da = dyn_cast<DefinedAtom>(a))
+    return static_cast<const MipsELFDefinedAtom<ELFT> *>(da)->file().isPIC();
+  return false;
+}
+
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getLocalGOTEntry(const Reference &ref) {
   const Atom *a = ref.target();
   LocalGotMapKeyT key(a, ref.addend());
 
@@ -351,7 +402,8 @@ const GOTAtom *RelocationPass::getLocalG
   return ga;
 }
 
-const GOTAtom *RelocationPass::getGlobalGOTEntry(const Atom *a) {
+template <typename ELFT>
+const GOTAtom *RelocationPass<ELFT>::getGlobalGOTEntry(const Atom *a) {
   auto got = _gotGlobalMap.find(a);
   if (got != _gotGlobalMap.end())
     return got->second;
@@ -374,7 +426,7 @@ const GOTAtom *RelocationPass::getGlobal
   return ga;
 }
 
-void RelocationPass::createPLTHeader() {
+template <typename ELFT> void RelocationPass<ELFT>::createPLTHeader() {
   assert(_pltVector.empty() && _gotpltVector.empty());
 
   auto pa = new (_file._alloc) PLT0Atom(_file);
@@ -400,7 +452,8 @@ void RelocationPass::createPLTHeader() {
   });
 }
 
-const PLTAtom *RelocationPass::getPLTEntry(const Atom *a) {
+template <typename ELFT>
+const PLTAtom *RelocationPass<ELFT>::getPLTEntry(const Atom *a) {
   auto plt = _pltMap.find(a);
   if (plt != _pltMap.end())
     return plt->second;
@@ -437,7 +490,32 @@ const PLTAtom *RelocationPass::getPLTEnt
   return pa;
 }
 
-const ObjectAtom *RelocationPass::getObjectEntry(const SharedLibraryAtom *a) {
+template <typename ELFT>
+const LA25Atom *RelocationPass<ELFT>::getLA25Entry(const Atom *a) {
+  auto la25 = _la25Map.find(a);
+  if (la25 != _la25Map.end())
+    return la25->second;
+
+  auto sa = new (_file._alloc) LA25Atom(_file);
+  _la25Map[a] = sa;
+  _la25Vector.push_back(sa);
+
+  // Setup reference to fixup the LA25 stub entry.
+  sa->addReferenceELF_Mips(R_MIPS_HI16, 0, a, 0);
+  sa->addReferenceELF_Mips(R_MIPS_26, 4, a, 0);
+  sa->addReferenceELF_Mips(R_MIPS_LO16, 8, a, 0);
+
+  DEBUG_WITH_TYPE("MipsGOT", {
+    sa->_name = ".pic.";
+    sa->_name += a->name();
+  });
+
+  return sa;
+}
+
+template <typename ELFT>
+const ObjectAtom *
+RelocationPass<ELFT>::getObjectEntry(const SharedLibraryAtom *a) {
   auto obj = _objectMap.find(a);
   if (obj != _objectMap.end())
     return obj->second;
@@ -460,7 +538,7 @@ lld::elf::createMipsRelocationPass(MipsL
   switch (ctx.getOutputELFType()) {
   case llvm::ELF::ET_EXEC:
   case llvm::ELF::ET_DYN:
-    return std::unique_ptr<Pass>(new RelocationPass(ctx));
+    return std::unique_ptr<Pass>(new RelocationPass<Mips32ElELFType>(ctx));
   case llvm::ELF::ET_REL:
     return std::unique_ptr<Pass>();
   default:

Added: lld/trunk/test/elf/Mips/Inputs/ext1.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/Mips/Inputs/ext1.s?rev=204503&view=auto
==============================================================================
--- lld/trunk/test/elf/Mips/Inputs/ext1.s (added)
+++ lld/trunk/test/elf/Mips/Inputs/ext1.s Fri Mar 21 14:08:02 2014
@@ -0,0 +1,39 @@
+# Assembly code defines set of externally visible labels.
+
+# Shared library generation:
+#   llvm-mc -triple=mipsel -filetype=obj -relocation-model=pic \
+#           -o=%t1 %p/Inputs/ext1.s
+#   lld -flavor gnu -target mipsel -shared -o %t2 %t1
+
+# Executable generation:
+#   llvm-mc -triple=mipsel -filetype=obj -o=%t1 %p/Inputs/ext1.s
+#   lld -flavor gnu -target mipsel -e ext4 -o %t2 %t1
+
+    .abicalls
+    .global ext4
+    .type   ext4, at function
+    .ent    ext4
+ext4:
+    nop
+    .end    ext4
+
+    .global ext5
+    .type   ext5, at function
+    .ent    ext5
+ext5:
+    nop
+    .end    ext5
+
+    .global ext6
+    .type   ext6, at function
+    .ent    ext6
+ext6:
+    nop
+    .end    ext6
+
+    .type   data4, at object
+    .comm   data4,4,4
+    .type   data5, at object
+    .comm   data5,4,4
+    .type   data6, at object
+    .comm   data6,4,4

Added: lld/trunk/test/elf/Mips/la25-stub.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/Mips/la25-stub.test?rev=204503&view=auto
==============================================================================
--- lld/trunk/test/elf/Mips/la25-stub.test (added)
+++ lld/trunk/test/elf/Mips/la25-stub.test Fri Mar 21 14:08:02 2014
@@ -0,0 +1,55 @@
+# Check LA25 stubs creation when PIC code is called from non-PIC routines.
+
+# Build executable from pic and non-pic code.
+# RUN: llvm-mc -triple=mipsel -filetype=obj -o=%t-npic-o %p/Inputs/ext.s
+# RUN: llvm-mc -triple=mipsel -filetype=obj -relocation-model=pic \
+# RUN:         -o=%t-pic-o %p/Inputs/ext1.s
+# RUN: llvm-mc -triple=mipsel -filetype=obj -o=%t-main-o %s
+# RUN: lld -flavor gnu -target mipsel -e glob -o %t-exe \
+# RUN:         %t-npic-o %t-pic-o %t-main-o
+#
+# RUN: llvm-objdump -disassemble %t-exe | FileCheck -check-prefix=EXE %s
+
+# EXE: Disassembly of section .text:
+# EXE: ext1:
+# EXE-NEXT:   400140:       00 00 00 00  nop
+
+# EXE: ext4:
+# EXE-NEXT:   40014c:       00 00 00 00  nop
+
+# EXE: glob:
+# EXE-NEXT:   400158:       09 f8 20 03  jalr    $25
+# EXE-NEXT:   40015c:       00 00 00 00  nop
+
+# Jump to 'loc' label address
+# EXE-NEXT:   400160:       5a 00 10 0c  jal     4194664
+# EXE-NEXT:   400164:       00 00 00 00  nop
+#
+# EXE: loc:
+# Jump to 'glob' non-pic symbol
+# EXE-NEXT:   400168:       56 00 10 0c  jal     4194648
+# EXE-NEXT:   40016c:       00 00 00 00  nop
+# Jump to 'ext1' non-pic symbol
+# EXE-NEXT:   400170:       50 00 10 0c  jal     4194624
+# EXE-NEXT:   400174:       00 00 00 00  nop
+# Jump to LA25 stub for 'ext4' pic symbol
+# EXE-NEXT:   400178:       60 00 10 0c  jal     4194688
+# EXE-NEXT:   40017c:       00 00 00 00  nop
+
+# LA25 Stub
+# EXE-NEXT:   400180:       40 00 19 3c  lui     $25, 64
+# Jump to 'ext4' label address
+# EXE-NEXT:   400184:       53 00 10 08  j       4194636
+# EXE-NEXT:   400188:       4c 01 39 27  addiu   $25, $25, 332
+# EXE-NEXT:   40018c:       00 00 00 00  nop
+
+    .global glob
+    .ent    glob
+glob:
+    jal     $t9
+    jal     loc
+loc:
+    jal     glob
+    jal     ext1
+    jal     ext4
+    .end    glob

Modified: lld/trunk/test/elf/Mips/r26-1.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf/Mips/r26-1.test?rev=204503&r1=204502&r2=204503&view=diff
==============================================================================
--- lld/trunk/test/elf/Mips/r26-1.test (original)
+++ lld/trunk/test/elf/Mips/r26-1.test Fri Mar 21 14:08:02 2014
@@ -61,7 +61,6 @@
 # EXE:   6 .plt          00000030 0000000000400170 TEXT DATA
 # EXE:  10 .got.plt      0000000c 0000000000402000 DATA
 
-    .abicalls
     .global glob
     .ent    glob
 glob:





More information about the llvm-commits mailing list