Index: docs/open_projects.rst =================================================================== --- docs/open_projects.rst +++ docs/open_projects.rst @@ -8,6 +8,7 @@ .. 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 Index: lib/Driver/GnuLdDriver.cpp =================================================================== --- lib/Driver/GnuLdDriver.cpp +++ lib/Driver/GnuLdDriver.cpp @@ -218,6 +218,10 @@ 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; } Index: lib/ReaderWriter/ELF/ARM/ARMELFFile.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ARM/ARMELFFile.h @@ -0,0 +1,73 @@ +//===--------- 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 ARMELFFile : public ELFFile { +public: + ARMELFFile(StringRef name, bool atomizeStrings) + : ELFFile(name, atomizeStrings) {} + + ARMELFFile(std::unique_ptr mb, bool atomizeStrings, + std::error_code &ec) + : ELFFile(std::move(mb), atomizeStrings, ec) {} + + static ErrorOr> + create(std::unique_ptr mb, bool atomizeStrings) { + std::error_code ec; + std::unique_ptr> file( + new ARMELFFile(mb->getBufferIdentifier(), atomizeStrings)); + + file->_objFile.reset( + new llvm::object::ELFFile(mb.release()->getBuffer(), ec)); + + if (ec) + return ec; + + // Read input sections from the input file that need to be converted to + // atoms + if ((ec = file->createAtomizableSections())) + return ec; + + // For mergeable strings, we would need to split the section into various + // atoms + if ((ec = file->createMergeableAtoms())) + return ec; + + // Create the necessary symbols that are part of the section that we + // created in createAtomizableSections function + if ((ec = file->createSymbolsFromAtomizableSections())) + return ec; + + // Create the appropriate atoms from the file + if ((ec = file->createAtoms())) + return ec; + + return std::move(file); + } +}; + +template class ARMDynamicFile : public DynamicFile { +public: + ARMDynamicFile(const ARMLinkingContext &context, StringRef name) + : DynamicFile(context, name) {} +}; + +} // elf +} // lld + +#endif // LLD_READER_WRITER_ELF_ARM_ARM_ELF_FILE_H Index: lib/ReaderWriter/ELF/ARM/ARMELFReader.h =================================================================== --- /dev/null +++ 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 ARMELFType; + +struct ARMDynamicFileCreateELFTraits { + typedef llvm::ErrorOr> result_type; + + template + static result_type create(std::unique_ptr mb, + bool useUndefines) { + return lld::elf::ARMDynamicFile::create(std::move(mb), useUndefines); + } +}; + +struct ARMELFFileCreateELFTraits { + typedef llvm::ErrorOr> result_type; + + template + static result_type create(std::unique_ptr mb, + bool atomizeStrings) { + return lld::elf::ARMELFFile::create(std::move(mb), atomizeStrings); + } +}; + +class ARMELFObjectReader + : public ELFObjectReader { +public: + ARMELFObjectReader(bool atomizeStrings) + : ELFObjectReader( + atomizeStrings, llvm::ELF::EM_ARM) {} +}; + +class ARMELFDSOReader + : public ELFDSOReader { +public: + ARMELFDSOReader(bool useUndefines) + : ELFDSOReader( + useUndefines, llvm::ELF::EM_ARM) {} +}; + +} // namespace elf +} // namespace lld + +#endif // LLD_READER_WRITER_ARM_ARM_ELF_READER_H Index: lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ARM/ARMExecutableWriter.h @@ -0,0 +1,107 @@ +//===--------- 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 ARM_EXECUTABLE_WRITER_H +#define ARM_EXECUTABLE_WRITER_H + +#include "ExecutableWriter.h" +#include "ARMLinkingContext.h" + +namespace lld { +namespace elf { + +template +class ARMExecutableWriter : public ExecutableWriter { +public: + ARMExecutableWriter(ARMLinkingContext &context, + ARMTargetLayout &layout); + +protected: + // Add any runtime files and their atoms to the output + bool createImplicitFiles(std::vector> &) override; + + // Finalize custom atom values + void finalizeARMAtomValues(); + + void finalizeDefaultAtomValues() override { + // Finalize the atom values that are part of the parent. + ExecutableWriter::finalizeDefaultAtomValues(); + finalizeARMAtomValues(); + } + + void addDefaultAtoms() override { + _armRuntimeFile->addAbsoluteAtom("__exidx_start"); + _armRuntimeFile->addAbsoluteAtom("__exidx_end"); + + _gotFile->addAtom(*new (_gotFile->_alloc) + GLOBAL_OFFSET_TABLEAtom(*_gotFile)); + } + +private: + class GOTFile : public SimpleFile { + public: + GOTFile(const ELFLinkingContext &eti) : SimpleFile("GOTFile") {} + llvm::BumpPtrAllocator _alloc; + }; + + /// \brief ARM Runtime file. + template + class ARMRuntimeFile final : public CRuntimeFile { + public: + ARMRuntimeFile(const ARMLinkingContext &ctx) + : CRuntimeFile(ctx, "ARM runtime file") {} + }; + + std::unique_ptr _gotFile; + std::unique_ptr> _armRuntimeFile; + ARMLinkingContext &_context; + ARMTargetLayout &_ARMLayout; +}; + +template +ARMExecutableWriter::ARMExecutableWriter(ARMLinkingContext &context, + ARMTargetLayout &layout) + : ExecutableWriter(context, layout), _gotFile(new GOTFile(context)), + _armRuntimeFile(new ARMRuntimeFile(context)), _context(context), + _ARMLayout(layout) {} + +template +bool ARMExecutableWriter::createImplicitFiles( + std::vector> &result) { + ExecutableWriter::createImplicitFiles(result); + // Add the default atoms as defined for ARM + addDefaultAtoms(); + result.push_back(std::move(_armRuntimeFile)); + result.push_back(std::move(_gotFile)); + return true; +} + +template +void ARMExecutableWriter::finalizeARMAtomValues() { + auto startEnd = [&](StringRef sym, StringRef sec) -> void { + std::string start = ("__" + sym + "_start").str(); + std::string end = ("__" + sym + "_end").str(); + auto s = this->_layout.findAbsoluteAtom(start); + auto e = this->_layout.findAbsoluteAtom(end); + auto section = this->_layout.findOutputSection(sec); + if (section) { + (*s)->_virtualAddr = section->virtualAddr(); + (*e)->_virtualAddr = section->virtualAddr() + section->memSize(); + } else { + (*s)->_virtualAddr = 0; + (*e)->_virtualAddr = 0; + } + }; + + startEnd("exidx", ".ARM.exidx"); +} + +} // namespace elf +} // namespace lld + +#endif Index: lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ARM/ARMLinkingContext.h @@ -0,0 +1,83 @@ +//===--------- 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( + new ARMTargetHandler(*this))) {} + + void addPasses(PassManager &) override; + + uint64_t getBaseAddress() const override { + if (_baseAddress == 0) + return 0x400000; + return _baseAddress; + } + + bool isDynamicRelocation(const DefinedAtom &, + const Reference &r) const override { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::ARM); + switch (r.kindValue()) { + case llvm::ELF::R_ARM_TLS_DTPMOD32: + case llvm::ELF::R_ARM_TLS_DTPOFF32: + case llvm::ELF::R_ARM_TLS_TPOFF32: + case llvm::ELF::R_ARM_COPY: + case llvm::ELF::R_ARM_GLOB_DAT: + case llvm::ELF::R_ARM_JUMP_SLOT: + case llvm::ELF::R_ARM_RELATIVE: + return true; + default: + return false; + } + } + + bool isPLTRelocation(const DefinedAtom &, const Reference &r) const override { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::ARM); + switch (r.kindValue()) { + case llvm::ELF::R_ARM_JUMP_SLOT: + return true; + default: + return false; + } + } + + bool isRelativeReloc(const Reference &r) const override { + if (r.kindNamespace() != Reference::KindNamespace::ELF) + return false; + assert(r.kindArch() == Reference::KindArch::ARM); + switch (r.kindValue()) { + case llvm::ELF::R_ARM_RELATIVE: + return true; + default: + return false; + } + } +}; +} // end namespace elf +} // end namespace lld + +#endif Index: lib/ReaderWriter/ELF/ARM/ARMLinkingContext.cpp =================================================================== --- /dev/null +++ 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); +} Index: lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.h @@ -0,0 +1,38 @@ +//===--------- 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 ARM_RELOCATION_HANDLER_H +#define ARM_RELOCATION_HANDLER_H + +#include "ARMTargetHandler.h" + +namespace lld { +namespace elf { +typedef llvm::object::ELFType ARMELFType; + +template class ARMTargetLayout; + +class ARMTargetRelocationHandler final + : public TargetRelocationHandler { +public: + ARMTargetRelocationHandler(ARMTargetLayout &layout) + : _ARMTargetLayout(layout) {} + + std::error_code applyRelocation(ELFWriter &, llvm::FileOutputBuffer &, + const lld::AtomLayout &, + const Reference &) const override; + +private: + ARMTargetLayout &_ARMTargetLayout; +}; + +} // end namespace elf +} // end namespace lld + +#endif // ARM_RELOCATION_HANDLER_H Index: lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ARM/ARMRelocationHandler.cpp @@ -0,0 +1,472 @@ +//===--------- 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" + +using namespace lld; +using namespace elf; + +template +static Reference::Addend signExtend(Type value, Type highBitPos) { + if (value & highBitPos) { + // calculate all higher bits for filling + const Type fillBits = ~((highBitPos << 1) - 1); + + assert(!(value & fillBits)); + value |= fillBits; + } + return value; +} + +static Reference::Addend readAddend_THM_MOV(const uint8_t *location) { + const auto halfHi = int16_t( + *reinterpret_cast(location)); + const auto halfLo = int16_t( + *reinterpret_cast(location + 2)); + + const int16_t imm8 = halfLo & 0xFF; + const int16_t imm3 = (halfLo >> 12) & 0x7; + + const int16_t imm4 = halfHi & 0xF; + const int16_t bitI = (halfHi >> 10) & 0x1; + + const int16_t result = (imm4 << 12) | (bitI << 11) | (imm3 << 8) | imm8; + return result; +} + +static Reference::Addend readAddend_THM_CALL(const uint8_t *location) { + const auto halfHi = int16_t( + *reinterpret_cast(location)); + const auto halfLo = int16_t( + *reinterpret_cast(location + 2)); + + const int16_t imm10 = halfHi & 0x3FF; + const int16_t bitS = (halfHi >> 10) & 0x1; + + const int16_t imm11 = halfLo & 0x7FF; + const int16_t bitJ2 = (halfLo >> 11) & 0x1; + const int16_t bitI2 = (~(bitJ2 ^ bitS)) & 0x1; + const int16_t bitJ1 = (halfLo >> 13) & 0x1; + const int16_t bitI1 = (~(bitJ1 ^ bitS)) & 0x1; + + const int32_t result = (bitS << 24) | (bitI1 << 23) | (bitI2 << 22) | + (imm10 << 12) | (imm11 << 1); + return signExtend(result, 0x1000000); +} + +static Reference::Addend readAddend_ARM_CALL(const uint8_t *location) { + const auto value = int32_t( + *reinterpret_cast(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 signExtend(result, 0x2000000); +} + +static Reference::Addend readInitialAddend(const uint8_t *location, + Reference::KindValue kindValue) { + switch (kindValue) { + case R_ARM_ABS32: + case R_ARM_REL32: + case R_ARM_BASE_PREL: + case R_ARM_TARGET1: + case R_ARM_TLS_IE32: + case R_ARM_TLS_LE32: + return int32_t( + *reinterpret_cast(location)); + case R_ARM_PREL31: + return int32_t(*reinterpret_cast( + location)) & 0x7FFFFFFF; + case R_ARM_THM_CALL: + case R_ARM_THM_JUMP24: + return readAddend_THM_CALL(location); + case R_ARM_CALL: + case R_ARM_JUMP24: + return readAddend_ARM_CALL(location); + case R_ARM_THM_MOVW_ABS_NC: + case R_ARM_THM_MOVT_ABS: + return readAddend_THM_MOV(location); + case R_ARM_THM_JUMP11: + return int16_t(*reinterpret_cast( + location)) & 0x7FF; + default: + return 0; + } +} + +static Reference::Addend readAddend(const uint8_t *location, + Reference::KindValue kindValue, + Reference::Addend addend) { + return addend + readInitialAddend(location, kindValue); +} + +static inline void applyArmReloc(uint8_t *location, uint32_t result, + uint32_t mask = 0xFFFFFFFF) { + assert(!(result & ~mask)); + *reinterpret_cast(location) = + (uint32_t(*reinterpret_cast(location)) & + ~mask) | (result & mask); +} + +static inline void applyThmReloc(uint8_t *location, uint16_t resHi, + uint16_t resLo, uint16_t maskHi, + uint16_t maskLo = 0xFFFF) { + assert(!(resHi & ~maskHi) && !(resLo & ~maskLo)); + *reinterpret_cast(location) = + (uint16_t(*reinterpret_cast(location)) & + ~maskHi) | (resHi & maskHi); + location += 2; + *reinterpret_cast(location) = + (uint16_t(*reinterpret_cast(location)) & + ~maskLo) | (resLo & maskLo); +} + +/// \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_REL32 - ((S + A) | T) - P => S + A - P +static void relocR_ARM_REL32(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + uint32_t result = (uint32_t)((S + A) - P); + 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 Relocate B/BL instructions. useJs defines whether J1 & J2 are used +static void relocR_ARM_THM_B_L(uint8_t *location, uint64_t P, uint64_t S, + int64_t A, bool useJs) { + uint32_t result = (uint32_t)((S + A) - P); + result = (result & 0x01FFFFFE) >> 1; + + const uint16_t imm10 = (result >> 11) & 0x3FF; + const uint16_t bitS = (result >> 23) & 0x1; + const uint16_t resHi = (bitS << 10) | imm10; + + const uint16_t imm11 = result & 0x7FF; + const uint16_t bitJ2 = useJs ? ((result >> 21) & 0x1) : bitS; + const uint16_t bitI2 = (~(bitJ2 ^ bitS)) & 0x1; + const uint16_t bitJ1 = useJs ? ((result >> 22) & 0x1) : bitS; + const uint16_t bitI1 = (~(bitJ1 ^ bitS)) & 0x1; + const uint16_t resLo = (bitI1 << 13) | (bitI2 << 11) | imm11; + 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() << " resHi: 0x" << Twine::utohexstr(resHi); + llvm::dbgs() << " resLo: 0x" << Twine::utohexstr(resLo) << "\n"); + applyThmReloc(location, resHi, resLo, 0x7FF, 0x2FFF); +} + +/// \brief R_ARM_THM_CALL - ((S + A) | T) - P => S + A - P +static void relocR_ARM_THM_CALL(uint8_t *location, uint64_t P, uint64_t S, + int64_t A, bool useJs) { + return relocR_ARM_THM_B_L(location, P, S, A, useJs); +} + +/// \brief R_ARM_THM_JUMP24 - ((S + A) | T) - P => S + A - P +static void relocR_ARM_THM_JUMP24(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + return relocR_ARM_THM_B_L(location, P, S, A, true); +} + +/// \brief R_ARM_TARGET1 - R_ARM_ABS32 or R_ARM_REL32 depending +/// on absNotRel flag +static void relocR_ARM_TARGET1(uint8_t *location, uint64_t P, uint64_t S, + int64_t A, bool absNotRel) { + if (absNotRel) { + return relocR_ARM_ABS32(location, P, S, A); + } else { + return relocR_ARM_REL32(location, P, S, A); + } +} + +/// \brief R_ARM_BASE_PREL - B(S) + A - P => S + A - P +static void relocR_ARM_BASE_PREL(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + uint32_t result = (uint32_t)(S + A - P); + 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_GOT_BREL - GOT(S) + A - GOT_ORG => S + A - GOT_ORG +static void relocR_ARM_GOT_BREL(uint8_t *location, uint64_t P, uint64_t S, + int64_t A, uint64_t GOT_ORG) { + uint32_t result = (uint32_t)(S + A - GOT_ORG); + 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 bitH = S & 0x1 ? ((result & 0x2) >> 1) : 1; + result = (result & 0x03FFFFFC) >> 2; + result |= (bitH << 24); + + 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, 0x1FFFFFF); +} + +/// \brief R_ARM_JUMP24 - ((S + A) | T) - P => S + A - P +static void relocR_ARM_JUMP24(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + uint32_t result = (uint32_t)((S + A) - P); + result = (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, result, 0xFFFFFF); +} + +/// \brief R_ARM_PREL31 - ((S + A) | T) - P => S + A - P +static void relocR_ARM_PREL31(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + uint32_t result = (uint32_t)((S + A) - P); + + const uint32_t mask = 0x7FFFFFFF; + result &= mask; + 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, mask); +} + +/// \brief Relocate MOVW/MOVT instructions +static void relocR_ARM_THM_MOV(uint8_t *location, uint32_t result) { + const uint16_t imm8 = result & 0xFF; + const uint16_t imm3 = (result >> 8) & 0x7; + const uint16_t resLo = (imm3 << 12) | imm8; + + const uint16_t imm4 = (result >> 12) & 0xF; + const uint16_t bitI = (result >> 11) & 0x1; + const uint16_t resHi = (bitI << 10) | imm4; + DEBUG_WITH_TYPE( + "ARM", llvm::dbgs() << "\t\tHandle " << LLVM_FUNCTION_NAME << " -"; + llvm::dbgs() << " resHi: 0x" << Twine::utohexstr(resHi); + llvm::dbgs() << " resLo: 0x" << Twine::utohexstr(resLo) << "\n"); + applyThmReloc(location, resHi, resLo, 0x40F, 0x70FF); +} + +/// \brief R_ARM_THM_MOVW_ABS_NC - (S + A) | T => S + A +static void relocR_ARM_THM_MOVW_ABS_NC(uint8_t *location, uint64_t P, + uint64_t S, int64_t A) { + uint32_t result = (uint32_t)(S + A); + result &= 0x0000FFFF; + 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"); + return relocR_ARM_THM_MOV(location, result); +} + +/// \brief R_ARM_THM_MOVT_ABS - S + A +static void relocR_ARM_THM_MOVT_ABS(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + uint32_t result = (uint32_t)(S + A); + result &= 0xFFFF0000; + result >>= 16; + 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"); + return relocR_ARM_THM_MOV(location, result); +} + +/// \brief R_ARM_THM_JUMP11 - S + A - P +static void relocR_ARM_THM_JUMP11(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + uint32_t result = (uint32_t)((S + A) - P); + result = (result & 0xFFE) >> 1; + 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, 0x7FF); +} + +/// \brief R_ARM_TLS_IE32 - GOT(S) + A - P +static void relocR_ARM_TLS_IE32(uint8_t *location, uint64_t P, uint64_t S, + int64_t A) { + uint32_t result = (uint32_t)((S + A) - P); + 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_TLS_LE32 - S + A - tp => S + A +static void relocR_ARM_TLS_LE32(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_TLS_TPOFF32 - S + A - tp => S + A +static void relocR_ARM_TLS_TPOFF32(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); +} + +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(); + + // Calculate proper initial addend for the relocation + const Reference::Addend addend = + readAddend(location, ref.kindValue(), ref.addend()); + + if (ref.kindNamespace() != Reference::KindNamespace::ELF) + return std::error_code(); + assert(ref.kindArch() == Reference::KindArch::ARM); + switch (ref.kindValue()) { + case R_ARM_NONE: + break; + case R_ARM_ABS32: + relocR_ARM_ABS32(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_REL32: + relocR_ARM_REL32(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_THM_CALL: + // TODO: consider adding bool variable to disable J1 & J2 for archs + // before ARMv6 + relocR_ARM_THM_CALL(location, relocVAddress, targetVAddress, addend, true); + break; + case R_ARM_BASE_PREL: + if (!targetVAddress) { + // GOT origin is used for NULL symbol + targetVAddress = _ARMTargetLayout.getGOTSymAddr(); + } else if (auto segment = + _ARMTargetLayout.findSegmentByAtom(ref.target())) { + targetVAddress = segment->virtualAddr(); + } else { + llvm_unreachable("The atom is not in any of the loadable segments"); + } + relocR_ARM_BASE_PREL(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_GOT_BREL: + relocR_ARM_GOT_BREL(location, relocVAddress, targetVAddress, addend, + _ARMTargetLayout.getGOTSymAddr()); + break; + case R_ARM_CALL: + relocR_ARM_CALL(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_JUMP24: + relocR_ARM_JUMP24(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_THM_JUMP24: + relocR_ARM_THM_JUMP24(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_TARGET1: + // TODO: add cases of handling relative relocations + relocR_ARM_TARGET1(location, relocVAddress, targetVAddress, addend, true); + break; + case R_ARM_PREL31: + relocR_ARM_PREL31(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_THM_MOVW_ABS_NC: + relocR_ARM_THM_MOVW_ABS_NC(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_THM_MOVT_ABS: + relocR_ARM_THM_MOVT_ABS(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_THM_JUMP11: + relocR_ARM_THM_JUMP11(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_TLS_IE32: + relocR_ARM_TLS_IE32(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_TLS_LE32: + relocR_ARM_TLS_LE32(location, relocVAddress, targetVAddress, addend); + break; + case R_ARM_TLS_TPOFF32: + relocR_ARM_TLS_TPOFF32(location, relocVAddress, targetVAddress, addend); + break; + default: { + std::string str; + llvm::raw_string_ostream s(str); + s << "Unhandled relocation: " << atom._atom->file().path() << ":" + << atom._atom->name() << "@" << ref.offsetInAtom() << " " + << "#" << ref.kindValue(); + s.flush(); + llvm_unreachable(str.c_str()); + } + } + + return std::error_code(); +} Index: lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h @@ -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 + +namespace lld { +class Pass; +namespace elf { +class ARMLinkingContext; + +/// \brief Create ARM relocation pass for the given linking context. +std::unique_ptr createARMRelocationPass(const ARMLinkingContext &); +} +} + +#endif Index: lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp @@ -0,0 +1,247 @@ +//===--------- 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 { +// .got values +const uint8_t ARMGotAtomContent[4] = {0}; + +/// \brief Atoms that are used by ARM dynamic linking +class ARMGOTAtom : public GOTAtom { +public: + ARMGOTAtom(const File &f, StringRef secName) : GOTAtom(f, secName) {} + + ArrayRef rawContent() const override { + return llvm::makeArrayRef(ARMGotAtomContent); + } + + Alignment alignment() const override { return Alignment(2); } +}; + +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 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()) { + case R_ARM_GOT_BREL: + static_cast(this)->handleGOT(ref); + break; + case R_ARM_TLS_IE32: + const_cast(ref).setTarget(getTLSIEGOTEntry(ref.target())); + break; + } + } + +protected: + /// \brief Create a GOT entry containing 0. + const GOTAtom *getNullGOT() { + if (!_null) { + _null = new (_file._alloc) ARMGOTAtom(_file, ".got.plt"); +#ifndef NDEBUG + _null->_name = "__got_null"; +#endif + } + return _null; + } + + const GOTAtom *getGOT(const DefinedAtom *da) { + auto got = _gotMap.find(da); + if (got == _gotMap.end()) { + auto g = new (_file._alloc) ARMGOTAtom(_file, ".got"); + g->addReferenceELF_ARM(R_ARM_ABS32, 0, da, 0); +#ifndef NDEBUG + g->_name = "__got_"; + g->_name += da->name(); +#endif + _gotMap[da] = g; + _gotVector.push_back(g); + return g; + } + return got->second; + } + + const GOTAtom *getTLSIEGOTEntry(const Atom *a) { + auto got = _gotMap.find(a); + if (got == _gotMap.end()) { + auto g = new (_file._alloc) ARMGOTAtom(_file, ".got"); + g->addReferenceELF_ARM(R_ARM_TLS_TPOFF32, 0, a, 0); +#ifndef NDEBUG + g->_name = "__got_tls_"; + g->_name += a->name(); +#endif + _gotMap[a] = g; + _gotVector.push_back(g); + return g; + } + return got->second; + } + +public: + ARMRelocationPass(const ELFLinkingContext &ctx) + : _file(ctx), _ctx(ctx), _null(nullptr) {} + + /// \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 &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); + } + } + + // Add all created atoms to the link. + uint64_t ordinal = 0; + for (auto &plt : _pltVector) { + plt->setOrdinal(ordinal++); + mf->addAtom(*plt); + } + if (_null) { + _null->setOrdinal(ordinal++); + mf->addAtom(*_null); + } + for (auto &got : _gotVector) { + got->setOrdinal(ordinal++); + mf->addAtom(*got); + } + for (auto obj : _objectVector) { + obj->setOrdinal(ordinal++); + mf->addAtom(*obj); + } + } + +protected: + /// \brief Owner of all the Atoms created by this pass. + ELFPassFile _file; + const ELFLinkingContext &_ctx; + + /// \brief Map Atoms to their GOT entries. + llvm::DenseMap _gotMap; + + /// \brief Map Atoms to their PLT entries. + llvm::DenseMap _pltMap; + + /// \brief Map Atoms to their Object entries. + llvm::DenseMap _objectMap; + + /// \brief the list of GOT/PLT atoms + std::vector _gotVector; + std::vector _pltVector; + std::vector _objectVector; + + /// \brief GOT entry that is always 0. Used for undefined weaks. + GOTAtom *_null; +}; + +/// 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 { +public: + ARMStaticRelocationPass(const elf::ARMLinkingContext &ctx) + : ARMRelocationPass(ctx) {} + + std::error_code handleGOT(const Reference &ref) { + if (isa(ref.target())) + const_cast(ref).setTarget(getNullGOT()); + else if (const DefinedAtom *da = dyn_cast(ref.target())) + const_cast(ref).setTarget(getGOT(da)); + return std::error_code(); + } +}; + +} // end anon namespace + +std::unique_ptr +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(new ARMStaticRelocationPass(ctx)); + default: + llvm_unreachable("Unhandled output file type"); + } +} Index: lib/ReaderWriter/ELF/ARM/ARMTarget.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ARM/ARMTarget.h @@ -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" Index: lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h @@ -0,0 +1,112 @@ +//===--------- 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 + +namespace lld { +namespace elf { +typedef llvm::object::ELFType ARMELFType; +class ARMLinkingContext; + +template class ARMTargetLayout : public TargetLayout { +public: + ARMTargetLayout(ARMLinkingContext &context) + : TargetLayout(context) {} + + uint64_t getGOTSymAddr() { + if (!_gotSymAddr.hasValue()) { + uint64_t addr = 0; + this->findAtomAddrByName("_GLOBAL_OFFSET_TABLE_", addr); + _gotSymAddr = addr; + } + return *_gotSymAddr; + } + + Segment *findSegmentByAtom(const Atom *atom) { + const auto atomName = atom->name(); + + // Try to find a cached value + typename AtomToSegmentMapT::iterator it = _atomToSegmentMap.find(atomName); + if (_atomToSegmentMap.end() != it) { + return it->second; + } + + for (auto segment : this->segments()) { + // Skip non loadable segments + if (segment->segmentType() != llvm::ELF::PT_LOAD) + continue; + + for (auto slice : segment->slices()) { + for (auto sec : slice->sections()) { + uint64_t atomAddr = 0; + + if (auto section = dyn_cast>(sec)) + if (section->findAtomAddrByName(atomName, atomAddr)) { + _atomToSegmentMap[atomName] = segment; + return segment; + } + } + } + } + return nullptr; + } + +private: + llvm::Optional _gotSymAddr; + + typedef std::map *> AtomToSegmentMapT; + AtomToSegmentMapT _atomToSegmentMap; +}; + +class ARMTargetHandler final : public DefaultTargetHandler { +public: + ARMTargetHandler(ARMLinkingContext &context); + + ARMTargetLayout &getTargetLayout() override { + return *(_ARMTargetLayout.get()); + } + + void registerRelocationNames(Registry ®istry) override; + + const ARMTargetRelocationHandler &getRelocationHandler() const override { + return *(_ARMRelocationHandler.get()); + } + + std::unique_ptr getObjReader(bool atomizeStrings) override { + return std::unique_ptr(new ARMELFObjectReader(atomizeStrings)); + } + + std::unique_ptr getDSOReader(bool useShlibUndefines) override { + return std::unique_ptr(new ARMELFDSOReader(useShlibUndefines)); + } + + std::unique_ptr getWriter() override; + +private: + static const Registry::KindStrings kindStrings[]; + ARMLinkingContext &_context; + std::unique_ptr> _ARMTargetLayout; + std::unique_ptr _ARMRelocationHandler; +}; + +} // end namespace elf +} // end namespace lld + +#endif Index: lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp @@ -0,0 +1,172 @@ +//===--------- 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) + : DefaultTargetHandler(context), _context(context), + _ARMTargetLayout(new ARMTargetLayout(context)), + _ARMRelocationHandler(new ARMTargetRelocationHandler(*_ARMTargetLayout)) { +} + +void ARMTargetHandler::registerRelocationNames(Registry ®istry) { + registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM, + kindStrings); +} + +std::unique_ptr ARMTargetHandler::getWriter() { + switch (this->_context.getOutputELFType()) { + case llvm::ELF::ET_EXEC: + return std::unique_ptr( + new ARMExecutableWriter(_context, *_ARMTargetLayout.get())); + default: + llvm_unreachable("unsupported output type"); + } +} + +const Registry::KindStrings ARMTargetHandler::kindStrings[] = { + LLD_KIND_STRING_ENTRY(R_ARM_NONE), + LLD_KIND_STRING_ENTRY(R_ARM_PC24), + LLD_KIND_STRING_ENTRY(R_ARM_ABS32), + LLD_KIND_STRING_ENTRY(R_ARM_REL32), + LLD_KIND_STRING_ENTRY(R_ARM_LDR_PC_G0), + LLD_KIND_STRING_ENTRY(R_ARM_ABS16), + LLD_KIND_STRING_ENTRY(R_ARM_ABS12), + LLD_KIND_STRING_ENTRY(R_ARM_THM_ABS5), + LLD_KIND_STRING_ENTRY(R_ARM_ABS8), + LLD_KIND_STRING_ENTRY(R_ARM_SBREL32), + LLD_KIND_STRING_ENTRY(R_ARM_THM_CALL), + LLD_KIND_STRING_ENTRY(R_ARM_THM_PC8), + LLD_KIND_STRING_ENTRY(R_ARM_BREL_ADJ), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_DESC), + LLD_KIND_STRING_ENTRY(R_ARM_THM_SWI8), + LLD_KIND_STRING_ENTRY(R_ARM_XPC25), + LLD_KIND_STRING_ENTRY(R_ARM_THM_XPC22), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_DTPMOD32), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_DTPOFF32), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_TPOFF32), + LLD_KIND_STRING_ENTRY(R_ARM_COPY), + LLD_KIND_STRING_ENTRY(R_ARM_GLOB_DAT), + LLD_KIND_STRING_ENTRY(R_ARM_JUMP_SLOT), + LLD_KIND_STRING_ENTRY(R_ARM_RELATIVE), + LLD_KIND_STRING_ENTRY(R_ARM_GOTOFF32), + LLD_KIND_STRING_ENTRY(R_ARM_BASE_PREL), + LLD_KIND_STRING_ENTRY(R_ARM_GOT_BREL), + LLD_KIND_STRING_ENTRY(R_ARM_PLT32), + LLD_KIND_STRING_ENTRY(R_ARM_CALL), + LLD_KIND_STRING_ENTRY(R_ARM_JUMP24), + LLD_KIND_STRING_ENTRY(R_ARM_THM_JUMP24), + LLD_KIND_STRING_ENTRY(R_ARM_BASE_ABS), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_PCREL_7_0), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_PCREL_15_8), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_PCREL_23_15), + LLD_KIND_STRING_ENTRY(R_ARM_LDR_SBREL_11_0_NC), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_SBREL_19_12_NC), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_SBREL_27_20_CK), + LLD_KIND_STRING_ENTRY(R_ARM_TARGET1), + LLD_KIND_STRING_ENTRY(R_ARM_SBREL31), + LLD_KIND_STRING_ENTRY(R_ARM_V4BX), + LLD_KIND_STRING_ENTRY(R_ARM_TARGET2), + LLD_KIND_STRING_ENTRY(R_ARM_PREL31), + LLD_KIND_STRING_ENTRY(R_ARM_MOVW_ABS_NC), + LLD_KIND_STRING_ENTRY(R_ARM_MOVT_ABS), + LLD_KIND_STRING_ENTRY(R_ARM_MOVW_PREL_NC), + LLD_KIND_STRING_ENTRY(R_ARM_MOVT_PREL), + LLD_KIND_STRING_ENTRY(R_ARM_THM_MOVW_ABS_NC), + LLD_KIND_STRING_ENTRY(R_ARM_THM_MOVT_ABS), + LLD_KIND_STRING_ENTRY(R_ARM_THM_MOVW_PREL_NC), + LLD_KIND_STRING_ENTRY(R_ARM_THM_MOVT_PREL), + LLD_KIND_STRING_ENTRY(R_ARM_THM_JUMP19), + LLD_KIND_STRING_ENTRY(R_ARM_THM_JUMP6), + LLD_KIND_STRING_ENTRY(R_ARM_THM_ALU_PREL_11_0), + LLD_KIND_STRING_ENTRY(R_ARM_THM_PC12), + LLD_KIND_STRING_ENTRY(R_ARM_ABS32_NOI), + LLD_KIND_STRING_ENTRY(R_ARM_REL32_NOI), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_PC_G0_NC), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_PC_G0), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_PC_G1_NC), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_PC_G1), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_PC_G2), + LLD_KIND_STRING_ENTRY(R_ARM_LDR_PC_G1), + LLD_KIND_STRING_ENTRY(R_ARM_LDR_PC_G2), + LLD_KIND_STRING_ENTRY(R_ARM_LDRS_PC_G0), + LLD_KIND_STRING_ENTRY(R_ARM_LDRS_PC_G1), + LLD_KIND_STRING_ENTRY(R_ARM_LDRS_PC_G2), + LLD_KIND_STRING_ENTRY(R_ARM_LDC_PC_G0), + LLD_KIND_STRING_ENTRY(R_ARM_LDC_PC_G1), + LLD_KIND_STRING_ENTRY(R_ARM_LDC_PC_G2), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_SB_G0_NC), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_SB_G0), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_SB_G1_NC), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_SB_G1), + LLD_KIND_STRING_ENTRY(R_ARM_ALU_SB_G2), + LLD_KIND_STRING_ENTRY(R_ARM_LDR_SB_G0), + LLD_KIND_STRING_ENTRY(R_ARM_LDR_SB_G1), + LLD_KIND_STRING_ENTRY(R_ARM_LDR_SB_G2), + LLD_KIND_STRING_ENTRY(R_ARM_LDRS_SB_G0), + LLD_KIND_STRING_ENTRY(R_ARM_LDRS_SB_G1), + LLD_KIND_STRING_ENTRY(R_ARM_LDRS_SB_G2), + LLD_KIND_STRING_ENTRY(R_ARM_LDC_SB_G0), + LLD_KIND_STRING_ENTRY(R_ARM_LDC_SB_G1), + LLD_KIND_STRING_ENTRY(R_ARM_LDC_SB_G2), + LLD_KIND_STRING_ENTRY(R_ARM_MOVW_BREL_NC), + LLD_KIND_STRING_ENTRY(R_ARM_MOVT_BREL), + LLD_KIND_STRING_ENTRY(R_ARM_MOVW_BREL), + LLD_KIND_STRING_ENTRY(R_ARM_THM_MOVW_BREL_NC), + LLD_KIND_STRING_ENTRY(R_ARM_THM_MOVT_BREL), + LLD_KIND_STRING_ENTRY(R_ARM_THM_MOVW_BREL), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_GOTDESC), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_CALL), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_DESCSEQ), + LLD_KIND_STRING_ENTRY(R_ARM_THM_TLS_CALL), + LLD_KIND_STRING_ENTRY(R_ARM_PLT32_ABS), + LLD_KIND_STRING_ENTRY(R_ARM_GOT_ABS), + LLD_KIND_STRING_ENTRY(R_ARM_GOT_PREL), + LLD_KIND_STRING_ENTRY(R_ARM_GOT_BREL12), + LLD_KIND_STRING_ENTRY(R_ARM_GOTOFF12), + LLD_KIND_STRING_ENTRY(R_ARM_GOTRELAX), + LLD_KIND_STRING_ENTRY(R_ARM_GNU_VTENTRY), + LLD_KIND_STRING_ENTRY(R_ARM_GNU_VTINHERIT), + LLD_KIND_STRING_ENTRY(R_ARM_THM_JUMP11), + LLD_KIND_STRING_ENTRY(R_ARM_THM_JUMP8), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_GD32), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_LDM32), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_LDO32), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_IE32), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_LE32), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_LDO12), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_LE12), + LLD_KIND_STRING_ENTRY(R_ARM_TLS_IE12GP), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_0), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_1), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_2), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_3), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_4), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_5), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_6), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_7), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_8), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_9), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_10), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_11), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_12), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_13), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_14), + LLD_KIND_STRING_ENTRY(R_ARM_PRIVATE_15), + LLD_KIND_STRING_ENTRY(R_ARM_ME_TOO), + LLD_KIND_STRING_ENTRY(R_ARM_THM_TLS_DESCSEQ16), + LLD_KIND_STRING_ENTRY(R_ARM_THM_TLS_DESCSEQ32), + LLD_KIND_STRING_ENTRY(R_ARM_IRELATIVE), + LLD_KIND_STRING_END}; Index: lib/ReaderWriter/ELF/ARM/CMakeLists.txt =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ARM/CMakeLists.txt @@ -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 + ) Index: lib/ReaderWriter/ELF/ARM/Makefile =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ARM/Makefile @@ -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 Index: lib/ReaderWriter/ELF/ARM/TODO.rst =================================================================== --- /dev/null +++ lib/ReaderWriter/ELF/ARM/TODO.rst @@ -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 Index: lib/ReaderWriter/ELF/Atoms.h =================================================================== --- lib/ReaderWriter/ELF/Atoms.h +++ lib/ReaderWriter/ELF/Atoms.h @@ -681,6 +681,11 @@ 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 Index: lib/ReaderWriter/ELF/CMakeLists.txt =================================================================== --- lib/ReaderWriter/ELF/CMakeLists.txt +++ lib/ReaderWriter/ELF/CMakeLists.txt @@ -14,6 +14,7 @@ lldX86ELFTarget lldX86_64ELFTarget lldAArch64ELFTarget + lldARMELFTarget ) include_directories(.) @@ -24,3 +25,4 @@ add_subdirectory(Mips) add_subdirectory(Hexagon) add_subdirectory(AArch64) +add_subdirectory(ARM) Index: lib/ReaderWriter/ELF/ELFLinkingContext.cpp =================================================================== --- lib/ReaderWriter/ELF/ELFLinkingContext.cpp +++ lib/ReaderWriter/ELF/ELFLinkingContext.cpp @@ -85,6 +85,8 @@ 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 @@ case llvm::Triple::aarch64: return std::unique_ptr( new lld::elf::AArch64LinkingContext(triple)); + case llvm::Triple::arm: + return std::unique_ptr( + new lld::elf::ARMLinkingContext(triple)); default: return nullptr; } Index: lib/ReaderWriter/ELF/Targets.h =================================================================== --- lib/ReaderWriter/ELF/Targets.h +++ lib/ReaderWriter/ELF/Targets.h @@ -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" Index: test/elf/ARM/defsym.test =================================================================== --- /dev/null +++ test/elf/ARM/defsym.test @@ -0,0 +1,72 @@ +# 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