[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