Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[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
- Loading branch information
Showing
24 changed files
with
907 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 |
Oops, something went wrong.