[lld][ELF][X86_64] Reorganize X86_64 Target specific code

This patch splits X86_64Target specific code so that 
the dynamic atoms and the Relocation handlers are in seperate 
files for easier maintenace. The files are sure to grow and this 
makes it easier to work with.

* There is no change in functionality *

llvm-svn: 182076
This commit is contained in:
Shankar Easwaran 2013-05-17 04:19:53 +00:00
parent 1239d84f77
commit f9a7933d90
7 changed files with 266 additions and 206 deletions

View File

@ -1,6 +1,7 @@
add_lld_library(lldX86_64ELFTarget
X86_64TargetInfo.cpp
X86_64TargetHandler.cpp
X86_64RelocationHandler.cpp
)
target_link_libraries(lldX86_64ELFTarget

View File

@ -0,0 +1,73 @@
//===- lib/ReaderWriter/ELF/X86_64/X86_64DynamicAtoms.h -------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef X86_64_DYNAMIC_ATOMS_H
#define X86_64_DYNAMIC_ATOMS_H
#include "Atoms.h"
#include "X86_64TargetInfo.h"
namespace lld {
namespace elf {
class X86_64GOTAtom : public GOTAtom {
static const uint8_t _defaultContent[8];
public:
X86_64GOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {}
virtual ArrayRef<uint8_t> rawContent() const {
return ArrayRef<uint8_t>(_defaultContent, 8);
}
};
const uint8_t X86_64GOTAtom::_defaultContent[8] = { 0 };
class X86_64PLTAtom : public PLTAtom {
static const uint8_t _defaultContent[16];
public:
X86_64PLTAtom(const File &f, StringRef secName) : PLTAtom(f, secName) {}
virtual ArrayRef<uint8_t> rawContent() const {
return ArrayRef<uint8_t>(_defaultContent, 16);
}
};
const uint8_t X86_64PLTAtom::_defaultContent[16] = {
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *gotatom(%rip)
0x68, 0x00, 0x00, 0x00, 0x00, // pushq reloc-index
0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[-1]
};
class X86_64PLT0Atom : public PLT0Atom {
static const uint8_t _plt0Content[16];
public:
X86_64PLT0Atom(const File &f) : PLT0Atom(f) {
#ifndef NDEBUG
_name = ".PLT0";
#endif
}
virtual ArrayRef<uint8_t> rawContent() const {
return ArrayRef<uint8_t>(_plt0Content, 16);
}
};
const uint8_t X86_64PLT0Atom::_plt0Content[16] = {
0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
0x90, 0x90, 0x90, 0x90 // nopnopnop
};
} // elf
} // lld
#endif

View File

@ -0,0 +1,146 @@
//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.cpp ------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "X86_64TargetHandler.h"
#include "X86_64TargetInfo.h"
using namespace lld;
using namespace elf;
namespace {
/// \brief R_X86_64_64 - word64: S + A
void reloc64(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
uint64_t result = S + A;
*reinterpret_cast<llvm::support::ulittle64_t *>(location) =
result |
(uint64_t) * reinterpret_cast<llvm::support::ulittle64_t *>(location);
}
/// \brief R_X86_64_PC32 - word32: S + A - P
void relocPC32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
uint32_t result = (uint32_t)((S + A) - P);
*reinterpret_cast<llvm::support::ulittle32_t *>(location) =
result +
(uint32_t) * reinterpret_cast<llvm::support::ulittle32_t *>(location);
}
/// \brief R_X86_64_32 - word32: S + A
void reloc32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
int32_t result = (uint32_t)(S + A);
*reinterpret_cast<llvm::support::ulittle32_t *>(location) =
result |
(uint32_t) * reinterpret_cast<llvm::support::ulittle32_t *>(location);
// TODO: Make sure that the result zero extends to the 64bit value.
}
/// \brief R_X86_64_32S - word32: S + A
void reloc32S(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
int32_t result = (int32_t)(S + A);
*reinterpret_cast<llvm::support::little32_t *>(location) =
result |
(int32_t) * reinterpret_cast<llvm::support::little32_t *>(location);
// TODO: Make sure that the result sign extends to the 64bit value.
}
} // end anon namespace
int64_t X86_64TargetRelocationHandler::relocAddend(const Reference &ref) const {
switch (ref.kind()) {
case R_X86_64_PC32:
return 4;
default:
return 0;
}
return 0;
}
ErrorOr<void> X86_64TargetRelocationHandler::applyRelocation(
ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
const Reference &ref) const {
uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
uint8_t *location = atomContent + ref.offsetInAtom();
uint64_t targetVAddress = writer.addressOfAtom(ref.target());
uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
switch (ref.kind()) {
case R_X86_64_NONE:
break;
case R_X86_64_64:
reloc64(location, relocVAddress, targetVAddress, ref.addend());
break;
case R_X86_64_PC32:
relocPC32(location, relocVAddress, targetVAddress, ref.addend());
break;
case R_X86_64_32:
reloc32(location, relocVAddress, targetVAddress, ref.addend());
break;
case R_X86_64_32S:
reloc32S(location, relocVAddress, targetVAddress, ref.addend());
break;
case R_X86_64_TPOFF64:
case R_X86_64_DTPOFF32:
case R_X86_64_TPOFF32: {
_tlsSize = _targetInfo.getTargetHandler<X86_64ELFType>().targetLayout()
.getTLSSize();
if (ref.kind() == R_X86_64_TPOFF32 || ref.kind() == R_X86_64_DTPOFF32) {
int32_t result = (int32_t)(targetVAddress - _tlsSize);
*reinterpret_cast<llvm::support::little32_t *>(location) = result;
} else {
int64_t result = (int64_t)(targetVAddress - _tlsSize);
*reinterpret_cast<llvm::support::little64_t *>(location) = result;
}
break;
}
case R_X86_64_TLSLD: {
// Rewrite to move %fs:0 into %rax. Technically we should verify that the
// next relocation is a PC32 to __tls_get_addr...
static uint8_t instr[] = { 0x66, 0x66, 0x66, 0x64, 0x48, 0x8b, 0x04, 0x25,
0x00, 0x00, 0x00, 0x00 };
std::memcpy(location - 3, instr, sizeof(instr));
break;
}
case LLD_R_X86_64_GOTRELINDEX: {
const DefinedAtom *target = cast<const DefinedAtom>(ref.target());
for (const Reference *r : *target) {
if (r->kind() == R_X86_64_JUMP_SLOT) {
uint32_t index;
if (!_targetInfo.getTargetHandler<X86_64ELFType>().targetLayout()
.getPLTRelocationTable()->getRelocationIndex(*r, index))
llvm_unreachable("Relocation doesn't exist");
reloc32(location, 0, index, 0);
break;
}
}
break;
}
// Runtime only relocations. Ignore here.
case R_X86_64_RELATIVE:
case R_X86_64_IRELATIVE:
case R_X86_64_JUMP_SLOT:
case R_X86_64_GLOB_DAT:
break;
case lld::Reference::kindLayoutAfter:
case lld::Reference::kindLayoutBefore:
case lld::Reference::kindInGroup:
break;
default: {
std::string str;
llvm::raw_string_ostream s(str);
auto name = _targetInfo.stringFromRelocKind(ref.kind());
s << "Unhandled relocation: " << atom._atom->file().path() << ":"
<< atom._atom->name() << "@" << ref.offsetInAtom() << " "
<< (name ? *name : "<unknown>") << " (" << ref.kind() << ")";
s.flush();
llvm_unreachable(str.c_str());
}
}
return error_code::success();
}

View File

@ -0,0 +1,42 @@
//===- lib/ReaderWriter/ELF/X86_64/X86_64RelocationHandler.h
//------------------===//
//
// The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef X86_64_RELOCATION_HANDLER_H
#define X86_64_RELOCATION_HANDLER_H
#include "X86_64TargetHandler.h"
namespace lld {
namespace elf {
typedef llvm::object::ELFType<llvm::support::little, 8, true> X86_64ELFType;
class X86_64TargetInfo;
class X86_64TargetRelocationHandler LLVM_FINAL
: public TargetRelocationHandler<X86_64ELFType> {
public:
X86_64TargetRelocationHandler(const X86_64TargetInfo &ti)
: _tlsSize(0), _targetInfo(ti) {}
virtual ErrorOr<void> applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
const AtomLayout &,
const Reference &) const;
virtual int64_t relocAddend(const Reference &) const;
private:
// Cached size of the TLS segment.
mutable uint64_t _tlsSize;
const X86_64TargetInfo &_targetInfo;
};
} // end namespace elf
} // end namespace lld
#endif

View File

@ -14,140 +14,10 @@
using namespace lld;
using namespace elf;
using namespace llvm::ELF;
X86_64TargetHandler::X86_64TargetHandler(X86_64TargetInfo &targetInfo)
: DefaultTargetHandler(targetInfo), _gotFile(targetInfo),
_relocationHandler(targetInfo), _targetLayout(targetInfo) {}
namespace {
/// \brief R_X86_64_64 - word64: S + A
void reloc64(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
uint64_t result = S + A;
*reinterpret_cast<llvm::support::ulittle64_t *>(location) = result |
(uint64_t)*reinterpret_cast<llvm::support::ulittle64_t *>(location);
}
/// \brief R_X86_64_PC32 - word32: S + A - P
void relocPC32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
uint32_t result = (uint32_t)((S + A) - P);
*reinterpret_cast<llvm::support::ulittle32_t *>(location) = result +
(uint32_t)*reinterpret_cast<llvm::support::ulittle32_t *>(location);
}
/// \brief R_X86_64_32 - word32: S + A
void reloc32(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
int32_t result = (uint32_t)(S + A);
*reinterpret_cast<llvm::support::ulittle32_t *>(location) = result |
(uint32_t)*reinterpret_cast<llvm::support::ulittle32_t *>(location);
// TODO: Make sure that the result zero extends to the 64bit value.
}
/// \brief R_X86_64_32S - word32: S + A
void reloc32S(uint8_t *location, uint64_t P, uint64_t S, int64_t A) {
int32_t result = (int32_t)(S + A);
*reinterpret_cast<llvm::support::little32_t *>(location) = result |
(int32_t)*reinterpret_cast<llvm::support::little32_t *>(location);
// TODO: Make sure that the result sign extends to the 64bit value.
}
} // end anon namespace
int64_t X86_64TargetRelocationHandler::relocAddend(const Reference &ref) const {
switch (ref.kind()) {
case R_X86_64_PC32:
return 4;
default:
return 0;
}
return 0;
}
ErrorOr<void> X86_64TargetRelocationHandler::applyRelocation(
ELFWriter &writer, llvm::FileOutputBuffer &buf, const AtomLayout &atom,
const Reference &ref) const {
uint8_t *atomContent = buf.getBufferStart() + atom._fileOffset;
uint8_t *location = atomContent + ref.offsetInAtom();
uint64_t targetVAddress = writer.addressOfAtom(ref.target());
uint64_t relocVAddress = atom._virtualAddr + ref.offsetInAtom();
switch (ref.kind()) {
case R_X86_64_NONE:
break;
case R_X86_64_64:
reloc64(location, relocVAddress, targetVAddress, ref.addend());
break;
case R_X86_64_PC32:
relocPC32(location, relocVAddress, targetVAddress, ref.addend());
break;
case R_X86_64_32:
reloc32(location, relocVAddress, targetVAddress, ref.addend());
break;
case R_X86_64_32S:
reloc32S(location, relocVAddress, targetVAddress, ref.addend());
break;
case R_X86_64_TPOFF64:
case R_X86_64_DTPOFF32:
case R_X86_64_TPOFF32: {
_tlsSize = _targetInfo.getTargetHandler<X86_64ELFType>().targetLayout()
.getTLSSize();
if (ref.kind() == R_X86_64_TPOFF32 || ref.kind() == R_X86_64_DTPOFF32) {
int32_t result = (int32_t)(targetVAddress - _tlsSize);
*reinterpret_cast<llvm::support::little32_t *>(location) = result;
} else {
int64_t result = (int64_t)(targetVAddress - _tlsSize);
*reinterpret_cast<llvm::support::little64_t *>(location) = result;
}
break;
}
case R_X86_64_TLSLD: {
// Rewrite to move %fs:0 into %rax. Technically we should verify that the
// next relocation is a PC32 to __tls_get_addr...
static uint8_t instr[] = { 0x66, 0x66, 0x66, 0x64, 0x48, 0x8b, 0x04, 0x25,
0x00, 0x00, 0x00, 0x00 };
std::memcpy(location - 3, instr, sizeof(instr));
break;
}
case LLD_R_X86_64_GOTRELINDEX: {
const DefinedAtom *target = cast<const DefinedAtom>(ref.target());
for (const Reference *r : *target) {
if (r->kind() == R_X86_64_JUMP_SLOT) {
uint32_t index;
if (!_targetInfo.getTargetHandler<X86_64ELFType>().targetLayout()
.getPLTRelocationTable()->getRelocationIndex(*r, index))
llvm_unreachable("Relocation doesn't exist");
reloc32(location, 0, index, 0);
break;
}
}
break;
}
// Runtime only relocations. Ignore here.
case R_X86_64_RELATIVE:
case R_X86_64_IRELATIVE:
case R_X86_64_JUMP_SLOT:
case R_X86_64_GLOB_DAT:
break;
case lld::Reference::kindLayoutAfter:
case lld::Reference::kindLayoutBefore:
case lld::Reference::kindInGroup:
break;
default : {
std::string str;
llvm::raw_string_ostream s(str);
auto name = _targetInfo.stringFromRelocKind(ref.kind());
s << "Unhandled relocation: " << atom._atom->file().path() << ":"
<< atom._atom->name() << "@" << ref.offsetInAtom() << " "
<< (name ? *name : "<unknown>") << " (" << ref.kind() << ")";
s.flush();
llvm_unreachable(str.c_str());
}
}
return error_code::success();
}
void X86_64TargetHandler::addFiles(InputFiles &f) {
_gotFile.addAtom(*new (_gotFile._alloc) GLOBAL_OFFSET_TABLEAtom(_gotFile));
_gotFile.addAtom(*new (_gotFile._alloc) TLSGETADDRAtom(_gotFile));

View File

@ -11,6 +11,7 @@
#define LLD_READER_WRITER_ELF_X86_64_TARGET_HANDLER_H
#include "DefaultTargetHandler.h"
#include "X86_64RelocationHandler.h"
#include "TargetLayout.h"
#include "lld/ReaderWriter/Simple.h"
@ -20,24 +21,6 @@ namespace elf {
typedef llvm::object::ELFType<llvm::support::little, 8, true> X86_64ELFType;
class X86_64TargetInfo;
class X86_64TargetRelocationHandler LLVM_FINAL
: public TargetRelocationHandler<X86_64ELFType> {
public:
X86_64TargetRelocationHandler(const X86_64TargetInfo &ti)
: _tlsSize(0), _targetInfo(ti) {}
virtual ErrorOr<void>
applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, const AtomLayout &,
const Reference &)const;
virtual int64_t relocAddend(const Reference &)const;
private:
// Cached size of the TLS segment.
mutable uint64_t _tlsSize;
const X86_64TargetInfo &_targetInfo;
};
class X86_64TargetHandler LLVM_FINAL
: public DefaultTargetHandler<X86_64ELFType> {
public:

View File

@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
#include "Atoms.h"
#include "X86_64DynamicAtoms.h"
#include "X86_64TargetInfo.h"
#include "lld/Core/File.h"
@ -25,61 +25,6 @@ using namespace lld::elf;
namespace {
using namespace llvm::ELF;
class X86_64GOTAtom : public GOTAtom {
static const uint8_t _defaultContent[8];
public:
X86_64GOTAtom(const File &f, StringRef secName)
: GOTAtom(f, secName) {
}
virtual ArrayRef<uint8_t> rawContent() const {
return ArrayRef<uint8_t>(_defaultContent, 8);
}
};
const uint8_t X86_64GOTAtom::_defaultContent[8] = { 0 };
class X86_64PLTAtom : public PLTAtom {
static const uint8_t _defaultContent[16];
public:
X86_64PLTAtom(const File &f, StringRef secName)
: PLTAtom(f, secName) {
}
virtual ArrayRef<uint8_t> rawContent() const {
return ArrayRef<uint8_t>(_defaultContent, 16);
}
};
const uint8_t X86_64PLTAtom::_defaultContent[16] = {
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmpq *gotatom(%rip)
0x68, 0x00, 0x00, 0x00, 0x00, // pushq reloc-index
0xe9, 0x00, 0x00, 0x00, 0x00 // jmpq plt[-1]
};
class X86_64PLT0Atom : public PLT0Atom {
static const uint8_t _plt0Content[16];
public:
X86_64PLT0Atom(const File &f) : PLT0Atom(f) {
#ifndef NDEBUG
_name = ".PLT0";
#endif
}
virtual ArrayRef<uint8_t> rawContent() const {
return ArrayRef<uint8_t>(_plt0Content, 16);
}
};
const uint8_t X86_64PLT0Atom::_plt0Content[16] = {
0xff, 0x35, 0x00, 0x00, 0x00, 0x00, // pushq GOT+8(%rip)
0xff, 0x25, 0x00, 0x00, 0x00, 0x00, // jmp *GOT+16(%rip)
0x90, 0x90, 0x90, 0x90 // nopnopnop
};
class ELFPassFile : public SimpleFile {
public:
ELFPassFile(const ELFTargetInfo &eti) : SimpleFile(eti, "ELFPassFile") {}
@ -420,7 +365,7 @@ void elf::X86_64TargetInfo::addPasses(PassManager &pm) const {
#define LLD_CASE(name) .Case(#name, llvm::ELF::name)
ErrorOr<Reference::Kind>
ErrorOr<Reference::Kind>
elf::X86_64TargetInfo::relocKindFromString(StringRef str) const {
int32_t ret = llvm::StringSwitch<int32_t>(str)
LLD_CASE(R_X86_64_NONE)
@ -473,7 +418,7 @@ elf::X86_64TargetInfo::relocKindFromString(StringRef str) const {
#define LLD_CASE(name) case llvm::ELF::name: return std::string(#name);
ErrorOr<std::string>
ErrorOr<std::string>
elf::X86_64TargetInfo::stringFromRelocKind(Reference::Kind kind) const {
switch (kind) {
LLD_CASE(R_X86_64_NONE)