Skip to content

Commit

Permalink
[ELF] Minimal implementation for ARM static linking
Browse files Browse the repository at this point in the history
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
  • Loading branch information
garious committed Jan 21, 2015
1 parent f38dea1 commit 8a1887f
Show file tree
Hide file tree
Showing 24 changed files with 907 additions and 0 deletions.
1 change: 1 addition & 0 deletions lld/docs/open_projects.rst
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions lld/lib/Driver/GnuLdDriver.cpp
Expand Up @@ -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;
}
Expand Down
41 changes: 41 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/ARMELFFile.h
@@ -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
60 changes: 60 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/ARMELFReader.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
58 changes: 58 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.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
21 changes: 21 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp
@@ -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);
}
40 changes: 40 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h
@@ -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
109 changes: 109 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp
@@ -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();
}
32 changes: 32 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h
@@ -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 comments on commit 8a1887f

Please sign in to comment.