[ELF][Hexagon] Add Hexagon dynamic relocations

llvm-svn: 177484
This commit is contained in:
Shankar Easwaran 2013-03-20 05:10:02 +00:00
parent 06a4039572
commit 452ba13271
3 changed files with 152 additions and 8 deletions

View File

@ -131,6 +131,81 @@ int relocHexGPRELN(uint8_t *location, uint64_t P, uint64_t S, uint64_t A,
}
return 1;
}
/// \brief Word32_LO: 0x00c03fff : (G) : Truncate
int relocHexGOTLO16(uint8_t *location, uint64_t G) {
uint32_t result = (uint32_t)(G);
result = lld::scatterBits<int32_t>(result, 0x00c03fff);
*reinterpret_cast<llvm::support::ulittle32_t *>(location) =
result |
(uint32_t) * reinterpret_cast<llvm::support::ulittle32_t *>(location);
return 0;
}
/// \brief Word32_LO: 0x00c03fff : (G) >> 16 : Truncate
int relocHexGOTHI16(uint8_t *location, uint64_t G) {
uint32_t result = (uint32_t)(G >> 16);
result = lld::scatterBits<int32_t>(result, 0x00c03fff);
*reinterpret_cast<llvm::support::ulittle32_t *>(location) =
result |
(uint32_t) * reinterpret_cast<llvm::support::ulittle32_t *>(location);
return 0;
}
/// \brief Word32: 0xffffffff : (G) : Truncate
int relocHexGOT32(uint8_t *location, uint64_t G) {
uint32_t result = (uint32_t)(G);
*reinterpret_cast<llvm::support::ulittle32_t *>(location) =
result |
(uint32_t) * reinterpret_cast<llvm::support::ulittle32_t *>(location);
return 0;
}
/// \brief Word32_U16 : (G) : Truncate
int relocHexGOT16(uint8_t *location, uint64_t G) {
uint32_t result = (uint32_t)(G);
uint32_t range = 1L << 16;
if (result <= range) {
result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
*reinterpret_cast<llvm::support::ulittle32_t *>(location) =
result |
(uint32_t) * reinterpret_cast<llvm::support::ulittle32_t *>(location);
return 0;
}
return 1;
}
int relocHexGOT32_6_X(uint8_t *location, uint64_t G) {
uint32_t result = (uint32_t)(G >> 6);
result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
*reinterpret_cast<llvm::support::ulittle32_t *>(location) =
result |
(uint32_t) * reinterpret_cast<llvm::support::ulittle32_t *>(location);
return 0;
}
int relocHexGOT16_X(uint8_t *location, uint64_t G) {
uint32_t result = (uint32_t)(G);
uint32_t range = 1L << 6;
if (result <= range) {
result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
*reinterpret_cast<llvm::support::ulittle32_t *>(location) =
result |
(uint32_t) * reinterpret_cast<llvm::support::ulittle32_t *>(location);
return 0;
}
return 1;
}
int relocHexGOT11_X(uint8_t *location, uint64_t G) {
uint32_t result = (uint32_t)(G);
result = lld::scatterBits<uint32_t>(result, FINDV4BITMASK(location));
*reinterpret_cast<llvm::support::ulittle32_t *>(location) =
result |
(uint32_t) * reinterpret_cast<llvm::support::ulittle32_t *>(location);
return 0;
}
} // end anon namespace
ErrorOr<void> HexagonTargetRelocationHandler::applyRelocation(
@ -211,6 +286,28 @@ ErrorOr<void> HexagonTargetRelocationHandler::applyRelocation(
relocHex6PCRELX(location, relocVAddress, targetVAddress, ref.addend());
break;
case R_HEX_JMP_SLOT:
case R_HEX_GLOB_DAT:
break;
case R_HEX_GOT_LO16:
relocHexGOTLO16(location, targetVAddress);
break;
case R_HEX_GOT_HI16:
relocHexGOTHI16(location, targetVAddress);
break;
case R_HEX_GOT_32:
relocHexGOT32(location, targetVAddress);
break;
case R_HEX_GOT_16:
relocHexGOT16(location, targetVAddress);
break;
case R_HEX_GOT_32_6_X:
relocHexGOT32_6_X(location, targetVAddress);
break;
case R_HEX_GOT_16_X:
relocHexGOT16_X(location, targetVAddress);
break;
case R_HEX_GOT_11_X:
relocHexGOT11_X(location, targetVAddress);
break;
case lld::Reference::kindLayoutAfter:
case lld::Reference::kindLayoutBefore:

View File

@ -40,6 +40,13 @@ template <class Derived> class GOTPLTPass : public Pass {
case R_HEX_PLT_B22_PCREL:
static_cast<Derived *>(this)->handlePLT32(ref);
break;
case R_HEX_GOT_LO16:
case R_HEX_GOT_HI16:
case R_HEX_GOT_32_6_X:
case R_HEX_GOT_16_X:
case R_HEX_GOT_11_X:
static_cast<Derived *>(this)->handleGOTREL(ref);
break;
}
}
@ -124,20 +131,21 @@ protected:
class DynamicGOTPLTPass LLVM_FINAL : public GOTPLTPass<DynamicGOTPLTPass> {
public:
DynamicGOTPLTPass(const elf::HexagonTargetInfo &ti) : GOTPLTPass(ti) {}
DynamicGOTPLTPass(const elf::HexagonTargetInfo &ti) : GOTPLTPass(ti) {
// Fill in the null entry.
getNullGOT();
_got0 = new (_file._alloc) HexagonGOTAtom(_file, ".got.plt");
#ifndef NDEBUG
_got0->_name = "__got0";
#endif
}
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
DEBUG_WITH_TYPE("PLT", llvm::dbgs() << "[ PLT0/GOT0 ] "
<< "Adding plt0/got0 \n");
return _PLT0;
@ -171,6 +179,30 @@ public:
return pa;
}
const GOTAtom *getGOTEntry(const Atom *a) {
auto got = _gotMap.find(a);
if (got != _gotMap.end())
return got->second;
auto ga = new (_file._alloc) HexagonGOTAtom(_file, ".got");
ga->addReference(R_HEX_GLOB_DAT, 0, a, 0);
#ifndef NDEBUG
ga->_name = "__got_";
ga->_name += a->name();
DEBUG_WITH_TYPE("GOT", llvm::dbgs() << "[" << a->name() << "] "
<< "Adding got: " << ga->_name << "\n");
#endif
_gotMap[a] = ga;
_gotVector.push_back(ga);
return ga;
}
ErrorOr<void> handleGOTREL(const Reference &ref) {
// Turn this so that the target is set to the GOT entry
const_cast<Reference &>(ref).setTarget(getGOTEntry(ref.target()));
return error_code::success();
}
ErrorOr<void> handlePLT32(const Reference &ref) {
// Turn this into a PC32 to the PLT entry.
const_cast<Reference &>(ref).setKind(R_HEX_B22_PCREL);

View File

@ -170,6 +170,8 @@ public:
void addDefaultAtoms() {
_hexagonRuntimeFile.addAbsoluteAtom("_SDA_BASE_");
if (_targetInfo.isDynamic())
_hexagonRuntimeFile.addAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
}
virtual void addFiles(InputFiles &inputFiles) {
@ -180,14 +182,27 @@ public:
void finalizeSymbolValues() {
auto sdabaseAtomIter = _targetLayout.findAbsoluteAtom("_SDA_BASE_");
(*sdabaseAtomIter)->_virtualAddr =
_targetLayout.getSDataSection()->virtualAddr();
_targetLayout.getSDataSection()->virtualAddr();
if (_targetInfo.isDynamic()) {
auto gotAtomIter =
_targetLayout.findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_");
_gotSymAtom = (*gotAtomIter);
auto gotpltSection = _targetLayout.findOutputSection(".got.plt");
if (gotpltSection)
_gotSymAtom->_virtualAddr = gotpltSection->virtualAddr();
else
_gotSymAtom->_virtualAddr = 0;
}
}
uint64_t getGOTSymAddr() { return _gotSymAtom->_virtualAddr; }
private:
HexagonTargetLayout<HexagonELFType> _targetLayout;
HexagonTargetRelocationHandler _relocationHandler;
HexagonTargetAtomHandler<HexagonELFType> _targetAtomHandler;
HexagonRuntimeFile<HexagonELFType> _hexagonRuntimeFile;
AtomLayout *_gotSymAtom;
};
} // end namespace elf
} // end namespace lld