blob: 590c14f55e4e90e413888764d41b6828c9395772 [file] [log] [blame]
//===- 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 <string>
#include <cstring>
#include <cassert>
#include <vector>
#include <algorithm>
#include <mcld/Module.h>
#include <mcld/LinkerConfig.h>
#include <mcld/IRBuilder.h>
#include <mcld/InputTree.h>
#include <mcld/Config/Config.h>
#include <mcld/ADT/SizeTraits.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/LDContext.h>
#include <mcld/Fragment/FillFragment.h>
#include <mcld/LD/EhFrame.h>
#include <mcld/LD/EhFrameHdr.h>
#include <mcld/LD/RelocData.h>
#include <mcld/LD/RelocationFactory.h>
#include <mcld/MC/Attribute.h>
#include <mcld/Fragment/FragmentLinker.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Support/MemoryAreaFactory.h>
#include <mcld/LD/BranchIslandFactory.h>
#include <mcld/LD/StubFactory.h>
#include <mcld/Object/ObjectBuilder.h>
using namespace mcld;
//===--------------------------------------------------------------------===//
// non-member functions
//===----------------------------------------------------------------------===//
/// isCIdentifier - return if the pName is a valid C identifier
static bool isCIdentifier(const std::string& pName)
{
std::string ident = "0123456789"
"ABCDEFGHIJKLMNOPWRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"_";
return (pName.find_first_not_of(ident) > pName.length());
}
//===----------------------------------------------------------------------===//
// 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_ELFSegmentTable(9), // magic number
m_pBRIslandFactory(NULL),
m_pStubFactory(NULL),
m_pEhFrame(NULL),
m_pEhFrameHdr(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_pSymIndexMap = new HashTableType(1024);
}
GNULDBackend::~GNULDBackend()
{
delete m_pInfo;
delete m_pDynObjFileFormat;
delete m_pExecFileFormat;
delete m_pSymIndexMap;
delete m_pEhFrame;
delete m_pEhFrameHdr;
if (NULL != m_pBRIslandFactory)
delete m_pBRIslandFactory;
if (NULL != m_pStubFactory)
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) +
numOfSegments() * sizeof(llvm::ELF::Elf32_Phdr);
case 64u:
return sizeof(llvm::ELF::Elf64_Ehdr) +
numOfSegments() * sizeof(llvm::ELF::Elf64_Phdr);
default:
fatal(diag::unsupported_bitclass) << config().targets().triple().str()
<< config().targets().bitclass();
return 0;
}
}
uint64_t GNULDBackend::segmentStartAddr(const FragmentLinker& pLinker) const
{
ScriptOptions::AddressMap::const_iterator mapping =
config().scripts().addressMap().find(".text");
if (mapping != config().scripts().addressMap().end())
return mapping.getEntry()->value();
else if (pLinker.isOutputPIC())
return 0x0;
else
return defaultTextSegmentAddr();
}
GNUArchiveReader*
GNULDBackend::createArchiveReader(Module& pModule)
{
assert(NULL != m_pObjectReader);
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(*this, pBuilder, config());
}
ELFObjectWriter* GNULDBackend::createObjectWriter()
{
return new ELFObjectWriter(*this, config());
}
ELFDynObjWriter* GNULDBackend::createDynObjWriter()
{
return new ELFDynObjWriter(*this, config());
}
ELFExecWriter* GNULDBackend::createExecWriter()
{
return new ELFExecWriter(*this, config());
}
ELFBinaryWriter* GNULDBackend::createBinaryWriter()
{
return new ELFBinaryWriter(*this, config());
}
bool GNULDBackend::initStdSections(ObjectBuilder& pBuilder)
{
switch (config().codeGenType()) {
case LinkerConfig::DynObj: {
if (NULL == m_pDynObjFileFormat)
m_pDynObjFileFormat = new ELFDynObjFileFormat();
m_pDynObjFileFormat->initStdSections(pBuilder,
config().targets().bitclass());
return true;
}
case LinkerConfig::Exec:
case LinkerConfig::Binary: {
if (NULL == m_pExecFileFormat)
m_pExecFileFormat = new ELFExecFileFormat();
m_pExecFileFormat->initStdSections(pBuilder,
config().targets().bitclass());
return true;
}
case LinkerConfig::Object: {
if (NULL == m_pObjectFileFormat)
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(FragmentLinker& pLinker,
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
// ref: GNU gold, Layout::define_section_symbols
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())) {
llvm::StringRef start_name = llvm::StringRef("__start_" + section->name());
FragmentRef* start_fragref = FragmentRef::Create(
section->getSectionData()->front(), 0x0);
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>(start_name,
false, // isDyn
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
0x0, // size
0x0, // value
start_fragref, // FragRef
ResolveInfo::Default);
llvm::StringRef stop_name = llvm::StringRef("__stop_" + section->name());
FragmentRef* stop_fragref = FragmentRef::Create(
section->getSectionData()->front(), section->size());
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>(stop_name,
false, // isDyn
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 =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("__preinit_array_start",
false, // isDyn
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
0x0, // size
0x0, // value
preinit_array, // FragRef
ResolveInfo::Hidden);
f_pPreInitArrayEnd =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("__preinit_array_end",
false, // isDyn
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 =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("__init_array_start",
false, // isDyn
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
0x0, // size
0x0, // value
init_array, // FragRef
ResolveInfo::Hidden);
f_pInitArrayEnd =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("__init_array_end",
false, // isDyn
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 =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("__fini_array_start",
false, // isDyn
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Global,
0x0, // size
0x0, // value
fini_array, // FragRef
ResolveInfo::Hidden);
f_pFiniArrayEnd =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("__fini_array_end",
false, // isDyn
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 =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("__stack",
false, // isDyn
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 =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("_DYNAMIC",
false, // isDyn
ResolveInfo::Object,
ResolveInfo::Define,
ResolveInfo::Local,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Hidden);
// ----- segment symbols ----- //
f_pExecutableStart =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("__executable_start",
false, // isDyn
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_pEText =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("etext",
false, // isDyn
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_p_EText =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("_etext",
false, // isDyn
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_p__EText =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("__etext",
false, // isDyn
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_pEData =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("edata",
false, // isDyn
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
f_pEnd =
pLinker.defineSymbol<FragmentLinker::AsRefered,
FragmentLinker::Resolve>("end",
false, // isDyn
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
// _edata is defined forcefully.
// @ref Google gold linker: defstd.cc: 186
f_p_EData =
pLinker.defineSymbol<FragmentLinker::Force,
FragmentLinker::Resolve>("_edata",
false, // isDyn
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
// __bss_start is defined forcefully.
// @ref Google gold linker: defstd.cc: 214
f_pBSSStart =
pLinker.defineSymbol<FragmentLinker::Force,
FragmentLinker::Resolve>("__bss_start",
false, // isDyn
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
// _end is defined forcefully.
// @ref Google gold linker: defstd.cc: 228
f_p_End =
pLinker.defineSymbol<FragmentLinker::Force,
FragmentLinker::Resolve>("_end",
false, // isDyn
ResolveInfo::NoType,
ResolveInfo::Define,
ResolveInfo::Absolute,
0x0, // size
0x0, // value
FragmentRef::Null(), // FragRef
ResolveInfo::Default);
return true;
}
bool
GNULDBackend::finalizeStandardSymbols(FragmentLinker& pLinker)
{
if (LinkerConfig::Object == config().codeGenType())
return true;
ELFFileFormat* file_format = getOutputFormat();
// ----- section symbols ----- //
if (NULL != f_pPreInitArrayStart) {
if (!f_pPreInitArrayStart->hasFragRef()) {
f_pPreInitArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute);
f_pPreInitArrayStart->setValue(0x0);
}
}
if (NULL != f_pPreInitArrayEnd) {
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 (NULL != f_pInitArrayStart) {
if (!f_pInitArrayStart->hasFragRef()) {
f_pInitArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute);
f_pInitArrayStart->setValue(0x0);
}
}
if (NULL != f_pInitArrayEnd) {
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 (NULL != f_pFiniArrayStart) {
if (!f_pFiniArrayStart->hasFragRef()) {
f_pFiniArrayStart->resolveInfo()->setBinding(ResolveInfo::Absolute);
f_pFiniArrayStart->setValue(0x0);
}
}
if (NULL != f_pFiniArrayEnd) {
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 (NULL != f_pStack) {
if (!f_pStack->hasFragRef()) {
f_pStack->resolveInfo()->setBinding(ResolveInfo::Absolute);
f_pStack->setValue(0x0);
}
}
if (NULL != f_pDynamic) {
f_pDynamic->resolveInfo()->setBinding(ResolveInfo::Local);
f_pDynamic->setValue(file_format->getDynamic().addr());
f_pDynamic->setSize(file_format->getDynamic().size());
}
// ----- segment symbols ----- //
if (NULL != f_pExecutableStart) {
ELFSegment* exec_start = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD, 0x0, 0x0);
if (NULL != exec_start) {
if (ResolveInfo::ThreadLocal != f_pExecutableStart->type()) {
f_pExecutableStart->setValue(f_pExecutableStart->value() +
exec_start->vaddr());
}
}
else
f_pExecutableStart->setValue(0x0);
}
if (NULL != f_pEText || NULL != f_p_EText || NULL !=f_p__EText) {
ELFSegment* etext = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD,
llvm::ELF::PF_X,
llvm::ELF::PF_W);
if (NULL != etext) {
if (NULL != f_pEText && ResolveInfo::ThreadLocal != f_pEText->type()) {
f_pEText->setValue(f_pEText->value() +
etext->vaddr() +
etext->memsz());
}
if (NULL != f_p_EText && ResolveInfo::ThreadLocal != f_p_EText->type()) {
f_p_EText->setValue(f_p_EText->value() +
etext->vaddr() +
etext->memsz());
}
if (NULL != f_p__EText && ResolveInfo::ThreadLocal != f_p__EText->type()) {
f_p__EText->setValue(f_p__EText->value() +
etext->vaddr() +
etext->memsz());
}
}
else {
if (NULL != f_pEText)
f_pEText->setValue(0x0);
if (NULL != f_p_EText)
f_p_EText->setValue(0x0);
if (NULL != f_p__EText)
f_p__EText->setValue(0x0);
}
}
if (NULL != f_pEData || NULL != f_p_EData || NULL != f_pBSSStart ||
NULL != f_pEnd || NULL != f_p_End) {
ELFSegment* edata = m_ELFSegmentTable.find(llvm::ELF::PT_LOAD,
llvm::ELF::PF_W,
0x0);
if (NULL != edata) {
if (NULL != f_pEData && ResolveInfo::ThreadLocal != f_pEData->type()) {
f_pEData->setValue(f_pEData->value() +
edata->vaddr() +
edata->filesz());
}
if (NULL != f_p_EData && ResolveInfo::ThreadLocal != f_p_EData->type()) {
f_p_EData->setValue(f_p_EData->value() +
edata->vaddr() +
edata->filesz());
}
if (NULL != f_pBSSStart && ResolveInfo::ThreadLocal != f_pBSSStart->type()) {
f_pBSSStart->setValue(f_pBSSStart->value() +
edata->vaddr() +
edata->filesz());
}
if (NULL != f_pEnd && ResolveInfo::ThreadLocal != f_pEnd->type()) {
f_pEnd->setValue(f_pEnd->value() +
edata->vaddr() +
edata->memsz());
}
if (NULL != f_p_End && ResolveInfo::ThreadLocal != f_p_End->type()) {
f_p_End->setValue(f_p_End->value() +
edata->vaddr() +
edata->memsz());
}
}
else {
if (NULL != f_pEData)
f_pEData->setValue(0x0);
if (NULL != f_p_EData)
f_p_EData->setValue(0x0);
if (NULL != f_pBSSStart)
f_pBSSStart->setValue(0x0);
if (NULL != f_pEnd)
f_pEnd->setValue(0x0);
if (NULL != f_p_End)
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
ELFSegment* tls_seg = m_ELFSegmentTable.find(llvm::ELF::PT_TLS,
llvm::ELF::PF_R, 0x0);
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(NULL != m_pDynObjFileFormat);
return m_pDynObjFileFormat;
case LinkerConfig::Exec:
case LinkerConfig::Binary:
assert(NULL != m_pExecFileFormat);
return m_pExecFileFormat;
case LinkerConfig::Object:
assert(NULL != m_pObjectFileFormat);
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(NULL != m_pDynObjFileFormat);
return m_pDynObjFileFormat;
case LinkerConfig::Exec:
case LinkerConfig::Binary:
assert(NULL != m_pExecFileFormat);
return m_pExecFileFormat;
case LinkerConfig::Object:
assert(NULL != m_pObjectFileFormat);
return m_pObjectFileFormat;
default:
fatal(diag::unrecognized_output_file) << config().codeGenType();
return NULL;
}
}
void GNULDBackend::partialScanRelocation(Relocation& pReloc,
FragmentLinker& pLinker,
Module& pModule,
const LDSection& pSection)
{
// if we meet a section symbol
if (pReloc.symInfo()->type() == ResolveInfo::Section) {
LDSymbol* input_sym = pReloc.symInfo()->outSymbol();
// 1. update the relocation target offset
assert(input_sym->hasFragRef());
uint64_t offset = input_sym->fragRef()->getOutputOffset();
pReloc.target() += offset;
// 2. get output section symbol
// get the output LDSection which the symbol defined in
const LDSection& out_sect =
input_sym->fragRef()->frag()->getParent()->getSection();
ResolveInfo* sym_info = pModule.getSectionSymbolSet().get(out_sect)->resolveInfo();
// set relocation target symbol to the output section symbol's resolveInfo
pReloc.setSymInfo(sym_info);
}
}
/// 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(const Module& pModule, bool pIsStaticLink)
{
// 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 = pIsStaticLink ? 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 = pIsStaticLink ? 0 : 1;
size_t shstrtab = 1;
size_t hash = 0;
// number of local symbol in the .dynsym
size_t dynsym_local_cnt = 0;
/// compute the size of .symtab, .dynsym and .strtab
/// @{
Module::const_sym_iterator symbol;
const Module::SymbolTable& symbols = pModule.getSymbolTable();
size_t str_size = 0;
// compute the size of symbols in Local and File category
Module::const_sym_iterator symEnd = symbols.localEnd();
for (symbol = symbols.localBegin(); symbol != symEnd; ++symbol) {
str_size = (*symbol)->nameSize() + 1;
if (!pIsStaticLink && isDynamicSymbol(**symbol)) {
++dynsym;
if (ResolveInfo::Section != (*symbol)->type())
dynstr += str_size;
}
++symtab;
if (ResolveInfo::Section != (*symbol)->type())
strtab += str_size;
}
// compute the size of symbols in TLS category
symEnd = symbols.tlsEnd();
for (symbol = symbols.tlsBegin(); symbol != symEnd; ++symbol) {
str_size = (*symbol)->nameSize() + 1;
if (!pIsStaticLink) {
++dynsym;
if (ResolveInfo::Section != (*symbol)->type())
dynstr += str_size;
}
++symtab;
if (ResolveInfo::Section != (*symbol)->type())
strtab += str_size;
}
dynsym_local_cnt = dynsym;
// compute the size of the reset of symbols
symEnd = pModule.sym_end();
for (symbol = symbols.tlsEnd(); symbol != symEnd; ++symbol) {
str_size = (*symbol)->nameSize() + 1;
if (!pIsStaticLink && isDynamicSymbol(**symbol)) {
++dynsym;
if (ResolveInfo::Section != (*symbol)->type())
dynstr += str_size;
}
++symtab;
if (ResolveInfo::Section != (*symbol)->type())
strtab += str_size;
}
ELFFileFormat* file_format = getOutputFormat();
switch(config().codeGenType()) {
// compute size of .dynstr and .hash
case LinkerConfig::DynObj: {
// soname
if (!pIsStaticLink)
dynstr += pModule.name().size() + 1;
}
/** fall through **/
case LinkerConfig::Exec:
case LinkerConfig::Binary: {
// add DT_NEED strings into .dynstr and .dynamic
// Rules:
// 1. ignore --no-add-needed
// 2. force count in --no-as-needed
// 3. judge --as-needed
if (!pIsStaticLink) {
Module::const_lib_iterator lib, libEnd = pModule.lib_end();
for (lib = pModule.lib_begin(); lib != libEnd; ++lib) {
// --add-needed
if ((*lib)->attribute()->isAddNeeded()) {
// --no-as-needed
if (!(*lib)->attribute()->isAsNeeded()) {
dynstr += (*lib)->name().size() + 1;
dynamic().reserveNeedEntry();
}
// --as-needed
else if ((*lib)->isNeeded()) {
dynstr += (*lib)->name().size() + 1;
dynamic().reserveNeedEntry();
}
}
}
// compute .hash
// Both Elf32_Word and Elf64_Word are 4 bytes
hash = (2 + getHashBucketCount(dynsym, false) + dynsym) *
sizeof(llvm::ELF::Elf32_Word);
}
// 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);
// set .dynsym sh_info to one greater than the symbol table
// index of the last local symbol
file_format->getDynSymTab().setInfo(dynsym_local_cnt);
}
/* 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(symbols.numOfLocals() + 1);
break;
}
default:
fatal(diag::fatal_illegal_codegen_type) << pModule.name();
break;
} // end of switch
/// @}
/// reserve fixed entries in the .dynamic section.
/// @{
if (LinkerConfig::DynObj == config().codeGenType() ||
LinkerConfig::Exec == config().codeGenType() ||
LinkerConfig::Binary == config().codeGenType()) {
// 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
if (!pIsStaticLink)
dynamic().reserveEntries(*file_format);
file_format->getDynamic().setSize(dynamic().numOfBytes());
}
/// @}
/// compute the size of .shstrtab section.
/// @{
Module::const_iterator sect, sectEnd = pModule.end();
for (sect = pModule.begin(); sect != sectEnd; ++sect) {
// StackNote sections will always be in output!
if (0 != (*sect)->size() || LDFileFormat::StackNote == (*sect)->kind()) {
shstrtab += ((*sect)->name().size() + 1);
}
}
shstrtab += (strlen(".shstrtab") + 1);
file_format->getShStrTab().setSize(shstrtab);
/// @}
}
/// 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 (ResolveInfo::Section != pSymbol.type()) {
pSym.st_name = pStrtabsize;
strcpy((pStrtab + pStrtabsize), pSymbol.name());
}
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
pSym.st_name = pStrtabsize;
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);
// write out string
strcpy((pStrtab + pStrtabsize), pSymbol.name());
}
/// 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,
MemoryArea& pOutput)
{
ELFFileFormat* file_format = getOutputFormat();
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->start();
else if (config().targets().is64Bits())
symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region->start();
else {
fatal(diag::unsupported_bitclass) << config().targets().triple().str()
<< config().targets().bitclass();
}
// set up strtab_region
char* strtab = (char*)strtab_region->start();
strtab[0] = '\0';
// initialize the first ELF symbol
if (config().targets().is32Bits()) {
symtab32[0].st_name = 0;
symtab32[0].st_value = 0;
symtab32[0].st_size = 0;
symtab32[0].st_info = 0;
symtab32[0].st_other = 0;
symtab32[0].st_shndx = 0;
}
else { // must 64
symtab64[0].st_name = 0;
symtab64[0].st_value = 0;
symtab64[0].st_size = 0;
symtab64[0].st_info = 0;
symtab64[0].st_other = 0;
symtab64[0].st_shndx = 0;
}
bool sym_exist = false;
HashTableType::entry_type* entry = NULL;
if (LinkerConfig::Object == config().codeGenType()) {
entry = m_pSymIndexMap->insert(NULL, sym_exist);
entry->setValue(0);
}
size_t symtabIdx = 1;
size_t strtabsize = 1;
// compute size of .symtab, .dynsym and .strtab
Module::const_sym_iterator symbol;
Module::const_sym_iterator symEnd = pModule.sym_end();
for (symbol = pModule.sym_begin(); symbol != symEnd; ++symbol) {
// maintain output's symbol and index map if building .o file
if (LinkerConfig::Object == config().codeGenType()) {
entry = m_pSymIndexMap->insert(*symbol, sym_exist);
entry->setValue(symtabIdx);
}
if (config().targets().is32Bits())
emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize,
symtabIdx);
else
emitSymbol64(symtab64[symtabIdx], **symbol, strtab, strtabsize,
symtabIdx);
// sum up counters
++symtabIdx;
if (ResolveInfo::Section != (*symbol)->type())
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(const Module& pModule,
MemoryArea& pOutput)
{
ELFFileFormat* file_format = getOutputFormat();
if (!file_format->hasDynSymTab() ||
!file_format->hasDynStrTab() ||
!file_format->hasHashTab() ||
!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& hash_sect = file_format->getHashTab();
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* hash_region = pOutput.request(hash_sect.offset(),
hash_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->start();
else if (config().targets().is64Bits())
symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region->start();
else {
fatal(diag::unsupported_bitclass) << config().targets().triple().str()
<< config().targets().bitclass();
}
// initialize the first ELF symbol
if (config().targets().is32Bits()) {
symtab32[0].st_name = 0;
symtab32[0].st_value = 0;
symtab32[0].st_size = 0;
symtab32[0].st_info = 0;
symtab32[0].st_other = 0;
symtab32[0].st_shndx = 0;
}
else { // must 64
symtab64[0].st_name = 0;
symtab64[0].st_value = 0;
symtab64[0].st_size = 0;
symtab64[0].st_info = 0;
symtab64[0].st_other = 0;
symtab64[0].st_shndx = 0;
}
// set up strtab_region
char* strtab = (char*)strtab_region->start();
strtab[0] = '\0';
// add the first symbol into m_pSymIndexMap
entry = m_pSymIndexMap->insert(NULL, sym_exist);
entry->setValue(0);
size_t symtabIdx = 1;
size_t strtabsize = 1;
// emit of .dynsym, and .dynstr
Module::const_sym_iterator symbol;
const Module::SymbolTable& symbols = pModule.getSymbolTable();
// emit symbol in File and Local category if it's dynamic symbol
Module::const_sym_iterator symEnd = symbols.localEnd();
for (symbol = symbols.localBegin(); symbol != symEnd; ++symbol) {
if (!isDynamicSymbol(**symbol))
continue;
if (config().targets().is32Bits())
emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize,
symtabIdx);
else
emitSymbol64(symtab64[symtabIdx], **symbol, strtab, strtabsize,
symtabIdx);
// maintain output's symbol and index map
entry = m_pSymIndexMap->insert(*symbol, sym_exist);
entry->setValue(symtabIdx);
// sum up counters
++symtabIdx;
if (ResolveInfo::Section != (*symbol)->type())
strtabsize += (*symbol)->nameSize() + 1;
}
// emit symbols in TLS category, all symbols in TLS category shold be emitited
symEnd = symbols.tlsEnd();
for (symbol = symbols.tlsBegin(); symbol != symEnd; ++symbol) {
if (config().targets().is32Bits())
emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize,
symtabIdx);
else
emitSymbol64(symtab64[symtabIdx], **symbol, strtab, strtabsize,
symtabIdx);
// maintain output's symbol and index map
entry = m_pSymIndexMap->insert(*symbol, sym_exist);
entry->setValue(symtabIdx);
// sum up counters
++symtabIdx;
if (ResolveInfo::Section != (*symbol)->type())
strtabsize += (*symbol)->nameSize() + 1;
}
// emit the reset of the symbols if the symbol is dynamic symbol
symEnd = pModule.sym_end();
for (symbol = symbols.tlsEnd(); symbol != symEnd; ++symbol) {
if (!isDynamicSymbol(**symbol))
continue;
if (config().targets().is32Bits())
emitSymbol32(symtab32[symtabIdx], **symbol, strtab, strtabsize,
symtabIdx);
else
emitSymbol64(symtab64[symtabIdx], **symbol, strtab, strtabsize,
symtabIdx);
// maintain output's symbol and index map
entry = m_pSymIndexMap->insert(*symbol, sym_exist);
entry->setValue(symtabIdx);
// sum up counters
++symtabIdx;
if (ResolveInfo::Section != (*symbol)->type())
strtabsize += (*symbol)->nameSize() + 1;
}
// emit DT_NEED
// add DT_NEED strings into .dynstr
// Rules:
// 1. ignore --no-add-needed
// 2. force count in --no-as-needed
// 3. judge --as-needed
ELFDynamic::iterator dt_need = dynamic().needBegin();
Module::const_lib_iterator lib, libEnd = pModule.lib_end();
for (lib = pModule.lib_begin(); lib != libEnd; ++lib) {
// --add-needed
if ((*lib)->attribute()->isAddNeeded()) {
// --no-as-needed
if (!(*lib)->attribute()->isAsNeeded()) {
strcpy((strtab + strtabsize), (*lib)->name().c_str());
(*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
strtabsize += (*lib)->name().size() + 1;
++dt_need;
}
// --as-needed
else if ((*lib)->isNeeded()) {
strcpy((strtab + strtabsize), (*lib)->name().c_str());
(*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
strtabsize += (*lib)->name().size() + 1;
++dt_need;
}
}
}
// 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()) {
strcpy((strtab + strtabsize), pModule.name().c_str());
strtabsize += pModule.name().size() + 1;
}
// emit hash table
// FIXME: this verion only emit SVR4 hash section.
// Please add GNU new hash section
// both 32 and 64 bits hash table use 32-bit entry
// set up hash_region
uint32_t* word_array = (uint32_t*)hash_region->start();
uint32_t& nbucket = word_array[0];
uint32_t& nchain = word_array[1];
nbucket = getHashBucketCount(symtabIdx, false);
nchain = symtabIdx;
uint32_t* bucket = (word_array + 2);
uint32_t* chain = (bucket + nbucket);
// initialize bucket
bzero((void*)bucket, nbucket);
StringHash<ELF> hash_func;
if (config().targets().is32Bits()) {
for (size_t sym_idx=0; sym_idx < symtabIdx; ++sym_idx) {
llvm::StringRef name(strtab + symtab32[sym_idx].st_name);
size_t bucket_pos = hash_func(name) % nbucket;
chain[sym_idx] = bucket[bucket_pos];
bucket[bucket_pos] = sym_idx;
}
}
else if (config().targets().is64Bits()) {
for (size_t sym_idx=0; sym_idx < symtabIdx; ++sym_idx) {
llvm::StringRef name(strtab + symtab64[sym_idx].st_name);
size_t bucket_pos = hash_func(name) % nbucket;
chain[sym_idx] = bucket[bucket_pos];
bucket[bucket_pos] = sym_idx;
}
}
}
/// 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 = dyld();
LDSection& interp = getOutputFormat()->getInterp();
interp.setSize(std::strlen(dyld_name) + 1);
}
/// emitInterp - emit the .interp
void GNULDBackend::emitInterp(MemoryArea& 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 = dyld();
std::memcpy(region->start(), dyld_name, interp.size());
}
}
/// 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 0;
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::Regular:
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;
}
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
case LDFileFormat::Note:
return SHO_INTERP;
case LDFileFormat::EhFrame:
case LDFileFormat::EhFrameHdr:
case LDFileFormat::GCCExceptTable:
return SHO_EXCEPTION;
case LDFileFormat::MetaData:
case LDFileFormat::Debug:
default:
return SHO_UNDEFINED;
}
}
/// getSymbolSize
uint64_t GNULDBackend::getSymbolSize(const LDSymbol& pSymbol) const
{
// @ref Google gold linker: symtab.cc: 2780
// 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()->isLocal()) {
switch (pSymbol.type()) {
case ResolveInfo::NoType:
case ResolveInfo::File:
return llvm::ELF::SHN_ABS;
}
}
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(LDSymbol* pSymbol) const
{
HashTableType::iterator entry = m_pSymIndexMap->find(pSymbol);
return entry.getEntry()->value();
}
/// allocateCommonSymbols - allocate common symbols in the corresponding
/// sections. This is executed at pre-layout stage.
/// @refer Google gold linker: common.cc: 214
bool
GNULDBackend::allocateCommonSymbols(Module& pModule)
{
SymbolCategory& symbol_list = pModule.getSymbolTable();
if (symbol_list.emptyCommons() && symbol_list.emptyLocals())
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());
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
// allocate TLS common symbol in tbss section
tbss_offset += ObjectBuilder::AppendFragment(*frag,
*tbss_sect_data,
(*com_sym)->value());
}
else {
bss_offset += ObjectBuilder::AppendFragment(*frag,
*bss_sect_data,
(*com_sym)->value());
}
}
}
// 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());
(*com_sym)->setFragmentRef(FragmentRef::Create(*frag, 0));
if (ResolveInfo::ThreadLocal == (*com_sym)->type()) {
// allocate TLS common symbol in tbss section
tbss_offset += ObjectBuilder::AppendFragment(*frag,
*tbss_sect_data,
(*com_sym)->value());
}
else {
bss_offset += ObjectBuilder::AppendFragment(*frag,
*bss_sect_data,
(*com_sym)->value());
}
}
bss_sect.setSize(bss_offset);
tbss_sect.setSize(tbss_offset);
symbol_list.changeCommonsToGlobal();
return true;
}
/// createProgramHdrs - base on output sections to create the program headers
void GNULDBackend::createProgramHdrs(Module& pModule,
const FragmentLinker& pLinker)
{
ELFFileFormat *file_format = getOutputFormat();
// make PT_PHDR
m_ELFSegmentTable.produce(llvm::ELF::PT_PHDR);
// make PT_INTERP
if (file_format->hasInterp()) {
ELFSegment* interp_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_INTERP);
interp_seg->addSection(&file_format->getInterp());
}
uint32_t cur_flag, prev_flag = getSegmentFlag(0);
ELFSegment* load_seg = NULL;
// make possible PT_LOAD segments
Module::iterator sect, sect_end = pModule.end();
for (sect = pModule.begin(); sect != sect_end; ++sect) {
if (0 == ((*sect)->flag() & llvm::ELF::SHF_ALLOC) &&
LDFileFormat::Null != (*sect)->kind())
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() &&
config().scripts().addressMap().find(".bss") !=
(config().scripts().addressMap().end())) {
// 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())) &&
(config().scripts().addressMap().find((*sect)->name()) !=
config().scripts().addressMap().end()))
// 4. create PT_LOAD for sections in address map except for text, data,
// and bss
createPT_LOAD = true;
}
if (createPT_LOAD) {
// create new PT_LOAD segment
load_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_LOAD, cur_flag);
load_seg->setAlign(abiPageSize());
}
assert(NULL != load_seg);
load_seg->addSection((*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 = m_ELFSegmentTable.produce(llvm::ELF::PT_DYNAMIC,
llvm::ELF::PF_R |
llvm::ELF::PF_W);
dyn_seg->addSection(&file_format->getDynamic());
}
if (config().options().hasRelro()) {
// make PT_GNU_RELRO
ELFSegment* relro_seg = m_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::sect_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->addSection(*sect);
}
}
}
}
// make PT_GNU_EH_FRAME
if (file_format->hasEhFrameHdr()) {
ELFSegment* eh_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_GNU_EH_FRAME);
eh_seg->addSection(&file_format->getEhFrameHdr());
}
// make PT_TLS
if (file_format->hasTData() || file_format->hasTBSS()) {
ELFSegment* tls_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_TLS);
if (file_format->hasTData())
tls_seg->addSection(&file_format->getTData());
if (file_format->hasTBSS())
tls_seg->addSection(&file_format->getTBSS());
}
// make PT_GNU_STACK
if (file_format->hasStackNote()) {
m_ELFSegmentTable.produce(llvm::ELF::PT_GNU_STACK,
llvm::ELF::PF_R |
llvm::ELF::PF_W |
getSegmentFlag(file_format->getStackNote().flag()));
}
// create target dependent segments
doCreateProgramHdrs(pModule, pLinker);
}
/// setupProgramHdrs - set up the attributes of segments
void GNULDBackend::setupProgramHdrs(const FragmentLinker& pLinker)
{
// update segment info
ELFSegmentFactory::iterator seg, seg_end = m_ELFSegmentTable.end();
for (seg = m_ELFSegmentTable.begin(); seg != seg_end; ++seg) {
ELFSegment& segment = *seg;
// update PT_PHDR
if (llvm::ELF::PT_PHDR == segment.type()) {
uint64_t offset, phdr_size;
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);
}
segment.setOffset(offset);
segment.setVaddr(segmentStartAddr(pLinker) + offset);
segment.setPaddr(segment.vaddr());
segment.setFilesz(numOfSegments() * phdr_size);
segment.setMemsz(numOfSegments() * phdr_size);
segment.setAlign(config().targets().bitclass() / 8);
continue;
}
// bypass if there is no section in this segment (e.g., PT_GNU_STACK)
if (segment.numOfSections() == 0)
continue;
segment.setOffset(segment.front()->offset());
if (llvm::ELF::PT_LOAD == segment.type() &&
LDFileFormat::Null == segment.front()->kind())
segment.setVaddr(segmentStartAddr(pLinker));
else
segment.setVaddr(segment.front()->addr());
segment.setPaddr(segment.vaddr());
const LDSection* last_sect = segment.back();
assert(NULL != last_sect);
uint64_t file_size = last_sect->offset() - segment.offset();
if (LDFileFormat::BSS != last_sect->kind())
file_size += last_sect->size();
segment.setFilesz(file_size);
segment.setMemsz(last_sect->addr() - segment.vaddr() + last_sect->size());
}
}
/// setupGNUStackInfo - setup the section flag of .note.GNU-stack in output
/// @ref gold linker: layout.cc:2608
void GNULDBackend::setupGNUStackInfo(Module& pModule, FragmentLinker& pLinker)
{
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 (NULL != sect) {
++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 (isDefaultExecStack())
flag = llvm::ELF::SHF_EXECINSTR;
}
if (getOutputFormat()->hasStackNote()) {
getOutputFormat()->getStackNote().setFlag(flag);
}
}
/// setupRelro - setup the offset constraint of PT_RELRO
void GNULDBackend::setupRelro(Module& pModule)
{
assert(config().options().hasRelro());
// if -z relro is given, we need to adjust sections' offset again, and let
// PT_GNU_RELRO end on a common page boundary
Module::iterator sect = pModule.begin();
for (Module::iterator sect_end = pModule.end(); sect != sect_end; ++sect) {
// find the first non-relro section
if (getSectionOrder(**sect) > SHO_RELRO_LAST)
break;
}
// align the first non-relro section to page boundary
uint64_t offset = (*sect)->offset();
alignAddress(offset, commonPageSize());
(*sect)->setOffset(offset);
// 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.offset() + got.size() != offset)) {
got.setOffset(offset - got.size());
}
// set up remaining section's offset
setOutputSectionOffset(pModule, ++sect, pModule.end());
}
/// setOutputSectionOffset - helper function to set a group of output sections'
/// offset, and set pSectBegin to pStartOffset if pStartOffset is not -1U.
void GNULDBackend::setOutputSectionOffset(Module& pModule,
Module::iterator pSectBegin,
Module::iterator pSectEnd,
uint64_t pStartOffset)
{
if (pSectBegin == pModule.end())
return;
assert(pSectEnd == pModule.end() ||
(pSectEnd != pModule.end() &&
(*pSectBegin)->index() <= (*pSectEnd)->index()));
if (pStartOffset != -1U) {
(*pSectBegin)->setOffset(pStartOffset);
++pSectBegin;
}
// set up the "cur" and "prev" iterator
Module::iterator cur = pSectBegin;
Module::iterator prev = pSectBegin;
if (cur != pModule.begin())
--prev;
else
++cur;
for (; cur != pSectEnd; ++cur, ++prev) {
uint64_t offset = 0x0;
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);
}
}
/// setOutputSectionOffset - helper function to set output sections' address
void GNULDBackend::setOutputSectionAddress(FragmentLinker& pLinker,
Module& pModule,
Module::iterator pSectBegin,
Module::iterator pSectEnd)
{
if (pSectBegin == pModule.end())
return;
assert(pSectEnd == pModule.end() ||
(pSectEnd != pModule.end() &&
(*pSectBegin)->index() <= (*pSectEnd)->index()));
for (ELFSegmentFactory::iterator seg = elfSegmentTable().begin(),
segEnd = elfSegmentTable().end(), prev = elfSegmentTable().end();
seg != segEnd; prev = seg, ++seg) {
if (llvm::ELF::PT_LOAD != (*seg).type())
continue;
uint64_t start_addr = 0x0;
ScriptOptions::AddressMap::const_iterator mapping;
if ((*seg).front()->kind() == LDFileFormat::Null)
mapping = config().scripts().addressMap().find(".text");
else if ((*seg).isDataSegment())
mapping = config().scripts().addressMap().find(".data");
else if ((*seg).isBssSegment())
mapping = config().scripts().addressMap().find(".bss");
else
mapping = config().scripts().addressMap().find((*seg).front()->name());
if (mapping != config().scripts().addressMap().end()) {
// check address mapping
start_addr = mapping.getEntry()->value();
if ((*seg).front()->kind() != LDFileFormat::Null) {
const uint64_t remainder = start_addr % abiPageSize();
if (remainder != (*seg).front()->offset() % abiPageSize()) {
uint64_t padding = abiPageSize() + remainder -
(*seg).front()->offset() % abiPageSize();
setOutputSectionOffset(pModule,
pModule.begin() + (*seg).front()->index(),
pModule.end(),
(*seg).front()->offset() + padding);
if (config().options().hasRelro())
setupRelro(pModule);
}
}
}
else {
if ((*seg).front()->kind() == LDFileFormat::Null) {
// 1st PT_LOAD
start_addr = segmentStartAddr(pLinker);
}
else if ((*prev).front()->kind() == LDFileFormat::Null) {
// prev segment is 1st PT_LOAD
start_addr = segmentStartAddr(pLinker) + (*seg).front()->offset();
}
else {
// Others
start_addr = (*prev).front()->addr() + (*seg).front()->offset();
}
// padding
if (((*seg).front()->offset() & (abiPageSize() - 1)) != 0)
start_addr += abiPageSize();
}
for (ELFSegment::sect_iterator sect = (*seg).begin(),
sectEnd = (*seg).end(); sect != sectEnd; ++sect) {
if ((*sect)->index() < (*pSectBegin)->index())
continue;
if (LDFileFormat::Null == (*sect)->kind())
continue;
if (sect == pSectEnd)
return;
if (sect != (*seg).begin())
(*sect)->setAddr(start_addr + (*sect)->offset() -
(*seg).front()->offset());
else
(*sect)->setAddr(start_addr);
}
}
}
/// layout - layout method
void GNULDBackend::layout(Module& pModule, FragmentLinker& pLinker)
{
std::vector<SHOEntry> output_list;
// 1. determine what sections will go into final output, and push the needed
// sections into output_list for later processing
for (Module::iterator it = pModule.begin(), ie = pModule.end(); it != ie;
++it) {
switch ((*it)->kind()) {
// take NULL and StackNote directly
case LDFileFormat::Null:
case LDFileFormat::StackNote:
output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
break;
// ignore if section size is 0
case LDFileFormat::Regular:
case LDFileFormat::Target:
case LDFileFormat::MetaData:
case LDFileFormat::BSS:
case LDFileFormat::Debug:
case LDFileFormat::EhFrame:
case LDFileFormat::GCCExceptTable:
case LDFileFormat::NamePool:
case LDFileFormat::Relocation:
case LDFileFormat::Note:
case LDFileFormat::EhFrameHdr:
if (0 != (*it)->size()) {
output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
}
break;
case LDFileFormat::Group:
if (LinkerConfig::Object == config().codeGenType()) {
//TODO: support incremental linking
;
}
break;
case LDFileFormat::Version:
if (0 != (*it)->size()) {
output_list.push_back(std::make_pair(*it, getSectionOrder(**it)));
warning(diag::warn_unsupported_symbolic_versioning) << (*it)->name();
}
break;
default:
if (0 != (*it)->size()) {
error(diag::err_unsupported_section) << (*it)->name() << (*it)->kind();
}
break;
}
} // end of for
// 2. sort output section orders
std::stable_sort(output_list.begin(), output_list.end(), SHOCompare());
// 3. update output sections in Module
pModule.getSectionTable().clear();
for(size_t index = 0; index < output_list.size(); ++index) {
(output_list[index].first)->setIndex(index);
pModule.getSectionTable().push_back(output_list[index].first);
}
// 4. create program headers
if (LinkerConfig::Object != config().codeGenType()) {
createProgramHdrs(pModule, pLinker);
}
// 5. set output section offset
setOutputSectionOffset(pModule, pModule.begin(), pModule.end(), 0x0);
}
/// preLayout - Backend can do any needed modification before layout
void GNULDBackend::preLayout(Module& pModule, FragmentLinker& pLinker)
{
// prelayout target first
doPreLayout(pLinker);
if (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();
}
// change .tbss and .tdata section symbol from Local to TLS category
if (NULL != f_pTDATA)
pModule.getSymbolTable().changeLocalToTLS(*f_pTDATA);
if (NULL != f_pTBSS)
pModule.getSymbolTable().changeLocalToTLS(*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 (NULL == output_sect) {
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(NULL != input_link && "Illegal input relocation section.");
// get the linked output section
LDSection* output_link = pModule.getSection(input_link->name());
assert(NULL != output_link);
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, pLinker);
}
/// postLayout - Backend can do any needed modification after layout
void GNULDBackend::postLayout(Module& pModule,
FragmentLinker& pLinker)
{
// 1. set up section address and segment attributes
if (LinkerConfig::Object != config().codeGenType()) {
if (config().options().hasRelro()) {
// 1.1 set up the offset constraint of PT_RELRO
setupRelro(pModule);
}
// 1.2 set up the output sections' address
setOutputSectionAddress(pLinker, pModule, pModule.begin(), pModule.end());
// 1.3 do relaxation
relax(pModule, pLinker);
// 1.4 set up the attributes of program headers
setupProgramHdrs(pLinker);
}
// 2. target specific post layout
doPostLayout(pModule, pLinker);
}
void GNULDBackend::postProcessing(FragmentLinker& pLinker, MemoryArea& pOutput)
{
if (config().options().hasEhFrameHdr() && getOutputFormat()->hasEhFrame()) {
// emit eh_frame_hdr
if (config().targets().is32Bits())
m_pEhFrameHdr->emitOutput<32>(pOutput);
}
}
/// getHashBucketCount - calculate hash bucket count.
/// @ref Google gold linker, dynobj.cc:791
unsigned GNULDBackend::getHashBucketCount(unsigned pNumOfSymbols,
bool pIsGNUStyle)
{
// @ref Google gold, dynobj.cc:loc 791
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;
}
/// isDynamicSymbol
/// @ref Google gold linker: symtab.cc:311
bool GNULDBackend::isDynamicSymbol(const LDSymbol& pSymbol)
{
// 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 ||
pSymbol.resolveInfo()->type() == ResolveInfo::ThreadLocal) {
return true;
}
}
return false;
}
/// isDynamicSymbol
/// @ref Google gold linker: symtab.cc:311
bool GNULDBackend::isDynamicSymbol(const ResolveInfo& pResolveInfo)
{
// 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 ||
pResolveInfo.type() == ResolveInfo::ThreadLocal) {
return true;
}
}
return false;
}
/// commonPageSize - the common page size of the target machine.
/// @ref gold linker: target.h:135
uint64_t GNULDBackend::commonPageSize() const
{
if (config().options().commPageSize() > 0)
return std::min(config().options().commPageSize(), abiPageSize());
else
return std::min(static_cast<uint64_t>(0x1000), abiPageSize());
}
/// abiPageSize - the abi page size of the target machine.
/// @ref gold linker: target.h:125
uint64_t GNULDBackend::abiPageSize() const
{
if (config().options().maxPageSize() > 0)
return config().options().maxPageSize();
else
return static_cast<uint64_t>(0x1000);
}
/// isSymbolPreemtible - whether the symbol can be preemted by other
/// link unit
/// @ref Google gold linker, symtab.h:551
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
/// @ref Google gold linker, symtab.h:645
bool GNULDBackend::symbolNeedsDynRel(const FragmentLinker& pLinker,
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;
if (pSym.isAbsolute())
return false;
if (pLinker.isOutputPIC() && isAbsReloc)
return true;
if (pSymHasPLT && ResolveInfo::Function == pSym.type())
return false;
if (!pLinker.isOutputPIC() && pSymHasPLT)
return false;
if (pSym.isDyn() || pSym.isUndef() ||
isSymbolPreemptible(pSym))
return true;
return false;
}
/// symbolNeedsPLT - return whether the symbol needs a PLT entry
/// @ref Google gold linker, symtab.h:596
bool GNULDBackend::symbolNeedsPLT(const FragmentLinker& pLinker,
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 (pLinker.isStaticLink() && !pLinker.isOutputPIC())
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
/// @ref Google gold linker, Symbol::final_value_is_known
bool GNULDBackend::symbolFinalValueIsKnown(const FragmentLinker& pLinker,
const ResolveInfo& pSym) const
{
// if the output is pic code or if not executables, symbols' value may change
// at runtime
if (pLinker.isOutputPIC() ||
(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 pLinker.isStaticLink();
}
/// symbolNeedsCopyReloc - return whether the symbol needs a copy relocation
bool GNULDBackend::symbolNeedsCopyReloc(const FragmentLinker& pLinker,
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 (pLinker.isOutputPIC() ||
!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(NULL != f_pTDATA);
return *f_pTDATA;
}
const LDSymbol& GNULDBackend::getTDATASymbol() const
{
assert(NULL != f_pTDATA);
return *f_pTDATA;
}
LDSymbol& GNULDBackend::getTBSSSymbol()
{
assert(NULL != f_pTBSS);
return *f_pTBSS;
}
const LDSymbol& GNULDBackend::getTBSSSymbol() const
{
assert(NULL != f_pTBSS);
return *f_pTBSS;
}
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;
}
/// initBRIslandFactory - initialize the branch island factory for relaxation
bool GNULDBackend::initBRIslandFactory()
{
if (NULL == m_pBRIslandFactory) {
m_pBRIslandFactory = new BranchIslandFactory(maxBranchOffset());
}
return true;
}
/// initStubFactory - initialize the stub factory for relaxation
bool GNULDBackend::initStubFactory()
{
if (NULL == m_pStubFactory) {
m_pStubFactory = new StubFactory();
}
return true;
}
bool GNULDBackend::relax(Module& pModule, FragmentLinker& pLinker)
{
if (!mayRelax())
return true;
bool finished = true;
do {
if (doRelax(pModule, pLinker, finished)) {
// If the sections (e.g., .text) are relaxed, the layout is also changed
// We need to do the following:
// 1. set up the offset
setOutputSectionOffset(pModule, pModule.begin(), pModule.end());
// 2. set up the offset constraint of PT_RELRO
if (config().options().hasRelro())
setupRelro(pModule);
// 3. set up the output sections' address
setOutputSectionAddress(pLinker, pModule, pModule.begin(), pModule.end());
}
} while (!finished);
return true;
}