175 lines
5.5 KiB
C++
175 lines
5.5 KiB
C++
//===--------- 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 "ARMRelocationHandler.h"
|
|
#include "ELFReader.h"
|
|
#include "TargetLayout.h"
|
|
|
|
namespace lld {
|
|
class ELFLinkingContext;
|
|
|
|
namespace elf {
|
|
|
|
/// \brief ARM specific section (.ARM.exidx) with indexes to exception handlers
|
|
class ARMExidxSection : public AtomSection<ELF32LE> {
|
|
typedef AtomSection<ELF32LE> Base;
|
|
|
|
public:
|
|
ARMExidxSection(const ELFLinkingContext &ctx, StringRef sectionName,
|
|
int32_t permissions, int32_t order)
|
|
: Base(ctx, sectionName, ARMELFDefinedAtom::typeARMExidx, permissions,
|
|
order) {
|
|
this->_type = SHT_ARM_EXIDX;
|
|
this->_isLoadedInMemory = true;
|
|
}
|
|
|
|
bool hasOutputSegment() const override { return true; }
|
|
|
|
const AtomLayout *appendAtom(const Atom *atom) override {
|
|
const DefinedAtom *definedAtom = cast<DefinedAtom>(atom);
|
|
assert((ARMELFDefinedAtom::ARMContentType)definedAtom->contentType() ==
|
|
ARMELFDefinedAtom::typeARMExidx &&
|
|
"atom content type for .ARM.exidx section has to be typeARMExidx");
|
|
|
|
DefinedAtom::Alignment atomAlign = definedAtom->alignment();
|
|
uint64_t fOffset = alignOffset(this->fileSize(), atomAlign);
|
|
uint64_t mOffset = alignOffset(this->memSize(), atomAlign);
|
|
|
|
_atoms.push_back(new (_alloc) AtomLayout(atom, fOffset, 0));
|
|
this->_fsize = fOffset + definedAtom->size();
|
|
this->_msize = mOffset + definedAtom->size();
|
|
DEBUG_WITH_TYPE("Section", llvm::dbgs()
|
|
<< "[" << this->name() << " " << this << "] "
|
|
<< "Adding atom: " << atom->name() << "@"
|
|
<< fOffset << "\n");
|
|
|
|
uint64_t alignment = atomAlign.value;
|
|
if (this->_alignment < alignment)
|
|
this->_alignment = alignment;
|
|
|
|
return _atoms.back();
|
|
}
|
|
};
|
|
|
|
class ARMTargetLayout : public TargetLayout<ELF32LE> {
|
|
public:
|
|
enum ARMSectionOrder {
|
|
ORDER_ARM_EXIDX = TargetLayout::ORDER_EH_FRAME + 1,
|
|
};
|
|
|
|
ARMTargetLayout(ELFLinkingContext &ctx) : TargetLayout(ctx) {}
|
|
|
|
SectionOrder getSectionOrder(StringRef name, int32_t contentType,
|
|
int32_t contentPermissions) override {
|
|
switch (contentType) {
|
|
case ARMELFDefinedAtom::typeARMExidx:
|
|
return ORDER_ARM_EXIDX;
|
|
default:
|
|
return TargetLayout::getSectionOrder(name, contentType,
|
|
contentPermissions);
|
|
}
|
|
}
|
|
|
|
StringRef getOutputSectionName(StringRef archivePath, StringRef memberPath,
|
|
StringRef inputSectionName) const override {
|
|
return llvm::StringSwitch<StringRef>(inputSectionName)
|
|
.StartsWith(".ARM.exidx", ".ARM.exidx")
|
|
.StartsWith(".ARM.extab", ".ARM.extab")
|
|
.Default(TargetLayout::getOutputSectionName(archivePath, memberPath,
|
|
inputSectionName));
|
|
}
|
|
|
|
SegmentType getSegmentType(Section<ELF32LE> *section) const override {
|
|
switch (section->order()) {
|
|
case ORDER_ARM_EXIDX:
|
|
return llvm::ELF::PT_ARM_EXIDX;
|
|
default:
|
|
return TargetLayout::getSegmentType(section);
|
|
}
|
|
}
|
|
|
|
AtomSection<ELF32LE> *
|
|
createSection(StringRef name, int32_t contentType,
|
|
DefinedAtom::ContentPermissions contentPermissions,
|
|
SectionOrder sectionOrder) override {
|
|
if ((ARMELFDefinedAtom::ARMContentType)contentType ==
|
|
ARMELFDefinedAtom::typeARMExidx)
|
|
return new ARMExidxSection(_ctx, name, contentPermissions, sectionOrder);
|
|
|
|
return TargetLayout::createSection(name, contentType, contentPermissions,
|
|
sectionOrder);
|
|
}
|
|
|
|
uint64_t getGOTSymAddr() {
|
|
std::call_once(_gotSymOnce, [this]() {
|
|
if (AtomLayout *gotAtom = findAbsoluteAtom("_GLOBAL_OFFSET_TABLE_"))
|
|
_gotSymAddr = gotAtom->_virtualAddr;
|
|
});
|
|
return _gotSymAddr;
|
|
}
|
|
|
|
uint64_t getTPOffset() {
|
|
std::call_once(_tpOffOnce, [this]() {
|
|
for (const auto &phdr : *_programHeader) {
|
|
if (phdr->p_type == llvm::ELF::PT_TLS) {
|
|
_tpOff = llvm::RoundUpToAlignment(TCB_SIZE, phdr->p_align);
|
|
break;
|
|
}
|
|
}
|
|
assert(_tpOff != 0 && "TLS segment not found");
|
|
});
|
|
return _tpOff;
|
|
}
|
|
|
|
bool target1Rel() const { return _ctx.armTarget1Rel(); }
|
|
|
|
private:
|
|
// TCB block size of the TLS.
|
|
enum { TCB_SIZE = 0x8 };
|
|
|
|
private:
|
|
uint64_t _gotSymAddr = 0;
|
|
uint64_t _tpOff = 0;
|
|
std::once_flag _gotSymOnce;
|
|
std::once_flag _tpOffOnce;
|
|
};
|
|
|
|
class ARMTargetHandler final : public TargetHandler {
|
|
public:
|
|
ARMTargetHandler(ARMLinkingContext &ctx);
|
|
|
|
const TargetRelocationHandler &getRelocationHandler() const override {
|
|
return *_relocationHandler;
|
|
}
|
|
|
|
std::unique_ptr<Reader> getObjReader() override {
|
|
return llvm::make_unique<ELFReader<ARMELFFile>>(_ctx);
|
|
}
|
|
|
|
std::unique_ptr<Reader> getDSOReader() override {
|
|
return llvm::make_unique<ELFReader<DynamicFile<ELF32LE>>>(_ctx);
|
|
}
|
|
|
|
std::unique_ptr<Writer> getWriter() override;
|
|
|
|
private:
|
|
ARMLinkingContext &_ctx;
|
|
std::unique_ptr<ARMTargetLayout> _targetLayout;
|
|
std::unique_ptr<ARMTargetRelocationHandler> _relocationHandler;
|
|
};
|
|
|
|
} // end namespace elf
|
|
} // end namespace lld
|
|
|
|
#endif // LLD_READER_WRITER_ELF_ARM_ARM_TARGET_HANDLER_H
|