forked from OSchip/llvm-project
[ELF][Hexagon] add initial changes to add GOT/PLT
llvm-svn: 176415
This commit is contained in:
parent
de6a39f759
commit
1729e12358
|
@ -0,0 +1,82 @@
|
|||
//===- lib/ReaderWriter/ELF/Hexagon/HexagonDynamicAtoms.h -----------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_ELF_HEXAGON_DYNAMIC_ATOMS_H
|
||||
#define LLD_READER_WRITER_ELF_HEXAGON_DYNAMIC_ATOMS_H
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "HexagonTargetInfo.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
class HexagonGOTAtom : public GOTAtom {
|
||||
static const uint8_t _defaultContent[8];
|
||||
|
||||
public:
|
||||
HexagonGOTAtom(const File &f, StringRef secName)
|
||||
: GOTAtom(f, secName) {
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
return ArrayRef<uint8_t>(_defaultContent, 8);
|
||||
}
|
||||
};
|
||||
|
||||
const uint8_t HexagonGOTAtom::_defaultContent[8] = { 0 };
|
||||
|
||||
class HexagonPLTAtom : public PLTAtom {
|
||||
static const uint8_t _defaultContent[16];
|
||||
|
||||
public:
|
||||
HexagonPLTAtom(const File &f, StringRef secName)
|
||||
: PLTAtom(f, secName) {
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
return ArrayRef<uint8_t>(_defaultContent, 16);
|
||||
}
|
||||
};
|
||||
|
||||
const uint8_t HexagonPLTAtom::_defaultContent[16] = {
|
||||
0x00, 0x40, 0x00, 0x00, // { immext (#0)
|
||||
0x0e, 0xc0, 0x49, 0x6a, // r14 = add (pc, ##GOTn@PCREL) } # address of GOTn
|
||||
0x1c, 0xc0, 0x8e, 0x91, // r28 = memw (r14) # contents of GOTn
|
||||
0x00, 0xc0, 0x9c, 0x52, // jumpr r28 # call it
|
||||
};
|
||||
|
||||
class HexagonPLT0Atom : public PLT0Atom {
|
||||
static const uint8_t _plt0Content[28];
|
||||
|
||||
public:
|
||||
HexagonPLT0Atom(const File &f) : PLT0Atom(f) {
|
||||
#ifndef NDEBUG
|
||||
_name = ".PLT0";
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual ArrayRef<uint8_t> rawContent() const {
|
||||
return ArrayRef<uint8_t>(_plt0Content, 28);
|
||||
}
|
||||
};
|
||||
|
||||
const uint8_t HexagonPLT0Atom::_plt0Content[28] = {
|
||||
0x00, 0x40, 0x00, 0x00, // { immext (#0)
|
||||
0x1c, 0xc0, 0x49, 0x6a, // r28 = add (pc, ##GOT0@PCREL) } # address of GOT0
|
||||
0x0e, 0x42, 0x9c, 0xe2, // { r14 -= add (r28, #16) # offset of GOTn from GOTa
|
||||
0x4f, 0x40, 0x9c, 0x91, // r15 = memw (r28 + #8) # object ID at GOT2
|
||||
0x3c, 0xc0, 0x9c, 0x91, // r28 = memw (r28 + #4) }# dynamic link at GOT1
|
||||
0x0e, 0x42, 0x0e, 0x8c, // { r14 = asr (r14, #2) # index of PLTn
|
||||
0x00, 0xc0, 0x9c, 0x52, // jumpr r28 } # call dynamic linker
|
||||
};
|
||||
|
||||
} // elf
|
||||
} // lld
|
||||
|
||||
#endif // LLD_READER_WRITER_ELF_HEXAGON_DYNAMIC_ATOMS_H
|
|
@ -97,6 +97,16 @@ int relocHexBNPCRELX(uint8_t *location, uint64_t P, uint64_t S, uint64_t A,
|
|||
return 1;
|
||||
}
|
||||
|
||||
// R_HEX_6_PCREL_X
|
||||
int relocHex6PCRELX(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
|
||||
int32_t result = (S + A - P);
|
||||
result = lld::scatterBits<int32_t>(result, FINDV4BITMASK(location));
|
||||
*reinterpret_cast<llvm::support::ulittle32_t *>(location) =
|
||||
result |
|
||||
(uint32_t) * reinterpret_cast<llvm::support::ulittle32_t *>(location);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// R_HEX_N_X : Word32_U6 : (S + A) : Unsigned Truncate
|
||||
int relocHex_N_X(uint8_t *location, uint64_t P, uint64_t S, uint64_t A) {
|
||||
uint32_t result = (S + A);
|
||||
|
@ -197,6 +207,11 @@ ErrorOr<void> HexagonTargetRelocationHandler::applyRelocation(
|
|||
case R_HEX_6_X:
|
||||
relocHex_N_X(location, relocVAddress, targetVAddress, ref.addend());
|
||||
break;
|
||||
case R_HEX_6_PCREL_X:
|
||||
relocHex6PCRELX(location, relocVAddress, targetVAddress, ref.addend());
|
||||
break;
|
||||
case R_HEX_JMP_SLOT:
|
||||
break;
|
||||
case lld::Reference::kindLayoutAfter:
|
||||
case lld::Reference::kindLayoutBefore:
|
||||
case lld::Reference::kindInGroup:
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "HexagonDynamicAtoms.h"
|
||||
#include "HexagonTargetHandler.h"
|
||||
#include "HexagonTargetInfo.h"
|
||||
|
||||
|
@ -19,3 +20,158 @@ HexagonTargetHandler::HexagonTargetHandler(HexagonTargetInfo &targetInfo)
|
|||
: DefaultTargetHandler(targetInfo), _targetLayout(targetInfo),
|
||||
_relocationHandler(targetInfo, _targetLayout),
|
||||
_hexagonRuntimeFile(targetInfo) {}
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace llvm::ELF;
|
||||
|
||||
class ELFPassFile : public SimpleFile {
|
||||
public:
|
||||
ELFPassFile(const ELFTargetInfo &eti) : SimpleFile(eti, "ELFPassFile") {}
|
||||
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
/// \brief Create GOT and PLT entries for relocations. Handles standard GOT/PLT
|
||||
template <class Derived> class GOTPLTPass : public Pass {
|
||||
/// \brief Handle a specific reference.
|
||||
void handleReference(const DefinedAtom &atom, const Reference &ref) {
|
||||
switch (ref.kind()) {
|
||||
case R_HEX_PLT_B22_PCREL:
|
||||
static_cast<Derived *>(this)->handlePLT32(ref);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/// \brief Create a GOT entry containing 0.
|
||||
const GOTAtom *getNullGOT() {
|
||||
if (!_null) {
|
||||
_null = new (_file._alloc) HexagonGOTAtom(_file, ".got.plt");
|
||||
#ifndef NDEBUG
|
||||
_null->_name = "__got_null";
|
||||
#endif
|
||||
}
|
||||
return _null;
|
||||
}
|
||||
|
||||
public:
|
||||
GOTPLTPass(const ELFTargetInfo &ti)
|
||||
: _file(ti), _null(nullptr), _PLT0(nullptr), _got0(nullptr) {}
|
||||
|
||||
/// \brief Do the pass.
|
||||
///
|
||||
/// The goal here is to first process each reference individually. Each call
|
||||
/// to handleReference may modify the reference itself and/or create new
|
||||
/// atoms which must be stored in one of the maps below.
|
||||
///
|
||||
/// After all references are handled, the atoms created during that are all
|
||||
/// added to mf.
|
||||
virtual void perform(MutableFile &mf) {
|
||||
// Process all references.
|
||||
for (const auto &atom : mf.defined())
|
||||
for (const auto &ref : *atom)
|
||||
handleReference(*atom, *ref);
|
||||
|
||||
// Add all created atoms to the link.
|
||||
uint64_t ordinal = 0;
|
||||
if (_PLT0) {
|
||||
_PLT0->setOrdinal(ordinal++);
|
||||
mf.addAtom(*_PLT0);
|
||||
}
|
||||
for (const auto &plt : _pltMap) {
|
||||
plt.second->setOrdinal(ordinal++);
|
||||
mf.addAtom(*plt.second);
|
||||
}
|
||||
if (_null) {
|
||||
_null->setOrdinal(ordinal++);
|
||||
mf.addAtom(*_null);
|
||||
}
|
||||
if (_PLT0) {
|
||||
_got0->setOrdinal(ordinal++);
|
||||
mf.addAtom(*_got0);
|
||||
}
|
||||
for (const auto &got : _gotMap) {
|
||||
got.second->setOrdinal(ordinal++);
|
||||
mf.addAtom(*got.second);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/// \brief Owner of all the Atoms created by this pass.
|
||||
ELFPassFile _file;
|
||||
|
||||
/// \brief Map Atoms to their GOT entries.
|
||||
llvm::DenseMap<const Atom *, GOTAtom *> _gotMap;
|
||||
|
||||
/// \brief Map Atoms to their PLT entries.
|
||||
llvm::DenseMap<const Atom *, PLTAtom *> _pltMap;
|
||||
|
||||
/// \brief GOT entry that is always 0. Used for undefined weaks.
|
||||
GOTAtom *_null;
|
||||
|
||||
/// \brief The got and plt entries for .PLT0. This is used to call into the
|
||||
/// dynamic linker for symbol resolution.
|
||||
/// @{
|
||||
PLT0Atom *_PLT0;
|
||||
GOTAtom *_got0;
|
||||
/// @}
|
||||
};
|
||||
|
||||
class DynamicGOTPLTPass LLVM_FINAL : public GOTPLTPass<DynamicGOTPLTPass> {
|
||||
public:
|
||||
DynamicGOTPLTPass(const elf::HexagonTargetInfo &ti) : GOTPLTPass(ti) {}
|
||||
|
||||
const PLT0Atom *getPLT0() {
|
||||
if (_PLT0)
|
||||
return _PLT0;
|
||||
// Fill in the null entry.
|
||||
getNullGOT();
|
||||
_PLT0 = new (_file._alloc) HexagonPLT0Atom(_file);
|
||||
_got0 = new (_file._alloc) HexagonGOTAtom(_file, ".got.plt");
|
||||
_PLT0->addReference(R_HEX_B32_PCREL_X, 0, _got0, 0);
|
||||
_PLT0->addReference(R_HEX_6_PCREL_X, 4, _got0, 0);
|
||||
#ifndef NDEBUG
|
||||
_got0->_name = "__got0";
|
||||
#endif
|
||||
return _PLT0;
|
||||
}
|
||||
|
||||
const PLTAtom *getPLTEntry(const Atom *a) {
|
||||
auto plt = _pltMap.find(a);
|
||||
if (plt != _pltMap.end())
|
||||
return plt->second;
|
||||
auto ga = new (_file._alloc) HexagonGOTAtom(_file, ".got.plt");
|
||||
ga->addReference(R_HEX_JMP_SLOT, 0, a, 0);
|
||||
auto pa = new (_file._alloc) HexagonPLTAtom(_file, ".plt");
|
||||
pa->addReference(R_HEX_B32_PCREL_X, 0, ga, 0);
|
||||
pa->addReference(R_HEX_6_PCREL_X, 4, ga, 4);
|
||||
|
||||
// Point the got entry to the PLT0 atom initially
|
||||
ga->addReference(R_HEX_32, 0, getPLT0(), 0);
|
||||
#ifndef NDEBUG
|
||||
ga->_name = "__got_";
|
||||
ga->_name += a->name();
|
||||
pa->_name = "__plt_";
|
||||
pa->_name += a->name();
|
||||
#endif
|
||||
_gotMap[a] = ga;
|
||||
_pltMap[a] = pa;
|
||||
return pa;
|
||||
}
|
||||
|
||||
ErrorOr<void> handlePLT32(const Reference &ref) {
|
||||
// Turn this into a PC32 to the PLT entry.
|
||||
const_cast<Reference &>(ref).setKind(R_HEX_B22_PCREL);
|
||||
const_cast<Reference &>(ref).setTarget(getPLTEntry(ref.target()));
|
||||
return error_code::success();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
void elf::HexagonTargetInfo::addPasses(PassManager &pm) const {
|
||||
if (_options._outputKind == OutputKind::DynamicExecutable ||
|
||||
_options._outputKind == OutputKind::Shared)
|
||||
pm.add(std::unique_ptr<Pass>(new DynamicGOTPLTPass(*this)));
|
||||
ELFTargetInfo::addPasses(pm);
|
||||
}
|
||||
|
|
|
@ -215,3 +215,4 @@ ErrorOr<std::string> elf::HexagonTargetInfo::stringFromRelocKind(
|
|||
|
||||
return make_error_code(yaml_reader_error::illegal_value);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,6 +32,29 @@ public:
|
|||
|
||||
virtual ErrorOr<int32_t> relocKindFromString(StringRef str) const;
|
||||
virtual ErrorOr<std::string> stringFromRelocKind(int32_t kind) const;
|
||||
|
||||
virtual void addPasses(PassManager &) const;
|
||||
|
||||
virtual bool isDynamicRelocation(const DefinedAtom &,
|
||||
const Reference &r) const {
|
||||
switch (r.kind()){
|
||||
case llvm::ELF::R_HEX_RELATIVE:
|
||||
case llvm::ELF::R_HEX_GLOB_DAT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool isPLTRelocation(const DefinedAtom &,
|
||||
const Reference &r) const {
|
||||
switch (r.kind()){
|
||||
case llvm::ELF::R_HEX_JMP_SLOT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // elf
|
||||
|
|
Binary file not shown.
|
@ -0,0 +1,15 @@
|
|||
RUN: lld -core -target hexagon %p/Inputs/use-shared.hexagon \
|
||||
RUN: -emit-yaml -output=%t2 -noinhibit-exec -output-type=dynamic
|
||||
RUN: FileCheck %s < %t2
|
||||
|
||||
CHECK: - name: fn3
|
||||
CHECK: references:
|
||||
CHECK: - kind: R_HEX_B22_PCREL
|
||||
CHECK: offset: 4
|
||||
target: __plt_fn1
|
||||
CHECK: - kind: R_HEX_B22_PCREL
|
||||
CHECK: offset: 8
|
||||
target: __plt_fn2
|
||||
CHECK: - kind: <unknown>
|
||||
CHECK: offset: 0
|
||||
CHECK: target: fn1
|
Loading…
Reference in New Issue