| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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"); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| //===--------- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp --------------===// | ||
| // | ||
| // The LLVM Linker | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #include "Atoms.h" | ||
| #include "ARMExecutableWriter.h" | ||
| #include "ARMTargetHandler.h" | ||
| #include "ARMLinkingContext.h" | ||
|
|
||
| using namespace lld; | ||
| using namespace elf; | ||
|
|
||
| ARMTargetHandler::ARMTargetHandler(ARMLinkingContext &context) | ||
| : _context(context), _armTargetLayout( | ||
| new ARMTargetLayout<ARMELFType>(context)), | ||
| _armRelocationHandler(new ARMTargetRelocationHandler()) {} | ||
|
|
||
| void ARMTargetHandler::registerRelocationNames(Registry ®istry) { | ||
| registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM, | ||
| kindStrings); | ||
| } | ||
|
|
||
| std::unique_ptr<Writer> ARMTargetHandler::getWriter() { | ||
| switch (this->_context.getOutputELFType()) { | ||
| case llvm::ELF::ET_EXEC: | ||
| return std::unique_ptr<Writer>( | ||
| new ARMExecutableWriter<ARMELFType>(_context, *_armTargetLayout.get())); | ||
| default: | ||
| llvm_unreachable("unsupported output type"); | ||
| } | ||
| } | ||
|
|
||
| #define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name), | ||
|
|
||
| const Registry::KindStrings ARMTargetHandler::kindStrings[] = { | ||
| #include "llvm/Support/ELFRelocs/ARM.def" | ||
| LLD_KIND_STRING_END | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,68 @@ | ||
| //===--------- lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h ----------------===// | ||
| // | ||
| // The LLVM Linker | ||
| // | ||
| // This file is distributed under the University of Illinois Open Source | ||
| // License. See LICENSE.TXT for details. | ||
| // | ||
| //===----------------------------------------------------------------------===// | ||
|
|
||
| #ifndef LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H | ||
| #define LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H | ||
|
|
||
| #include "ARMELFFile.h" | ||
| #include "ARMELFReader.h" | ||
| #include "ARMRelocationHandler.h" | ||
| #include "DefaultTargetHandler.h" | ||
| #include "TargetLayout.h" | ||
|
|
||
| #include "lld/Core/Simple.h" | ||
| #include "llvm/ADT/Optional.h" | ||
| #include <map> | ||
|
|
||
| namespace lld { | ||
| namespace elf { | ||
| typedef llvm::object::ELFType<llvm::support::little, 2, false> ARMELFType; | ||
| class ARMLinkingContext; | ||
|
|
||
| template <class ELFT> class ARMTargetLayout : public TargetLayout<ELFT> { | ||
| public: | ||
| ARMTargetLayout(ARMLinkingContext &context) | ||
| : TargetLayout<ELFT>(context) {} | ||
| }; | ||
|
|
||
| class ARMTargetHandler final : public DefaultTargetHandler<ARMELFType> { | ||
| public: | ||
| ARMTargetHandler(ARMLinkingContext &context); | ||
|
|
||
| ARMTargetLayout<ARMELFType> &getTargetLayout() override { | ||
| return *(_armTargetLayout.get()); | ||
| } | ||
|
|
||
| void registerRelocationNames(Registry ®istry) override; | ||
|
|
||
| const ARMTargetRelocationHandler &getRelocationHandler() const override { | ||
| return *(_armRelocationHandler.get()); | ||
| } | ||
|
|
||
| std::unique_ptr<Reader> getObjReader(bool atomizeStrings) override { | ||
| return std::unique_ptr<Reader>(new ARMELFObjectReader(atomizeStrings)); | ||
| } | ||
|
|
||
| std::unique_ptr<Reader> getDSOReader(bool useShlibUndefines) override { | ||
| return std::unique_ptr<Reader>(new ARMELFDSOReader(useShlibUndefines)); | ||
| } | ||
|
|
||
| std::unique_ptr<Writer> getWriter() override; | ||
|
|
||
| private: | ||
| static const Registry::KindStrings kindStrings[]; | ||
| ARMLinkingContext &_context; | ||
| std::unique_ptr<ARMTargetLayout<ARMELFType>> _armTargetLayout; | ||
| std::unique_ptr<ARMTargetRelocationHandler> _armRelocationHandler; | ||
| }; | ||
|
|
||
| } // end namespace elf | ||
| } // end namespace lld | ||
|
|
||
| #endif // LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| ... |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 | ||
| ... |