[ELF][x86-64] Add X86_64TargetRelocationHandler and friends.

llvm-svn: 173897
This commit is contained in:
Michael J. Spencer 2013-01-30 05:26:03 +00:00
parent 4e9d9cd23b
commit 457a77739b
4 changed files with 147 additions and 7 deletions

View File

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

View File

@ -0,0 +1,90 @@
//===- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.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;
using namespace llvm::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
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_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;
// Runtime only relocations. Ignore here.
case R_X86_64_IRELATIVE:
break;
default: {
std::string str;
llvm::raw_string_ostream s(str);
auto name = _targetInfo.stringFromRelocKind(ref.kind());
s << "Unhandled relocation: "
<< (name ? *name : "<unknown>" ) << " (" << ref.kind() << ")";
s.flush();
llvm_unreachable(str.c_str());
}
}
return error_code::success();
}
X86_64TargetHandler::X86_64TargetHandler(X86_64TargetInfo &targetInfo)
: DefaultTargetHandler(targetInfo), _relocationHandler(targetInfo) {
}

View File

@ -0,0 +1,48 @@
//===- lib/ReaderWriter/ELF/X86_64/X86_64TargetHandler.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_X86_64_TARGET_HANDLER_H
#define LLD_READER_WRITER_ELF_X86_64_TARGET_HANDLER_H
#include "DefaultTargetHandler.h"
namespace lld {
namespace elf {
typedef llvm::object::ELFType<llvm::support::little, 8, false> X86_64ELFType;
class X86_64TargetInfo;
class X86_64TargetRelocationHandler LLVM_FINAL
: public TargetRelocationHandler<X86_64ELFType> {
public:
X86_64TargetRelocationHandler(const X86_64TargetInfo &ti) : _targetInfo(ti) {}
virtual ErrorOr<void> applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
const AtomLayout &,
const Reference &)const;
private:
const X86_64TargetInfo &_targetInfo;
};
class X86_64TargetHandler LLVM_FINAL
: public DefaultTargetHandler<X86_64ELFType> {
public:
X86_64TargetHandler(X86_64TargetInfo &targetInfo);
virtual const X86_64TargetRelocationHandler &getRelocationHandler() const {
return _relocationHandler;
}
private:
X86_64TargetRelocationHandler _relocationHandler;
};
} // end namespace elf
} // end namespace lld
#endif

View File

@ -10,7 +10,7 @@
#ifndef LLD_READER_WRITER_ELF_X86_64_TARGETINFO_H
#define LLD_READER_WRITER_ELF_X86_64_TARGETINFO_H
#include "DefaultTargetHandler.h"
#include "X86_64TargetHandler.h"
#include "lld/Core/LinkerOptions.h"
#include "lld/ReaderWriter/ELFTargetInfo.h"
@ -20,12 +20,13 @@
namespace lld {
namespace elf {
typedef llvm::object::ELFType<llvm::support::little, 8, false> X86_64ELFType;
class X86_64TargetInfo LLVM_FINAL : public ELFTargetInfo {
public:
X86_64TargetInfo(const LinkerOptions &lo) : ELFTargetInfo(lo) {
_targetHandler = std::unique_ptr<TargetHandlerBase>(
new DefaultTargetHandler<llvm::object::ELFType<llvm::support::little,
8, false> >(*this));
_targetHandler =
std::unique_ptr<TargetHandlerBase>(new X86_64TargetHandler(*this));
}
virtual uint64_t getPageSize() const { return 0x1000; }
@ -47,7 +48,7 @@ public:
virtual ErrorOr<std::string> stringFromRelocKind(int32_t kind) const;
};
} // elf
} // lld
} // end namespace elf
} // end namespace lld
#endif // LLD_READER_WRITER_ELF_X86_64_TARGETINFO_H
#endif