blob: b82af7304f42a5799638ae58f1389156b95313d4 [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 <llvm/Support/ELF.h>
#include <mcld/ADT/SizeTraits.h>
#include <mcld/Target/GNULDBackend.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/MC/MCLDOutput.h>
#include <mcld/MC/MCLDInputTree.h>
#include <mcld/MC/SymbolCategory.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/Layout.h>
#include <mcld/Support/MemoryArea.h>
#include <mcld/Support/MemoryRegion.h>
#include <string>
#include <cstring>
#include <cassert>
using namespace mcld;
//===----------------------------------------------------------------------===//
// GNULDBackend
GNULDBackend::GNULDBackend()
: m_pArchiveReader(0),
m_pObjectReader(0),
m_pDynObjReader(0),
m_pObjectWriter(0),
m_pDynObjWriter(0),
m_pDynObjFileFormat(0),
m_pExecFileFormat(0),
m_ELFSegmentTable(9)// magic number
{
m_pSymIndexMap = new HashTableType(1024);
}
GNULDBackend::~GNULDBackend()
{
if (m_pArchiveReader)
delete m_pArchiveReader;
if (m_pObjectReader)
delete m_pObjectReader;
if (m_pDynObjReader)
delete m_pDynObjReader;
if (m_pObjectWriter)
delete m_pObjectWriter;
if (m_pDynObjWriter)
delete m_pDynObjWriter;
if (m_pDynObjFileFormat)
delete m_pDynObjFileFormat;
if (m_pExecFileFormat)
delete m_pExecFileFormat;
if(m_pSymIndexMap)
delete m_pSymIndexMap;
}
size_t GNULDBackend::sectionStartOffset() const
{
// FIXME: use fixed offset, we need 10 segments by default
return sizeof(llvm::ELF::Elf64_Ehdr)+10*sizeof(llvm::ELF::Elf64_Phdr);
}
bool GNULDBackend::initArchiveReader(MCLinker&, MCLDInfo &pInfo)
{
if (0 == m_pArchiveReader)
{
LDReader::Endian isLittleEndian = LDReader::LittleEndian;
m_pArchiveReader = new GNUArchiveReader(pInfo, isLittleEndian);
}
return true;
}
bool GNULDBackend::initObjectReader(MCLinker& pLinker)
{
if (0 == m_pObjectReader)
m_pObjectReader = new ELFObjectReader(*this, pLinker);
return true;
}
bool GNULDBackend::initDynObjReader(MCLinker& pLinker)
{
if (0 == m_pDynObjReader)
m_pDynObjReader = new ELFDynObjReader(*this, pLinker);
return true;
}
bool GNULDBackend::initObjectWriter(MCLinker&)
{
// TODO
return true;
}
bool GNULDBackend::initDynObjWriter(MCLinker& pLinker)
{
if (0 == m_pDynObjWriter)
m_pDynObjWriter = new ELFDynObjWriter(*this, pLinker);
return true;
}
bool GNULDBackend::initExecSections(MCLinker& pMCLinker)
{
if (0 == m_pExecFileFormat)
m_pExecFileFormat = new ELFExecFileFormat(*this);
// initialize standard sections
m_pExecFileFormat->initStdSections(pMCLinker);
return true;
}
bool GNULDBackend::initDynObjSections(MCLinker& pMCLinker)
{
if (0 == m_pDynObjFileFormat)
m_pDynObjFileFormat = new ELFDynObjFileFormat(*this);
// initialize standard sections
m_pDynObjFileFormat->initStdSections(pMCLinker);
return true;
}
bool GNULDBackend::initStandardSymbols(MCLinker& pLinker)
{
return true;
}
GNUArchiveReader *GNULDBackend::getArchiveReader()
{
assert(0 != m_pArchiveReader);
return m_pArchiveReader;
}
GNUArchiveReader *GNULDBackend::getArchiveReader() const
{
assert(0 != m_pArchiveReader);
return m_pArchiveReader;
}
ELFObjectReader *GNULDBackend::getObjectReader()
{
assert(0 != m_pObjectReader);
return m_pObjectReader;
}
ELFObjectReader *GNULDBackend::getObjectReader() const
{
assert(0 != m_pObjectReader);
return m_pObjectReader;
}
ELFDynObjReader *GNULDBackend::getDynObjReader()
{
assert(0 != m_pDynObjReader);
return m_pDynObjReader;
}
ELFDynObjReader *GNULDBackend::getDynObjReader() const
{
assert(0 != m_pDynObjReader);
return m_pDynObjReader;
}
ELFObjectWriter *GNULDBackend::getObjectWriter()
{
// TODO
return NULL;
}
ELFObjectWriter *GNULDBackend::getObjectWriter() const
{
// TODO
return NULL;
}
ELFDynObjWriter *GNULDBackend::getDynObjWriter()
{
assert(0 != m_pDynObjWriter);
return m_pDynObjWriter;
}
ELFDynObjWriter *GNULDBackend::getDynObjWriter() const
{
assert(0 != m_pDynObjWriter);
return m_pDynObjWriter;
}
ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat()
{
assert(0 != m_pDynObjFileFormat);
return m_pDynObjFileFormat;
}
ELFDynObjFileFormat* GNULDBackend::getDynObjFileFormat() const
{
assert(0 != m_pDynObjFileFormat);
return m_pDynObjFileFormat;
}
ELFExecFileFormat* GNULDBackend::getExecFileFormat()
{
assert(0 != m_pExecFileFormat);
return m_pExecFileFormat;
}
ELFExecFileFormat* GNULDBackend::getExecFileFormat() const
{
assert(0 != m_pExecFileFormat);
return m_pExecFileFormat;
}
/// sizeNamePools - compute the size of regular name pools
/// In ELF executable files, regular name pools are .symtab, .strtab,
/// .dynsym, .dynstr, and .hash
void
GNULDBackend::sizeNamePools(const Output& pOutput,
const SymbolCategory& pSymbols,
const MCLDInfo& pLDInfo)
{
// size of string tables starts from 1 to hold the null character in their
// first byte
size_t symtab = 1;
size_t dynsym = 1;
// 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 strtab = 1;
size_t dynstr = 1;
size_t hash = 0;
// compute size of .symtab, .dynsym and .strtab
SymbolCategory::const_iterator symbol;
SymbolCategory::const_iterator symEnd = pSymbols.end();
for (symbol = pSymbols.begin(); symbol != symEnd; ++symbol) {
size_t str_size = (*symbol)->nameSize() + 1;
if (isDynamicSymbol(**symbol, pOutput)) {
++dynsym;
dynstr += str_size;
}
++symtab;
strtab += str_size;
}
ELFFileFormat* file_format = NULL;
switch(pOutput.type()) {
// compute size of .dynstr and .hash
case Output::DynObj:
file_format = getDynObjFileFormat();
break;
case Output::Exec:
file_format = getExecFileFormat();
break;
case Output::Object:
default:
// TODO: not support yet
return;
}
switch(pOutput.type()) {
// compute size of .dynstr and .hash
case Output::DynObj:
case Output::Exec: {
// 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
InputTree::const_bfs_iterator input, inputEnd = pLDInfo.inputs().bfs_end();
for (input = pLDInfo.inputs().bfs_begin(); input != inputEnd; ++input) {
if (Input::DynObj == (*input)->type()) {
// --add-needed
if ((*input)->attribute()->isAddNeeded()) {
// --no-as-needed
if (!(*input)->attribute()->isAsNeeded()) {
dynstr += (*input)->name().size() + 1;
dynamic().reserveNeedEntry();
}
// --as-needed
else if ((*input)->isNeeded()) {
dynstr += (*input)->name().size() + 1;
dynamic().reserveNeedEntry();
}
}
}
} // for
// compute .hash
// Both Elf32_Word and Elf64_Word are 4 bytes
hash = (2 + getHashBucketCount(dynsym, false) + dynsym) *
sizeof(llvm::ELF::Elf32_Word);
// set size
dynstr += pOutput.name().size() + 1;
if (32 == bitclass())
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);
}
/* fall through */
case Output::Object: {
if (32 == bitclass())
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);
break;
}
} // end of switch
// reserve fixed entries in the .dynamic section.
if (Output::DynObj == pOutput.type() || Output::Exec == pOutput.type()) {
// 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(pLDInfo, *file_format);
file_format->getDynamic().setSize(dynamic().numOfBytes());
}
}
/// 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(Output& pOutput,
SymbolCategory& pSymbols,
const Layout& pLayout,
const MCLDInfo& pLDInfo)
{
assert(pOutput.hasMemArea());
bool sym_exist = false;
HashTableType::entry_type* entry = 0;
ELFFileFormat* file_format = NULL;
switch(pOutput.type()) {
// compute size of .dynstr and .hash
case Output::DynObj:
file_format = getDynObjFileFormat();
break;
case Output::Exec:
file_format = getExecFileFormat();
break;
case Output::Object:
default:
// add first symbol into m_pSymIndexMap
entry = m_pSymIndexMap->insert(NULL, sym_exist);
entry->setValue(0);
// TODO: not support yet
return;
}
LDSection& symtab_sect = file_format->getSymTab();
LDSection& strtab_sect = file_format->getStrTab();
MemoryRegion* symtab_region = pOutput.memArea()->request(symtab_sect.offset(),
symtab_sect.size());
MemoryRegion* strtab_region = pOutput.memArea()->request(strtab_sect.offset(),
strtab_sect.size());
// set up symtab_region
llvm::ELF::Elf32_Sym* symtab32 = NULL;
llvm::ELF::Elf64_Sym* symtab64 = NULL;
if (32 == bitclass())
symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region->start();
else if (64 == bitclass())
symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region->start();
else
llvm::report_fatal_error(llvm::Twine("unsupported bitclass ") +
llvm::Twine(bitclass()) +
llvm::Twine(".\n"));
// set up strtab_region
char* strtab = (char*)strtab_region->start();
strtab[0] = '\0';
// initialize the first ELF symbol
if (32 == bitclass()) {
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;
}
size_t symtabIdx = 1;
size_t strtabsize = 1;
// compute size of .symtab, .dynsym and .strtab
SymbolCategory::iterator symbol;
SymbolCategory::iterator symEnd = pSymbols.end();
for (symbol = pSymbols.begin(); symbol != symEnd; ++symbol) {
// maintain output's symbol and index map if building .o file
if (Output::Object == pOutput.type()) {
entry = m_pSymIndexMap->insert(NULL, sym_exist);
entry->setValue(symtabIdx);
}
// FIXME: check the endian between host and target
// write out symbol
if (32 == bitclass()) {
symtab32[symtabIdx].st_name = strtabsize;
symtab32[symtabIdx].st_value = getSymbolValue(**symbol);
symtab32[symtabIdx].st_size = getSymbolSize(**symbol);
symtab32[symtabIdx].st_info = getSymbolInfo(**symbol);
symtab32[symtabIdx].st_other = (*symbol)->visibility();
symtab32[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout);
}
else { // must 64
symtab64[symtabIdx].st_name = strtabsize;
symtab64[symtabIdx].st_value = getSymbolValue(**symbol);
symtab64[symtabIdx].st_size = getSymbolSize(**symbol);
symtab64[symtabIdx].st_info = getSymbolInfo(**symbol);
symtab64[symtabIdx].st_other = (*symbol)->visibility();
symtab64[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout);
}
// write out string
strcpy((strtab + strtabsize), (*symbol)->name());
// write out
// sum up counters
++symtabIdx;
strtabsize += (*symbol)->nameSize() + 1;
}
}
/// emitNamePools - 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(Output& pOutput,
SymbolCategory& pSymbols,
const Layout& pLayout,
const MCLDInfo& pLDInfo)
{
assert(pOutput.hasMemArea());
ELFFileFormat* file_format = NULL;
bool sym_exist = false;
HashTableType::entry_type* entry = 0;
switch(pOutput.type()) {
// compute size of .dynstr and .hash
case Output::DynObj:
file_format = getDynObjFileFormat();
break;
case Output::Exec:
file_format = getExecFileFormat();
break;
case Output::Object:
default:
// TODO: not support yet
return;
}
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.memArea()->request(symtab_sect.offset(),
symtab_sect.size());
MemoryRegion* strtab_region = pOutput.memArea()->request(strtab_sect.offset(),
strtab_sect.size());
MemoryRegion* hash_region = pOutput.memArea()->request(hash_sect.offset(),
hash_sect.size());
MemoryRegion* dyn_region = pOutput.memArea()->request(dyn_sect.offset(),
dyn_sect.size());
// set up symtab_region
llvm::ELF::Elf32_Sym* symtab32 = NULL;
llvm::ELF::Elf64_Sym* symtab64 = NULL;
if (32 == bitclass())
symtab32 = (llvm::ELF::Elf32_Sym*)symtab_region->start();
else if (64 == bitclass())
symtab64 = (llvm::ELF::Elf64_Sym*)symtab_region->start();
else
llvm::report_fatal_error(llvm::Twine("unsupported bitclass ") +
llvm::Twine(bitclass()) +
llvm::Twine(".\n"));
// initialize the first ELF symbol
if (32 == bitclass()) {
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
SymbolCategory::iterator symbol;
SymbolCategory::iterator symEnd = pSymbols.end();
for (symbol = pSymbols.begin(); symbol != symEnd; ++symbol) {
if (!isDynamicSymbol(**symbol, pOutput))
continue;
// maintain output's symbol and index map
entry = m_pSymIndexMap->insert(*symbol, sym_exist);
entry->setValue(symtabIdx);
// FIXME: check the endian between host and target
// write out symbol
if (32 == bitclass()) {
symtab32[symtabIdx].st_name = strtabsize;
symtab32[symtabIdx].st_value = (*symbol)->value();
symtab32[symtabIdx].st_size = getSymbolSize(**symbol);
symtab32[symtabIdx].st_info = getSymbolInfo(**symbol);
symtab32[symtabIdx].st_other = (*symbol)->visibility();
symtab32[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout);
}
else { // must 64
symtab64[symtabIdx].st_name = strtabsize;
symtab64[symtabIdx].st_value = (*symbol)->value();
symtab64[symtabIdx].st_size = getSymbolSize(**symbol);
symtab64[symtabIdx].st_info = getSymbolInfo(**symbol);
symtab64[symtabIdx].st_other = (*symbol)->visibility();
symtab64[symtabIdx].st_shndx = getSymbolShndx(**symbol, pLayout);
}
// write out string
strcpy((strtab + strtabsize), (*symbol)->name());
// sum up counters
++symtabIdx;
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();
InputTree::const_bfs_iterator input, inputEnd = pLDInfo.inputs().bfs_end();
for (input = pLDInfo.inputs().bfs_begin(); input != inputEnd; ++input) {
if (Input::DynObj == (*input)->type()) {
// --add-needed
if ((*input)->attribute()->isAddNeeded()) {
// --no-as-needed
if (!(*input)->attribute()->isAsNeeded()) {
strcpy((strtab + strtabsize), (*input)->name().c_str());
(*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
strtabsize += (*input)->name().size() + 1;
++dt_need;
}
// --as-needed
else if ((*input)->isNeeded()) {
strcpy((strtab + strtabsize), (*input)->name().c_str());
(*dt_need)->setValue(llvm::ELF::DT_NEEDED, strtabsize);
strtabsize += (*input)->name().size() + 1;
++dt_need;
}
}
}
} // for
// emit soname
// initialize value of ELF .dynamic section
dynamic().applySoname(strtabsize);
dynamic().applyEntries(pLDInfo, *file_format);
dynamic().emit(dyn_sect, *dyn_region);
strcpy((strtab + strtabsize), pOutput.name().c_str());
strtabsize += pOutput.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 (32 == bitclass()) {
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 (64 == bitclass()) {
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;
}
}
}
/// getSectionOrder
unsigned int GNULDBackend::getSectionOrder(const Output& pOutput,
const LDSection& pSectHdr) const
{
// NULL section should be the "1st" section
if (LDFileFormat::Null == pSectHdr.kind())
return 0;
// 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;
ELFFileFormat* file_format = NULL;
switch (pOutput.type()) {
case Output::DynObj:
file_format = getDynObjFileFormat();
break;
case Output::Exec:
file_format = getExecFileFormat();
break;
case Output::Object:
default:
assert(0 && "Not support yet.\n");
break;
}
// 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 (pSectHdr.type() == llvm::ELF::SHT_PREINIT_ARRAY ||
pSectHdr.type() == llvm::ELF::SHT_INIT_ARRAY ||
pSectHdr.type() == llvm::ELF::SHT_FINI_ARRAY ||
&pSectHdr == &file_format->getCtors() ||
&pSectHdr == &file_format->getDtors())
return SHO_RELRO;
return SHO_DATA;
}
case LDFileFormat::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(pOutput, pSectHdr);
// handle .interp
case LDFileFormat::Note:
return SHO_INTERP;
case LDFileFormat::Exception:
return SHO_EHFRAME;
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 (pSymbol.visibility() == llvm::ELF::STV_INTERNAL ||
pSymbol.visibility() == llvm::ELF::STV_HIDDEN)
bind = llvm::ELF::STB_LOCAL;
return (pSymbol.resolveInfo()->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 Layout& pLayout) 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;
}
}
assert(pSymbol.hasFragRef());
return pLayout.getOutputLDSection(*pSymbol.fragRef()->frag())->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();
}
/// emitProgramHdrs - emit ELF program headers
void GNULDBackend::emitProgramHdrs(Output& pOutput)
{
assert(NULL != pOutput.context());
createProgramHdrs(*pOutput.context());
if (32 == bitclass())
writeELF32ProgramHdrs(pOutput);
else
writeELF64ProgramHdrs(pOutput);
}
/// createProgramHdrs - base on output sections to create the program headers
void GNULDBackend::createProgramHdrs(LDContext& pContext)
{
// make PT_PHDR
m_ELFSegmentTable.produce(llvm::ELF::PT_PHDR);
// make PT_INTERP
LDSection* interp = pContext.getSection(".interp");
if (NULL != interp) {
ELFSegment* interp_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_INTERP);
interp_seg->addSection(interp);
interp_seg->setAlign(bitclass() / 8);
}
uint32_t cur_seg_flag, prev_seg_flag = getSegmentFlag(0);
uint64_t padding = 0;
ELFSegment* load_seg = NULL;
// make possible PT_LOAD segments
LDContext::sect_iterator sect, sect_end = pContext.sectEnd();
for (sect = pContext.sectBegin(); sect != sect_end; ++sect) {
if (0 == ((*sect)->flag() & llvm::ELF::SHF_ALLOC) &&
LDFileFormat::Null != (*sect)->kind())
continue;
// FIXME: Now only separate writable and non-writable PT_LOAD
cur_seg_flag = getSegmentFlag((*sect)->flag());
if ((prev_seg_flag & llvm::ELF::PF_W) ^ (cur_seg_flag & llvm::ELF::PF_W) ||
LDFileFormat::Null == (*sect)->kind()) {
// create new PT_LOAD segment
load_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_LOAD);
load_seg->setAlign(pagesize());
// check if this segment needs padding
padding = 0;
if (((*sect)->offset() & (load_seg->align() - 1)) != 0)
padding = load_seg->align();
}
assert(NULL != load_seg);
load_seg->addSection(*sect);
load_seg->updateFlag(cur_seg_flag);
// FIXME: set section's vma
// need to handle start vma for user-defined one or for executable.
(*sect)->setAddr((*sect)->offset() + padding);
prev_seg_flag = cur_seg_flag;
}
// make PT_DYNAMIC
LDSection* dynamic = pContext.getSection(".dynamic");
if (NULL != dynamic) {
ELFSegment* dyn_seg = m_ELFSegmentTable.produce(llvm::ELF::PT_DYNAMIC);
dyn_seg->setFlag(llvm::ELF::PF_R | llvm::ELF::PF_W);
dyn_seg->addSection(dynamic);
dyn_seg->setAlign(bitclass() / 8);
}
// update segment info
uint64_t file_size = 0;
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 (32 == bitclass()) {
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(offset);
segment.setPaddr(segment.vaddr());
segment.setFilesz(numOfSegments() * phdr_size);
segment.setMemsz(numOfSegments() * phdr_size);
segment.setAlign(bitclass() / 8);
continue;
}
assert(NULL != segment.getFirstSection());
segment.setOffset(segment.getFirstSection()->offset());
segment.setVaddr(segment.getFirstSection()->addr());
segment.setPaddr(segment.vaddr());
const LDSection* last_sect = segment.getLastSection();
assert(NULL != last_sect);
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());
}
}
/// writeELF32ProgramHdrs - write out the ELF32 program headers
void GNULDBackend::writeELF32ProgramHdrs(Output& pOutput)
{
assert(pOutput.hasMemArea());
uint64_t start_offset, phdr_size;
start_offset = sizeof(llvm::ELF::Elf32_Ehdr);
phdr_size = sizeof(llvm::ELF::Elf32_Phdr);
// Program header must start directly after ELF header
MemoryRegion *region = pOutput.memArea()->request(start_offset,
numOfSegments()*phdr_size);
llvm::ELF::Elf32_Phdr* phdr = (llvm::ELF::Elf32_Phdr*)region->start();
size_t index = 0;
ELFSegmentFactory::iterator seg, segEnd = m_ELFSegmentTable.end();
for (seg = m_ELFSegmentTable.begin(); seg != segEnd; ++seg, ++index) {
phdr[index].p_type = (*seg).type();
phdr[index].p_flags = (*seg).flag();
phdr[index].p_offset = (*seg).offset();
phdr[index].p_vaddr = (*seg).vaddr();
phdr[index].p_paddr = (*seg).paddr();
phdr[index].p_filesz = (*seg).filesz();
phdr[index].p_memsz = (*seg).memsz();
phdr[index].p_align = (*seg).align();
}
}
/// writeELF64ProgramHdrs - write out the ELF64 program headers
void GNULDBackend::writeELF64ProgramHdrs(Output& pOutput)
{
assert(pOutput.hasMemArea());
uint64_t start_offset, phdr_size;
start_offset = sizeof(llvm::ELF::Elf64_Ehdr);
phdr_size = sizeof(llvm::ELF::Elf64_Phdr);
// Program header must start directly after ELF header
MemoryRegion *region = pOutput.memArea()->request(start_offset,
numOfSegments() *phdr_size);
llvm::ELF::Elf64_Phdr* phdr = (llvm::ELF::Elf64_Phdr*)region->start();
size_t index = 0;
ELFSegmentFactory::iterator seg, segEnd = m_ELFSegmentTable.end();
for (seg = m_ELFSegmentTable.begin(); seg != segEnd; ++seg, ++index) {
phdr[index].p_type = (*seg).type();
phdr[index].p_flags = (*seg).flag();
phdr[index].p_offset = (*seg).offset();
phdr[index].p_vaddr = (*seg).vaddr();
phdr[index].p_paddr = (*seg).paddr();
phdr[index].p_filesz = (*seg).filesz();
phdr[index].p_memsz = (*seg).memsz();
phdr[index].p_align = (*seg).align();
}
}
/// preLayout - Backend can do any needed modification before layout
void GNULDBackend::preLayout(const Output& pOutput,
const MCLDInfo& pLDInfo,
MCLinker& pLinker)
{
// prelayout target first
doPreLayout(pOutput, pLDInfo, pLinker);
}
/// postLayout -Backend can do any needed modification after layout
void GNULDBackend::postLayout(const Output& pOutput,
const MCLDInfo& pInfo,
MCLinker& pLinker)
{
// post layout target first
doPostLayout(pOutput, pInfo, pLinker);
}
/// 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,
const Output& pOutput)
{
// 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 (Output::DynObj == pOutput.type())
if (pSymbol.resolveInfo()->visibility() == ResolveInfo::Default ||
pSymbol.resolveInfo()->visibility() == ResolveInfo::Protected)
return true;
return false;
}