You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
625 lines
21 KiB
625 lines
21 KiB
//===- AArch64LDBackend.cpp -----------------------------------------------===//
|
|
//
|
|
// The MCLinker Project
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "AArch64.h"
|
|
#include "AArch64CA53Erratum835769Stub.h"
|
|
#include "AArch64CA53Erratum843419Stub.h"
|
|
#include "AArch64CA53Erratum843419Stub2.h"
|
|
#include "AArch64ELFDynamic.h"
|
|
#include "AArch64GNUInfo.h"
|
|
#include "AArch64InsnHelpers.h"
|
|
#include "AArch64LDBackend.h"
|
|
#include "AArch64LongBranchStub.h"
|
|
#include "AArch64Relocator.h"
|
|
|
|
#include "mcld/IRBuilder.h"
|
|
#include "mcld/LinkerConfig.h"
|
|
#include "mcld/Fragment/AlignFragment.h"
|
|
#include "mcld/Fragment/FillFragment.h"
|
|
#include "mcld/Fragment/NullFragment.h"
|
|
#include "mcld/Fragment/RegionFragment.h"
|
|
#include "mcld/Fragment/Stub.h"
|
|
#include "mcld/LD/BranchIslandFactory.h"
|
|
#include "mcld/LD/ELFFileFormat.h"
|
|
#include "mcld/LD/ELFSegment.h"
|
|
#include "mcld/LD/ELFSegmentFactory.h"
|
|
#include "mcld/LD/LDContext.h"
|
|
#include "mcld/LD/StubFactory.h"
|
|
#include "mcld/Support/MemoryRegion.h"
|
|
#include "mcld/Support/MemoryArea.h"
|
|
#include "mcld/Support/MsgHandling.h"
|
|
#include "mcld/Support/TargetRegistry.h"
|
|
#include "mcld/Target/ELFAttribute.h"
|
|
#include "mcld/Target/GNUInfo.h"
|
|
#include "mcld/Object/ObjectBuilder.h"
|
|
|
|
#include <llvm/ADT/Triple.h>
|
|
#include <llvm/ADT/Twine.h>
|
|
#include <llvm/Support/Casting.h>
|
|
#include <llvm/Support/ELF.h>
|
|
|
|
#include <cstring>
|
|
|
|
namespace mcld {
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// AArch64GNULDBackend
|
|
//===----------------------------------------------------------------------===//
|
|
AArch64GNULDBackend::AArch64GNULDBackend(const LinkerConfig& pConfig,
|
|
GNUInfo* pInfo)
|
|
: GNULDBackend(pConfig, pInfo),
|
|
m_pRelocator(NULL),
|
|
m_pGOT(NULL),
|
|
m_pGOTPLT(NULL),
|
|
m_pPLT(NULL),
|
|
m_pRelaDyn(NULL),
|
|
m_pRelaPLT(NULL),
|
|
m_pDynamic(NULL),
|
|
m_pGOTSymbol(NULL) {
|
|
}
|
|
|
|
AArch64GNULDBackend::~AArch64GNULDBackend() {
|
|
if (m_pRelocator != NULL)
|
|
delete m_pRelocator;
|
|
if (m_pGOT == m_pGOTPLT) {
|
|
if (m_pGOT != NULL)
|
|
delete m_pGOT;
|
|
} else {
|
|
if (m_pGOT != NULL)
|
|
delete m_pGOT;
|
|
if (m_pGOTPLT != NULL)
|
|
delete m_pGOTPLT;
|
|
}
|
|
if (m_pPLT != NULL)
|
|
delete m_pPLT;
|
|
if (m_pRelaDyn != NULL)
|
|
delete m_pRelaDyn;
|
|
if (m_pRelaPLT != NULL)
|
|
delete m_pRelaPLT;
|
|
if (m_pDynamic != NULL)
|
|
delete m_pDynamic;
|
|
}
|
|
|
|
void AArch64GNULDBackend::initTargetSections(Module& pModule,
|
|
ObjectBuilder& pBuilder) {
|
|
if (LinkerConfig::Object != config().codeGenType()) {
|
|
ELFFileFormat* file_format = getOutputFormat();
|
|
|
|
// initialize .got
|
|
LDSection& got = file_format->getGOT();
|
|
m_pGOT = new AArch64GOT(got);
|
|
if (config().options().hasNow()) {
|
|
// when -z now is given, there will be only one .got section (contains
|
|
// both GOTPLT and normal GOT entries), create GOT0 for .got section and
|
|
// set m_pGOTPLT to the same .got
|
|
m_pGOT->createGOT0();
|
|
m_pGOTPLT = m_pGOT;
|
|
} else {
|
|
// Otherwise, got should be seperated to two sections, .got and .got.plt
|
|
// initialize .got.plt
|
|
LDSection& gotplt = file_format->getGOTPLT();
|
|
m_pGOTPLT = new AArch64GOT(gotplt);
|
|
m_pGOTPLT->createGOT0();
|
|
}
|
|
|
|
// initialize .plt
|
|
LDSection& plt = file_format->getPLT();
|
|
m_pPLT = new AArch64PLT(plt, *m_pGOTPLT);
|
|
|
|
// initialize .rela.plt
|
|
LDSection& relaplt = file_format->getRelaPlt();
|
|
relaplt.setLink(&plt);
|
|
m_pRelaPLT = new OutputRelocSection(pModule, relaplt);
|
|
|
|
// initialize .rela.dyn
|
|
LDSection& reladyn = file_format->getRelaDyn();
|
|
m_pRelaDyn = new OutputRelocSection(pModule, reladyn);
|
|
}
|
|
}
|
|
|
|
void AArch64GNULDBackend::initTargetSymbols(IRBuilder& pBuilder,
|
|
Module& pModule) {
|
|
// Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
|
|
// same name in input
|
|
if (LinkerConfig::Object != config().codeGenType()) {
|
|
m_pGOTSymbol =
|
|
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
|
|
"_GLOBAL_OFFSET_TABLE_",
|
|
ResolveInfo::Object,
|
|
ResolveInfo::Define,
|
|
ResolveInfo::Local,
|
|
0x0, // size
|
|
0x0, // value
|
|
FragmentRef::Null(),
|
|
ResolveInfo::Hidden);
|
|
}
|
|
}
|
|
|
|
bool AArch64GNULDBackend::initRelocator() {
|
|
if (m_pRelocator == NULL) {
|
|
m_pRelocator = new AArch64Relocator(*this, config());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
const Relocator* AArch64GNULDBackend::getRelocator() const {
|
|
assert(m_pRelocator != NULL);
|
|
return m_pRelocator;
|
|
}
|
|
|
|
Relocator* AArch64GNULDBackend::getRelocator() {
|
|
assert(m_pRelocator != NULL);
|
|
return m_pRelocator;
|
|
}
|
|
|
|
void AArch64GNULDBackend::defineGOTSymbol(IRBuilder& pBuilder) {
|
|
// define symbol _GLOBAL_OFFSET_TABLE_ when .got create
|
|
if (m_pGOTSymbol != NULL) {
|
|
pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
|
|
"_GLOBAL_OFFSET_TABLE_",
|
|
ResolveInfo::Object,
|
|
ResolveInfo::Define,
|
|
ResolveInfo::Local,
|
|
0x0, // size
|
|
0x0, // value
|
|
FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0),
|
|
ResolveInfo::Hidden);
|
|
} else {
|
|
m_pGOTSymbol = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
|
|
"_GLOBAL_OFFSET_TABLE_",
|
|
ResolveInfo::Object,
|
|
ResolveInfo::Define,
|
|
ResolveInfo::Local,
|
|
0x0, // size
|
|
0x0, // value
|
|
FragmentRef::Create(*(m_pGOTPLT->begin()), 0x0),
|
|
ResolveInfo::Hidden);
|
|
}
|
|
}
|
|
|
|
void AArch64GNULDBackend::doPreLayout(IRBuilder& pBuilder) {
|
|
// initialize .dynamic data
|
|
if (!config().isCodeStatic() && m_pDynamic == NULL)
|
|
m_pDynamic = new AArch64ELFDynamic(*this, config());
|
|
|
|
if (LinkerConfig::Object != config().codeGenType()) {
|
|
// set .got size
|
|
if (config().options().hasNow()) {
|
|
// when building shared object, the GOTPLT section is must
|
|
if (LinkerConfig::DynObj == config().codeGenType() || m_pGOT->hasGOT1() ||
|
|
m_pGOTSymbol != NULL) {
|
|
m_pGOT->finalizeSectionSize();
|
|
defineGOTSymbol(pBuilder);
|
|
}
|
|
} else {
|
|
// when building shared object, the GOTPLT section is must
|
|
if (LinkerConfig::DynObj == config().codeGenType() ||
|
|
m_pGOTPLT->hasGOT1() || m_pGOTSymbol != NULL) {
|
|
m_pGOTPLT->finalizeSectionSize();
|
|
defineGOTSymbol(pBuilder);
|
|
}
|
|
if (m_pGOT->hasGOT1())
|
|
m_pGOT->finalizeSectionSize();
|
|
}
|
|
|
|
// set .plt size
|
|
if (m_pPLT->hasPLT1())
|
|
m_pPLT->finalizeSectionSize();
|
|
|
|
ELFFileFormat* file_format = getOutputFormat();
|
|
// set .rela.dyn size
|
|
if (!m_pRelaDyn->empty()) {
|
|
assert(
|
|
!config().isCodeStatic() &&
|
|
"static linkage should not result in a dynamic relocation section");
|
|
file_format->getRelaDyn().setSize(m_pRelaDyn->numOfRelocs() *
|
|
getRelaEntrySize());
|
|
}
|
|
|
|
// set .rela.plt size
|
|
if (!m_pRelaPLT->empty()) {
|
|
assert(
|
|
!config().isCodeStatic() &&
|
|
"static linkage should not result in a dynamic relocation section");
|
|
file_format->getRelaPlt().setSize(m_pRelaPLT->numOfRelocs() *
|
|
getRelaEntrySize());
|
|
}
|
|
}
|
|
}
|
|
|
|
void AArch64GNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder) {
|
|
const ELFFileFormat* file_format = getOutputFormat();
|
|
|
|
// apply PLT
|
|
if (file_format->hasPLT()) {
|
|
assert(m_pPLT != NULL);
|
|
m_pPLT->applyPLT0();
|
|
m_pPLT->applyPLT1();
|
|
}
|
|
|
|
// apply GOTPLT
|
|
if ((config().options().hasNow() && file_format->hasGOT()) ||
|
|
file_format->hasGOTPLT()) {
|
|
assert(m_pGOTPLT != NULL);
|
|
if (LinkerConfig::DynObj == config().codeGenType())
|
|
m_pGOTPLT->applyGOT0(file_format->getDynamic().addr());
|
|
else {
|
|
// executable file and object file? should fill with zero.
|
|
m_pGOTPLT->applyGOT0(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
AArch64ELFDynamic& AArch64GNULDBackend::dynamic() {
|
|
assert(m_pDynamic != NULL);
|
|
return *m_pDynamic;
|
|
}
|
|
|
|
const AArch64ELFDynamic& AArch64GNULDBackend::dynamic() const {
|
|
assert(m_pDynamic != NULL);
|
|
return *m_pDynamic;
|
|
}
|
|
|
|
uint64_t AArch64GNULDBackend::emitSectionData(const LDSection& pSection,
|
|
MemoryRegion& pRegion) const {
|
|
assert(pRegion.size() && "Size of MemoryRegion is zero!");
|
|
|
|
const ELFFileFormat* file_format = getOutputFormat();
|
|
|
|
if (file_format->hasPLT() && (&pSection == &(file_format->getPLT()))) {
|
|
uint64_t result = m_pPLT->emit(pRegion);
|
|
return result;
|
|
}
|
|
|
|
if (file_format->hasGOT() && (&pSection == &(file_format->getGOT()))) {
|
|
uint64_t result = m_pGOT->emit(pRegion);
|
|
return result;
|
|
}
|
|
|
|
if (file_format->hasGOTPLT() && (&pSection == &(file_format->getGOTPLT()))) {
|
|
uint64_t result = m_pGOT->emit(pRegion);
|
|
return result;
|
|
}
|
|
|
|
return pRegion.size();
|
|
}
|
|
|
|
unsigned int AArch64GNULDBackend::getTargetSectionOrder(
|
|
const LDSection& pSectHdr) const {
|
|
const ELFFileFormat* file_format = getOutputFormat();
|
|
|
|
if (file_format->hasGOT() && (&pSectHdr == &file_format->getGOT())) {
|
|
if (config().options().hasNow())
|
|
return SHO_RELRO;
|
|
return SHO_RELRO_LAST;
|
|
}
|
|
|
|
if (file_format->hasGOTPLT() && (&pSectHdr == &file_format->getGOTPLT()))
|
|
return SHO_NON_RELRO_FIRST;
|
|
|
|
if (file_format->hasPLT() && (&pSectHdr == &file_format->getPLT()))
|
|
return SHO_PLT;
|
|
|
|
return SHO_UNDEFINED;
|
|
}
|
|
|
|
void AArch64GNULDBackend::scanErrata(Module& pModule,
|
|
IRBuilder& pBuilder,
|
|
size_t& num_new_stubs,
|
|
size_t& stubs_strlen) {
|
|
// TODO: Implement AArch64 ErrataStubFactory to create the specific erratum
|
|
// stub and simplify the logics.
|
|
for (Module::iterator sect = pModule.begin(), sectEnd = pModule.end();
|
|
sect != sectEnd; ++sect) {
|
|
if (((*sect)->kind() == LDFileFormat::TEXT) && (*sect)->hasSectionData()) {
|
|
SectionData* sd = (*sect)->getSectionData();
|
|
for (SectionData::iterator it = sd->begin(), ie = sd->end(); it != ie;
|
|
++it) {
|
|
Fragment* frag = llvm::dyn_cast<RegionFragment>(it);
|
|
if (frag != NULL) {
|
|
FragmentRef* frag_ref = FragmentRef::Create(*frag, 0);
|
|
for (unsigned offset = 0; offset < frag->size();
|
|
offset += AArch64InsnHelpers::InsnSize) {
|
|
Stub* stub = getStubFactory()->create(*frag_ref,
|
|
pBuilder,
|
|
*getBRIslandFactory());
|
|
if (stub != NULL) {
|
|
// A stub symbol should be local
|
|
assert(stub->symInfo() != NULL && stub->symInfo()->isLocal());
|
|
const AArch64CA53ErratumStub* erratum_stub =
|
|
reinterpret_cast<const AArch64CA53ErratumStub*>(stub);
|
|
assert(erratum_stub != NULL);
|
|
// Rewrite the erratum instruction as a branch to the stub.
|
|
uint64_t offset = frag_ref->offset() +
|
|
erratum_stub->getErratumInsnOffset();
|
|
Relocation* reloc =
|
|
Relocation::Create(llvm::ELF::R_AARCH64_JUMP26,
|
|
*(FragmentRef::Create(*frag, offset)),
|
|
/* pAddend */0);
|
|
reloc->setSymInfo(stub->symInfo());
|
|
reloc->target() = AArch64InsnHelpers::buildBranchInsn();
|
|
addExtraRelocation(reloc);
|
|
|
|
++num_new_stubs;
|
|
stubs_strlen += stub->symInfo()->nameSize() + 1;
|
|
}
|
|
|
|
frag_ref->assign(*frag, offset + AArch64InsnHelpers::InsnSize);
|
|
} // for each INSN
|
|
}
|
|
} // for each FRAGMENT
|
|
}
|
|
} // for each TEXT section
|
|
}
|
|
|
|
bool AArch64GNULDBackend::doRelax(Module& pModule,
|
|
IRBuilder& pBuilder,
|
|
bool& pFinished) {
|
|
assert(getStubFactory() != NULL && getBRIslandFactory() != NULL);
|
|
|
|
// Number of new stubs added
|
|
size_t num_new_stubs = 0;
|
|
// String lengh to hold new stub symbols
|
|
size_t stubs_strlen = 0;
|
|
|
|
if (config().targets().fixCA53Erratum835769() ||
|
|
config().targets().fixCA53Erratum843419()) {
|
|
scanErrata(pModule, pBuilder, num_new_stubs, stubs_strlen);
|
|
}
|
|
|
|
ELFFileFormat* file_format = getOutputFormat();
|
|
// check branch relocs and create the related stubs if needed
|
|
Module::obj_iterator input, inEnd = pModule.obj_end();
|
|
for (input = pModule.obj_begin(); input != inEnd; ++input) {
|
|
LDContext::sect_iterator rs, rsEnd = (*input)->context()->relocSectEnd();
|
|
for (rs = (*input)->context()->relocSectBegin(); rs != rsEnd; ++rs) {
|
|
if (LDFileFormat::Ignore == (*rs)->kind() || !(*rs)->hasRelocData())
|
|
continue;
|
|
RelocData::iterator reloc, rEnd = (*rs)->getRelocData()->end();
|
|
for (reloc = (*rs)->getRelocData()->begin(); reloc != rEnd; ++reloc) {
|
|
Relocation* relocation = llvm::cast<Relocation>(reloc);
|
|
|
|
switch (relocation->type()) {
|
|
case llvm::ELF::R_AARCH64_CALL26:
|
|
case llvm::ELF::R_AARCH64_JUMP26: {
|
|
// calculate the possible symbol value
|
|
uint64_t sym_value = 0x0;
|
|
LDSymbol* symbol = relocation->symInfo()->outSymbol();
|
|
if (symbol->hasFragRef()) {
|
|
uint64_t value = symbol->fragRef()->getOutputOffset();
|
|
uint64_t addr =
|
|
symbol->fragRef()->frag()->getParent()->getSection().addr();
|
|
sym_value = addr + value;
|
|
}
|
|
if ((relocation->symInfo()->reserved() &
|
|
AArch64Relocator::ReservePLT) != 0x0) {
|
|
// FIXME: we need to find out the address of the specific plt
|
|
// entry
|
|
assert(file_format->hasPLT());
|
|
sym_value = file_format->getPLT().addr();
|
|
}
|
|
Stub* stub = getStubFactory()->create(*relocation, // relocation
|
|
sym_value, // symbol value
|
|
pBuilder,
|
|
*getBRIslandFactory());
|
|
if (stub != NULL) {
|
|
// a stub symbol should be local
|
|
assert(stub->symInfo() != NULL && stub->symInfo()->isLocal());
|
|
// reset the branch target of the reloc to this stub instead
|
|
relocation->setSymInfo(stub->symInfo());
|
|
|
|
++num_new_stubs;
|
|
stubs_strlen += stub->symInfo()->nameSize() + 1;
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
break;
|
|
}
|
|
} // end of switch
|
|
} // for all relocations
|
|
} // for all relocation section
|
|
} // for all inputs
|
|
|
|
// Find the first fragment w/ invalid offset due to stub insertion.
|
|
std::vector<Fragment*> invalid_frags;
|
|
pFinished = true;
|
|
for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(),
|
|
island_end = getBRIslandFactory()->end();
|
|
island != island_end;
|
|
++island) {
|
|
if ((*island).size() > stubGroupSize()) {
|
|
error(diag::err_no_space_to_place_stubs) << stubGroupSize();
|
|
return false;
|
|
}
|
|
|
|
if ((*island).numOfStubs() == 0) {
|
|
continue;
|
|
}
|
|
|
|
Fragment* exit = &*(*island).end();
|
|
if (exit == &*(*island).begin()->getParent()->end()) {
|
|
continue;
|
|
}
|
|
|
|
if (((*island).offset() + (*island).size()) > exit->getOffset()) {
|
|
if (invalid_frags.empty() ||
|
|
(invalid_frags.back()->getParent() != (*island).getParent())) {
|
|
invalid_frags.push_back(exit);
|
|
pFinished = false;
|
|
}
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Reset the offset of invalid fragments.
|
|
for (auto it = invalid_frags.begin(), ie = invalid_frags.end(); it != ie;
|
|
++it) {
|
|
Fragment* invalid = *it;
|
|
while (invalid != NULL) {
|
|
invalid->setOffset(invalid->getPrevNode()->getOffset() +
|
|
invalid->getPrevNode()->size());
|
|
invalid = invalid->getNextNode();
|
|
}
|
|
}
|
|
|
|
// Fix up the size of .symtab, .strtab, and TEXT sections
|
|
if (num_new_stubs == 0) {
|
|
return false;
|
|
} else {
|
|
switch (config().options().getStripSymbolMode()) {
|
|
case GeneralOptions::StripSymbolMode::StripAllSymbols:
|
|
case GeneralOptions::StripSymbolMode::StripLocals:
|
|
break;
|
|
default: {
|
|
LDSection& symtab = file_format->getSymTab();
|
|
LDSection& strtab = file_format->getStrTab();
|
|
|
|
symtab.setSize(symtab.size() +
|
|
sizeof(llvm::ELF::Elf64_Sym) * num_new_stubs);
|
|
symtab.setInfo(symtab.getInfo() + num_new_stubs);
|
|
strtab.setSize(strtab.size() + stubs_strlen);
|
|
}
|
|
} // switch (config().options().getStripSymbolMode())
|
|
|
|
SectionData* prev = NULL;
|
|
for (BranchIslandFactory::iterator island = getBRIslandFactory()->begin(),
|
|
island_end = getBRIslandFactory()->end();
|
|
island != island_end;
|
|
++island) {
|
|
SectionData* sd = (*island).begin()->getParent();
|
|
if ((*island).numOfStubs() != 0) {
|
|
if (sd != prev) {
|
|
sd->getSection().setSize(sd->back().getOffset() + sd->back().size());
|
|
}
|
|
}
|
|
prev = sd;
|
|
}
|
|
return true;
|
|
} // if (num_new_stubs == 0)
|
|
}
|
|
|
|
bool AArch64GNULDBackend::initTargetStubs() {
|
|
StubFactory* factory = getStubFactory();
|
|
if (factory != NULL) {
|
|
factory->addPrototype(new AArch64LongBranchStub(config().isCodeIndep()));
|
|
if (config().targets().fixCA53Erratum835769()) {
|
|
factory->addPrototype(new AArch64CA53Erratum835769Stub());
|
|
}
|
|
if (config().targets().fixCA53Erratum843419()) {
|
|
factory->addPrototype(new AArch64CA53Erratum843419Stub());
|
|
factory->addPrototype(new AArch64CA53Erratum843419Stub2());
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void AArch64GNULDBackend::doCreateProgramHdrs(Module& pModule) {
|
|
}
|
|
|
|
bool AArch64GNULDBackend::finalizeTargetSymbols() {
|
|
return true;
|
|
}
|
|
|
|
bool AArch64GNULDBackend::mergeSection(Module& pModule,
|
|
const Input& pInput,
|
|
LDSection& pSection) {
|
|
return true;
|
|
}
|
|
|
|
bool AArch64GNULDBackend::readSection(Input& pInput, SectionData& pSD) {
|
|
return true;
|
|
}
|
|
|
|
AArch64GOT& AArch64GNULDBackend::getGOT() {
|
|
assert(m_pGOT != NULL && "GOT section not exist");
|
|
return *m_pGOT;
|
|
}
|
|
|
|
const AArch64GOT& AArch64GNULDBackend::getGOT() const {
|
|
assert(m_pGOT != NULL && "GOT section not exist");
|
|
return *m_pGOT;
|
|
}
|
|
|
|
AArch64GOT& AArch64GNULDBackend::getGOTPLT() {
|
|
assert(m_pGOTPLT != NULL && "GOTPLT section not exist");
|
|
return *m_pGOTPLT;
|
|
}
|
|
|
|
const AArch64GOT& AArch64GNULDBackend::getGOTPLT() const {
|
|
assert(m_pGOTPLT != NULL && "GOTPLT section not exist");
|
|
return *m_pGOTPLT;
|
|
}
|
|
|
|
AArch64PLT& AArch64GNULDBackend::getPLT() {
|
|
assert(m_pPLT != NULL && "PLT section not exist");
|
|
return *m_pPLT;
|
|
}
|
|
|
|
const AArch64PLT& AArch64GNULDBackend::getPLT() const {
|
|
assert(m_pPLT != NULL && "PLT section not exist");
|
|
return *m_pPLT;
|
|
}
|
|
|
|
OutputRelocSection& AArch64GNULDBackend::getRelaDyn() {
|
|
assert(m_pRelaDyn != NULL && ".rela.dyn section not exist");
|
|
return *m_pRelaDyn;
|
|
}
|
|
|
|
const OutputRelocSection& AArch64GNULDBackend::getRelaDyn() const {
|
|
assert(m_pRelaDyn != NULL && ".rela.dyn section not exist");
|
|
return *m_pRelaDyn;
|
|
}
|
|
|
|
OutputRelocSection& AArch64GNULDBackend::getRelaPLT() {
|
|
assert(m_pRelaPLT != NULL && ".rela.plt section not exist");
|
|
return *m_pRelaPLT;
|
|
}
|
|
|
|
const OutputRelocSection& AArch64GNULDBackend::getRelaPLT() const {
|
|
assert(m_pRelaPLT != NULL && ".rela.plt section not exist");
|
|
return *m_pRelaPLT;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// createAArch64LDBackend - the help funtion to create corresponding
|
|
// AArch64LDBackend
|
|
//===----------------------------------------------------------------------===//
|
|
TargetLDBackend* createAArch64LDBackend(const LinkerConfig& pConfig) {
|
|
if (pConfig.targets().triple().isOSDarwin()) {
|
|
assert(0 && "MachO linker is not supported yet");
|
|
/**
|
|
return new AArch64MachOLDBackend(createAArch64MachOArchiveReader,
|
|
createAArch64MachOObjectReader,
|
|
createAArch64MachOObjectWriter);
|
|
**/
|
|
}
|
|
if (pConfig.targets().triple().isOSWindows()) {
|
|
assert(0 && "COFF linker is not supported yet");
|
|
/**
|
|
return new AArch64COFFLDBackend(createAArch64COFFArchiveReader,
|
|
createAArch64COFFObjectReader,
|
|
createAArch64COFFObjectWriter);
|
|
**/
|
|
}
|
|
return new AArch64GNULDBackend(
|
|
pConfig, new AArch64GNUInfo(pConfig.targets().triple()));
|
|
}
|
|
|
|
} // namespace mcld
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Force static initialization.
|
|
//===----------------------------------------------------------------------===//
|
|
extern "C" void MCLDInitializeAArch64LDBackend() {
|
|
// Register the linker backend
|
|
mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheAArch64Target,
|
|
mcld::createAArch64LDBackend);
|
|
}
|