forked from OSchip/llvm-project
[ELF] Minimal implementation for ARM static linking
The code is able to statically link the simplest case of: int main() { return 0; } * Only works with ARM code - no Thumb code, no interwork (-marm -mno-thumb-interwork) * musl libc built with no interwork and no Thumb code Differential Revision: http://reviews.llvm.org/D6716 From: Denis Protivensky <dprotivensky@accesssoftek.com> llvm-svn: 226643
This commit is contained in:
parent
f38dea1cfa
commit
8a1887f1f1
|
@ -8,6 +8,7 @@ Open Projects
|
|||
.. include:: ../lib/Driver/TODO.rst
|
||||
.. include:: ../lib/ReaderWriter/ELF/X86_64/TODO.rst
|
||||
.. include:: ../lib/ReaderWriter/ELF/AArch64/TODO.rst
|
||||
.. include:: ../lib/ReaderWriter/ELF/ARM/TODO.rst
|
||||
.. include:: ../tools/lld/TODO.txt
|
||||
|
||||
Documentation TODOs
|
||||
|
|
|
@ -192,6 +192,10 @@ getArchType(const llvm::Triple &triple, StringRef value) {
|
|||
if (value == "aarch64linux")
|
||||
return llvm::Triple::aarch64;
|
||||
return llvm::None;
|
||||
case llvm::Triple::arm:
|
||||
if (value == "armelf_linux_eabi")
|
||||
return llvm::Triple::arm;
|
||||
return llvm::None;
|
||||
default:
|
||||
return llvm::None;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
//===--------- lib/ReaderWriter/ELF/ARM/ARMELFFile.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_ARM_ARM_ELF_FILE_H
|
||||
#define LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H
|
||||
|
||||
#include "ELFReader.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
class ARMLinkingContext;
|
||||
|
||||
template <class ELFT> class ARMELFFile : public ELFFile<ELFT> {
|
||||
public:
|
||||
ARMELFFile(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings)
|
||||
: ELFFile<ELFT>(std::move(mb), atomizeStrings) {}
|
||||
|
||||
static ErrorOr<std::unique_ptr<ARMELFFile>>
|
||||
create(std::unique_ptr<MemoryBuffer> mb, bool atomizeStrings) {
|
||||
return std::unique_ptr<ARMELFFile<ELFT>>(
|
||||
new ARMELFFile<ELFT>(std::move(mb), atomizeStrings));
|
||||
}
|
||||
};
|
||||
|
||||
template <class ELFT> class ARMDynamicFile : public DynamicFile<ELFT> {
|
||||
public:
|
||||
ARMDynamicFile(const ARMLinkingContext &context, StringRef name)
|
||||
: DynamicFile<ELFT>(context, name) {}
|
||||
};
|
||||
|
||||
} // elf
|
||||
} // lld
|
||||
|
||||
#endif // LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H
|
|
@ -0,0 +1,60 @@
|
|||
//===--------- lib/ReaderWriter/ELF/ARM/ARMELFReader.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_ARM_ARM_ELF_READER_H
|
||||
#define LLD_READER_WRITER_ARM_ARM_ELF_READER_H
|
||||
|
||||
#include "ARMELFFile.h"
|
||||
#include "ELFReader.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
|
||||
|
||||
struct ARMDynamicFileCreateELFTraits {
|
||||
typedef llvm::ErrorOr<std::unique_ptr<lld::SharedLibraryFile>> result_type;
|
||||
|
||||
template <class ELFT>
|
||||
static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
|
||||
bool useUndefines) {
|
||||
return lld::elf::ARMDynamicFile<ELFT>::create(std::move(mb), useUndefines);
|
||||
}
|
||||
};
|
||||
|
||||
struct ARMELFFileCreateELFTraits {
|
||||
typedef llvm::ErrorOr<std::unique_ptr<lld::File>> result_type;
|
||||
|
||||
template <class ELFT>
|
||||
static result_type create(std::unique_ptr<llvm::MemoryBuffer> mb,
|
||||
bool atomizeStrings) {
|
||||
return lld::elf::ARMELFFile<ELFT>::create(std::move(mb), atomizeStrings);
|
||||
}
|
||||
};
|
||||
|
||||
class ARMELFObjectReader
|
||||
: public ELFObjectReader<ARMELFType, ARMELFFileCreateELFTraits> {
|
||||
public:
|
||||
ARMELFObjectReader(bool atomizeStrings)
|
||||
: ELFObjectReader<ARMELFType, ARMELFFileCreateELFTraits>(
|
||||
atomizeStrings, llvm::ELF::EM_ARM) {}
|
||||
};
|
||||
|
||||
class ARMELFDSOReader
|
||||
: public ELFDSOReader<ARMELFType, ARMDynamicFileCreateELFTraits> {
|
||||
public:
|
||||
ARMELFDSOReader(bool useUndefines)
|
||||
: ELFDSOReader<ARMELFType, ARMDynamicFileCreateELFTraits>(
|
||||
useUndefines, llvm::ELF::EM_ARM) {}
|
||||
};
|
||||
|
||||
} // namespace elf
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_READER_WRITER_ARM_ARM_ELF_READER_H
|
|
@ -0,0 +1,58 @@
|
|||
//===--------- lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.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_ARM_ARM_EXECUTABLE_WRITER_H
|
||||
#define LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H
|
||||
|
||||
#include "ExecutableWriter.h"
|
||||
#include "ARMLinkingContext.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
template <class ELFT>
|
||||
class ARMExecutableWriter : public ExecutableWriter<ELFT> {
|
||||
public:
|
||||
ARMExecutableWriter(ARMLinkingContext &context,
|
||||
ARMTargetLayout<ELFT> &layout);
|
||||
|
||||
protected:
|
||||
// Add any runtime files and their atoms to the output
|
||||
bool createImplicitFiles(std::vector<std::unique_ptr<File>> &) override;
|
||||
|
||||
void finalizeDefaultAtomValues() override {
|
||||
// Finalize the atom values that are part of the parent.
|
||||
ExecutableWriter<ELFT>::finalizeDefaultAtomValues();
|
||||
}
|
||||
|
||||
void addDefaultAtoms() override {
|
||||
ExecutableWriter<ELFT>::addDefaultAtoms();
|
||||
}
|
||||
|
||||
private:
|
||||
ARMLinkingContext &_context;
|
||||
ARMTargetLayout<ELFT> &_armLayout;
|
||||
};
|
||||
|
||||
template <class ELFT>
|
||||
ARMExecutableWriter<ELFT>::ARMExecutableWriter(ARMLinkingContext &context,
|
||||
ARMTargetLayout<ELFT> &layout)
|
||||
: ExecutableWriter<ELFT>(context, layout), _context(context),
|
||||
_armLayout(layout) {}
|
||||
|
||||
template <class ELFT>
|
||||
bool ARMExecutableWriter<ELFT>::createImplicitFiles(
|
||||
std::vector<std::unique_ptr<File>> &result) {
|
||||
ExecutableWriter<ELFT>::createImplicitFiles(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace elf
|
||||
} // namespace lld
|
||||
|
||||
#endif // LLD_READER_WRITER_ELF_ARM_ARM_EXECUTABLE_WRITER_H
|
|
@ -0,0 +1,21 @@
|
|||
//===--------- lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp -------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ARMLinkingContext.h"
|
||||
#include "ARMRelocationPass.h"
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf;
|
||||
|
||||
void elf::ARMLinkingContext::addPasses(PassManager &pm) {
|
||||
auto pass = createARMRelocationPass(*this);
|
||||
if (pass)
|
||||
pm.add(std::move(pass));
|
||||
ELFLinkingContext::addPasses(pm);
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
//===--------- lib/ReaderWriter/ELF/ARM/ARMLinkingContext.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_ARM_ARM_LINKING_CONTEXT_H
|
||||
#define LLD_READER_WRITER_ELF_ARM_ARM_LINKING_CONTEXT_H
|
||||
|
||||
#include "ARMTargetHandler.h"
|
||||
|
||||
#include "lld/ReaderWriter/ELFLinkingContext.h"
|
||||
|
||||
#include "llvm/Object/ELF.h"
|
||||
#include "llvm/Support/ELF.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
|
||||
class ARMLinkingContext final : public ELFLinkingContext {
|
||||
public:
|
||||
ARMLinkingContext(llvm::Triple triple)
|
||||
: ELFLinkingContext(triple, std::unique_ptr<TargetHandlerBase>(
|
||||
new ARMTargetHandler(*this))) {}
|
||||
|
||||
void addPasses(PassManager &) override;
|
||||
|
||||
uint64_t getBaseAddress() const override {
|
||||
if (_baseAddress == 0)
|
||||
return 0x400000;
|
||||
return _baseAddress;
|
||||
}
|
||||
};
|
||||
} // end namespace elf
|
||||
} // end namespace lld
|
||||
|
||||
#endif
|
|
@ -0,0 +1,109 @@
|
|||
//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp ----------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ARMTargetHandler.h"
|
||||
#include "ARMLinkingContext.h"
|
||||
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
|
||||
using namespace lld;
|
||||
using namespace elf;
|
||||
|
||||
static Reference::Addend readAddend_ARM_CALL(const uint8_t *location) {
|
||||
const auto value = int32_t(
|
||||
*reinterpret_cast<const llvm::support::little32_t *>(location));
|
||||
|
||||
const bool isBLX = (value & 0xF0000000) == 0xF0000000;
|
||||
const int32_t bitH = isBLX ? ((value & 0x1000000) >> 24) : 0;
|
||||
|
||||
const int32_t result = ((value & 0xFFFFFF) << 2) | (bitH << 1);
|
||||
return llvm::SignExtend64<26>(result);
|
||||
}
|
||||
|
||||
static Reference::Addend readAddend(const uint8_t *location,
|
||||
Reference::KindValue kindValue) {
|
||||
switch (kindValue) {
|
||||
case R_ARM_ABS32:
|
||||
return int32_t(
|
||||
*reinterpret_cast<const llvm::support::little32_t *>(location));
|
||||
case R_ARM_CALL:
|
||||
return readAddend_ARM_CALL(location);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void applyArmReloc(uint8_t *location, uint32_t result,
|
||||
uint32_t mask = 0xFFFFFFFF) {
|
||||
assert(!(result & ~mask));
|
||||
*reinterpret_cast<llvm::support::ulittle32_t *>(location) =
|
||||
(uint32_t(*reinterpret_cast<llvm::support::ulittle32_t *>(location)) &
|
||||
~mask) | (result & mask);
|
||||
}
|
||||
|
||||
/// \brief R_ARM_ABS32 - (S + A) | T => S + A
|
||||
static void relocR_ARM_ABS32(uint8_t *location, uint64_t P, uint64_t S,
|
||||
int64_t A) {
|
||||
uint32_t result = (uint32_t)(S + A);
|
||||
DEBUG_WITH_TYPE(
|
||||
"ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
|
||||
llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
|
||||
llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
|
||||
llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
|
||||
llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
|
||||
applyArmReloc(location, result);
|
||||
}
|
||||
|
||||
/// \brief R_ARM_CALL - ((S + A) | T) - P => S + A - P
|
||||
static void relocR_ARM_CALL(uint8_t *location, uint64_t P, uint64_t S,
|
||||
int64_t A) {
|
||||
uint32_t result = (uint32_t)((S + A) - P);
|
||||
const uint32_t imm24 = (result & 0x03FFFFFC) >> 2;
|
||||
|
||||
DEBUG_WITH_TYPE(
|
||||
"ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -";
|
||||
llvm::dbgs() << " S: 0x" << Twine::utohexstr(S);
|
||||
llvm::dbgs() << " A: 0x" << Twine::utohexstr(A);
|
||||
llvm::dbgs() << " P: 0x" << Twine::utohexstr(P);
|
||||
llvm::dbgs() << " result: 0x" << Twine::utohexstr(result) << "\n");
|
||||
applyArmReloc(location, imm24, 0xFFFFFF);
|
||||
}
|
||||
|
||||
std::error_code ARMTargetRelocationHandler::applyRelocation(
|
||||
ELFWriter &writer, llvm::FileOutputBuffer &buf, const lld::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();
|
||||
|
||||
if (ref.kindNamespace() != Reference::KindNamespace::ELF)
|
||||
return std::error_code();
|
||||
assert(ref.kindArch() == Reference::KindArch::ARM);
|
||||
|
||||
// Calculate proper initial addend for the relocation
|
||||
const Reference::Addend addend =
|
||||
readAddend(location, ref.kindValue());
|
||||
|
||||
switch (ref.kindValue()) {
|
||||
case R_ARM_NONE:
|
||||
break;
|
||||
case R_ARM_ABS32:
|
||||
relocR_ARM_ABS32(location, relocVAddress, targetVAddress, addend);
|
||||
break;
|
||||
case R_ARM_CALL:
|
||||
relocR_ARM_CALL(location, relocVAddress, targetVAddress, addend);
|
||||
break;
|
||||
default:
|
||||
make_unhandled_reloc_error();
|
||||
}
|
||||
|
||||
return std::error_code();
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.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_ARM_ARM_RELOCATION_HANDLER_H
|
||||
#define LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H
|
||||
|
||||
#include "ARMTargetHandler.h"
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
|
||||
|
||||
template <class ELFT> class ARMTargetLayout;
|
||||
|
||||
class ARMTargetRelocationHandler final
|
||||
: public TargetRelocationHandler {
|
||||
public:
|
||||
std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &,
|
||||
const lld::AtomLayout &,
|
||||
const Reference &) const override;
|
||||
};
|
||||
|
||||
} // end namespace elf
|
||||
} // end namespace lld
|
||||
|
||||
#endif // LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_HANDLER_H
|
|
@ -0,0 +1,138 @@
|
|||
//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp -------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Defines the relocation processing pass for ARM. This includes
|
||||
/// GOT and PLT entries, TLS, COPY, and ifunc.
|
||||
///
|
||||
/// This also includes additional behavior that gnu-ld and gold implement but
|
||||
/// which is not specified anywhere.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ARMRelocationPass.h"
|
||||
|
||||
#include "lld/Core/Simple.h"
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "ARMLinkingContext.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
|
||||
using namespace lld;
|
||||
using namespace lld::elf;
|
||||
using namespace llvm::ELF;
|
||||
|
||||
namespace {
|
||||
class ELFPassFile : public SimpleFile {
|
||||
public:
|
||||
ELFPassFile(const ELFLinkingContext &eti) : SimpleFile("ELFPassFile") {
|
||||
setOrdinal(eti.getNextOrdinalAndIncrement());
|
||||
}
|
||||
|
||||
llvm::BumpPtrAllocator _alloc;
|
||||
};
|
||||
|
||||
/// \brief CRTP base for handling relocations.
|
||||
template <class Derived> class ARMRelocationPass : public Pass {
|
||||
/// \brief Handle a specific reference.
|
||||
void handleReference(const DefinedAtom &atom, const Reference &ref) {
|
||||
DEBUG_WITH_TYPE(
|
||||
"ARM", llvm::dbgs() << "\t" << LLVM_FUNCTION_NAME << "()"
|
||||
<< ": Name of Defined Atom: " << atom.name().str();
|
||||
llvm::dbgs() << " kindValue: " << ref.kindValue() << "\n");
|
||||
if (ref.kindNamespace() != Reference::KindNamespace::ELF)
|
||||
return;
|
||||
assert(ref.kindArch() == Reference::KindArch::ARM);
|
||||
switch (ref.kindValue()) {
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
public:
|
||||
ARMRelocationPass(const ELFLinkingContext &ctx)
|
||||
: _file(ctx), _ctx(ctx) {}
|
||||
|
||||
/// \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.
|
||||
void perform(std::unique_ptr<MutableFile> &mf) override {
|
||||
ScopedTask task(getDefaultDomain(), "ARM GOT/PLT Pass");
|
||||
DEBUG_WITH_TYPE(
|
||||
"ARM", llvm::dbgs() << "Undefined Atoms" << "\n";
|
||||
for (const auto &atom
|
||||
: mf->undefined()) {
|
||||
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
|
||||
}
|
||||
|
||||
llvm::dbgs() << "Shared Library Atoms" << "\n";
|
||||
for (const auto &atom
|
||||
: mf->sharedLibrary()) {
|
||||
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
|
||||
}
|
||||
|
||||
llvm::dbgs() << "Absolute Atoms" << "\n";
|
||||
for (const auto &atom
|
||||
: mf->absolute()) {
|
||||
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
|
||||
}
|
||||
|
||||
llvm::dbgs() << "Defined Atoms" << "\n";
|
||||
for (const auto &atom
|
||||
: mf->defined()) {
|
||||
llvm::dbgs() << " Name of Atom: " << atom->name().str() << "\n";
|
||||
});
|
||||
|
||||
// Process all references.
|
||||
for (const auto &atom : mf->defined()) {
|
||||
for (const auto &ref : *atom) {
|
||||
handleReference(*atom, *ref);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
/// \brief Owner of all the Atoms created by this pass.
|
||||
ELFPassFile _file;
|
||||
const ELFLinkingContext &_ctx;
|
||||
};
|
||||
|
||||
/// This implements the static relocation model. Meaning GOT and PLT entries are
|
||||
/// not created for references that can be directly resolved. These are
|
||||
/// converted to a direct relocation. For entries that do require a GOT or PLT
|
||||
/// entry, that entry is statically bound.
|
||||
///
|
||||
/// TLS always assumes module 1 and attempts to remove indirection.
|
||||
class ARMStaticRelocationPass final
|
||||
: public ARMRelocationPass<ARMStaticRelocationPass> {
|
||||
public:
|
||||
ARMStaticRelocationPass(const elf::ARMLinkingContext &ctx)
|
||||
: ARMRelocationPass(ctx) {}
|
||||
};
|
||||
|
||||
} // end anon namespace
|
||||
|
||||
std::unique_ptr<Pass>
|
||||
lld::elf::createARMRelocationPass(const ARMLinkingContext &ctx) {
|
||||
switch (ctx.getOutputELFType()) {
|
||||
case llvm::ELF::ET_EXEC:
|
||||
if (ctx.isDynamic())
|
||||
llvm_unreachable("Unhandled output file type");
|
||||
else
|
||||
return std::unique_ptr<Pass>(new ARMStaticRelocationPass(ctx));
|
||||
default:
|
||||
llvm_unreachable("Unhandled output file type");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//===--------- lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h ---------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// \brief Declares the relocation processing pass for ARM. This includes
|
||||
/// GOT and PLT entries, TLS, COPY, and ifunc.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_PASS_H
|
||||
#define LLD_READER_WRITER_ELF_ARM_ARM_RELOCATION_PASS_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace lld {
|
||||
class Pass;
|
||||
namespace elf {
|
||||
class ARMLinkingContext;
|
||||
|
||||
/// \brief Create ARM relocation pass for the given linking context.
|
||||
std::unique_ptr<Pass> createARMRelocationPass(const ARMLinkingContext &);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,10 @@
|
|||
//===--------- lib/ReaderWriter/ELF/ARM/ARMTarget.h -----------------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ARMLinkingContext.h"
|
|
@ -0,0 +1,43 @@
|
|||
//===--------- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp --------------===//
|
||||
//
|
||||
// The LLVM Linker
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "Atoms.h"
|
||||
#include "ARMExecutableWriter.h"
|
||||
#include "ARMTargetHandler.h"
|
||||
#include "ARMLinkingContext.h"
|
||||
|
||||
using namespace lld;
|
||||
using namespace elf;
|
||||
|
||||
ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &context)
|
||||
: _context(context), _armTargetLayout(
|
||||
new ARMTargetLayout<ARMELFType>(context)),
|
||||
_armRelocationHandler(new ARMTargetRelocationHandler()) {}
|
||||
|
||||
void ARMTargetHandler::registerRelocationNames(Registry ®istry) {
|
||||
registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM,
|
||||
kindStrings);
|
||||
}
|
||||
|
||||
std::unique_ptr<Writer> ARMTargetHandler::getWriter() {
|
||||
switch (this->_context.getOutputELFType()) {
|
||||
case llvm::ELF::ET_EXEC:
|
||||
return std::unique_ptr<Writer>(
|
||||
new ARMExecutableWriter<ARMELFType>(_context, *_armTargetLayout.get()));
|
||||
default:
|
||||
llvm_unreachable("unsupported output type");
|
||||
}
|
||||
}
|
||||
|
||||
#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),
|
||||
|
||||
const Registry::KindStrings ARMTargetHandler::kindStrings[] = {
|
||||
#include "llvm/Support/ELFRelocs/ARM.def"
|
||||
LLD_KIND_STRING_END
|
||||
};
|
|
@ -0,0 +1,68 @@
|
|||
//===--------- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.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_ARM_ARM_TARGET_HANDLER_H
|
||||
#define LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H
|
||||
|
||||
#include "ARMELFFile.h"
|
||||
#include "ARMELFReader.h"
|
||||
#include "ARMRelocationHandler.h"
|
||||
#include "DefaultTargetHandler.h"
|
||||
#include "TargetLayout.h"
|
||||
|
||||
#include "lld/Core/Simple.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include <map>
|
||||
|
||||
namespace lld {
|
||||
namespace elf {
|
||||
typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType;
|
||||
class ARMLinkingContext;
|
||||
|
||||
template <class ELFT> class ARMTargetLayout : public TargetLayout<ELFT> {
|
||||
public:
|
||||
ARMTargetLayout(ARMLinkingContext &context)
|
||||
: TargetLayout<ELFT>(context) {}
|
||||
};
|
||||
|
||||
class ARMTargetHandler final : public DefaultTargetHandler<ARMELFType> {
|
||||
public:
|
||||
ARMTargetHandler(ARMLinkingContext &context);
|
||||
|
||||
ARMTargetLayout<ARMELFType> &getTargetLayout() override {
|
||||
return *(_armTargetLayout.get());
|
||||
}
|
||||
|
||||
void registerRelocationNames(Registry ®istry) override;
|
||||
|
||||
const ARMTargetRelocationHandler &getRelocationHandler() const override {
|
||||
return *(_armRelocationHandler.get());
|
||||
}
|
||||
|
||||
std::unique_ptr<Reader> getObjReader(bool atomizeStrings) override {
|
||||
return std::unique_ptr<Reader>(new ARMELFObjectReader(atomizeStrings));
|
||||
}
|
||||
|
||||
std::unique_ptr<Reader> getDSOReader(bool useShlibUndefines) override {
|
||||
return std::unique_ptr<Reader>(new ARMELFDSOReader(useShlibUndefines));
|
||||
}
|
||||
|
||||
std::unique_ptr<Writer> getWriter() override;
|
||||
|
||||
private:
|
||||
static const Registry::KindStrings kindStrings[];
|
||||
ARMLinkingContext &_context;
|
||||
std::unique_ptr<ARMTargetLayout<ARMELFType>> _armTargetLayout;
|
||||
std::unique_ptr<ARMTargetRelocationHandler> _armRelocationHandler;
|
||||
};
|
||||
|
||||
} // end namespace elf
|
||||
} // end namespace lld
|
||||
|
||||
#endif // LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H
|
|
@ -0,0 +1,10 @@
|
|||
add_lld_library(lldARMELFTarget
|
||||
ARMLinkingContext.cpp
|
||||
ARMTargetHandler.cpp
|
||||
ARMRelocationHandler.cpp
|
||||
ARMRelocationPass.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(lldARMELFTarget ${cmake_2_8_12_INTERFACE}
|
||||
lldCore
|
||||
)
|
|
@ -0,0 +1,15 @@
|
|||
##===------ lld/lib/ReaderWriter/ELF/ARM/Makefile ----------*- Makefile -*-===##
|
||||
#
|
||||
# The LLVM Compiler Infrastructure
|
||||
#
|
||||
# This file is distributed under the University of Illinois Open Source
|
||||
# License. See LICENSE.TXT for details.
|
||||
#
|
||||
##===----------------------------------------------------------------------===##
|
||||
|
||||
LLD_LEVEL := ../../../..
|
||||
LIBRARYNAME := lldARMELFTarget
|
||||
USEDLIBS = lldCore.a
|
||||
CPP.Flags += -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF/ARM -I$(PROJ_SRC_DIR)/$(LLD_LEVEL)/lib/ReaderWriter/ELF
|
||||
|
||||
include $(LLD_LEVEL)/Makefile
|
|
@ -0,0 +1,20 @@
|
|||
ELF ARM
|
||||
~~~~~~~~~~~
|
||||
|
||||
Unimplemented Features
|
||||
######################
|
||||
|
||||
* Static executable linking - in progress
|
||||
* Dynamic executable linking
|
||||
* DSO linking
|
||||
* PLT entries' generation for images larger than 2^28 bytes (see Sec. A.3 of the ELF reference)
|
||||
* ARM and Thumb interworking (see http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0203j/Bcghfebi.html)
|
||||
* .ARM.exidx section handling
|
||||
* -init/-fini options
|
||||
* Lots of relocations
|
||||
|
||||
Unimplemented Relocations
|
||||
#########################
|
||||
|
||||
All of these relocations are defined in:
|
||||
http://infocenter.arm.com/help/topic/com.arm.doc.ihi0044e/IHI0044E_aaelf.pdf
|
|
@ -682,6 +682,11 @@ public:
|
|||
Reference::Addend a) {
|
||||
this->addReferenceELF(Reference::KindArch::AArch64, relocType, off, t, a);
|
||||
}
|
||||
|
||||
void addReferenceELF_ARM(uint16_t relocType, uint64_t off, const Atom *t,
|
||||
Reference::Addend a) {
|
||||
this->addReferenceELF(Reference::KindArch::ARM, relocType, off, t, a);
|
||||
}
|
||||
};
|
||||
|
||||
/// \brief Atom which represents an object for which a COPY relocation will be
|
||||
|
|
|
@ -14,6 +14,7 @@ target_link_libraries(lldELF ${cmake_2_8_12_INTERFACE}
|
|||
lldX86ELFTarget
|
||||
lldX86_64ELFTarget
|
||||
lldAArch64ELFTarget
|
||||
lldARMELFTarget
|
||||
)
|
||||
|
||||
include_directories(.)
|
||||
|
@ -24,3 +25,4 @@ add_subdirectory(PPC)
|
|||
add_subdirectory(Mips)
|
||||
add_subdirectory(Hexagon)
|
||||
add_subdirectory(AArch64)
|
||||
add_subdirectory(ARM)
|
||||
|
|
|
@ -85,6 +85,8 @@ uint16_t ELFLinkingContext::getOutputMachine() const {
|
|||
return llvm::ELF::EM_PPC;
|
||||
case llvm::Triple::aarch64:
|
||||
return llvm::ELF::EM_AARCH64;
|
||||
case llvm::Triple::arm:
|
||||
return llvm::ELF::EM_ARM;
|
||||
default:
|
||||
llvm_unreachable("Unhandled arch");
|
||||
}
|
||||
|
@ -148,6 +150,9 @@ ELFLinkingContext::create(llvm::Triple triple) {
|
|||
case llvm::Triple::aarch64:
|
||||
return std::unique_ptr<ELFLinkingContext>(
|
||||
new lld::elf::AArch64LinkingContext(triple));
|
||||
case llvm::Triple::arm:
|
||||
return std::unique_ptr<ELFLinkingContext>(
|
||||
new lld::elf::ARMLinkingContext(triple));
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#define LLD_READER_WRITER_ELF_TARGETS_H
|
||||
|
||||
#include "AArch64/AArch64Target.h"
|
||||
#include "ARM/ARMTarget.h"
|
||||
#include "Hexagon/HexagonTarget.h"
|
||||
#include "Mips/MipsTarget.h"
|
||||
#include "PPC/PPCTarget.h"
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
# Check that defined symbols are present in the generated executable
|
||||
|
||||
# RUN: yaml2obj -format=elf %s > %t-o.o
|
||||
# RUN: lld -flavor gnu -target arm-linux-gnu --defsym=main=fn -e=fn \
|
||||
# RUN: -static --noinhibit-exec %t-o.o -o %t
|
||||
# RUN: llvm-readobj -symbols %t | FileCheck %s
|
||||
|
||||
# CHECK: Symbol {
|
||||
# CHECK: Name: main (1)
|
||||
# CHECK: Value: 0x400075
|
||||
# CHECK: Size: 0
|
||||
# CHECK: Binding: Global (0x1)
|
||||
# CHECK: Type: Function (0x2)
|
||||
# CHECK: Other: 0
|
||||
# CHECK: Section: .text (0x1)
|
||||
# CHECK: }
|
||||
# CHECK: Symbol {
|
||||
# CHECK: Name: fn (6)
|
||||
# CHECK: Value: 0x400075
|
||||
# CHECK: Size: 15
|
||||
# CHECK: Binding: Global (0x1)
|
||||
# CHECK: Type: Function (0x2)
|
||||
# CHECK: Other: 0
|
||||
# CHECK: Section: .text (0x1)
|
||||
# CHECK: }
|
||||
|
||||
---
|
||||
FileHeader:
|
||||
Class: ELFCLASS32
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_REL
|
||||
Machine: EM_ARM
|
||||
Flags: [ EF_ARM_EABI_VER5 ]
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
AddressAlign: 0x0000000000000004
|
||||
Content: 80B400AF00231846BD465DF8047B7047
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
- Name: .bss
|
||||
Type: SHT_NOBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
- Name: .note.GNU-stack
|
||||
Type: SHT_PROGBITS
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
Symbols:
|
||||
Local:
|
||||
- Name: .text
|
||||
Type: STT_SECTION
|
||||
Section: .text
|
||||
- Name: .data
|
||||
Type: STT_SECTION
|
||||
Section: .data
|
||||
- Name: .bss
|
||||
Type: STT_SECTION
|
||||
Section: .bss
|
||||
- Name: .note.GNU-stack
|
||||
Type: STT_SECTION
|
||||
Section: .note.GNU-stack
|
||||
Global:
|
||||
- Name: fn
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 0x0000000000000001
|
||||
Size: 0x0000000000000010
|
||||
...
|
|
@ -0,0 +1,59 @@
|
|||
# Check handling of R_ARM_ABS32 relocation.
|
||||
# RUN: yaml2obj -format=elf %s > %t-o.o
|
||||
# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
|
||||
# RUN: --noinhibit-exec %t-o.o -o %t
|
||||
# RUN: llvm-objdump -s -t %t | FileCheck %s
|
||||
|
||||
# CHECK: Contents of section .data:
|
||||
# CHECK-NEXT: 401000 84004000
|
||||
# data = 0x400084 ^^
|
||||
# data main addr content
|
||||
# 0x400084 = 0x400074 + 0x10
|
||||
# CHECK: SYMBOL TABLE:
|
||||
# CHECK: 00400074 g F .text 0000001c main
|
||||
# CHECK: 00401000 g .data 00000004 data
|
||||
|
||||
---
|
||||
FileHeader:
|
||||
Class: ELFCLASS32
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_REL
|
||||
Machine: EM_ARM
|
||||
Flags: [ EF_ARM_EABI_VER5 ]
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
AddressAlign: 0x0000000000000004
|
||||
Content: 04B02DE500B08DE20030A0E30300A0E100D04BE204B09DE41EFF2FE1
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000004
|
||||
Content: '10000000'
|
||||
- Name: .rel.data
|
||||
Type: SHT_REL
|
||||
Link: .symtab
|
||||
AddressAlign: 0x0000000000000004
|
||||
Info: .data
|
||||
Relocations:
|
||||
- Offset: 0x0000000000000000
|
||||
Symbol: main
|
||||
Type: R_ARM_ABS32
|
||||
Addend: 0
|
||||
- Name: .bss
|
||||
Type: SHT_NOBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
Symbols:
|
||||
Global:
|
||||
- Name: main
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Size: 0x000000000000001C
|
||||
- Name: data
|
||||
Type: STT_OBJECT
|
||||
Section: .data
|
||||
Size: 0x0000000000000004
|
||||
...
|
|
@ -0,0 +1,60 @@
|
|||
# Check handling of R_ARM_CALL relocation.
|
||||
# RUN: yaml2obj -format=elf %s > %t-o.o
|
||||
# RUN: lld -flavor gnu -target arm -m armelf_linux_eabi -Bstatic \
|
||||
# RUN: --noinhibit-exec %t-o.o -o %t
|
||||
# RUN: llvm-objdump -s -t %t | FileCheck %s
|
||||
|
||||
# CHECK: Contents of section .text:
|
||||
# CHECK: 400084 1eff2fe1 00482de9 04b08de2 f7ffffeb
|
||||
# offset = -0x24 ^^
|
||||
# call site offset PC(arm) _Z1fv addr
|
||||
# 0x400090 + (-0x24) + 0x8 = 0x400074
|
||||
# CHECK: SYMBOL TABLE:
|
||||
# CHECK: 00400074 g F .text 00000014 _Z1fv
|
||||
# CHECK: 00400088 g F .text 00000018 main
|
||||
|
||||
---
|
||||
FileHeader:
|
||||
Class: ELFCLASS32
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_REL
|
||||
Machine: EM_ARM
|
||||
Flags: [ EF_ARM_EABI_VER5 ]
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
AddressAlign: 0x0000000000000004
|
||||
Content: 04B02DE500B08DE200D04BE204B09DE41EFF2FE100482DE904B08DE2FEFFFFEB0030A0E30300A0E10088BDE8
|
||||
- Name: .rel.text
|
||||
Type: SHT_REL
|
||||
Link: .symtab
|
||||
AddressAlign: 0x0000000000000004
|
||||
Info: .text
|
||||
Relocations:
|
||||
- Offset: 0x000000000000001C
|
||||
Symbol: _Z1fv
|
||||
Type: R_ARM_CALL
|
||||
Addend: 0
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
- Name: .bss
|
||||
Type: SHT_NOBITS
|
||||
Flags: [ SHF_WRITE, SHF_ALLOC ]
|
||||
AddressAlign: 0x0000000000000001
|
||||
Content: ''
|
||||
Symbols:
|
||||
Global:
|
||||
- Name: _Z1fv
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Size: 0x0000000000000014
|
||||
- Name: main
|
||||
Type: STT_FUNC
|
||||
Section: .text
|
||||
Value: 0x0000000000000014
|
||||
Size: 0x0000000000000018
|
||||
...
|
Loading…
Reference in New Issue