[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:
Greg Fitzgerald 2015-01-21 07:35:48 +00:00
parent f38dea1cfa
commit 8a1887f1f1
24 changed files with 907 additions and 0 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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();
}

View File

@ -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

View File

@ -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");
}
}

View File

@ -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

View File

@ -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"

View File

@ -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 &registry) {
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
};

View File

@ -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 &registry) 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

View File

@ -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
)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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;
}

View File

@ -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"

View File

@ -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
...

View File

@ -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
...

View File

@ -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
...