1
0
Fork 0
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.

2980 lines
101 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

//===- GNULDBackend.cpp ---------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "mcld/Target/GNULDBackend.h"
#include "mcld/IRBuilder.h"
#include "mcld/InputTree.h"
#include "mcld/LinkerConfig.h"
#include "mcld/LinkerScript.h"
#include "mcld/Module.h"
#include "mcld/ADT/SizeTraits.h"
#include "mcld/Config/Config.h"
#include "mcld/Fragment/FillFragment.h"
#include "mcld/LD/BranchIslandFactory.h"
#include "mcld/LD/EhFrame.h"
#include "mcld/LD/EhFrameHdr.h"
#include "mcld/LD/ELFDynObjFileFormat.h"
#include "mcld/LD/ELFExecFileFormat.h"
#include "mcld/LD/ELFFileFormat.h"
#include "mcld/LD/ELFObjectFileFormat.h"
#include "mcld/LD/ELFSegment.h"
#include "mcld/LD/ELFSegmentFactory.h"
#include "mcld/LD/LDContext.h"
#include "mcld/LD/LDSymbol.h"
#include "mcld/LD/RelocData.h"
#include "mcld/LD/RelocationFactory.h"
#include "mcld/LD/StubFactory.h"
#include "mcld/MC/Attribute.h"
#include "mcld/Object/ObjectBuilder.h"
#include "mcld/Object/SectionMap.h"
#include "mcld/Script/Operand.h"
#include "mcld/Script/OutputSectDesc.h"
#include "mcld/Script/RpnEvaluator.h"
#include "mcld/Support/FileOutputBuffer.h"
#include "mcld/Support/MsgHandling.h"
#include "mcld/Target/ELFAttribute.h"
#include "mcld/Target/ELFDynamic.h"
#include "mcld/Target/GNUInfo.h"
#include <llvm/ADT/StringRef.h>
#include <llvm/Support/Host.h>
#include <algorithm>
#include <cstring>
#include <cassert>
#include <map>
#include <string>
#include <vector>
namespace {
//===----------------------------------------------------------------------===//
// non-member functions
//===----------------------------------------------------------------------===//
static const std::string simple_c_identifier_allowed_chars =
"0123456789"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"_";
/// isCIdentifier - return if the pName is a valid C identifier
static bool isCIdentifier(const std::string& pName) {
return (pName.find_first_not_of(simple_c_identifier_allowed_chars) ==
std::string::npos);
}
} // anonymous namespace
namespace mcld {
//===----------------------------------------------------------------------===//
// GNULDBackend
//===----------------------------------------------------------------------===//
GNULDBackend::GNULDBackend(const LinkerConfig& pConfig, GNUInfo* pInfo)
: TargetLDBackend(pConfig),
m_pObjectReader(NULL),
m_pDynObjFileFormat(NULL),
m_pExecFileFormat(NULL),
m_pObjectFileFormat(NULL),
m_pInfo(pInfo),
m_pELFSegmentTable(NULL),
m_pBRIslandFactory(NULL),
m_pStubFactory(NULL),
m_pEhFrameHdr(NULL),
m_pAttribute(NULL),
m_bHasTextRel(false),
m_bHasStaticTLS(false),
f_pPreInitArrayStart(NULL),
f_pPreInitArrayEnd(NULL),
f_pInitArrayStart(NULL),
f_pInitArrayEnd(NULL),
f_pFiniArrayStart(NULL),
f_pFiniArrayEnd(NULL),
f_pStack(NULL),
f_pDynamic(NULL),
f_pTDATA(NULL),
f_pTBSS(NULL),
f_pExecutableStart(NULL),
f_pEText(NULL),
f_p_EText(NULL),
f_p__EText(NULL),
f_pEData(NULL),
f_p_EData(NULL),
f_pBSSStart(NULL),
f_pEnd(NULL),
f_p_End(NULL) {
m_pELFSegmentTable = new ELFSegmentFactory();
m_pSymIndexMap = new HashTableType(1024);
m_pAttribute = new ELFAttribute(*this, pConfig);
}
GNULDBackend::~GNULDBackend() {
delete m_pELFSegmentTable;
delete m_pInfo;
delete m_pDynObjFileFormat;
delete m_pExecFileFormat;
delete m_pObjectFileFormat;
delete m_pSymIndexMap;
delete m_pEhFrameHdr;
delete m_pAttribute;
delete m_pBRIslandFactory;
delete m_pStubFactory;
}
size_t GNULDBackend::sectionStartOffset() const {
if (LinkerConfig::Binary == config().codeGenType())
return 0x0;
switch (config().targets().bitclass()) {
case 32u:
return sizeof(llvm::ELF::Elf32_Ehdr) +
elfSegmentTable().size() * sizeof(llvm::ELF::Elf32_Phdr);
case 64u:
return sizeof(llvm::ELF::Elf64_Ehdr) +
elfSegmentTable().size() * sizeof(llvm::ELF::Elf64_Phdr);
default:
fatal(diag::unsupported_bitclass) << config().targets().triple().str()
<< config().targets().bitclass();
return 0;
}
}
uint64_t GNULDBackend::getSegmentStartAddr(const LinkerScript& pScript) const {
LinkerScript::AddressMap::const_iterator mapping =
pScript.addressMap().find(".text");
if (pScript.addressMap().end() != mapping)
return mapping.getEntry()->value();
else if (config().isCodeIndep())
return 0x0;
else
return m_pInfo->defaultTextSegmentAddr();
}
GNUArchiveReader* GNULDBackend::createArchiveReader(Module& pModule) {
assert(m_pObjectReader != NULL);
return new GNUArchiveReader(pModule, *m_pObjectReader);
}
ELFObjectReader* GNULDBackend::createObjectReader(IRBuilder& pBuilder) {
m_pObjectReader = new ELFObjectReader(*this, pBuilder, config());
return m_pObjectReader;
}
ELFDynObjReader* GNULDBackend::createDynObjReader(IRBuilder& pBuilder) {
return new ELFDynObjReader(*this, pBuilder, config());
}
ELFBinaryReader* GNULDBackend::createBinaryReader(IRBuilder& pBuilder) {
return new ELFBinaryReader(pBuilder, config());
}
ELFObjectWriter* GNULDBackend::createWriter() {
return new ELFObjectWriter(*this, config());
}
bool GNULDBackend::initStdSections(ObjectBuilder& pBuilder) {
switch (config().codeGenType()) {
case LinkerConfig::DynObj: {
if (m_pDynObjFileFormat == NULL)
m_pDynObjFileFormat = new ELFDynObjFileFormat();
m_pDynObjFileFormat->initStdSections(pBuilder,
config().targets().bitclass());
return true;
}
case LinkerConfig::Exec:
case LinkerConfig::Binary: {
if (m_pExecFileFormat == NULL)
m_pExecFileFormat = new ELFExecFileFormat();
m_pExecFileFormat->initStdSections(pBuilder,
config().targets().bitclass());
return true;
}
case LinkerConfig::Object: {
if (m_pObjectFileFormat == NULL)
m_pObjectFileFormat = new ELFObjectFileFormat();
m_pObjectFileFormat->initStdSections(pBuilder,
config().targets().bitclass());
return true;
}
default:
fatal(diag::unrecognized_output_file) << config().codeGenType();
return false;
}
}
/// initStandardSymbols - define and initialize standard symbols.
/// This function is called after section merging but before read relocations.
bool GNULDBackend::initStandardSymbols(IRBuilder& pBuilder, Module& pModule) {
if (LinkerConfig::Object == config().codeGenType())
return true;
// GNU extension: define __start and __stop symbols for the sections whose
// name can be presented as C symbol
Module::iterator iter, iterEnd = pModule.end();
for (iter = pModule.begin(); iter != iterEnd; ++iter) {
LDSection* section = *iter;
switch (section->kind()) {
case LDFileFormat::Relocation:
continue;
case LDFileFormat::EhFrame:
if (!section->hasEhFrame())
continue;
break;
default:
if (!section->hasSectionData())
continue;
break;
} // end of switch
if (isCIdentifier(section->name())) {
std::string start_name = "__start_" + section->name();
FragmentRef* start_fragref =
FragmentRef::Create(section->getSectionData()->front(), 0x0);
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
start_name,
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
0x0, // size
0x0, // value
start_fragref, // FragRef
ResolveInfo::Default);
std::string stop_name = "__stop_" + section->name();
FragmentRef* stop_fragref = FragmentRef::Create(
section->getSectionData()->front(), section->size());
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
stop_name,
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
0x0, // size
0x0, // value
stop_fragref, // FragRef
ResolveInfo::Default);
}
}
ELFFileFormat* file_format = getOutputFormat();
// ----- section symbols ----- //
// .preinit_array
FragmentRef* preinit_array = NULL;
if (file_format->hasPreInitArray()) {
preinit_array = FragmentRef::Create(
file_format->getPreInitArray().getSectionData()->front(), 0x0);
} else {
preinit_array = FragmentRef::Null();
}
f_pPreInitArrayStart =
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"__preinit_array_start",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
0x0, // size
0x0, // value
preinit_array, // FragRef
ResolveInfo::Hidden);
f_pPreInitArrayEnd =
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"__preinit_array_end",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Hidden);
// .init_array
FragmentRef* init_array = NULL;
if (file_format->hasInitArray()) {
init_array = FragmentRef::Create(
file_format->getInitArray().getSectionData()->front(), 0x0);
} else {
init_array = FragmentRef::Null();
}
f_pInitArrayStart =
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"__init_array_start",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
0x0, // size
0x0, // value
init_array, // FragRef
ResolveInfo::Hidden);
f_pInitArrayEnd =
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"__init_array_end",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
0x0, // size
0x0, // value
init_array, // FragRef
ResolveInfo::Hidden);
// .fini_array
FragmentRef* fini_array = NULL;
if (file_format->hasFiniArray()) {
fini_array = FragmentRef::Create(
file_format->getFiniArray().getSectionData()->front(), 0x0);
} else {
fini_array = FragmentRef::Null();
}
f_pFiniArrayStart =
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"__fini_array_start",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
0x0, // size
0x0, // value
fini_array, // FragRef
ResolveInfo::Hidden);
f_pFiniArrayEnd =
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"__fini_array_end",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
0x0, // size
0x0, // value
fini_array, // FragRef
ResolveInfo::Hidden);
// .stack
FragmentRef* stack = NULL;
if (file_format->hasStack()) {
stack = FragmentRef::Create(
file_format->getStack().getSectionData()->front(), 0x0);
} else {
stack = FragmentRef::Null();
}
f_pStack = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"__stack",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
0x0, // size
0x0, // value
stack, // FragRef
ResolveInfo::Hidden);
// _DYNAMIC
// TODO: add SectionData for .dynamic section, and then we can get the correct
// symbol section index for _DYNAMIC. Now it will be ABS.
f_pDynamic = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"_DYNAMIC",
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Local,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Hidden);
// ----- segment symbols ----- //
f_pExecutableStart =
pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"__executable_start",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_pEText = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"etext",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_p_EText = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"_etext",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_p__EText = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"__etext",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_pEData = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"edata",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_pEnd = pBuilder.AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
"end",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
// _edata is defined forcefully.
f_p_EData = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
"_edata",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
// __bss_start is defined forcefully.
f_pBSSStart = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
"__bss_start",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
// _end is defined forcefully.
f_p_End = pBuilder.AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
"_end",
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
return true;
}
bool GNULDBackend::finalizeStandardSymbols() {
if (LinkerConfig::Object == config().codeGenType())
return true;
ELFFileFormat* file_format = getOutputFormat();
// ----- section symbols ----- //
if (f_pPreInitArrayStart != NULL) {
if (!f_pPreInitArrayStart->hasFragRef()) {
f_pPreInitArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute);
f_pPreInitArrayStart->setValue(0x0);
}
}
if (f_pPreInitArrayEnd != NULL) {
if (f_pPreInitArrayEnd->hasFragRef()) {
f_pPreInitArrayEnd->setValue(f_pPreInitArrayEnd->value() +
file_format->getPreInitArray().size());
} else {
f_pPreInitArrayEnd->resolveInfo()->setBinding(ResolveInfo::Absolute);
f_pPreInitArrayEnd->setValue(0x0);
}
}
if (f_pInitArrayStart != NULL) {
if (!f_pInitArrayStart->hasFragRef()) {
f_pInitArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute);
f_pInitArrayStart->setValue(0x0);
}
}
if (f_pInitArrayEnd != NULL) {
if (f_pInitArrayEnd->hasFragRef()) {
f_pInitArrayEnd->setValue(f_pInitArrayEnd->value() +
file_format->getInitArray().size());
} else {
f_pInitArrayEnd->resolveInfo()->setBinding(ResolveInfo::Absolute);
f_pInitArrayEnd->setValue(0x0);
}
}
if (f_pFiniArrayStart != NULL) {
if (!f_pFiniArrayStart->hasFragRef()) {
f_pFiniArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute);
f_pFiniArrayStart->setValue(0x0);
}
}
if (f_pFiniArrayEnd != NULL) {
if (f_pFiniArrayEnd->hasFragRef()) {
f_pFiniArrayEnd->setValue(f_pFiniArrayEnd->value() +
file_format->getFiniArray().size());
} else {
f_pFiniArrayEnd->resolveInfo()->setBinding(ResolveInfo::Absolute);
f_pFiniArrayEnd->setValue(0x0);
}
}
if (f_pStack != NULL) {
if (!f_pStack->hasFragRef()) {
f_pStack->resolveInfo()->setBinding(ResolveInfo::Absolute);
f_pStack->setValue(0x0);
}
}
if (f_pDynamic != NULL) {
f_pDynamic->resolveInfo()->setBinding(ResolveInfo::Local);
f_pDynamic->setValue(file_format->getDynamic().addr());
f_pDynamic->setSize(file_format->getDynamic().size());
}
// ----- segment symbols ----- //
if (f_pExecutableStart != NULL) {
ELFSegmentFactory::const_iterator exec_start =
elfSegmentTable().find(llvm::ELF::PT_LOAD, 0x0, 0x0);
if (elfSegmentTable().end() != exec_start) {
if (ResolveInfo::ThreadLocal != f_pExecutableStart->type()) {
f_pExecutableStart->setValue(f_pExecutableStart->value() +
(*exec_start)->vaddr());
}
} else {
f_pExecutableStart->setValue(0x0);
}
}
if (f_pEText != NULL || f_p_EText != NULL || f_p__EText != NULL) {
ELFSegmentFactory::const_iterator etext = elfSegmentTable().find(
llvm::ELF::PT_LOAD, llvm::ELF::PF_X, llvm::ELF::PF_W);
if (elfSegmentTable().end() != etext) {
if (f_pEText != NULL && ResolveInfo::ThreadLocal != f_pEText->type()) {
f_pEText->setValue(f_pEText->value() + (*etext)->vaddr() +
(*etext)->memsz());
}
if (f_p_EText != NULL && ResolveInfo::ThreadLocal != f_p_EText->type()) {
f_p_EText->setValue(f_p_EText->value() + (*etext)->vaddr() +
(*etext)->memsz());
}
if (f_p__EText != NULL &&
ResolveInfo::ThreadLocal != f_p__EText->type()) {
f_p__EText->setValue(f_p__EText->value() + (*etext)->vaddr() +
(*etext)->memsz());
}
} else {
if (f_pEText != NULL)
f_pEText->setValue(0x0);
if (f_p_EText != NULL)
f_p_EText->setValue(0x0);
if (f_p__EText != NULL)
f_p__EText->setValue(0x0);
}
}
if (f_pEData != NULL || f_p_EData != NULL || f_pBSSStart != NULL ||
f_pEnd != NULL || f_p_End != NULL) {
ELFSegmentFactory::const_iterator edata =
elfSegmentTable().find(llvm::ELF::PT_LOAD, llvm::ELF::PF_W, 0x0);
if (elfSegmentTable().end() != edata) {
if (f_pEData != NULL && ResolveInfo::ThreadLocal != f_pEData->type()) {
f_pEData->setValue(f_pEData->value() + (*edata)->vaddr() +
(*edata)->filesz());
}
if (f_p_EData != NULL && ResolveInfo::ThreadLocal != f_p_EData->type()) {
f_p_EData->setValue(f_p_EData->value() + (*edata)->vaddr() +
(*edata)->filesz());
}
if (f_pBSSStart != NULL &&
ResolveInfo::ThreadLocal != f_pBSSStart->type()) {
f_pBSSStart->setValue(f_pBSSStart->value() + (*edata)->vaddr() +
(*edata)->filesz());
}
if (f_pEnd != NULL && ResolveInfo::ThreadLocal != f_pEnd->type()) {
f_pEnd->setValue(f_pEnd->value() + (*edata)->vaddr() +
(*edata)->memsz());
}
if (f_p_End != NULL && ResolveInfo::ThreadLocal != f_p_End->type()) {
f_p_End->setValue(f_p_End->value() + (*edata)->vaddr() +
(*edata)->memsz());
}
} else {
if (f_pEData != NULL)
f_pEData->setValue(0x0);
if (f_p_EData != NULL)
f_p_EData->setValue(0x0);
if (f_pBSSStart != NULL)
f_pBSSStart->setValue(0x0);
if (f_pEnd != NULL)
f_pEnd->setValue(0x0);
if (f_p_End != NULL)
f_p_End->setValue(0x0);
}
}
return true;
}
bool GNULDBackend::finalizeTLSSymbol(LDSymbol& pSymbol) {
// ignore if symbol has no fragRef
if (!pSymbol.hasFragRef())
return true;
// the value of a TLS symbol is the offset to the TLS segment
ELFSegmentFactory::iterator tls_seg =
elfSegmentTable().find(llvm::ELF::PT_TLS, llvm::ELF::PF_R, 0x0);
assert(tls_seg != elfSegmentTable().end());
uint64_t value = pSymbol.fragRef()->getOutputOffset();
uint64_t addr = pSymbol.fragRef()->frag()->getParent()->getSection().addr();
pSymbol.setValue(value + addr - (*tls_seg)->vaddr());
return true;
}
ELFFileFormat* GNULDBackend::getOutputFormat() {
switch (config().codeGenType()) {
case LinkerConfig::DynObj:
assert(m_pDynObjFileFormat != NULL);
return m_pDynObjFileFormat;
case LinkerConfig::Exec:
case LinkerConfig::Binary:
assert(m_pExecFileFormat != NULL);
return m_pExecFileFormat;
case LinkerConfig::Object:
assert(m_pObjectFileFormat != NULL);
return m_pObjectFileFormat;
default:
fatal(diag::unrecognized_output_file) << config().codeGenType();
return NULL;
}
}
const ELFFileFormat* GNULDBackend::getOutputFormat() const {
switch (config().codeGenType()) {
case LinkerConfig::DynObj:
assert(m_pDynObjFileFormat != NULL);
return m_pDynObjFileFormat;
case LinkerConfig::Exec:
case LinkerConfig::Binary:
assert(m_pExecFileFormat != NULL);
return m_pExecFileFormat;
case LinkerConfig::Object:
assert(m_pObjectFileFormat != NULL);
return m_pObjectFileFormat;
default:
fatal(diag::unrecognized_output_file) << config().codeGenType();
return NULL;
}
}
/// sizeShstrtab - compute the size of .shstrtab
void GNULDBackend::sizeShstrtab(Module& pModule) {
size_t shstrtab = 0;
// compute the size of .shstrtab section.
Module::const_iterator sect, sectEnd = pModule.end();
for (sect = pModule.begin(); sect != sectEnd; ++sect) {
shstrtab += (*sect)->name().size() + 1;
} // end of for
getOutputFormat()->getShStrTab().setSize(shstrtab);
}
/// sizeNamePools - compute the size of regular name pools
/// In ELF executable files, regular name pools are .symtab, .strtab,
/// .dynsym, .dynstr, .hash and .shstrtab.
void GNULDBackend::sizeNamePools(Module& pModule) {
assert(LinkerConfig::Unset != config().codePosition());
// number of entries in symbol tables starts from 1 to hold the special entry
// at index 0 (STN_UNDEF). See ELF Spec Book I, p1-21.
size_t symtab = 1;
size_t dynsym = config().isCodeStatic() ? 0 : 1;
// size of string tables starts from 1 to hold the null character in their
// first byte
size_t strtab = 1;
size_t dynstr = config().isCodeStatic() ? 0 : 1;
size_t hash = 0;
size_t gnuhash = 0;
// number of local symbol in the .symtab and .dynsym
size_t symtab_local_cnt = 0;
size_t dynsym_local_cnt = 0;
Module::SymbolTable& symbols = pModule.getSymbolTable();
Module::const_sym_iterator symbol, symEnd;
/// Compute the size of .symtab, .strtab, and symtab_local_cnt
/// @{
/* TODO:
1. discard locals and temporary locals
2. check whether the symbol is used
*/
switch (config().options().getStripSymbolMode()) {
case GeneralOptions::StripSymbolMode::StripAllSymbols: {
symtab = strtab = 0;
break;
}
default: {
symEnd = symbols.end();
for (symbol = symbols.begin(); symbol != symEnd; ++symbol) {
++symtab;
if (hasEntryInStrTab(**symbol))
strtab += (*symbol)->nameSize() + 1;
}
symtab_local_cnt = 1 + symbols.numOfFiles() + symbols.numOfLocals() +
symbols.numOfLocalDyns();
break;
}
} // end of switch
ELFFileFormat* file_format = getOutputFormat();
switch (config().codeGenType()) {
case LinkerConfig::DynObj: {
// soname
dynstr += config().options().soname().size() + 1;
}
/** fall through **/
case LinkerConfig::Exec:
case LinkerConfig::Binary: {
if (!config().isCodeStatic()) {
/// Compute the size of .dynsym, .dynstr, and dynsym_local_cnt
symEnd = symbols.dynamicEnd();
for (symbol = symbols.localDynBegin(); symbol != symEnd; ++symbol) {
++dynsym;
if (hasEntryInStrTab(**symbol))
dynstr += (*symbol)->nameSize() + 1;
}
dynsym_local_cnt = 1 + symbols.numOfLocalDyns();
// compute .gnu.hash
if (config().options().hasGNUHash()) {
// count the number of dynsym to hash
size_t hashed_sym_cnt = 0;
symEnd = symbols.dynamicEnd();
for (symbol = symbols.dynamicBegin(); symbol != symEnd; ++symbol) {
if (DynsymCompare().needGNUHash(**symbol))
++hashed_sym_cnt;
}
// Special case for empty .dynsym
if (hashed_sym_cnt == 0)
gnuhash = 5 * 4 + config().targets().bitclass() / 8;
else {
size_t nbucket = getHashBucketCount(hashed_sym_cnt, true);
gnuhash = (4 + nbucket + hashed_sym_cnt) * 4;
gnuhash += (1U << getGNUHashMaskbitslog2(hashed_sym_cnt)) / 8;
}
}
// compute .hash
if (config().options().hasSysVHash()) {
// Both Elf32_Word and Elf64_Word are 4 bytes
hash = (2 + getHashBucketCount(dynsym, false) + dynsym) *
sizeof(llvm::ELF::Elf32_Word);
}
// add DT_NEEDED
Module::const_lib_iterator lib, libEnd = pModule.lib_end();
for (lib = pModule.lib_begin(); lib != libEnd; ++lib) {
if (!(*lib)->attribute()->isAsNeeded() || (*lib)->isNeeded()) {
dynstr += (*lib)->name().size() + 1;
dynamic().reserveNeedEntry();
}
}
// add DT_RPATH
if (!config().options().getRpathList().empty()) {
dynamic().reserveNeedEntry();
GeneralOptions::const_rpath_iterator rpath,
rpathEnd = config().options().rpath_end();
for (rpath = config().options().rpath_begin(); rpath != rpathEnd;
++rpath)
dynstr += (*rpath).size() + 1;
}
// set size
if (config().targets().is32Bits()) {
file_format->getDynSymTab().setSize(dynsym *
sizeof(llvm::ELF::Elf32_Sym));
} else {
file_format->getDynSymTab().setSize(dynsym *
sizeof(llvm::ELF::Elf64_Sym));
}
file_format->getDynStrTab().setSize(dynstr);
file_format->getHashTab().setSize(hash);
file_format->getGNUHashTab().setSize(gnuhash);
// set .dynsym sh_info to one greater than the symbol table
// index of the last local symbol
file_format->getDynSymTab().setInfo(dynsym_local_cnt);
// Because some entries in .dynamic section need information of .dynsym,
// .dynstr, .symtab, .strtab and .hash, we can not reserve non-DT_NEEDED
// entries until we get the size of the sections mentioned above
dynamic().reserveEntries(*file_format);
file_format->getDynamic().setSize(dynamic().numOfBytes());
}
}
/* fall through */
case LinkerConfig::Object: {
if (config().targets().is32Bits())
file_format->getSymTab().setSize(symtab * sizeof(llvm::ELF::Elf32_Sym));
else
file_format->getSymTab().setSize(symtab * sizeof(llvm::ELF::Elf64_Sym));
file_format->getStrTab().setSize(strtab);
// set .symtab sh_info to one greater than the symbol table
// index of the last local symbol
file_format->getSymTab().setInfo(symtab_local_cnt);
// The size of .shstrtab should be decided after output sections are all
// set, so we just set it to 1 here.
file_format->getShStrTab().setSize(0x1);
break;
}
default:
fatal(diag::fatal_illegal_codegen_type) << pModule.name();
break;
} // end of switch
}
/// emitSymbol32 - emit an ELF32 symbol
void GNULDBackend::emitSymbol32(llvm::ELF::Elf32_Sym& pSym,
LDSymbol& pSymbol,
char* pStrtab,
size_t pStrtabsize,
size_t pSymtabIdx) {
// FIXME: check the endian between host and target
// write out symbol
if (hasEntryInStrTab(pSymbol)) {
pSym.st_name = pStrtabsize;
::memcpy((pStrtab + pStrtabsize), pSymbol.name(), pSymbol.nameSize());
} else {
pSym.st_name = 0;
}
pSym.st_value = pSymbol.value();
pSym.st_size = getSymbolSize(pSymbol);
pSym.st_info = getSymbolInfo(pSymbol);
pSym.st_other = pSymbol.visibility();
pSym.st_shndx = getSymbolShndx(pSymbol);
}
/// emitSymbol64 - emit an ELF64 symbol
void GNULDBackend::emitSymbol64(llvm::ELF::Elf64_Sym& pSym,
LDSymbol& pSymbol,
char* pStrtab,
size_t pStrtabsize,
size_t pSymtabIdx) {
// FIXME: check the endian between host and target
// write out symbol
if (hasEntryInStrTab(pSymbol)) {
pSym.st_name = pStrtabsize;
::memcpy((pStrtab + pStrtabsize), pSymbol.name(), pSymbol.nameSize());
} else {
pSym.st_name = 0;
}
pSym.st_value = pSymbol.value();
pSym.st_size = getSymbolSize(pSymbol);
pSym.st_info = getSymbolInfo(pSymbol);
pSym.st_other = pSymbol.visibility();
pSym.st_shndx = getSymbolShndx(pSymbol);
}
/// emitRegNamePools - emit regular name pools - .symtab, .strtab
///
/// the size of these tables should be computed before layout
/// layout should computes the start offset of these tables
void GNULDBackend::emitRegNamePools(const Module& pModule,
FileOutputBuffer& pOutput) {
ELFFileFormat* file_format = getOutputFormat();
if (!file_format->hasSymTab())
return;
LDSection& symtab_sect = file_format->getSymTab();
LDSection& strtab_sect = file_format->getStrTab();
MemoryRegion symtab_region =
pOutput.request(symtab_sect.offset(), symtab_sect.size());
MemoryRegion strtab_region =
pOutput.request(strtab_sect.offset(), strtab_sect.size());
// set up symtab_region
llvm::ELF::Elf32_Sym* symtab32 = NULL;
llvm::ELF::Elf64_Sym* symtab64 = NULL;
if (config().targets().is32Bits())
symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region.begin();
else if (config().targets().is64Bits())
symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region.begin();
else {
fatal(diag::unsupported_bitclass) << config().targets().triple().str()
<< config().targets().bitclass();
}
// set up strtab_region
char* strtab = reinterpret_cast<char*>(strtab_region.begin());
// emit the first ELF symbol
if (config().targets().is32Bits())
emitSymbol32(symtab32[0], *LDSymbol::Null(), strtab, 0, 0);
else
emitSymbol64(symtab64[0], *LDSymbol::Null(), strtab, 0, 0);
bool sym_exist = false;
HashTableType::entry_type* entry = NULL;
if (LinkerConfig::Object == config().codeGenType()) {
entry = m_pSymIndexMap->insert(LDSymbol::Null(), sym_exist);
entry->setValue(0);
}
size_t symIdx = 1;
size_t strtabsize = 1;
const Module::SymbolTable& symbols = pModule.getSymbolTable();
Module::const_sym_iterator symbol, symEnd;
symEnd = symbols.end();
for (symbol = symbols.begin(); symbol != symEnd; ++symbol) {
if (LinkerConfig::Object == config().codeGenType()) {
entry = m_pSymIndexMap->insert(*symbol, sym_exist);
entry->setValue(symIdx);
}
if (config().targets().is32Bits())
emitSymbol32(symtab32[symIdx], **symbol, strtab, strtabsize, symIdx);
else
emitSymbol64(symtab64[symIdx], **symbol, strtab, strtabsize, symIdx);
++symIdx;
if (hasEntryInStrTab(**symbol))
strtabsize += (*symbol)->nameSize() + 1;
}
}
/// emitDynNamePools - emit dynamic name pools - .dyntab, .dynstr, .hash
///
/// the size of these tables should be computed before layout
/// layout should computes the start offset of these tables
void GNULDBackend::emitDynNamePools(Module& pModule,
FileOutputBuffer& pOutput) {
ELFFileFormat* file_format = getOutputFormat();
if (!file_format->hasDynSymTab() || !file_format->hasDynStrTab() ||
!file_format->hasDynamic())
return;
bool sym_exist = false;
HashTableType::entry_type* entry = 0;
LDSection& symtab_sect = file_format->getDynSymTab();
LDSection& strtab_sect = file_format->getDynStrTab();
LDSection& dyn_sect = file_format->getDynamic();
MemoryRegion symtab_region =
pOutput.request(symtab_sect.offset(), symtab_sect.size());
MemoryRegion strtab_region =
pOutput.request(strtab_sect.offset(), strtab_sect.size());
MemoryRegion dyn_region = pOutput.request(dyn_sect.offset(), dyn_sect.size());
// set up symtab_region
llvm::ELF::Elf32_Sym* symtab32 = NULL;
llvm::ELF::Elf64_Sym* symtab64 = NULL;
if (config().targets().is32Bits())
symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region.begin();
else if (config().targets().is64Bits())
symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region.begin();
else {
fatal(diag::unsupported_bitclass) << config().targets().triple().str()
<< config().targets().bitclass();
}
// set up strtab_region
char* strtab = reinterpret_cast<char*>(strtab_region.begin());
// emit the first ELF symbol
if (config().targets().is32Bits())
emitSymbol32(symtab32[0], *LDSymbol::Null(), strtab, 0, 0);
else
emitSymbol64(symtab64[0], *LDSymbol::Null(), strtab, 0, 0);
size_t symIdx = 1;
size_t strtabsize = 1;
Module::SymbolTable& symbols = pModule.getSymbolTable();
// emit .gnu.hash
if (config().options().hasGNUHash())
emitGNUHashTab(symbols, pOutput);
// emit .hash
if (config().options().hasSysVHash())
emitELFHashTab(symbols, pOutput);
// emit .dynsym, and .dynstr (emit LocalDyn and Dynamic category)
Module::const_sym_iterator symbol, symEnd = symbols.dynamicEnd();
for (symbol = symbols.localDynBegin(); symbol != symEnd; ++symbol) {
if (config().targets().is32Bits())
emitSymbol32(symtab32[symIdx], **symbol, strtab, strtabsize, symIdx);
else
emitSymbol64(symtab64[symIdx], **symbol, strtab, strtabsize, symIdx);
// maintain output's symbol and index map
entry = m_pSymIndexMap->insert(*symbol, sym_exist);
entry->setValue(symIdx);
// sum up counters
++symIdx;
if (hasEntryInStrTab(**symbol))
strtabsize += (*symbol)->nameSize() + 1;
}
// emit DT_NEED
// add DT_NEED strings into .dynstr
ELFDynamic::iterator dt_need = dynamic().needBegin();
Module::const_lib_iterator lib, libEnd = pModule.lib_end();
for (lib = pModule.lib_begin(); lib != libEnd; ++lib) {
if (!(*lib)->attribute()->isAsNeeded() || (*lib)->isNeeded()) {
::memcpy((strtab + strtabsize),
(*lib)->name().c_str(),
(*lib)->name().size());
(*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
strtabsize += (*lib)->name().size() + 1;
++dt_need;
}
}
if (!config().options().getRpathList().empty()) {
if (!config().options().hasNewDTags())
(*dt_need)->setValue(llvm::ELF::DT_RPATH, strtabsize);
else
(*dt_need)->setValue(llvm::ELF::DT_RUNPATH, strtabsize);
++dt_need;
GeneralOptions::const_rpath_iterator rpath,
rpathEnd = config().options().rpath_end();
for (rpath = config().options().rpath_begin(); rpath != rpathEnd; ++rpath) {
memcpy((strtab + strtabsize), (*rpath).data(), (*rpath).size());
strtabsize += (*rpath).size();
strtab[strtabsize++] = (rpath + 1 == rpathEnd ? '\0' : ':');
}
}
// initialize value of ELF .dynamic section
if (LinkerConfig::DynObj == config().codeGenType()) {
// set pointer to SONAME entry in dynamic string table.
dynamic().applySoname(strtabsize);
}
dynamic().applyEntries(*file_format);
dynamic().emit(dyn_sect, dyn_region);
// emit soname
if (LinkerConfig::DynObj == config().codeGenType()) {
::memcpy((strtab + strtabsize),
config().options().soname().c_str(),
config().options().soname().size());
strtabsize += config().options().soname().size() + 1;
}
}
/// emitELFHashTab - emit .hash
void GNULDBackend::emitELFHashTab(const Module::SymbolTable& pSymtab,
FileOutputBuffer& pOutput) {
ELFFileFormat* file_format = getOutputFormat();
if (!file_format->hasHashTab())
return;
LDSection& hash_sect = file_format->getHashTab();
MemoryRegion hash_region =
pOutput.request(hash_sect.offset(), hash_sect.size());
// both 32 and 64 bits hash table use 32-bit entry
// set up hash_region
uint32_t* word_array = reinterpret_cast<uint32_t*>(hash_region.begin());
uint32_t& nbucket = word_array[0];
uint32_t& nchain = word_array[1];
size_t dynsymSize = 1 + pSymtab.numOfLocalDyns() + pSymtab.numOfDynamics();
nbucket = getHashBucketCount(dynsymSize, false);
nchain = dynsymSize;
uint32_t* bucket = (word_array + 2);
uint32_t* chain = (bucket + nbucket);
// initialize bucket
memset(reinterpret_cast<void*>(bucket), 0, nbucket);
hash::StringHash<hash::ELF> hash_func;
size_t idx = 1;
Module::const_sym_iterator symbol, symEnd = pSymtab.dynamicEnd();
for (symbol = pSymtab.localDynBegin(); symbol != symEnd; ++symbol) {
llvm::StringRef name((*symbol)->name());
size_t bucket_pos = hash_func(name) % nbucket;
chain[idx] = bucket[bucket_pos];
bucket[bucket_pos] = idx;
++idx;
}
}
/// emitGNUHashTab - emit .gnu.hash
void GNULDBackend::emitGNUHashTab(Module::SymbolTable& pSymtab,
FileOutputBuffer& pOutput) {
ELFFileFormat* file_format = getOutputFormat();
if (!file_format->hasGNUHashTab())
return;
MemoryRegion gnuhash_region =
pOutput.request(file_format->getGNUHashTab().offset(),
file_format->getGNUHashTab().size());
uint32_t* word_array = reinterpret_cast<uint32_t*>(gnuhash_region.begin());
// fixed-length fields
uint32_t& nbucket = word_array[0];
uint32_t& symidx = word_array[1];
uint32_t& maskwords = word_array[2];
uint32_t& shift2 = word_array[3];
// variable-length fields
uint8_t* bitmask = reinterpret_cast<uint8_t*>(word_array + 4);
uint32_t* bucket = NULL;
uint32_t* chain = NULL;
// count the number of dynsym to hash
size_t unhashed_sym_cnt = pSymtab.numOfLocalDyns();
size_t hashed_sym_cnt = pSymtab.numOfDynamics();
Module::const_sym_iterator symbol, symEnd = pSymtab.dynamicEnd();
for (symbol = pSymtab.dynamicBegin(); symbol != symEnd; ++symbol) {
if (DynsymCompare().needGNUHash(**symbol))
break;
++unhashed_sym_cnt;
--hashed_sym_cnt;
}
// special case for the empty hash table
if (hashed_sym_cnt == 0) {
nbucket = 1; // one empty bucket
symidx = 1 + unhashed_sym_cnt; // symidx above unhashed symbols
maskwords = 1; // bitmask length
shift2 = 0; // bloom filter
if (config().targets().is32Bits()) {
uint32_t* maskval = reinterpret_cast<uint32_t*>(bitmask);
*maskval = 0; // no valid hashes
} else {
// must be 64
uint64_t* maskval = reinterpret_cast<uint64_t*>(bitmask);
*maskval = 0; // no valid hashes
}
bucket = reinterpret_cast<uint32_t*>(bitmask +
config().targets().bitclass() / 8);
*bucket = 0; // no hash in the only bucket
return;
}
uint32_t maskbitslog2 = getGNUHashMaskbitslog2(hashed_sym_cnt);
uint32_t maskbits = 1u << maskbitslog2;
uint32_t shift1 = config().targets().is32Bits() ? 5 : 6;
uint32_t mask = (1u << shift1) - 1;
nbucket = getHashBucketCount(hashed_sym_cnt, true);
symidx = 1 + unhashed_sym_cnt;
maskwords = 1 << (maskbitslog2 - shift1);
shift2 = maskbitslog2;
// setup bucket and chain
bucket = reinterpret_cast<uint32_t*>(bitmask + maskbits / 8);
chain = (bucket + nbucket);
// build the gnu style hash table
typedef std::multimap<uint32_t, std::pair<LDSymbol*, uint32_t> > SymMapType;
SymMapType symmap;
symEnd = pSymtab.dynamicEnd();
for (symbol = pSymtab.localDynBegin() + symidx - 1; symbol != symEnd;
++symbol) {
hash::StringHash<hash::DJB> hasher;
uint32_t djbhash = hasher((*symbol)->name());
uint32_t hash = djbhash % nbucket;
symmap.insert(std::make_pair(hash, std::make_pair(*symbol, djbhash)));
}
// compute bucket, chain, and bitmask
std::vector<uint64_t> bitmasks(maskwords);
size_t hashedidx = symidx;
for (size_t idx = 0; idx < nbucket; ++idx) {
size_t count = 0;
std::pair<SymMapType::iterator, SymMapType::iterator> ret;
ret = symmap.equal_range(idx);
for (SymMapType::iterator it = ret.first; it != ret.second;) {
// rearrange the hashed symbol ordering
*(pSymtab.localDynBegin() + hashedidx - 1) = it->second.first;
uint32_t djbhash = it->second.second;
uint32_t val = ((djbhash >> shift1) & ((maskbits >> shift1) - 1));
bitmasks[val] |= 1u << (djbhash & mask);
bitmasks[val] |= 1u << ((djbhash >> shift2) & mask);
val = djbhash & ~1u;
// advance the iterator and check if we're dealing w/ the last elment
if (++it == ret.second) {
// last element terminates the chain
val |= 1;
}
chain[hashedidx - symidx] = val;
++hashedidx;
++count;
}
if (count == 0)
bucket[idx] = 0;
else
bucket[idx] = hashedidx - count;
}
// write the bitmasks
if (config().targets().is32Bits()) {
uint32_t* maskval = reinterpret_cast<uint32_t*>(bitmask);
for (size_t i = 0; i < maskwords; ++i)
std::memcpy(maskval + i, &bitmasks[i], 4);
} else {
// must be 64
uint64_t* maskval = reinterpret_cast<uint64_t*>(bitmask);
for (size_t i = 0; i < maskwords; ++i)
std::memcpy(maskval + i, &bitmasks[i], 8);
}
}
/// sizeInterp - compute the size of the .interp section
void GNULDBackend::sizeInterp() {
const char* dyld_name;
if (config().options().hasDyld())
dyld_name = config().options().dyld().c_str();
else
dyld_name = m_pInfo->dyld();
LDSection& interp = getOutputFormat()->getInterp();
interp.setSize(std::strlen(dyld_name) + 1);
}
/// emitInterp - emit the .interp
void GNULDBackend::emitInterp(FileOutputBuffer& pOutput) {
if (getOutputFormat()->hasInterp()) {
const LDSection& interp = getOutputFormat()->getInterp();
MemoryRegion region = pOutput.request(interp.offset(), interp.size());
const char* dyld_name;
if (config().options().hasDyld())
dyld_name = config().options().dyld().c_str();
else
dyld_name = m_pInfo->dyld();
std::memcpy(region.begin(), dyld_name, interp.size());
}
}
bool GNULDBackend::hasEntryInStrTab(const LDSymbol& pSym) const {
return ResolveInfo::Section != pSym.type();
}
void GNULDBackend::orderSymbolTable(Module& pModule) {
Module::SymbolTable& symbols = pModule.getSymbolTable();
if (config().options().hasGNUHash()) {
// Currently we may add output symbols after sizeNamePools(), and a
// non-stable sort is used in SymbolCategory::arrange(), so we just
// sort .dynsym right before emitting .gnu.hash
std::stable_sort(
symbols.dynamicBegin(), symbols.dynamicEnd(), DynsymCompare());
}
}
/// getSectionOrder
unsigned int GNULDBackend::getSectionOrder(const LDSection& pSectHdr) const {
const ELFFileFormat* file_format = getOutputFormat();
// NULL section should be the "1st" section
if (LDFileFormat::Null == pSectHdr.kind())
return SHO_NULL;
if (&pSectHdr == &file_format->getStrTab())
return SHO_STRTAB;
// if the section is not ALLOC, lay it out until the last possible moment
if (0 == (pSectHdr.flag() & llvm::ELF::SHF_ALLOC))
return SHO_UNDEFINED;
bool is_write = (pSectHdr.flag() & llvm::ELF::SHF_WRITE) != 0;
bool is_exec = (pSectHdr.flag() & llvm::ELF::SHF_EXECINSTR) != 0;
// TODO: need to take care other possible output sections
switch (pSectHdr.kind()) {
case LDFileFormat::TEXT:
case LDFileFormat::DATA:
if (is_exec) {
if (&pSectHdr == &file_format->getInit())
return SHO_INIT;
if (&pSectHdr == &file_format->getFini())
return SHO_FINI;
return SHO_TEXT;
} else if (!is_write) {
return SHO_RO;
} else {
if (config().options().hasRelro()) {
if (&pSectHdr == &file_format->getPreInitArray() ||
&pSectHdr == &file_format->getInitArray() ||
&pSectHdr == &file_format->getFiniArray() ||
&pSectHdr == &file_format->getCtors() ||
&pSectHdr == &file_format->getDtors() ||
&pSectHdr == &file_format->getJCR() ||
&pSectHdr == &file_format->getDataRelRo())
return SHO_RELRO;
if (&pSectHdr == &file_format->getDataRelRoLocal())
return SHO_RELRO_LOCAL;
// Make special sections that end with .rel.ro suffix as RELRO.
llvm::StringRef name(pSectHdr.name());
if (name.endswith(".rel.ro")) {
return SHO_RELRO;
}
}
if ((pSectHdr.flag() & llvm::ELF::SHF_TLS) != 0x0) {
return SHO_TLS_DATA;
}
return SHO_DATA;
}
case LDFileFormat::BSS:
if ((pSectHdr.flag() & llvm::ELF::SHF_TLS) != 0x0)
return SHO_TLS_BSS;
return SHO_BSS;
case LDFileFormat::NamePool: {
if (&pSectHdr == &file_format->getDynamic())
return SHO_RELRO;
return SHO_NAMEPOOL;
}
case LDFileFormat::Relocation:
if (&pSectHdr == &file_format->getRelPlt() ||
&pSectHdr == &file_format->getRelaPlt())
return SHO_REL_PLT;
return SHO_RELOCATION;
// get the order from target for target specific sections
case LDFileFormat::Target:
return getTargetSectionOrder(pSectHdr);
// handle .interp and .note.* sections
case LDFileFormat::Note:
if (file_format->hasInterp() && (&pSectHdr == &file_format->getInterp()))
return SHO_INTERP;
else if (is_write)
return SHO_RW_NOTE;
else
return SHO_RO_NOTE;
case LDFileFormat::EhFrame:
// set writable .eh_frame as relro
if (is_write)
return SHO_RELRO;
case LDFileFormat::EhFrameHdr:
case LDFileFormat::GCCExceptTable:
return SHO_EXCEPTION;
case LDFileFormat::MetaData:
case LDFileFormat::Debug:
case LDFileFormat::DebugString:
default:
return SHO_UNDEFINED;
}
}
/// getSymbolSize
uint64_t GNULDBackend::getSymbolSize(const LDSymbol& pSymbol) const {
// undefined and dynamic symbols should have zero size.
if (pSymbol.isDyn() || pSymbol.desc() == ResolveInfo::Undefined)
return 0x0;
return pSymbol.resolveInfo()->size();
}
/// getSymbolInfo
uint64_t GNULDBackend::getSymbolInfo(const LDSymbol& pSymbol) const {
// set binding
uint8_t bind = 0x0;
if (pSymbol.resolveInfo()->isLocal())
bind = llvm::ELF::STB_LOCAL;
else if (pSymbol.resolveInfo()->isGlobal())
bind = llvm::ELF::STB_GLOBAL;
else if (pSymbol.resolveInfo()->isWeak())
bind = llvm::ELF::STB_WEAK;
else if (pSymbol.resolveInfo()->isAbsolute()) {
// (Luba) Is a absolute but not global (weak or local) symbol meaningful?
bind = llvm::ELF::STB_GLOBAL;
}
if (config().codeGenType() != LinkerConfig::Object &&
(pSymbol.visibility() == llvm::ELF::STV_INTERNAL ||
pSymbol.visibility() == llvm::ELF::STV_HIDDEN))
bind = llvm::ELF::STB_LOCAL;
uint32_t type = pSymbol.resolveInfo()->type();
// if the IndirectFunc symbol (i.e., STT_GNU_IFUNC) is from dynobj, change
// its type to Function
if (type == ResolveInfo::IndirectFunc && pSymbol.isDyn())
type = ResolveInfo::Function;
return (type | (bind << 4));
}
/// getSymbolValue - this function is called after layout()
uint64_t GNULDBackend::getSymbolValue(const LDSymbol& pSymbol) const {
if (pSymbol.isDyn())
return 0x0;
return pSymbol.value();
}
/// getSymbolShndx - this function is called after layout()
uint64_t GNULDBackend::getSymbolShndx(const LDSymbol& pSymbol) const {
if (pSymbol.resolveInfo()->isAbsolute())
return llvm::ELF::SHN_ABS;
if (pSymbol.resolveInfo()->isCommon())
return llvm::ELF::SHN_COMMON;
if (pSymbol.resolveInfo()->isUndef() || pSymbol.isDyn())
return llvm::ELF::SHN_UNDEF;
if (pSymbol.resolveInfo()->isDefine() && !pSymbol.hasFragRef())
return llvm::ELF::SHN_ABS;
assert(pSymbol.hasFragRef() &&
"symbols must have fragment reference to get its index");
return pSymbol.fragRef()->frag()->getParent()->getSection().index();
}
/// getSymbolIdx - called by emitRelocation to get the ouput symbol table index
size_t GNULDBackend::getSymbolIdx(const LDSymbol* pSymbol) const {
HashTableType::iterator entry =
m_pSymIndexMap->find(const_cast<LDSymbol*>(pSymbol));
assert(entry != m_pSymIndexMap->end() &&
"symbol not found in the symbol table");
return entry.getEntry()->value();
}
/// isTemporary - Whether pSymbol is a local label.
bool GNULDBackend::isTemporary(const LDSymbol& pSymbol) const {
if (ResolveInfo::Local != pSymbol.binding())
return false;
if (pSymbol.nameSize() < 2)
return false;
const char* name = pSymbol.name();
if ('.' == name[0] && 'L' == name[1])
return true;
// UnixWare 2.1 cc generate DWARF debugging symbols with `..' prefix.
if (name[0] == '.' && name[1] == '.')
return true;
// Work arround for gcc's bug
// gcc sometimes generate symbols with '_.L_' prefix.
if (pSymbol.nameSize() < 4)
return false;
if (name[0] == '_' && name[1] == '.' && name[2] == 'L' && name[3] == '_')
return true;
return false;
}
/// allocateCommonSymbols - allocate common symbols in the corresponding
/// sections. This is executed at pre-layout stage.
bool GNULDBackend::allocateCommonSymbols(Module& pModule) {
SymbolCategory& symbol_list = pModule.getSymbolTable();
if (symbol_list.emptyCommons() && symbol_list.emptyFiles() &&
symbol_list.emptyLocals() && symbol_list.emptyLocalDyns())
return true;
SymbolCategory::iterator com_sym, com_end;
// FIXME: If the order of common symbols is defined, then sort common symbols
// std::sort(com_sym, com_end, some kind of order);
// get corresponding BSS LDSection
ELFFileFormat* file_format = getOutputFormat();
LDSection& bss_sect = file_format->getBSS();
LDSection& tbss_sect = file_format->getTBSS();
// get or create corresponding BSS SectionData
SectionData* bss_sect_data = NULL;
if (bss_sect.hasSectionData())
bss_sect_data = bss_sect.getSectionData();
else
bss_sect_data = IRBuilder::CreateSectionData(bss_sect);
SectionData* tbss_sect_data = NULL;
if (tbss_sect.hasSectionData())
tbss_sect_data = tbss_sect.getSectionData();
else
tbss_sect_data = IRBuilder::CreateSectionData(tbss_sect);
// remember original BSS size
uint64_t bss_offset = bss_sect.size();
uint64_t tbss_offset = tbss_sect.size();
// allocate all local common symbols
com_end = symbol_list.localEnd();
for (com_sym = symbol_list.localBegin(); com_sym != com_end; ++com_sym) {
if (ResolveInfo::Common == (*com_sym)->desc()) {
// We have to reset the description of the symbol here. When doing
// incremental linking, the output relocatable object may have common
// symbols. Therefore, we can not treat common symbols as normal symbols
// when emitting the regular name pools. We must change the symbols'
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
// allocate TLS common symbol in tbss section
tbss_offset += ObjectBuilder::AppendFragment(
*frag, *tbss_sect_data, (*com_sym)->value());
ObjectBuilder::UpdateSectionAlign(tbss_sect, (*com_sym)->value());
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
} else {
bss_offset += ObjectBuilder::AppendFragment(
*frag, *bss_sect_data, (*com_sym)->value());
ObjectBuilder::UpdateSectionAlign(bss_sect, (*com_sym)->value());
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
}
}
// allocate all global common symbols
com_end = symbol_list.commonEnd();
for (com_sym = symbol_list.commonBegin(); com_sym != com_end; ++com_sym) {
// We have to reset the description of the symbol here. When doing
// incremental linking, the output relocatable object may have common
// symbols. Therefore, we can not treat common symbols as normal symbols
// when emitting the regular name pools. We must change the symbols'
// description here.
(*com_sym)->resolveInfo()->setDesc(ResolveInfo::Define);
Fragment* frag = new FillFragment(0x0, 1, (*com_sym)->size());
if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
// allocate TLS common symbol in tbss section
tbss_offset += ObjectBuilder::AppendFragment(
*frag, *tbss_sect_data, (*com_sym)->value());
ObjectBuilder::UpdateSectionAlign(tbss_sect, (*com_sym)->value());
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
} else {
bss_offset += ObjectBuilder::AppendFragment(
*frag, *bss_sect_data, (*com_sym)->value());
ObjectBuilder::UpdateSectionAlign(bss_sect, (*com_sym)->value());
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
}
}
bss_sect.setSize(bss_offset);
tbss_sect.setSize(tbss_offset);
symbol_list.changeCommonsToGlobal();
return true;
}
/// updateSectionFlags - update pTo's flags when merging pFrom
/// update the output section flags based on input section flags.
bool GNULDBackend::updateSectionFlags(LDSection& pTo, const LDSection& pFrom) {
// union the flags from input
uint32_t flags = pTo.flag();
flags |= (pFrom.flag() & (llvm::ELF::SHF_WRITE | llvm::ELF::SHF_ALLOC |
llvm::ELF::SHF_EXECINSTR));
// if there is an input section is not SHF_MERGE, clean this flag
if (0 == (pFrom.flag() & llvm::ELF::SHF_MERGE))
flags &= ~llvm::ELF::SHF_MERGE;
// if there is an input section is not SHF_STRINGS, clean this flag
if (0 == (pFrom.flag() & llvm::ELF::SHF_STRINGS))
flags &= ~llvm::ELF::SHF_STRINGS;
pTo.setFlag(flags);
return true;
}
/// readRelocation - read ELF32_Rel entry
bool GNULDBackend::readRelocation(const llvm::ELF::Elf32_Rel& pRel,
Relocation::Type& pType,
uint32_t& pSymIdx,
uint32_t& pOffset) const {
uint32_t r_info = 0x0;
if (llvm::sys::IsLittleEndianHost) {
pOffset = pRel.r_offset;
r_info = pRel.r_info;
} else {
pOffset = mcld::bswap32(pRel.r_offset);
r_info = mcld::bswap32(pRel.r_info);
}
pType = static_cast<unsigned char>(r_info);
pSymIdx = (r_info >> 8);
return true;
}
/// readRelocation - read ELF32_Rela entry
bool GNULDBackend::readRelocation(const llvm::ELF::Elf32_Rela& pRel,
Relocation::Type& pType,
uint32_t& pSymIdx,
uint32_t& pOffset,
int32_t& pAddend) const {
uint32_t r_info = 0x0;
if (llvm::sys::IsLittleEndianHost) {
pOffset = pRel.r_offset;
r_info = pRel.r_info;
pAddend = pRel.r_addend;
} else {
pOffset = mcld::bswap32(pRel.r_offset);
r_info = mcld::bswap32(pRel.r_info);
pAddend = mcld::bswap32(pRel.r_addend);
}
pType = static_cast<unsigned char>(r_info);
pSymIdx = (r_info >> 8);
return true;
}
/// readRelocation - read ELF64_Rel entry
bool GNULDBackend::readRelocation(const llvm::ELF::Elf64_Rel& pRel,
Relocation::Type& pType,
uint32_t& pSymIdx,
uint64_t& pOffset) const {
uint64_t r_info = 0x0;
if (llvm::sys::IsLittleEndianHost) {
pOffset = pRel.r_offset;
r_info = pRel.r_info;
} else {
pOffset = mcld::bswap64(pRel.r_offset);
r_info = mcld::bswap64(pRel.r_info);
}
pType = static_cast<uint32_t>(r_info);
pSymIdx = (r_info >> 32);
return true;
}
/// readRel - read ELF64_Rela entry
bool GNULDBackend::readRelocation(const llvm::ELF::Elf64_Rela& pRel,
Relocation::Type& pType,
uint32_t& pSymIdx,
uint64_t& pOffset,
int64_t& pAddend) const {
uint64_t r_info = 0x0;
if (llvm::sys::IsLittleEndianHost) {
pOffset = pRel.r_offset;
r_info = pRel.r_info;
pAddend = pRel.r_addend;
} else {
pOffset = mcld::bswap64(pRel.r_offset);
r_info = mcld::bswap64(pRel.r_info);
pAddend = mcld::bswap64(pRel.r_addend);
}
pType = static_cast<uint32_t>(r_info);
pSymIdx = (r_info >> 32);
return true;
}
/// emitRelocation - write data to the ELF32_Rel entry
void GNULDBackend::emitRelocation(llvm::ELF::Elf32_Rel& pRel,
Relocation::Type pType,
uint32_t pSymIdx,
uint32_t pOffset) const {
pRel.r_offset = pOffset;
pRel.setSymbolAndType(pSymIdx, pType);
}
/// emitRelocation - write data to the ELF32_Rela entry
void GNULDBackend::emitRelocation(llvm::ELF::Elf32_Rela& pRel,
Relocation::Type pType,
uint32_t pSymIdx,
uint32_t pOffset,
int32_t pAddend) const {
pRel.r_offset = pOffset;
pRel.r_addend = pAddend;
pRel.setSymbolAndType(pSymIdx, pType);
}
/// emitRelocation - write data to the ELF64_Rel entry
void GNULDBackend::emitRelocation(llvm::ELF::Elf64_Rel& pRel,
Relocation::Type pType,
uint32_t pSymIdx,
uint64_t pOffset) const {
pRel.r_offset = pOffset;
pRel.setSymbolAndType(pSymIdx, pType);
}
/// emitRelocation - write data to the ELF64_Rela entry
void GNULDBackend::emitRelocation(llvm::ELF::Elf64_Rela& pRel,
Relocation::Type pType,
uint32_t pSymIdx,
uint64_t pOffset,
int64_t pAddend) const {
pRel.r_offset = pOffset;
pRel.r_addend = pAddend;
pRel.setSymbolAndType(pSymIdx, pType);
}
/// createProgramHdrs - base on output sections to create the program headers
void GNULDBackend::createProgramHdrs(Module& pModule) {
ELFFileFormat* file_format = getOutputFormat();
// make PT_INTERP
if (file_format->hasInterp()) {
// make PT_PHDR
elfSegmentTable().produce(llvm::ELF::PT_PHDR);
ELFSegment* interp_seg = elfSegmentTable().produce(llvm::ELF::PT_INTERP);
interp_seg->append(&file_format->getInterp());
}
uint32_t cur_flag, prev_flag = 0x0;
ELFSegment* load_seg = NULL;
// make possible PT_LOAD segments
LinkerScript& ldscript = pModule.getScript();
LinkerScript::AddressMap::iterator addrEnd = ldscript.addressMap().end();
SectionMap::iterator out, prev, outBegin, outEnd;
outBegin = ldscript.sectionMap().begin();
outEnd = ldscript.sectionMap().end();
for (out = outBegin, prev = outEnd; out != outEnd; prev = out, ++out) {
LDSection* sect = (*out)->getSection();
if (0 == (sect->flag() & llvm::ELF::SHF_ALLOC) &&
LDFileFormat::Null != sect->kind())
break;
// bypass empty sections
if (!(*out)->hasContent() &&
(*out)->getSection()->kind() != LDFileFormat::Null)
continue;
cur_flag = getSegmentFlag(sect->flag());
bool createPT_LOAD = false;
if (LDFileFormat::Null == sect->kind()) {
// 1. create text segment
createPT_LOAD = true;
} else if (!config().options().omagic() &&
(prev_flag & llvm::ELF::PF_W) ^ (cur_flag & llvm::ELF::PF_W)) {
// 2. create data segment if w/o omagic set
createPT_LOAD = true;
} else if (sect->kind() == LDFileFormat::BSS && load_seg->isDataSegment() &&
addrEnd != ldscript.addressMap().find(".bss")) {
// 3. create bss segment if w/ -Tbss and there is a data segment
createPT_LOAD = true;
} else if ((sect != &(file_format->getText())) &&
(sect != &(file_format->getData())) &&
(sect != &(file_format->getBSS())) &&
(addrEnd != ldscript.addressMap().find(sect->name()))) {
// 4. create PT_LOAD for sections in address map except for text, data,
// and bss
createPT_LOAD = true;
} else if (LDFileFormat::Null == (*prev)->getSection()->kind() &&
!config().options().getScriptList().empty()) {
// 5. create PT_LOAD to hold NULL section if there is a default ldscript
createPT_LOAD = true;
}
if (createPT_LOAD) {
// create new PT_LOAD segment
load_seg = elfSegmentTable().produce(llvm::ELF::PT_LOAD, cur_flag);
if (!config().options().nmagic() && !config().options().omagic())
load_seg->setAlign(abiPageSize());
}
assert(load_seg != NULL);
load_seg->append(sect);
if (cur_flag != prev_flag)
load_seg->updateFlag(cur_flag);
prev_flag = cur_flag;
}
// make PT_DYNAMIC
if (file_format->hasDynamic()) {
ELFSegment* dyn_seg = elfSegmentTable().produce(
llvm::ELF::PT_DYNAMIC, llvm::ELF::PF_R | llvm::ELF::PF_W);
dyn_seg->append(&file_format->getDynamic());
}
if (config().options().hasRelro()) {
// make PT_GNU_RELRO
ELFSegment* relro_seg = elfSegmentTable().produce(llvm::ELF::PT_GNU_RELRO);
for (ELFSegmentFactory::iterator seg = elfSegmentTable().begin(),
segEnd = elfSegmentTable().end();
seg != segEnd;
++seg) {
if (llvm::ELF::PT_LOAD != (*seg)->type())
continue;
for (ELFSegment::iterator sect = (*seg)->begin(), sectEnd = (*seg)->end();
sect != sectEnd;
++sect) {
unsigned int order = getSectionOrder(**sect);
if (SHO_RELRO_LOCAL == order || SHO_RELRO == order ||
SHO_RELRO_LAST == order) {
relro_seg->append(*sect);
}
}
}
}
// make PT_GNU_EH_FRAME
if (file_format->hasEhFrameHdr()) {
ELFSegment* eh_seg = elfSegmentTable().produce(llvm::ELF::PT_GNU_EH_FRAME);
eh_seg->append(&file_format->getEhFrameHdr());
}
// make PT_TLS
if (file_format->hasTData() || file_format->hasTBSS()) {
ELFSegment* tls_seg = elfSegmentTable().produce(llvm::ELF::PT_TLS);
if (file_format->hasTData())
tls_seg->append(&file_format->getTData());
if (file_format->hasTBSS())
tls_seg->append(&file_format->getTBSS());
}
// make PT_GNU_STACK
if (file_format->hasStackNote()) {
uint32_t flag = getSegmentFlag(file_format->getStackNote().flag());
elfSegmentTable().produce(llvm::ELF::PT_GNU_STACK,
llvm::ELF::PF_R | llvm::ELF::PF_W | flag);
}
// make PT_NOTE
ELFSegment* note_seg = NULL;
prev_flag = 0x0;
Module::iterator sect, sectBegin, sectEnd;
sectBegin = pModule.begin();
sectEnd = pModule.end();
for (sect = sectBegin; sect != sectEnd; ++sect) {
if ((*sect)->type() != llvm::ELF::SHT_NOTE ||
((*sect)->flag() & llvm::ELF::SHF_ALLOC) == 0)
continue;
cur_flag = getSegmentFlag((*sect)->flag());
// we have different section orders for read-only and writable notes, so
// create 2 segments if needed.
if (note_seg == NULL ||
(cur_flag & llvm::ELF::PF_W) != (prev_flag & llvm::ELF::PF_W))
note_seg = elfSegmentTable().produce(llvm::ELF::PT_NOTE, cur_flag);
note_seg->append(*sect);
prev_flag = cur_flag;
}
// create target dependent segments
doCreateProgramHdrs(pModule);
}
/// setupProgramHdrs - set up the attributes of segments
void GNULDBackend::setupProgramHdrs(const LinkerScript& pScript) {
// update segment info
for (ELFSegmentFactory::iterator seg = elfSegmentTable().begin(),
segEnd = elfSegmentTable().end();
seg != segEnd;
++seg) {
// bypass if there is no section in this segment (e.g., PT_GNU_STACK)
if ((*seg)->size() == 0)
continue;
// bypass the PT_LOAD that only has NULL section now
if ((*seg)->type() == llvm::ELF::PT_LOAD &&
(*seg)->front()->kind() == LDFileFormat::Null && (*seg)->size() == 1)
continue;
(*seg)->setOffset((*seg)->front()->offset());
if ((*seg)->type() == llvm::ELF::PT_LOAD &&
(*seg)->front()->kind() == LDFileFormat::Null) {
const LDSection* second = *((*seg)->begin() + 1);
assert(second != NULL);
(*seg)->setVaddr(second->addr() - second->offset());
} else {
(*seg)->setVaddr((*seg)->front()->addr());
}
(*seg)->setPaddr((*seg)->vaddr());
ELFSegment::reverse_iterator sect, sectREnd = (*seg)->rend();
for (sect = (*seg)->rbegin(); sect != sectREnd; ++sect) {
if ((*sect)->kind() != LDFileFormat::BSS)
break;
}
if (sect != sectREnd) {
(*seg)->setFilesz((*sect)->offset() + (*sect)->size() - (*seg)->offset());
} else {
(*seg)->setFilesz(0x0);
}
(*seg)->setMemsz((*seg)->back()->addr() + (*seg)->back()->size() -
(*seg)->vaddr());
} // end of for
// handle the case if text segment only has NULL section
LDSection* null_sect = &getOutputFormat()->getNULLSection();
ELFSegmentFactory::iterator null_seg =
elfSegmentTable().find(llvm::ELF::PT_LOAD, null_sect);
if ((*null_seg)->size() == 1) {
// find 2nd PT_LOAD
ELFSegmentFactory::iterator seg, segEnd = elfSegmentTable().end();
for (seg = null_seg + 1; seg != segEnd; ++seg) {
if ((*seg)->type() == llvm::ELF::PT_LOAD)
break;
}
if (seg != segEnd) {
uint64_t addr = (*seg)->front()->addr() - (*seg)->front()->offset();
uint64_t size = sectionStartOffset();
if (addr + size == (*seg)->front()->addr()) {
// if there is no space between the 2 segments, we can merge them.
(*seg)->setOffset(0x0);
(*seg)->setVaddr(addr);
(*seg)->setPaddr(addr);
ELFSegment::iterator sect, sectEnd = (*seg)->end();
for (sect = (*seg)->begin(); sect != sectEnd; ++sect) {
if ((*sect)->kind() == LDFileFormat::BSS) {
--sect;
break;
}
}
if (sect == sectEnd) {
(*seg)->setFilesz((*seg)->back()->offset() + (*seg)->back()->size() -
(*seg)->offset());
} else if (*sect != (*seg)->front()) {
--sect;
(*seg)->setFilesz((*sect)->offset() + (*sect)->size() -
(*seg)->offset());
} else {
(*seg)->setFilesz(0x0);
}
(*seg)->setMemsz((*seg)->back()->addr() + (*seg)->back()->size() -
(*seg)->vaddr());
(*seg)->insert((*seg)->begin(), null_sect);
elfSegmentTable().erase(null_seg);
} else if (addr + size < (*seg)->vaddr()) {
(*null_seg)->setOffset(0x0);
(*null_seg)->setVaddr(addr);
(*null_seg)->setPaddr(addr);
(*null_seg)->setFilesz(size);
(*null_seg)->setMemsz(size);
} else {
// erase the non valid segment contains NULL.
elfSegmentTable().erase(null_seg);
}
}
}
// set up PT_PHDR
ELFSegmentFactory::iterator phdr =
elfSegmentTable().find(llvm::ELF::PT_PHDR, llvm::ELF::PF_R, 0x0);
if (phdr != elfSegmentTable().end()) {
ELFSegmentFactory::iterator null_seg =
elfSegmentTable().find(llvm::ELF::PT_LOAD, null_sect);
if (null_seg != elfSegmentTable().end()) {
uint64_t offset = 0x0, phdr_size = 0x0;
if (config().targets().is32Bits()) {
offset = sizeof(llvm::ELF::Elf32_Ehdr);
phdr_size = sizeof(llvm::ELF::Elf32_Phdr);
} else {
offset = sizeof(llvm::ELF::Elf64_Ehdr);
phdr_size = sizeof(llvm::ELF::Elf64_Phdr);
}
(*phdr)->setOffset(offset);
(*phdr)->setVaddr((*null_seg)->vaddr() + offset);
(*phdr)->setPaddr((*phdr)->vaddr());
(*phdr)->setFilesz(elfSegmentTable().size() * phdr_size);
(*phdr)->setMemsz(elfSegmentTable().size() * phdr_size);
(*phdr)->setAlign(config().targets().bitclass() / 8);
} else {
elfSegmentTable().erase(phdr);
}
}
}
/// getSegmentFlag - give a section flag and return the corresponding segment
/// flag
uint32_t GNULDBackend::getSegmentFlag(const uint32_t pSectionFlag) {
uint32_t flag = 0x0;
if ((pSectionFlag & llvm::ELF::SHF_ALLOC) != 0x0)
flag |= llvm::ELF::PF_R;
if ((pSectionFlag & llvm::ELF::SHF_WRITE) != 0x0)
flag |= llvm::ELF::PF_W;
if ((pSectionFlag & llvm::ELF::SHF_EXECINSTR) != 0x0)
flag |= llvm::ELF::PF_X;
return flag;
}
/// setupGNUStackInfo - setup the section flag of .note.GNU-stack in output
void GNULDBackend::setupGNUStackInfo(Module& pModule) {
uint32_t flag = 0x0;
if (config().options().hasStackSet()) {
// 1. check the command line option (-z execstack or -z noexecstack)
if (config().options().hasExecStack())
flag = llvm::ELF::SHF_EXECINSTR;
} else {
// 2. check the stack info from the input objects
// FIXME: since we alway emit .note.GNU-stack in output now, we may be able
// to check this from the output .note.GNU-stack directly after section
// merging is done
size_t object_count = 0, stack_note_count = 0;
Module::const_obj_iterator obj, objEnd = pModule.obj_end();
for (obj = pModule.obj_begin(); obj != objEnd; ++obj) {
++object_count;
const LDSection* sect = (*obj)->context()->getSection(".note.GNU-stack");
if (sect != NULL) {
++stack_note_count;
// 2.1 found a stack note that is set as executable
if (0 != (llvm::ELF::SHF_EXECINSTR & sect->flag())) {
flag = llvm::ELF::SHF_EXECINSTR;
break;
}
}
}
// 2.2 there are no stack note sections in all input objects
if (0 == stack_note_count)
return;
// 2.3 a special case. Use the target default to decide if the stack should
// be executable
if (llvm::ELF::SHF_EXECINSTR != flag && object_count != stack_note_count)
if (m_pInfo->isDefaultExecStack())
flag = llvm::ELF::SHF_EXECINSTR;
}
if (getOutputFormat()->hasStackNote()) {
getOutputFormat()->getStackNote().setFlag(flag);
}
}
/// setOutputSectionOffset - helper function to set output sections' offset.
void GNULDBackend::setOutputSectionOffset(Module& pModule) {
LinkerScript& script = pModule.getScript();
uint64_t offset = 0x0;
LDSection* cur = NULL;
LDSection* prev = NULL;
SectionMap::iterator out, outBegin, outEnd;
outBegin = script.sectionMap().begin();
outEnd = script.sectionMap().end();
for (out = outBegin; out != outEnd; ++out, prev = cur) {
cur = (*out)->getSection();
if (cur->kind() == LDFileFormat::Null) {
cur->setOffset(0x0);
continue;
}
switch (prev->kind()) {
case LDFileFormat::Null:
offset = sectionStartOffset();
break;
case LDFileFormat::BSS:
offset = prev->offset();
break;
default:
offset = prev->offset() + prev->size();
break;
}
alignAddress(offset, cur->align());
cur->setOffset(offset);
}
}
/// setOutputSectionAddress - helper function to set output sections' address.
void GNULDBackend::setOutputSectionAddress(Module& pModule) {
RpnEvaluator evaluator(pModule, *this);
LinkerScript& script = pModule.getScript();
uint64_t vma = 0x0, offset = 0x0;
LDSection* cur = NULL;
LDSection* prev = NULL;
LinkerScript::AddressMap::iterator addr, addrEnd = script.addressMap().end();
ELFSegmentFactory::iterator seg, segEnd = elfSegmentTable().end();
SectionMap::Output::dot_iterator dot;
SectionMap::iterator out, outBegin, outEnd;
outBegin = script.sectionMap().begin();
outEnd = script.sectionMap().end();
for (out = outBegin; out != outEnd; prev = cur, ++out) {
cur = (*out)->getSection();
if (cur->kind() == LDFileFormat::Null) {
cur->setOffset(0x0);
continue;
}
// process dot assignments between 2 output sections
for (SectionMap::Output::dot_iterator it = (*out)->dot_begin(),
ie = (*out)->dot_end();
it != ie;
++it) {
(*it).assign(evaluator);
}
seg = elfSegmentTable().find(llvm::ELF::PT_LOAD, cur);
if (seg != segEnd && cur == (*seg)->front()) {
if ((*seg)->isBssSegment())
addr = script.addressMap().find(".bss");
else if ((*seg)->isDataSegment())
addr = script.addressMap().find(".data");
else
addr = script.addressMap().find(cur->name());
} else
addr = addrEnd;
if (addr != addrEnd) {
// use address mapping in script options
vma = addr.getEntry()->value();
} else if ((*out)->prolog().hasVMA()) {
// use address from output section description
evaluator.eval((*out)->prolog().vma(), vma);
} else if ((dot = (*out)->find_last_explicit_dot()) != (*out)->dot_end()) {
// assign address based on `.' symbol in ldscript
vma = (*dot).symbol().value();
alignAddress(vma, cur->align());
} else {
if ((*out)->prolog().type() == OutputSectDesc::NOLOAD) {
vma = prev->addr() + prev->size();
} else if ((cur->flag() & llvm::ELF::SHF_ALLOC) != 0) {
if (prev->kind() == LDFileFormat::Null) {
// Let SECTIONS starts at 0 if we have a default ldscript but don't
// have any initial value (VMA or `.').
if (!config().options().getScriptList().empty())
vma = 0x0;
else
vma = getSegmentStartAddr(script) + sectionStartOffset();
} else {
if ((prev->kind() == LDFileFormat::BSS))
vma = prev->addr();
else
vma = prev->addr() + prev->size();
}
alignAddress(vma, cur->align());
if (config().options().getScriptList().empty()) {
if (seg != segEnd && cur == (*seg)->front()) {
// Try to align p_vaddr at page boundary if not in script options.
// To do so will add more padding in file, but can save one page
// at runtime.
// Avoid doing this optimization if -z relro is given, because there
// seems to be too many padding.
if (!config().options().hasRelro()) {
alignAddress(vma, (*seg)->align());
} else {
vma += abiPageSize();
}
}
}
} else {
vma = 0x0;
}
}
if (config().options().hasRelro()) {
// if -z relro is given, we need to adjust sections' offset again, and
// let PT_GNU_RELRO end on a abi page boundary
// check if current is the first non-relro section
SectionMap::iterator relro_last = out - 1;
if (relro_last != outEnd && (*relro_last)->order() <= SHO_RELRO_LAST &&
(*out)->order() > SHO_RELRO_LAST) {
// align the first non-relro section to page boundary
alignAddress(vma, abiPageSize());
// It seems that compiler think .got and .got.plt are continuous (w/o
// any padding between). If .got is the last section in PT_RELRO and
// it's not continuous to its next section (i.e. .got.plt), we need to
// add padding in front of .got instead.
// FIXME: Maybe we can handle this in a more general way.
LDSection& got = getOutputFormat()->getGOT();
if ((getSectionOrder(got) == SHO_RELRO_LAST) &&
(got.addr() + got.size() < vma)) {
uint64_t diff = vma - got.addr() - got.size();
got.setAddr(vma - got.size());
got.setOffset(got.offset() + diff);
}
}
} // end of if - for relro processing
cur->setAddr(vma);
switch (prev->kind()) {
case LDFileFormat::Null:
offset = sectionStartOffset();
break;
case LDFileFormat::BSS:
offset = prev->offset();
break;
default:
offset = prev->offset() + prev->size();
break;
}
alignAddress(offset, cur->align());
// in p75, http://www.sco.com/developers/devspecs/gabi41.pdf
// p_align: As "Program Loading" describes in this chapter of the
// processor supplement, loadable process segments must have congruent
// values for p_vaddr and p_offset, modulo the page size.
// FIXME: Now make all sh_addr and sh_offset are congruent, modulo the page
// size. Otherwise, old objcopy (e.g., binutils 2.17) may fail with our
// output!
if ((cur->flag() & llvm::ELF::SHF_ALLOC) != 0 &&
(vma & (abiPageSize() - 1)) != (offset & (abiPageSize() - 1))) {
uint64_t padding = abiPageSize() + (vma & (abiPageSize() - 1)) -
(offset & (abiPageSize() - 1));
offset += padding;
}
cur->setOffset(offset);
// process dot assignments in the output section
bool changed = false;
Fragment* invalid = NULL;
for (SectionMap::Output::iterator in = (*out)->begin(),
inEnd = (*out)->end();
in != inEnd;
++in) {
if (invalid != NULL && !(*in)->dotAssignments().empty()) {
while (invalid != (*in)->dotAssignments().front().first) {
Fragment* prev = invalid->getPrevNode();
invalid->setOffset(prev->getOffset() + prev->size());
invalid = invalid->getNextNode();
}
invalid = NULL;
}
for (SectionMap::Input::dot_iterator it = (*in)->dot_begin(),
ie = (*in)->dot_end();
it != ie;
++it) {
(*it).second.assign(evaluator);
if ((*it).first != NULL) {
uint64_t new_offset = (*it).second.symbol().value() - vma;
if (new_offset != (*it).first->getOffset()) {
(*it).first->setOffset(new_offset);
invalid = (*it).first->getNextNode();
changed = true;
}
}
} // for each dot assignment
} // for each input description
if (changed) {
while (invalid != NULL) {
Fragment* prev = invalid->getPrevNode();
invalid->setOffset(prev->getOffset() + prev->size());
invalid = invalid->getNextNode();
}
cur->setSize(cur->getSectionData()->back().getOffset() +
cur->getSectionData()->back().size());
}
} // for each output section description
}
/// placeOutputSections - place output sections based on SectionMap
void GNULDBackend::placeOutputSections(Module& pModule) {
typedef std::vector<LDSection*> Orphans;
Orphans orphans;
SectionMap& sectionMap = pModule.getScript().sectionMap();
for (Module::iterator it = pModule.begin(), ie = pModule.end(); it != ie;
++it) {
bool wanted = false;
switch ((*it)->kind()) {
// take NULL and StackNote directly
case LDFileFormat::Null:
case LDFileFormat::StackNote:
wanted = true;
break;
// ignore if section size is 0
case LDFileFormat::EhFrame:
if (((*it)->size() != 0) ||
((*it)->hasEhFrame() &&
config().codeGenType() == LinkerConfig::Object))
wanted = true;
break;
case LDFileFormat::Relocation:
if (((*it)->size() != 0) ||
((*it)->hasRelocData() &&
config().codeGenType() == LinkerConfig::Object))
wanted = true;
break;
case LDFileFormat::TEXT:
case LDFileFormat::DATA:
case LDFileFormat::Target:
case LDFileFormat::MetaData:
case LDFileFormat::BSS:
case LDFileFormat::Debug:
case LDFileFormat::DebugString:
case LDFileFormat::GCCExceptTable:
case LDFileFormat::Note:
case LDFileFormat::NamePool:
case LDFileFormat::EhFrameHdr:
if (((*it)->size() != 0) ||
((*it)->hasSectionData() &&
config().codeGenType() == LinkerConfig::Object))
wanted = true;
break;
case LDFileFormat::Group:
if (LinkerConfig::Object == config().codeGenType()) {
// TODO: support incremental linking
}
break;
case LDFileFormat::Version:
if ((*it)->size() != 0) {
wanted = true;
warning(diag::warn_unsupported_symbolic_versioning) << (*it)->name();
}
break;
default:
if ((*it)->size() != 0) {
error(diag::err_unsupported_section) << (*it)->name()
<< (*it)->kind();
}
break;
} // end of switch
if (wanted) {
SectionMap::iterator out, outBegin, outEnd;
outBegin = sectionMap.begin();
outEnd = sectionMap.end();
for (out = outBegin; out != outEnd; ++out) {
bool matched = false;
if ((*it)->name().compare((*out)->name()) == 0) {
switch ((*out)->prolog().constraint()) {
case OutputSectDesc::NO_CONSTRAINT:
matched = true;
break;
case OutputSectDesc::ONLY_IF_RO:
matched = ((*it)->flag() & llvm::ELF::SHF_WRITE) == 0;
break;
case OutputSectDesc::ONLY_IF_RW:
matched = ((*it)->flag() & llvm::ELF::SHF_WRITE) != 0;
break;
} // end of switch
if (matched)
break;
}
} // for each output section description
if (out != outEnd) {
// set up the section
(*out)->setSection(*it);
(*out)->setOrder(getSectionOrder(**it));
} else {
orphans.push_back(*it);
}
}
} // for each section in Module
// set up sections in SectionMap but do not exist at all.
uint32_t flag = 0x0;
unsigned int order = SHO_UNDEFINED;
OutputSectDesc::Type type = OutputSectDesc::LOAD;
for (SectionMap::reverse_iterator out = sectionMap.rbegin(),
outEnd = sectionMap.rend();
out != outEnd;
++out) {
if ((*out)->hasContent() ||
(*out)->getSection()->kind() == LDFileFormat::Null ||
(*out)->getSection()->kind() == LDFileFormat::StackNote) {
flag = (*out)->getSection()->flag();
order = (*out)->order();
type = (*out)->prolog().type();
} else {
(*out)->getSection()->setFlag(flag);
(*out)->setOrder(order);
(*out)->prolog().setType(type);
}
} // for each output section description
// place orphan sections
for (Orphans::iterator it = orphans.begin(), ie = orphans.end(); it != ie;
++it) {
size_t order = getSectionOrder(**it);
SectionMap::iterator out, outBegin, outEnd;
outBegin = sectionMap.begin();
outEnd = sectionMap.end();
if ((*it)->kind() == LDFileFormat::Null)
out = sectionMap.insert(outBegin, *it);
else {
for (out = outBegin; out != outEnd; ++out) {
if ((*out)->order() > order)
break;
}
out = sectionMap.insert(out, *it);
}
(*out)->setOrder(order);
} // for each orphan section
// sort output section orders if there is no default ldscript
if (config().options().getScriptList().empty()) {
std::stable_sort(
sectionMap.begin(), sectionMap.end(), SectionMap::SHOCompare());
}
// when section ordering is fixed, now we can make sure dot assignments are
// all set appropriately
sectionMap.fixupDotSymbols();
}
/// layout - layout method
void GNULDBackend::layout(Module& pModule) {
// 1. place output sections based on SectionMap from SECTIONS command
placeOutputSections(pModule);
// 2. update output sections in Module
SectionMap& sectionMap = pModule.getScript().sectionMap();
pModule.getSectionTable().clear();
for (SectionMap::iterator out = sectionMap.begin(), outEnd = sectionMap.end();
out != outEnd;
++out) {
if ((*out)->hasContent() ||
(*out)->getSection()->kind() == LDFileFormat::Null ||
(*out)->getSection()->kind() == LDFileFormat::StackNote ||
config().codeGenType() == LinkerConfig::Object) {
(*out)->getSection()->setIndex(pModule.size());
pModule.getSectionTable().push_back((*out)->getSection());
}
} // for each output section description
// 3. update the size of .shstrtab
sizeShstrtab(pModule);
// 4. create program headers
if (LinkerConfig::Object != config().codeGenType()) {
createProgramHdrs(pModule);
}
// 5. set output section address/offset
if (LinkerConfig::Object != config().codeGenType())
setOutputSectionAddress(pModule);
else
setOutputSectionOffset(pModule);
}
void GNULDBackend::createAndSizeEhFrameHdr(Module& pModule) {
if (LinkerConfig::Object != config().codeGenType() &&
config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) {
// init EhFrameHdr and size the output section
ELFFileFormat* format = getOutputFormat();
m_pEhFrameHdr =
new EhFrameHdr(format->getEhFrameHdr(), format->getEhFrame());
m_pEhFrameHdr->sizeOutput();
}
}
/// mayHaveUnsafeFunctionPointerAccess - check if the section may have unsafe
/// function pointer access
bool GNULDBackend::mayHaveUnsafeFunctionPointerAccess(
const LDSection& pSection) const {
llvm::StringRef name(pSection.name());
return !name.startswith(".rodata._ZTV") &&
!name.startswith(".data.rel.ro._ZTV") &&
!name.startswith(".rodata._ZTC") &&
!name.startswith(".data.rel.ro._ZTC") && !name.startswith(".eh_frame");
}
/// preLayout - Backend can do any needed modification before layout
void GNULDBackend::preLayout(Module& pModule, IRBuilder& pBuilder) {
// prelayout target first
doPreLayout(pBuilder);
// change .tbss and .tdata section symbol from Local to LocalDyn category
if (f_pTDATA != NULL)
pModule.getSymbolTable().changeToDynamic(*f_pTDATA);
if (f_pTBSS != NULL)
pModule.getSymbolTable().changeToDynamic(*f_pTBSS);
// To merge input's relocation sections into output's relocation sections.
//
// If we are generating relocatables (-r), move input relocation sections
// to corresponding output relocation sections.
if (LinkerConfig::Object == config().codeGenType()) {
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) {
// get the output relocation LDSection with identical name.
LDSection* output_sect = pModule.getSection((*rs)->name());
if (output_sect == NULL) {
output_sect = LDSection::Create(
(*rs)->name(), (*rs)->kind(), (*rs)->type(), (*rs)->flag());
output_sect->setAlign((*rs)->align());
pModule.getSectionTable().push_back(output_sect);
}
// set output relocation section link
const LDSection* input_link = (*rs)->getLink();
assert(input_link != NULL && "Illegal input relocation section.");
// get the linked output section
LDSection* output_link = pModule.getSection(input_link->name());
assert(output_link != NULL);
output_sect->setLink(output_link);
// get output relcoationData, create one if not exist
if (!output_sect->hasRelocData())
IRBuilder::CreateRelocData(*output_sect);
RelocData* out_reloc_data = output_sect->getRelocData();
// move relocations from input's to output's RelcoationData
RelocData::RelocationListType& out_list =
out_reloc_data->getRelocationList();
RelocData::RelocationListType& in_list =
(*rs)->getRelocData()->getRelocationList();
out_list.splice(out_list.end(), in_list);
// size output
if (llvm::ELF::SHT_REL == output_sect->type())
output_sect->setSize(out_reloc_data->size() * getRelEntrySize());
else if (llvm::ELF::SHT_RELA == output_sect->type())
output_sect->setSize(out_reloc_data->size() * getRelaEntrySize());
else {
fatal(diag::unknown_reloc_section_type) << output_sect->type()
<< output_sect->name();
}
} // end of for each relocation section
} // end of for each input
} // end of if
// set up the section flag of .note.GNU-stack section
setupGNUStackInfo(pModule);
}
/// postLayout - Backend can do any needed modification after layout
void GNULDBackend::postLayout(Module& pModule, IRBuilder& pBuilder) {
if (LinkerConfig::Object != config().codeGenType()) {
// do relaxation
relax(pModule, pBuilder);
// set up the attributes of program headers
setupProgramHdrs(pModule.getScript());
}
doPostLayout(pModule, pBuilder);
}
void GNULDBackend::postProcessing(FileOutputBuffer& pOutput) {
if (LinkerConfig::Object != config().codeGenType() &&
config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) {
// emit eh_frame_hdr
m_pEhFrameHdr->emitOutput<32>(pOutput);
}
}
/// getHashBucketCount - calculate hash bucket count.
unsigned GNULDBackend::getHashBucketCount(unsigned pNumOfSymbols,
bool pIsGNUStyle) {
static const unsigned int buckets[] = {
1, 3, 17, 37, 67, 97, 131, 197, 263, 521, 1031, 2053, 4099, 8209, 16411,
32771, 65537, 131101, 262147
};
const unsigned buckets_count = sizeof buckets / sizeof buckets[0];
unsigned int result = 1;
for (unsigned i = 0; i < buckets_count; ++i) {
if (pNumOfSymbols < buckets[i])
break;
result = buckets[i];
}
if (pIsGNUStyle && result < 2)
result = 2;
return result;
}
/// getGNUHashMaskbitslog2 - calculate the number of mask bits in log2
unsigned GNULDBackend::getGNUHashMaskbitslog2(unsigned pNumOfSymbols) const {
uint32_t maskbitslog2 = 1;
for (uint32_t x = pNumOfSymbols >> 1; x != 0; x >>= 1)
++maskbitslog2;
if (maskbitslog2 < 3)
maskbitslog2 = 5;
else if (((1U << (maskbitslog2 - 2)) & pNumOfSymbols) != 0)
maskbitslog2 += 3;
else
maskbitslog2 += 2;
if (config().targets().bitclass() == 64 && maskbitslog2 == 5)
maskbitslog2 = 6;
return maskbitslog2;
}
/// isDynamicSymbol
bool GNULDBackend::isDynamicSymbol(const LDSymbol& pSymbol) const {
// If a local symbol is in the LDContext's symbol table, it's a real local
// symbol. We should not add it
if (pSymbol.binding() == ResolveInfo::Local)
return false;
// If we are building shared object, and the visibility is external, we
// need to add it.
if (LinkerConfig::DynObj == config().codeGenType() ||
LinkerConfig::Exec == config().codeGenType() ||
LinkerConfig::Binary == config().codeGenType()) {
if (pSymbol.resolveInfo()->visibility() == ResolveInfo::Default ||
pSymbol.resolveInfo()->visibility() == ResolveInfo::Protected)
return true;
}
return false;
}
/// isDynamicSymbol
bool GNULDBackend::isDynamicSymbol(const ResolveInfo& pResolveInfo) const {
// If a local symbol is in the LDContext's symbol table, it's a real local
// symbol. We should not add it
if (pResolveInfo.binding() == ResolveInfo::Local)
return false;
// If we are building shared object, and the visibility is external, we
// need to add it.
if (LinkerConfig::DynObj == config().codeGenType() ||
LinkerConfig::Exec == config().codeGenType() ||
LinkerConfig::Binary == config().codeGenType()) {
if (pResolveInfo.visibility() == ResolveInfo::Default ||
pResolveInfo.visibility() == ResolveInfo::Protected)
return true;
}
return false;
}
/// elfSegmentTable - return the reference of the elf segment table
ELFSegmentFactory& GNULDBackend::elfSegmentTable() {
assert(m_pELFSegmentTable != NULL && "Do not create ELFSegmentTable!");
return *m_pELFSegmentTable;
}
/// elfSegmentTable - return the reference of the elf segment table
const ELFSegmentFactory& GNULDBackend::elfSegmentTable() const {
assert(m_pELFSegmentTable != NULL && "Do not create ELFSegmentTable!");
return *m_pELFSegmentTable;
}
/// commonPageSize - the common page size of the target machine.
uint64_t GNULDBackend::commonPageSize() const {
if (config().options().commPageSize() > 0)
return std::min(config().options().commPageSize(), abiPageSize());
else
return std::min(m_pInfo->commonPageSize(), abiPageSize());
}
/// abiPageSize - the abi page size of the target machine.
uint64_t GNULDBackend::abiPageSize() const {
if (config().options().maxPageSize() > 0)
return config().options().maxPageSize();
else
return m_pInfo->abiPageSize();
}
/// isSymbolPreemtible - whether the symbol can be preemted by other
/// link unit
bool GNULDBackend::isSymbolPreemptible(const ResolveInfo& pSym) const {
if (pSym.other() != ResolveInfo::Default)
return false;
// This is because the codeGenType of pie is DynObj. And gold linker check
// the "shared" option instead.
if (config().options().isPIE())
return false;
if (LinkerConfig::DynObj != config().codeGenType())
return false;
if (config().options().Bsymbolic())
return false;
// A local defined symbol should be non-preemptible.
// This issue is found when linking libstdc++ on freebsd. A R_386_GOT32
// relocation refers to a local defined symbol, and we should generate a
// relative dynamic relocation when applying the relocation.
if (pSym.isDefine() && pSym.binding() == ResolveInfo::Local)
return false;
return true;
}
/// symbolNeedsDynRel - return whether the symbol needs a dynamic relocation
bool GNULDBackend::symbolNeedsDynRel(const ResolveInfo& pSym,
bool pSymHasPLT,
bool isAbsReloc) const {
// an undefined reference in the executables should be statically
// resolved to 0 and no need a dynamic relocation
if (pSym.isUndef() && !pSym.isDyn() &&
(LinkerConfig::Exec == config().codeGenType() ||
LinkerConfig::Binary == config().codeGenType()))
return false;
// An absolute symbol can be resolved directly if it is either local
// or we are linking statically. Otherwise it can still be overridden
// at runtime.
if (pSym.isAbsolute() &&
(pSym.binding() == ResolveInfo::Local || config().isCodeStatic()))
return false;
if (config().isCodeIndep() && isAbsReloc)
return true;
if (pSymHasPLT && ResolveInfo::Function == pSym.type())
return false;
if (!config().isCodeIndep() && pSymHasPLT)
return false;
if (pSym.isDyn() || pSym.isUndef() || isSymbolPreemptible(pSym))
return true;
return false;
}
/// symbolNeedsPLT - return whether the symbol needs a PLT entry
bool GNULDBackend::symbolNeedsPLT(const ResolveInfo& pSym) const {
if (pSym.isUndef() && !pSym.isDyn() &&
LinkerConfig::DynObj != config().codeGenType())
return false;
// An IndirectFunc symbol (i.e., STT_GNU_IFUNC) always needs a plt entry
if (pSym.type() == ResolveInfo::IndirectFunc)
return true;
if (pSym.type() != ResolveInfo::Function)
return false;
if (config().isCodeStatic())
return false;
if (config().options().isPIE())
return false;
return (pSym.isDyn() || pSym.isUndef() || isSymbolPreemptible(pSym));
}
/// symbolHasFinalValue - return true if the symbol's value can be decided at
/// link time
bool GNULDBackend::symbolFinalValueIsKnown(const ResolveInfo& pSym) const {
// if the output is pic code or if not executables, symbols' value may change
// at runtime
// FIXME: CodeIndep() || LinkerConfig::Relocatable == CodeGenType
if (config().isCodeIndep() ||
(LinkerConfig::Exec != config().codeGenType() &&
LinkerConfig::Binary != config().codeGenType()))
return false;
// if the symbol is from dynamic object, then its value is unknown
if (pSym.isDyn())
return false;
// if the symbol is not in dynamic object and is not undefined, then its value
// is known
if (!pSym.isUndef())
return true;
// if the symbol is undefined and not in dynamic objects, for example, a weak
// undefined symbol, then whether the symbol's final value can be known
// depends on whrther we're doing static link
return config().isCodeStatic();
}
/// symbolNeedsCopyReloc - return whether the symbol needs a copy relocation
bool GNULDBackend::symbolNeedsCopyReloc(const Relocation& pReloc,
const ResolveInfo& pSym) const {
// only the reference from dynamic executable to non-function symbol in
// the dynamic objects may need copy relocation
if (config().isCodeIndep() || !pSym.isDyn() ||
pSym.type() == ResolveInfo::Function || pSym.size() == 0)
return false;
// check if the option -z nocopyreloc is given
if (config().options().hasNoCopyReloc())
return false;
// TODO: Is this check necessary?
// if relocation target place is readonly, a copy relocation is needed
uint32_t flag = pReloc.targetRef().frag()->getParent()->getSection().flag();
if (0 == (flag & llvm::ELF::SHF_WRITE))
return true;
return false;
}
LDSymbol& GNULDBackend::getTDATASymbol() {
assert(f_pTDATA != NULL);
return *f_pTDATA;
}
const LDSymbol& GNULDBackend::getTDATASymbol() const {
assert(f_pTDATA != NULL);
return *f_pTDATA;
}
LDSymbol& GNULDBackend::getTBSSSymbol() {
assert(f_pTBSS != NULL);
return *f_pTBSS;
}
const LDSymbol& GNULDBackend::getTBSSSymbol() const {
assert(f_pTBSS != NULL);
return *f_pTBSS;
}
llvm::StringRef GNULDBackend::getEntry(const Module& pModule) const {
if (pModule.getScript().hasEntry())
return pModule.getScript().entry();
else
return getInfo().entry();
}
void GNULDBackend::checkAndSetHasTextRel(const LDSection& pSection) {
if (m_bHasTextRel)
return;
// if the target section of the dynamic relocation is ALLOCATE but is not
// writable, than we should set DF_TEXTREL
const uint32_t flag = pSection.flag();
if (0 == (flag & llvm::ELF::SHF_WRITE) && (flag & llvm::ELF::SHF_ALLOC))
m_bHasTextRel = true;
return;
}
/// sortRelocation - sort the dynamic relocations to let dynamic linker
/// process relocations more efficiently
void GNULDBackend::sortRelocation(LDSection& pSection) {
if (!config().options().hasCombReloc())
return;
assert(pSection.kind() == LDFileFormat::Relocation);
switch (config().codeGenType()) {
case LinkerConfig::DynObj:
case LinkerConfig::Exec:
if (&pSection == &getOutputFormat()->getRelDyn() ||
&pSection == &getOutputFormat()->getRelaDyn()) {
if (pSection.hasRelocData())
pSection.getRelocData()->sort(RelocCompare(*this));
}
default:
return;
}
}
unsigned GNULDBackend::stubGroupSize() const {
const unsigned group_size = config().targets().getStubGroupSize();
if (group_size == 0) {
return m_pInfo->stubGroupSize();
} else {
return group_size;
}
}
/// initBRIslandFactory - initialize the branch island factory for relaxation
bool GNULDBackend::initBRIslandFactory() {
if (m_pBRIslandFactory == NULL) {
m_pBRIslandFactory = new BranchIslandFactory(maxFwdBranchOffset(),
maxBwdBranchOffset(),
stubGroupSize());
}
return true;
}
/// initStubFactory - initialize the stub factory for relaxation
bool GNULDBackend::initStubFactory() {
if (m_pStubFactory == NULL) {
m_pStubFactory = new StubFactory();
}
return true;
}
bool GNULDBackend::relax(Module& pModule, IRBuilder& pBuilder) {
if (!mayRelax())
return true;
getBRIslandFactory()->group(pModule);
bool finished = true;
do {
if (doRelax(pModule, pBuilder, finished)) {
setOutputSectionAddress(pModule);
}
} while (!finished);
return true;
}
bool GNULDBackend::DynsymCompare::needGNUHash(const LDSymbol& X) const {
// FIXME: in bfd and gold linker, an undefined symbol might be hashed
// when the ouput is not PIC, if the symbol is referred by a non pc-relative
// reloc, and its value is set to the addr of the plt entry.
return !X.resolveInfo()->isUndef() && !X.isDyn();
}
bool GNULDBackend::DynsymCompare::operator()(const LDSymbol* X,
const LDSymbol* Y) const {
return !needGNUHash(*X) && needGNUHash(*Y);
}
bool GNULDBackend::RelocCompare::operator()(const Relocation& X,
const Relocation& Y) const {
// 1. compare if relocation is relative
if (X.symInfo() == NULL) {
if (Y.symInfo() != NULL)
return true;
} else if (Y.symInfo() == NULL) {
return false;
} else {
// 2. compare the symbol index
size_t symIdxX = m_Backend.getSymbolIdx(X.symInfo()->outSymbol());
size_t symIdxY = m_Backend.getSymbolIdx(Y.symInfo()->outSymbol());
if (symIdxX < symIdxY)
return true;
if (symIdxX > symIdxY)
return false;
}
// 3. compare the relocation address
if (X.place() < Y.place())
return true;
if (X.place() > Y.place())
return false;
// 4. compare the relocation type
if (X.type() < Y.type())
return true;
if (X.type() > Y.type())
return false;
// 5. compare the addend
if (X.addend() < Y.addend())
return true;
if (X.addend() > Y.addend())
return false;
return false;
}
} // namespace mcld