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.
737 lines
22 KiB
737 lines
22 KiB
//===- X86LDBackend.cpp ---------------------------------------------------===//
|
|
//
|
|
// The MCLinker Project
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "X86.h"
|
|
#include "X86ELFDynamic.h"
|
|
#include "X86LDBackend.h"
|
|
#include "X86Relocator.h"
|
|
#include "X86GNUInfo.h"
|
|
|
|
#include "mcld/IRBuilder.h"
|
|
#include "mcld/LinkerConfig.h"
|
|
#include "mcld/Fragment/FillFragment.h"
|
|
#include "mcld/Fragment/RegionFragment.h"
|
|
#include "mcld/LD/ELFFileFormat.h"
|
|
#include "mcld/Object/ObjectBuilder.h"
|
|
#include "mcld/Support/MsgHandling.h"
|
|
#include "mcld/Support/TargetRegistry.h"
|
|
|
|
#include <llvm/ADT/StringRef.h>
|
|
#include <llvm/ADT/Triple.h>
|
|
#include <llvm/Support/Casting.h>
|
|
#include <llvm/Support/Dwarf.h>
|
|
|
|
#include <cstring>
|
|
|
|
namespace mcld {
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// X86GNULDBackend
|
|
//===----------------------------------------------------------------------===//
|
|
X86GNULDBackend::X86GNULDBackend(const LinkerConfig& pConfig,
|
|
GNUInfo* pInfo,
|
|
Relocation::Type pCopyRel)
|
|
: GNULDBackend(pConfig, pInfo),
|
|
m_pRelocator(NULL),
|
|
m_pPLT(NULL),
|
|
m_pRelDyn(NULL),
|
|
m_pRelPLT(NULL),
|
|
m_pDynamic(NULL),
|
|
m_pGOTSymbol(NULL),
|
|
m_CopyRel(pCopyRel) {
|
|
llvm::Triple::ArchType arch = pConfig.targets().triple().getArch();
|
|
assert(arch == llvm::Triple::x86 || arch == llvm::Triple::x86_64);
|
|
if (arch == llvm::Triple::x86 ||
|
|
pConfig.targets().triple().getEnvironment() == llvm::Triple::GNUX32) {
|
|
m_RelEntrySize = 8;
|
|
m_RelaEntrySize = 12;
|
|
if (arch == llvm::Triple::x86)
|
|
m_PointerRel = llvm::ELF::R_386_32;
|
|
else
|
|
m_PointerRel = llvm::ELF::R_X86_64_32;
|
|
} else {
|
|
m_RelEntrySize = 16;
|
|
m_RelaEntrySize = 24;
|
|
m_PointerRel = llvm::ELF::R_X86_64_64;
|
|
}
|
|
}
|
|
|
|
X86GNULDBackend::~X86GNULDBackend() {
|
|
delete m_pRelocator;
|
|
delete m_pPLT;
|
|
delete m_pRelDyn;
|
|
delete m_pRelPLT;
|
|
delete m_pDynamic;
|
|
}
|
|
|
|
const Relocator* X86GNULDBackend::getRelocator() const {
|
|
assert(m_pRelocator != NULL);
|
|
return m_pRelocator;
|
|
}
|
|
|
|
Relocator* X86GNULDBackend::getRelocator() {
|
|
assert(m_pRelocator != NULL);
|
|
return m_pRelocator;
|
|
}
|
|
|
|
void X86GNULDBackend::doPreLayout(IRBuilder& pBuilder) {
|
|
// initialize .dynamic data
|
|
if (!config().isCodeStatic() && m_pDynamic == NULL)
|
|
m_pDynamic = new X86ELFDynamic(*this, config());
|
|
|
|
// set .got.plt and .got sizes
|
|
// when building shared object, the .got section is must
|
|
if (LinkerConfig::Object != config().codeGenType()) {
|
|
setGOTSectionSize(pBuilder);
|
|
|
|
// set .plt size
|
|
if (m_pPLT->hasPLT1())
|
|
m_pPLT->finalizeSectionSize();
|
|
|
|
// set .rel.dyn/.rela.dyn size
|
|
if (!m_pRelDyn->empty()) {
|
|
assert(
|
|
!config().isCodeStatic() &&
|
|
"static linkage should not result in a dynamic relocation section");
|
|
setRelDynSize();
|
|
}
|
|
// set .rel.plt/.rela.plt size
|
|
if (!m_pRelPLT->empty()) {
|
|
assert(
|
|
!config().isCodeStatic() &&
|
|
"static linkage should not result in a dynamic relocation section");
|
|
setRelPLTSize();
|
|
}
|
|
}
|
|
|
|
if (config().options().genUnwindInfo())
|
|
addEhFrameForPLT(pBuilder.getModule());
|
|
}
|
|
|
|
void X86GNULDBackend::doPostLayout(Module& pModule, IRBuilder& pBuilder) {
|
|
}
|
|
|
|
/// dynamic - the dynamic section of the target machine.
|
|
/// Use co-variant return type to return its own dynamic section.
|
|
X86ELFDynamic& X86GNULDBackend::dynamic() {
|
|
assert(m_pDynamic != NULL);
|
|
return *m_pDynamic;
|
|
}
|
|
|
|
/// dynamic - the dynamic section of the target machine.
|
|
/// Use co-variant return type to return its own dynamic section.
|
|
const X86ELFDynamic& X86GNULDBackend::dynamic() const {
|
|
assert(m_pDynamic != NULL);
|
|
return *m_pDynamic;
|
|
}
|
|
|
|
void X86GNULDBackend::defineGOTSymbol(IRBuilder& pBuilder, Fragment& pFrag) {
|
|
// define symbol _GLOBAL_OFFSET_TABLE_
|
|
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(pFrag, 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(pFrag, 0x0),
|
|
ResolveInfo::Hidden);
|
|
}
|
|
}
|
|
|
|
uint64_t X86GNULDBackend::emitSectionData(const LDSection& pSection,
|
|
MemoryRegion& pRegion) const {
|
|
assert(pRegion.size() && "Size of MemoryRegion is zero!");
|
|
|
|
const ELFFileFormat* FileFormat = getOutputFormat();
|
|
assert(FileFormat &&
|
|
"ELFFileFormat is NULL in X86GNULDBackend::emitSectionData!");
|
|
|
|
unsigned int EntrySize = 0;
|
|
uint64_t RegionSize = 0;
|
|
|
|
if (FileFormat->hasPLT() && (&pSection == &(FileFormat->getPLT()))) {
|
|
unsigned char* buffer = pRegion.begin();
|
|
|
|
m_pPLT->applyPLT0();
|
|
m_pPLT->applyPLT1();
|
|
X86PLT::iterator it = m_pPLT->begin();
|
|
unsigned int plt0_size = llvm::cast<PLTEntryBase>((*it)).size();
|
|
|
|
memcpy(buffer, llvm::cast<PLTEntryBase>((*it)).getValue(), plt0_size);
|
|
RegionSize += plt0_size;
|
|
++it;
|
|
|
|
PLTEntryBase* plt1 = 0;
|
|
X86PLT::iterator ie = m_pPLT->end();
|
|
while (it != ie) {
|
|
plt1 = &(llvm::cast<PLTEntryBase>(*it));
|
|
EntrySize = plt1->size();
|
|
memcpy(buffer + RegionSize, plt1->getValue(), EntrySize);
|
|
RegionSize += EntrySize;
|
|
++it;
|
|
}
|
|
} else if (FileFormat->hasGOT() && (&pSection == &(FileFormat->getGOT()))) {
|
|
RegionSize += emitGOTSectionData(pRegion);
|
|
} else if (FileFormat->hasGOTPLT() &&
|
|
(&pSection == &(FileFormat->getGOTPLT()))) {
|
|
RegionSize += emitGOTPLTSectionData(pRegion, FileFormat);
|
|
} else {
|
|
fatal(diag::unrecognized_output_sectoin) << pSection.name()
|
|
<< "mclinker@googlegroups.com";
|
|
}
|
|
return RegionSize;
|
|
}
|
|
|
|
X86PLT& X86GNULDBackend::getPLT() {
|
|
assert(m_pPLT != NULL && "PLT section not exist");
|
|
return *m_pPLT;
|
|
}
|
|
|
|
const X86PLT& X86GNULDBackend::getPLT() const {
|
|
assert(m_pPLT != NULL && "PLT section not exist");
|
|
return *m_pPLT;
|
|
}
|
|
|
|
OutputRelocSection& X86GNULDBackend::getRelDyn() {
|
|
assert(m_pRelDyn != NULL && ".rel.dyn/.rela.dyn section not exist");
|
|
return *m_pRelDyn;
|
|
}
|
|
|
|
const OutputRelocSection& X86GNULDBackend::getRelDyn() const {
|
|
assert(m_pRelDyn != NULL && ".rel.dyn/.rela.dyn section not exist");
|
|
return *m_pRelDyn;
|
|
}
|
|
|
|
OutputRelocSection& X86GNULDBackend::getRelPLT() {
|
|
assert(m_pRelPLT != NULL && ".rel.plt/.rela.plt section not exist");
|
|
return *m_pRelPLT;
|
|
}
|
|
|
|
const OutputRelocSection& X86GNULDBackend::getRelPLT() const {
|
|
assert(m_pRelPLT != NULL && ".rel.plt/.rela.plt section not exist");
|
|
return *m_pRelPLT;
|
|
}
|
|
|
|
unsigned int X86GNULDBackend::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())) {
|
|
if (config().options().hasNow())
|
|
return SHO_RELRO;
|
|
return SHO_NON_RELRO_FIRST;
|
|
}
|
|
|
|
if (file_format->hasPLT() && (&pSectHdr == &file_format->getPLT()))
|
|
return SHO_PLT;
|
|
|
|
return SHO_UNDEFINED;
|
|
}
|
|
|
|
void X86GNULDBackend::initTargetSymbols(IRBuilder& pBuilder, Module& pModule) {
|
|
if (LinkerConfig::Object != config().codeGenType()) {
|
|
// Define the symbol _GLOBAL_OFFSET_TABLE_ if there is a symbol with the
|
|
// same name in input
|
|
m_pGOTSymbol =
|
|
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
|
|
"_GLOBAL_OFFSET_TABLE_",
|
|
ResolveInfo::Object,
|
|
ResolveInfo::Define,
|
|
ResolveInfo::Local,
|
|
0x0, // size
|
|
0x0, // value
|
|
FragmentRef::Null(), // FragRef
|
|
ResolveInfo::Hidden);
|
|
}
|
|
}
|
|
|
|
void X86GNULDBackend::addEhFrameForPLT(Module& pModule) {
|
|
LDSection* plt_sect = pModule.getSection(".plt");
|
|
if (!plt_sect || plt_sect->size() == 0u)
|
|
return;
|
|
|
|
LDSection* eh_sect = pModule.getSection(".eh_frame");
|
|
if (!eh_sect || !eh_sect->hasEhFrame())
|
|
return;
|
|
|
|
EhFrame* eh_frame = eh_sect->getEhFrame();
|
|
SectionData::FragmentListType& frag_list =
|
|
eh_frame->getSectionData()->getFragmentList();
|
|
llvm::StringRef cie_region = createCIERegionForPLT();
|
|
llvm::StringRef fde_region = createFDERegionForPLT();
|
|
EhFrame::CIE* cie = new EhFrame::GeneratedCIE(cie_region);
|
|
EhFrame::FDE* fde = new EhFrame::GeneratedFDE(fde_region, *cie);
|
|
// Augmentation data only contains FDE encoding.
|
|
uint8_t aug_data =
|
|
(uint8_t)(llvm::dwarf::DW_EH_PE_pcrel | llvm::dwarf::DW_EH_PE_sdata4);
|
|
cie->setFDEEncode(aug_data);
|
|
cie->setAugmentationData(std::string(1, aug_data));
|
|
|
|
EhFrame::cie_iterator i = eh_frame->cie_begin();
|
|
for (EhFrame::cie_iterator e = eh_frame->cie_end(); i != e; ++i) {
|
|
EhFrame::CIE& exist_cie = **i;
|
|
if (exist_cie == *cie) {
|
|
// Insert the FDE fragment
|
|
SectionData::iterator cur_iter(exist_cie);
|
|
frag_list.insertAfter(cur_iter, fde);
|
|
fde->setCIE(exist_cie);
|
|
|
|
// Cleanup the CIE we created
|
|
cie->clearFDEs();
|
|
delete cie;
|
|
break;
|
|
}
|
|
}
|
|
if (i == eh_frame->cie_end()) {
|
|
// Newly insert
|
|
eh_frame->addCIE(*cie);
|
|
eh_frame->addFDE(*fde);
|
|
}
|
|
}
|
|
|
|
/// finalizeSymbol - finalize the symbol value
|
|
bool X86GNULDBackend::finalizeTargetSymbols() {
|
|
return true;
|
|
}
|
|
|
|
/// doCreateProgramHdrs - backend can implement this function to create the
|
|
/// target-dependent segments
|
|
void X86GNULDBackend::doCreateProgramHdrs(Module& pModule) {
|
|
// TODO
|
|
}
|
|
|
|
X86_32GNULDBackend::X86_32GNULDBackend(const LinkerConfig& pConfig,
|
|
GNUInfo* pInfo)
|
|
: X86GNULDBackend(pConfig, pInfo, llvm::ELF::R_386_COPY),
|
|
m_pGOT(NULL),
|
|
m_pGOTPLT(NULL) {
|
|
}
|
|
|
|
X86_32GNULDBackend::~X86_32GNULDBackend() {
|
|
delete m_pGOT;
|
|
delete m_pGOTPLT;
|
|
}
|
|
|
|
bool X86_32GNULDBackend::initRelocator() {
|
|
if (m_pRelocator == NULL) {
|
|
m_pRelocator = new X86_32Relocator(*this, config());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void X86_32GNULDBackend::initTargetSections(Module& pModule,
|
|
ObjectBuilder& pBuilder) {
|
|
if (LinkerConfig::Object != config().codeGenType()) {
|
|
ELFFileFormat* file_format = getOutputFormat();
|
|
// initialize .got
|
|
LDSection& got = file_format->getGOT();
|
|
m_pGOT = new X86_32GOT(got);
|
|
|
|
// initialize .got.plt
|
|
LDSection& gotplt = file_format->getGOTPLT();
|
|
m_pGOTPLT = new X86_32GOTPLT(gotplt);
|
|
|
|
// initialize .plt
|
|
LDSection& plt = file_format->getPLT();
|
|
plt.setAlign(16u);
|
|
m_pPLT = new X86_32PLT(plt, *m_pGOTPLT, config());
|
|
|
|
// initialize .rel.plt
|
|
LDSection& relplt = file_format->getRelPlt();
|
|
relplt.setLink(&plt);
|
|
m_pRelPLT = new OutputRelocSection(pModule, relplt);
|
|
|
|
// initialize .rel.dyn
|
|
LDSection& reldyn = file_format->getRelDyn();
|
|
m_pRelDyn = new OutputRelocSection(pModule, reldyn);
|
|
}
|
|
}
|
|
|
|
X86_32GOT& X86_32GNULDBackend::getGOT() {
|
|
assert(m_pGOT != NULL);
|
|
return *m_pGOT;
|
|
}
|
|
|
|
const X86_32GOT& X86_32GNULDBackend::getGOT() const {
|
|
assert(m_pGOT != NULL);
|
|
return *m_pGOT;
|
|
}
|
|
|
|
X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT() {
|
|
assert(m_pGOTPLT != NULL);
|
|
return *m_pGOTPLT;
|
|
}
|
|
|
|
const X86_32GOTPLT& X86_32GNULDBackend::getGOTPLT() const {
|
|
assert(m_pGOTPLT != NULL);
|
|
return *m_pGOTPLT;
|
|
}
|
|
|
|
llvm::StringRef X86_32GNULDBackend::createCIERegionForPLT() {
|
|
static const uint8_t data[4 + 4 + 16] = {
|
|
0x14, 0, 0, 0, // length
|
|
0, 0, 0, 0, // ID
|
|
1, // version
|
|
'z', 'R', '\0', // augmentation string
|
|
1, // code alignment factor
|
|
0x7c, // data alignment factor
|
|
8, // return address column
|
|
1, // augmentation data size
|
|
llvm::dwarf::DW_EH_PE_pcrel
|
|
| llvm::dwarf::DW_EH_PE_sdata4, // FDE encoding
|
|
llvm::dwarf::DW_CFA_def_cfa, 4, 4,
|
|
llvm::dwarf::DW_CFA_offset + 8, 1,
|
|
llvm::dwarf::DW_CFA_nop,
|
|
llvm::dwarf::DW_CFA_nop
|
|
};
|
|
return llvm::StringRef((const char*)data, 4 + 4 + 16);
|
|
}
|
|
|
|
llvm::StringRef X86_32GNULDBackend::createFDERegionForPLT() {
|
|
static const uint8_t data[4 + 4 + 32] = {
|
|
0x24, 0, 0, 0, // length
|
|
0, 0, 0, 0, // offset to CIE
|
|
0, 0, 0, 0, // offset to PLT
|
|
0, 0, 0, 0, // size of PLT
|
|
0, // augmentation data size
|
|
llvm::dwarf::DW_CFA_def_cfa_offset, 8,
|
|
llvm::dwarf::DW_CFA_advance_loc + 6,
|
|
llvm::dwarf::DW_CFA_def_cfa_offset, 12,
|
|
llvm::dwarf::DW_CFA_advance_loc + 10,
|
|
llvm::dwarf::DW_CFA_def_cfa_expression,
|
|
11,
|
|
llvm::dwarf::DW_OP_breg4, 4,
|
|
llvm::dwarf::DW_OP_breg8, 0,
|
|
llvm::dwarf::DW_OP_lit15,
|
|
llvm::dwarf::DW_OP_and,
|
|
llvm::dwarf::DW_OP_lit11,
|
|
llvm::dwarf::DW_OP_ge,
|
|
llvm::dwarf::DW_OP_lit2,
|
|
llvm::dwarf::DW_OP_shl,
|
|
llvm::dwarf::DW_OP_plus,
|
|
llvm::dwarf::DW_CFA_nop,
|
|
llvm::dwarf::DW_CFA_nop,
|
|
llvm::dwarf::DW_CFA_nop,
|
|
llvm::dwarf::DW_CFA_nop
|
|
};
|
|
return llvm::StringRef((const char*)data, 4 + 4 + 32);
|
|
}
|
|
|
|
void X86_32GNULDBackend::setRelDynSize() {
|
|
ELFFileFormat* file_format = getOutputFormat();
|
|
file_format->getRelDyn().setSize(m_pRelDyn->numOfRelocs() *
|
|
getRelEntrySize());
|
|
}
|
|
|
|
void X86_32GNULDBackend::setRelPLTSize() {
|
|
ELFFileFormat* file_format = getOutputFormat();
|
|
file_format->getRelPlt().setSize(m_pRelPLT->numOfRelocs() *
|
|
getRelEntrySize());
|
|
}
|
|
|
|
void X86_32GNULDBackend::setGOTSectionSize(IRBuilder& pBuilder) {
|
|
// set .got.plt size
|
|
if (LinkerConfig::DynObj == config().codeGenType() || m_pGOTPLT->hasGOT1() ||
|
|
m_pGOTSymbol != NULL) {
|
|
m_pGOTPLT->finalizeSectionSize();
|
|
defineGOTSymbol(pBuilder, *(m_pGOTPLT->begin()));
|
|
}
|
|
|
|
// set .got size
|
|
if (!m_pGOT->empty())
|
|
m_pGOT->finalizeSectionSize();
|
|
}
|
|
|
|
uint64_t X86_32GNULDBackend::emitGOTSectionData(MemoryRegion& pRegion) const {
|
|
assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!");
|
|
|
|
uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin());
|
|
|
|
X86_32GOTEntry* got = 0;
|
|
unsigned int EntrySize = X86_32GOTEntry::EntrySize;
|
|
uint64_t RegionSize = 0;
|
|
|
|
for (X86_32GOT::iterator it = m_pGOT->begin(), ie = m_pGOT->end(); it != ie;
|
|
++it, ++buffer) {
|
|
got = &(llvm::cast<X86_32GOTEntry>((*it)));
|
|
*buffer = static_cast<uint32_t>(got->getValue());
|
|
RegionSize += EntrySize;
|
|
}
|
|
|
|
return RegionSize;
|
|
}
|
|
|
|
uint64_t X86_32GNULDBackend::emitGOTPLTSectionData(
|
|
MemoryRegion& pRegion,
|
|
const ELFFileFormat* FileFormat) const {
|
|
assert(m_pGOTPLT && "emitGOTPLTSectionData failed, m_pGOTPLT is NULL!");
|
|
m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr());
|
|
m_pGOTPLT->applyAllGOTPLT(*m_pPLT);
|
|
|
|
uint32_t* buffer = reinterpret_cast<uint32_t*>(pRegion.begin());
|
|
|
|
X86_32GOTEntry* got = 0;
|
|
unsigned int EntrySize = X86_32GOTEntry::EntrySize;
|
|
uint64_t RegionSize = 0;
|
|
|
|
for (X86_32GOTPLT::iterator it = m_pGOTPLT->begin(), ie = m_pGOTPLT->end();
|
|
it != ie;
|
|
++it, ++buffer) {
|
|
got = &(llvm::cast<X86_32GOTEntry>((*it)));
|
|
*buffer = static_cast<uint32_t>(got->getValue());
|
|
RegionSize += EntrySize;
|
|
}
|
|
|
|
return RegionSize;
|
|
}
|
|
|
|
X86_64GNULDBackend::X86_64GNULDBackend(const LinkerConfig& pConfig,
|
|
GNUInfo* pInfo)
|
|
: X86GNULDBackend(pConfig, pInfo, llvm::ELF::R_X86_64_COPY),
|
|
m_pGOT(NULL),
|
|
m_pGOTPLT(NULL) {
|
|
}
|
|
|
|
X86_64GNULDBackend::~X86_64GNULDBackend() {
|
|
delete m_pGOT;
|
|
delete m_pGOTPLT;
|
|
}
|
|
|
|
bool X86_64GNULDBackend::initRelocator() {
|
|
if (m_pRelocator == NULL) {
|
|
m_pRelocator = new X86_64Relocator(*this, config());
|
|
}
|
|
return true;
|
|
}
|
|
|
|
X86_64GOT& X86_64GNULDBackend::getGOT() {
|
|
assert(m_pGOT != NULL);
|
|
return *m_pGOT;
|
|
}
|
|
|
|
const X86_64GOT& X86_64GNULDBackend::getGOT() const {
|
|
assert(m_pGOT != NULL);
|
|
return *m_pGOT;
|
|
}
|
|
|
|
X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT() {
|
|
assert(m_pGOTPLT != NULL);
|
|
return *m_pGOTPLT;
|
|
}
|
|
|
|
const X86_64GOTPLT& X86_64GNULDBackend::getGOTPLT() const {
|
|
assert(m_pGOTPLT != NULL);
|
|
return *m_pGOTPLT;
|
|
}
|
|
|
|
llvm::StringRef X86_64GNULDBackend::createCIERegionForPLT() {
|
|
static const uint8_t data[4 + 4 + 16] = {
|
|
0x14, 0, 0, 0, // length
|
|
0, 0, 0, 0, // ID
|
|
1, // CIE version
|
|
'z', 'R', '\0', // augmentation string
|
|
1, // code alignment factor
|
|
0x78, // data alignment factor
|
|
16, // return address column
|
|
1, // augmentation data size
|
|
llvm::dwarf::DW_EH_PE_pcrel
|
|
| llvm::dwarf::DW_EH_PE_sdata4, // FDE encoding
|
|
llvm::dwarf::DW_CFA_def_cfa, 7, 8,
|
|
llvm::dwarf::DW_CFA_offset + 16, 1,
|
|
llvm::dwarf::DW_CFA_nop,
|
|
llvm::dwarf::DW_CFA_nop
|
|
};
|
|
return llvm::StringRef((const char*)data, 4 + 4 + 16);
|
|
}
|
|
|
|
llvm::StringRef X86_64GNULDBackend::createFDERegionForPLT() {
|
|
static const uint8_t data[4 + 4 + 32] = {
|
|
0x24, 0, 0, 0, // length
|
|
0, 0, 0, 0, // ID
|
|
0, 0, 0, 0, // offset to PLT
|
|
0, 0, 0, 0, // size of PLT
|
|
0, // augmentation data size
|
|
llvm::dwarf::DW_CFA_def_cfa_offset, 16,
|
|
llvm::dwarf::DW_CFA_advance_loc + 6,
|
|
llvm::dwarf::DW_CFA_def_cfa_offset, 24,
|
|
llvm::dwarf::DW_CFA_advance_loc + 10,
|
|
llvm::dwarf::DW_CFA_def_cfa_expression,
|
|
11,
|
|
llvm::dwarf::DW_OP_breg7, 8,
|
|
llvm::dwarf::DW_OP_breg16, 0,
|
|
llvm::dwarf::DW_OP_lit15,
|
|
llvm::dwarf::DW_OP_and,
|
|
llvm::dwarf::DW_OP_lit11,
|
|
llvm::dwarf::DW_OP_ge,
|
|
llvm::dwarf::DW_OP_lit3,
|
|
llvm::dwarf::DW_OP_shl,
|
|
llvm::dwarf::DW_OP_plus,
|
|
llvm::dwarf::DW_CFA_nop,
|
|
llvm::dwarf::DW_CFA_nop,
|
|
llvm::dwarf::DW_CFA_nop,
|
|
llvm::dwarf::DW_CFA_nop
|
|
};
|
|
return llvm::StringRef((const char*)data, 4 + 4 + 32);
|
|
}
|
|
|
|
void X86_64GNULDBackend::setRelDynSize() {
|
|
ELFFileFormat* file_format = getOutputFormat();
|
|
file_format->getRelaDyn().setSize(m_pRelDyn->numOfRelocs() *
|
|
getRelaEntrySize());
|
|
}
|
|
|
|
void X86_64GNULDBackend::setRelPLTSize() {
|
|
ELFFileFormat* file_format = getOutputFormat();
|
|
file_format->getRelaPlt().setSize(m_pRelPLT->numOfRelocs() *
|
|
getRelaEntrySize());
|
|
}
|
|
|
|
void X86_64GNULDBackend::initTargetSections(Module& pModule,
|
|
ObjectBuilder& pBuilder) {
|
|
if (LinkerConfig::Object != config().codeGenType()) {
|
|
ELFFileFormat* file_format = getOutputFormat();
|
|
// initialize .got
|
|
LDSection& got = file_format->getGOT();
|
|
m_pGOT = new X86_64GOT(got);
|
|
|
|
// initialize .got.plt
|
|
LDSection& gotplt = file_format->getGOTPLT();
|
|
m_pGOTPLT = new X86_64GOTPLT(gotplt);
|
|
|
|
// initialize .plt
|
|
LDSection& plt = file_format->getPLT();
|
|
plt.setAlign(16u);
|
|
m_pPLT = new X86_64PLT(plt, *m_pGOTPLT, config());
|
|
|
|
// initialize .rela.plt
|
|
LDSection& relplt = file_format->getRelaPlt();
|
|
relplt.setLink(&plt);
|
|
m_pRelPLT = new OutputRelocSection(pModule, relplt);
|
|
|
|
// initialize .rela.dyn
|
|
LDSection& reldyn = file_format->getRelaDyn();
|
|
m_pRelDyn = new OutputRelocSection(pModule, reldyn);
|
|
}
|
|
}
|
|
|
|
void X86_64GNULDBackend::setGOTSectionSize(IRBuilder& pBuilder) {
|
|
// set .got.plt size
|
|
if (LinkerConfig::DynObj == config().codeGenType() || m_pGOTPLT->hasGOT1() ||
|
|
m_pGOTSymbol != NULL) {
|
|
m_pGOTPLT->finalizeSectionSize();
|
|
defineGOTSymbol(pBuilder, *(m_pGOTPLT->begin()));
|
|
}
|
|
|
|
// set .got size
|
|
if (!m_pGOT->empty())
|
|
m_pGOT->finalizeSectionSize();
|
|
}
|
|
|
|
uint64_t X86_64GNULDBackend::emitGOTSectionData(MemoryRegion& pRegion) const {
|
|
assert(m_pGOT && "emitGOTSectionData failed, m_pGOT is NULL!");
|
|
|
|
uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.begin());
|
|
|
|
X86_64GOTEntry* got = 0;
|
|
unsigned int EntrySize = X86_64GOTEntry::EntrySize;
|
|
uint64_t RegionSize = 0;
|
|
|
|
for (X86_64GOT::iterator it = m_pGOT->begin(), ie = m_pGOT->end(); it != ie;
|
|
++it, ++buffer) {
|
|
got = &(llvm::cast<X86_64GOTEntry>((*it)));
|
|
*buffer = static_cast<uint64_t>(got->getValue());
|
|
RegionSize += EntrySize;
|
|
}
|
|
|
|
return RegionSize;
|
|
}
|
|
|
|
uint64_t X86_64GNULDBackend::emitGOTPLTSectionData(
|
|
MemoryRegion& pRegion,
|
|
const ELFFileFormat* FileFormat) const {
|
|
assert(m_pGOTPLT && "emitGOTPLTSectionData failed, m_pGOTPLT is NULL!");
|
|
m_pGOTPLT->applyGOT0(FileFormat->getDynamic().addr());
|
|
m_pGOTPLT->applyAllGOTPLT(*m_pPLT);
|
|
|
|
uint64_t* buffer = reinterpret_cast<uint64_t*>(pRegion.begin());
|
|
|
|
X86_64GOTEntry* got = 0;
|
|
unsigned int EntrySize = X86_64GOTEntry::EntrySize;
|
|
uint64_t RegionSize = 0;
|
|
|
|
for (X86_64GOTPLT::iterator it = m_pGOTPLT->begin(), ie = m_pGOTPLT->end();
|
|
it != ie;
|
|
++it, ++buffer) {
|
|
got = &(llvm::cast<X86_64GOTEntry>((*it)));
|
|
*buffer = static_cast<uint64_t>(got->getValue());
|
|
RegionSize += EntrySize;
|
|
}
|
|
|
|
return RegionSize;
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
/// createX86LDBackend - the help funtion to create corresponding X86LDBackend
|
|
///
|
|
TargetLDBackend* createX86LDBackend(const LinkerConfig& pConfig) {
|
|
if (pConfig.targets().triple().isOSDarwin()) {
|
|
assert(0 && "MachO linker is not supported yet");
|
|
/**
|
|
return new X86MachOLDBackend(createX86MachOArchiveReader,
|
|
createX86MachOObjectReader,
|
|
createX86MachOObjectWriter);
|
|
**/
|
|
}
|
|
if (pConfig.targets().triple().isOSWindows()) {
|
|
assert(0 && "COFF linker is not supported yet");
|
|
/**
|
|
return new X86COFFLDBackend(createX86COFFArchiveReader,
|
|
createX86COFFObjectReader,
|
|
createX86COFFObjectWriter);
|
|
**/
|
|
}
|
|
llvm::Triple::ArchType arch = pConfig.targets().triple().getArch();
|
|
if (arch == llvm::Triple::x86)
|
|
return new X86_32GNULDBackend(
|
|
pConfig, new X86_32GNUInfo(pConfig.targets().triple()));
|
|
assert(arch == llvm::Triple::x86_64);
|
|
return new X86_64GNULDBackend(pConfig,
|
|
new X86_64GNUInfo(pConfig.targets().triple()));
|
|
}
|
|
|
|
} // namespace mcld
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Force static initialization.
|
|
//===----------------------------------------------------------------------===//
|
|
extern "C" void MCLDInitializeX86LDBackend() {
|
|
// Register the linker backend
|
|
mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheX86_32Target,
|
|
mcld::createX86LDBackend);
|
|
mcld::TargetRegistry::RegisterTargetLDBackend(mcld::TheX86_64Target,
|
|
mcld::createX86LDBackend);
|
|
}
|