138 changes: 138 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.cpp
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");
}
}
31 changes: 31 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/ARMRelocationPass.h
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
10 changes: 10 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/ARMTarget.h
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"
43 changes: 43 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.cpp
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 &registry) {
registry.addKindTable(Reference::KindNamespace::ELF, Reference::KindArch::ARM,
kindStrings);
}

std::unique_ptr<Writer> ARMTargetHandler::getWriter() {
switch (this->_context.getOutputELFType()) {
case llvm::ELF::ET_EXEC:
return std::unique_ptr<Writer>(
new ARMExecutableWriter<ARMELFType>(_context, *_armTargetLayout.get()));
default:
llvm_unreachable("unsupported output type");
}
}

#define ELF_RELOC(name, value) LLD_KIND_STRING_ENTRY(name),

const Registry::KindStrings ARMTargetHandler::kindStrings[] = {
#include "llvm/Support/ELFRelocs/ARM.def"
LLD_KIND_STRING_END
};
68 changes: 68 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/ARMTargetHandler.h
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 &registry) override;

const ARMTargetRelocationHandler &getRelocationHandler() const override {
return *(_armRelocationHandler.get());
}

std::unique_ptr<Reader> getObjReader(bool atomizeStrings) override {
return std::unique_ptr<Reader>(new ARMELFObjectReader(atomizeStrings));
}

std::unique_ptr<Reader> getDSOReader(bool useShlibUndefines) override {
return std::unique_ptr<Reader>(new ARMELFDSOReader(useShlibUndefines));
}

std::unique_ptr<Writer> getWriter() override;

private:
static const Registry::KindStrings kindStrings[];
ARMLinkingContext &_context;
std::unique_ptr<ARMTargetLayout<ARMELFType>> _armTargetLayout;
std::unique_ptr<ARMTargetRelocationHandler> _armRelocationHandler;
};

} // end namespace elf
} // end namespace lld

#endif // LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H
10 changes: 10 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/CMakeLists.txt
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
)
15 changes: 15 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/Makefile
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
20 changes: 20 additions & 0 deletions lld/lib/ReaderWriter/ELF/ARM/TODO.rst
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
5 changes: 5 additions & 0 deletions lld/lib/ReaderWriter/ELF/Atoms.h
Original file line number Diff line number Diff line change
Expand Up @@ -682,6 +682,11 @@ class SimpleELFDefinedAtom : public SimpleDefinedAtom {
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
Expand Down
2 changes: 2 additions & 0 deletions lld/lib/ReaderWriter/ELF/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ target_link_libraries(lldELF ${cmake_2_8_12_INTERFACE}
lldX86ELFTarget
lldX86_64ELFTarget
lldAArch64ELFTarget
lldARMELFTarget
)

include_directories(.)
Expand All @@ -24,3 +25,4 @@ add_subdirectory(PPC)
add_subdirectory(Mips)
add_subdirectory(Hexagon)
add_subdirectory(AArch64)
add_subdirectory(ARM)
5 changes: 5 additions & 0 deletions lld/lib/ReaderWriter/ELF/ELFLinkingContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ uint16_t ELFLinkingContext::getOutputMachine() const {
return llvm::ELF::EM_PPC;
case llvm::Triple::aarch64:
return llvm::ELF::EM_AARCH64;
case llvm::Triple::arm:
return llvm::ELF::EM_ARM;
default:
llvm_unreachable("Unhandled arch");
}
Expand Down Expand Up @@ -148,6 +150,9 @@ ELFLinkingContext::create(llvm::Triple triple) {
case llvm::Triple::aarch64:
return std::unique_ptr<ELFLinkingContext>(
new lld::elf::AArch64LinkingContext(triple));
case llvm::Triple::arm:
return std::unique_ptr<ELFLinkingContext>(
new lld::elf::ARMLinkingContext(triple));
default:
return nullptr;
}
Expand Down
1 change: 1 addition & 0 deletions lld/lib/ReaderWriter/ELF/Targets.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
74 changes: 74 additions & 0 deletions lld/test/elf/ARM/defsym.test
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
...
59 changes: 59 additions & 0 deletions lld/test/elf/ARM/rel-abs32.test
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
...
60 changes: 60 additions & 0 deletions lld/test/elf/ARM/rel-arm-call.test
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
...