//===- MCLinker.cpp -------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the MCLinker class
//
//===----------------------------------------------------------------------===//
#include <mcld/MC/MCLinker.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/raw_ostream.h>
#include <mcld/MC/MCLDInput.h>
#include <mcld/MC/MCLDInfo.h>
#include <mcld/LD/Resolver.h>
#include <mcld/LD/LDContext.h>
#include <mcld/LD/LDSymbol.h>
#include <mcld/LD/LDSectionFactory.h>
#include <mcld/LD/SectionMap.h>
#include <mcld/LD/RelocationFactory.h>
#include <mcld/LD/FillFragment.h>
#include <mcld/LD/RegionFragment.h>
#include <mcld/LD/EhFrame.h>
#include <mcld/LD/EhFrameHdr.h>
#include <mcld/Support/MemoryRegion.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Target/TargetLDBackend.h>
using namespace mcld;
/// Constructor
MCLinker::MCLinker(TargetLDBackend& pBackend,
MCLDInfo& pInfo,
SectionMap& pSectionMap)
: m_Backend(pBackend),
m_LDInfo(pInfo),
m_SectionMap(pSectionMap),
m_LDSymbolFactory(128),
m_LDSectHdrFactory(10), // the average number of sections. (assuming 10.)
m_LDSectDataFactory(10),
m_pSectionMerger(NULL)
{
}
/// Destructor
MCLinker::~MCLinker()
{
if (NULL != m_pSectionMerger)
delete m_pSectionMerger;
}
//===----------------------------------------------------------------------===//
// Symbol Operations
//===----------------------------------------------------------------------===//
/// addSymbolFromObject - add a symbol from object file and resolve it
/// immediately
LDSymbol* MCLinker::addSymbolFromObject(const llvm::StringRef& pName,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
ResolveInfo::SizeType pSize,
LDSymbol::ValueType pValue,
FragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
// resolved_result is a triple <resolved_info, existent, override>
Resolver::Result resolved_result;
ResolveInfo old_info; // used for arrange output symbols
if (pBinding == ResolveInfo::Local) {
// if the symbol is a local symbol, create a LDSymbol for input, but do not
// resolve them.
resolved_result.info = m_LDInfo.getNamePool().createSymbol(pName,
false,
pType,
pDesc,
pBinding,
pSize,
pVisibility);
// No matter if there is a symbol with the same name, insert the symbol
// into output symbol table. So, we let the existent false.
resolved_result.existent = false;
resolved_result.overriden = true;
}
else {
// if the symbol is not local, insert and resolve it immediately
m_LDInfo.getNamePool().insertSymbol(pName, false, pType, pDesc, pBinding,
pSize, pVisibility,
&old_info, resolved_result);
}
// the return ResolveInfo should not NULL
assert(NULL != resolved_result.info);
// create a LDSymbol for the input file.
LDSymbol* input_sym = m_LDSymbolFactory.allocate();
new (input_sym) LDSymbol();
// set the relation between input LDSymbol and its ResolveInfo
input_sym->setResolveInfo(*resolved_result.info);
// set up input LDSymbol
input_sym->setFragmentRef(pFragmentRef);
input_sym->setValue(pValue);
LDSymbol* output_sym = resolved_result.info->outSymbol();
bool has_output_sym = (NULL != output_sym);
if (!resolved_result.existent || !has_output_sym) {
// it is a new symbol, the output_sym should be NULL.
assert(NULL == output_sym);
// if it is a new symbol, create a LDSymbol for the output
output_sym = m_LDSymbolFactory.allocate();
new (output_sym) LDSymbol();
// set up the relation between output LDSymbol and its ResolveInfo
output_sym->setResolveInfo(*resolved_result.info);
resolved_result.info->setSymPtr(output_sym);
}
if (resolved_result.overriden || !has_output_sym) {
// symbol can be overriden only if it exists.
assert(output_sym != NULL);
// should override output LDSymbol
output_sym->setFragmentRef(pFragmentRef);
output_sym->setValue(pValue);
}
// After symbol resolution, visibility is changed to the most restrict one.
// we need to arrange its position in the output symbol .
if (pType != ResolveInfo::Section) {
if (!has_output_sym) {
// We merge sections when reading them. So we do not need to output symbols
// with section type
// No matter the symbol is already in the output or not, add it if it
// should be forcefully set local.
if (shouldForceLocal(*resolved_result.info))
m_OutputSymbols.forceLocal(*output_sym);
else {
// the symbol should not be forcefully local.
m_OutputSymbols.add(*output_sym);
}
}
else if (resolved_result.overriden) {
if (!shouldForceLocal(old_info) ||
!shouldForceLocal(*resolved_result.info)) {
// If the old info and the new info are both forcefully local, then
// we should keep the output_sym in forcefully local category. Else,
// we should re-sort the output_sym
m_OutputSymbols.arrange(*output_sym, old_info);
}
}
}
return input_sym;
}
/// addSymbolFromDynObj - add a symbol from object file and resolve it
/// immediately
LDSymbol* MCLinker::addSymbolFromDynObj(const llvm::StringRef& pName,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
ResolveInfo::SizeType pSize,
LDSymbol::ValueType pValue,
FragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
// We merge sections when reading them. So we do not need symbols with
// section type
if (pType == ResolveInfo::Section)
return NULL;
// ignore symbols with local binding or that have internal or hidden
// visibility
if (pBinding == ResolveInfo::Local ||
pVisibility == ResolveInfo::Internal ||
pVisibility == ResolveInfo::Hidden)
return NULL;
// A protected symbol in a shared library must be treated as a
// normal symbol when viewed from outside the shared library.
if (pVisibility == ResolveInfo::Protected)
pVisibility = ResolveInfo::Default;
// insert symbol and resolve it immediately
// resolved_result is a triple <resolved_info, existent, override>
Resolver::Result resolved_result;
m_LDInfo.getNamePool().insertSymbol(pName, true, pType, pDesc,
pBinding, pSize, pVisibility,
NULL, resolved_result);
// the return ResolveInfo should not NULL
assert(NULL != resolved_result.info);
// create a LDSymbol for the input file.
LDSymbol* input_sym = m_LDSymbolFactory.allocate();
new (input_sym) LDSymbol();
// set up the relation between input LDSymbol and its ResolveInfo
input_sym->setResolveInfo(*resolved_result.info);
// set up input LDSymbol
input_sym->setFragmentRef(pFragmentRef);
input_sym->setValue(pValue);
LDSymbol* output_sym = NULL;
if (!resolved_result.existent) {
// we get a new symbol, leave it as NULL
resolved_result.info->setSymPtr(NULL);
}
else {
// we saw the symbol before, but the output_sym still may be NULL.
output_sym = resolved_result.info->outSymbol();
}
if (output_sym != NULL) {
// After symbol resolution, visibility is changed to the most restrict one.
// If we are not doing incremental linking, then any symbol with hidden
// or internal visibility is forcefully set as a local symbol.
if (shouldForceLocal(*resolved_result.info)) {
m_OutputSymbols.forceLocal(*output_sym);
}
}
return input_sym;
}
/// defineSymbolForcefully - define an output symbol and override it immediately
LDSymbol* MCLinker::defineSymbolForcefully(const llvm::StringRef& pName,
bool pIsDyn,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
ResolveInfo::SizeType pSize,
LDSymbol::ValueType pValue,
FragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
ResolveInfo* info = m_LDInfo.getNamePool().findInfo(pName);
LDSymbol* output_sym = NULL;
if (NULL == info) {
// the symbol is not in the pool, create a new one.
// create a ResolveInfo
Resolver::Result result;
m_LDInfo.getNamePool().insertSymbol(pName, pIsDyn, pType, pDesc,
pBinding, pSize, pVisibility,
NULL, result);
assert(!result.existent);
// create a output LDSymbol
output_sym = m_LDSymbolFactory.allocate();
new (output_sym) LDSymbol();
output_sym->setResolveInfo(*result.info);
result.info->setSymPtr(output_sym);
if (shouldForceLocal(*result.info))
m_OutputSymbols.forceLocal(*output_sym);
else
m_OutputSymbols.add(*output_sym);
}
else {
// the symbol is already in the pool, override it
ResolveInfo old_info;
old_info.override(*info);
info->setSource(pIsDyn);
info->setType(pType);
info->setDesc(pDesc);
info->setBinding(pBinding);
info->setVisibility(pVisibility);
info->setIsSymbol(true);
info->setSize(pSize);
output_sym = info->outSymbol();
if (NULL != output_sym)
m_OutputSymbols.arrange(*output_sym, old_info);
else {
// create a output LDSymbol
output_sym = m_LDSymbolFactory.allocate();
new (output_sym) LDSymbol();
output_sym->setResolveInfo(*info);
info->setSymPtr(output_sym);
m_OutputSymbols.add(*output_sym);
}
}
if (NULL != output_sym) {
output_sym->setFragmentRef(pFragmentRef);
output_sym->setValue(pValue);
}
return output_sym;
}
/// defineSymbolAsRefered - define an output symbol and override it immediately
LDSymbol* MCLinker::defineSymbolAsRefered(const llvm::StringRef& pName,
bool pIsDyn,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
ResolveInfo::SizeType pSize,
LDSymbol::ValueType pValue,
FragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
ResolveInfo* info = m_LDInfo.getNamePool().findInfo(pName);
if (NULL == info || !(info->isUndef() || info->isDyn())) {
// only undefined symbol and dynamic symbol can make a reference.
return NULL;
}
// the symbol is already in the pool, override it
ResolveInfo old_info;
old_info.override(*info);
info->setSource(pIsDyn);
info->setType(pType);
info->setDesc(pDesc);
info->setBinding(pBinding);
info->setVisibility(pVisibility);
info->setIsSymbol(true);
info->setSize(pSize);
LDSymbol* output_sym = info->outSymbol();
if (NULL != output_sym) {
output_sym->setFragmentRef(pFragmentRef);
output_sym->setValue(pValue);
m_OutputSymbols.arrange(*output_sym, old_info);
}
else {
// create a output LDSymbol
output_sym = m_LDSymbolFactory.allocate();
new (output_sym) LDSymbol();
output_sym->setResolveInfo(*info);
info->setSymPtr(output_sym);
m_OutputSymbols.add(*output_sym);
}
return output_sym;
}
/// defineAndResolveSymbolForcefully - define an output symbol and resolve it
/// immediately
LDSymbol* MCLinker::defineAndResolveSymbolForcefully(const llvm::StringRef& pName,
bool pIsDyn,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
ResolveInfo::SizeType pSize,
LDSymbol::ValueType pValue,
FragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
// Result is <info, existent, override>
Resolver::Result result;
ResolveInfo old_info;
m_LDInfo.getNamePool().insertSymbol(pName, pIsDyn, pType, pDesc, pBinding,
pSize, pVisibility,
&old_info, result);
LDSymbol* output_sym = result.info->outSymbol();
bool has_output_sym = (NULL != output_sym);
if (!result.existent || !has_output_sym) {
output_sym = m_LDSymbolFactory.allocate();
new (output_sym) LDSymbol();
output_sym->setResolveInfo(*result.info);
result.info->setSymPtr(output_sym);
}
if (result.overriden || !has_output_sym) {
output_sym->setFragmentRef(pFragmentRef);
output_sym->setValue(pValue);
}
// After symbol resolution, the visibility is changed to the most restrict.
// arrange the output position
if (shouldForceLocal(*result.info))
m_OutputSymbols.forceLocal(*output_sym);
else if (has_output_sym)
m_OutputSymbols.arrange(*output_sym, old_info);
else
m_OutputSymbols.add(*output_sym);
return output_sym;
}
/// defineAndResolveSymbolAsRefered - define an output symbol and resolve it
/// immediately.
LDSymbol* MCLinker::defineAndResolveSymbolAsRefered(const llvm::StringRef& pName,
bool pIsDyn,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
ResolveInfo::SizeType pSize,
LDSymbol::ValueType pValue,
FragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
ResolveInfo* info = m_LDInfo.getNamePool().findInfo(pName);
if (NULL == info || !(info->isUndef() || info->isDyn())) {
// only undefined symbol and dynamic symbol can make a reference.
return NULL;
}
return defineAndResolveSymbolForcefully(pName,
pIsDyn,
pType,
pDesc,
pBinding,
pSize,
pValue,
pFragmentRef,
pVisibility);
}
bool MCLinker::finalizeSymbols()
{
SymbolCategory::iterator symbol, symEnd = m_OutputSymbols.end();
for (symbol = m_OutputSymbols.begin(); symbol != symEnd; ++symbol) {
if ((*symbol)->resolveInfo()->isAbsolute() ||
(*symbol)->resolveInfo()->type() == ResolveInfo::File) {
// absolute symbols or symbols with function type should have
// zero value
(*symbol)->setValue(0x0);
continue;
}
if ((*symbol)->hasFragRef()) {
// set the virtual address of the symbol. If the output file is
// relocatable object file, the section's virtual address becomes zero.
// And the symbol's value become section relative offset.
uint64_t value = getLayout().getOutputOffset(*(*symbol)->fragRef());
assert(NULL != (*symbol)->fragRef()->frag());
uint64_t addr = getLayout().getOutputLDSection(*(*symbol)->fragRef()->frag())->addr();
(*symbol)->setValue(value + addr);
continue;
}
}
// finialize target-dependent symbols
return m_Backend.finalizeSymbols(*this, m_LDInfo.output());
}
bool MCLinker::shouldForceLocal(const ResolveInfo& pInfo) const
{
// forced local symbol matches all rules:
// 1. We are not doing incremental linking.
// 2. The symbol is with Hidden or Internal visibility.
// 3. The symbol should be global or weak. Otherwise, local symbol is local.
// 4. The symbol is defined or common
if (m_LDInfo.output().type() != Output::Object &&
(pInfo.visibility() == ResolveInfo::Hidden ||
pInfo.visibility() == ResolveInfo::Internal) &&
(pInfo.isGlobal() || pInfo.isWeak()) &&
(pInfo.isDefine() || pInfo.isCommon()))
return true;
return false;
}
//===----------------------------------------------------------------------===//
// Section Operations
//===----------------------------------------------------------------------===//
/// createSectHdr - create the input section header
LDSection& MCLinker::createSectHdr(const std::string& pName,
LDFileFormat::Kind pKind,
uint32_t pType,
uint32_t pFlag)
{
assert(m_LDInfo.output().hasContext());
// for user such as reader, standard/target fromat
LDSection* result =
m_LDSectHdrFactory.produce(pName, pKind, pType, pFlag);
// check if we need to create a output section for output LDContext
std::string sect_name = m_SectionMap.getOutputSectName(pName);
LDSection* output_sect = m_LDInfo.output().context()->getSection(sect_name);
if (NULL == output_sect) {
// create a output section and push it into output LDContext
output_sect =
m_LDSectHdrFactory.produce(sect_name, pKind, pType, pFlag);
m_LDInfo.output().context()->getSectionTable().push_back(output_sect);
m_pSectionMerger->addMapping(pName, output_sect);
}
return *result;
}
/// getOrCreateOutputSectHdr - for reader and standard/target format to get
/// or create the output's section header
LDSection& MCLinker::getOrCreateOutputSectHdr(const std::string& pName,
LDFileFormat::Kind pKind,
uint32_t pType,
uint32_t pFlag,
uint32_t pAlign)
{
assert(m_LDInfo.output().hasContext());
// check if we need to create a output section for output LDContext
std::string sect_name = m_SectionMap.getOutputSectName(pName);
LDSection* output_sect = m_LDInfo.output().context()->getSection(sect_name);
if (NULL == output_sect) {
// create a output section and push it into output LDContext
output_sect =
m_LDSectHdrFactory.produce(sect_name, pKind, pType, pFlag);
output_sect->setAlign(pAlign);
m_LDInfo.output().context()->getSectionTable().push_back(output_sect);
m_pSectionMerger->addMapping(pName, output_sect);
}
return *output_sect;
}
/// getOrCreateSectData - get or create SectionData
/// pSection is input LDSection
SectionData& MCLinker::getOrCreateSectData(LDSection& pSection)
{
// if there is already a section data pointed by section, return it.
SectionData* sect_data = pSection.getSectionData();
if (NULL != sect_data) {
m_Layout.addInputRange(*sect_data, pSection);
return *sect_data;
}
// try to get one from output LDSection
LDSection* output_sect =
m_pSectionMerger->getOutputSectHdr(pSection.name());
assert(NULL != output_sect);
sect_data = output_sect->getSectionData();
if (NULL != sect_data) {
pSection.setSectionData(sect_data);
m_Layout.addInputRange(*sect_data, pSection);
return *sect_data;
}
// if the output LDSection also has no SectionData, then create one.
sect_data = m_LDSectDataFactory.allocate();
new (sect_data) SectionData(*output_sect);
pSection.setSectionData(sect_data);
output_sect->setSectionData(sect_data);
m_Layout.addInputRange(*sect_data, pSection);
return *sect_data;
}
void MCLinker::initSectionMap()
{
assert(m_LDInfo.output().hasContext());
if (NULL == m_pSectionMerger)
m_pSectionMerger = new SectionMerger(m_SectionMap, *m_LDInfo.output().context());
}
bool MCLinker::layout()
{
return m_Layout.layout(m_LDInfo.output(), m_Backend, m_LDInfo);
}
//===----------------------------------------------------------------------===//
// Relocation Operations
//===----------------------------------------------------------------------===//
/// addRelocation - add a relocation entry in MCLinker (only for object file)
///
/// All symbols should be read and resolved before calling this function.
Relocation* MCLinker::addRelocation(Relocation::Type pType,
const LDSymbol& pSym,
ResolveInfo& pResolveInfo,
FragmentRef& pFragmentRef,
const LDSection& pSection,
Relocation::Address pAddend)
{
// FIXME: we should dicard sections and symbols first instead
// if the symbol is in the discarded input section, then we also need to
// discard this relocation.
if (pSym.fragRef() == NULL &&
pResolveInfo.type() == ResolveInfo::Section &&
pResolveInfo.desc() == ResolveInfo::Undefined)
return NULL;
Relocation* relocation = m_Backend.getRelocFactory()->produce(pType,
pFragmentRef,
pAddend);
relocation->setSymInfo(&pResolveInfo);
m_RelocationList.push_back(relocation);
m_Backend.scanRelocation(*relocation, pSym, *this, m_LDInfo,
m_LDInfo.output(), pSection);
if (pResolveInfo.isUndef() && !pResolveInfo.isDyn() && !pResolveInfo.isWeak())
fatal(diag::undefined_reference) << pResolveInfo.name();
return relocation;
}
bool MCLinker::applyRelocations()
{
RelocationListType::iterator relocIter, relocEnd = m_RelocationList.end();
for (relocIter = m_RelocationList.begin(); relocIter != relocEnd; ++relocIter) {
Fragment* frag = (Fragment*)relocIter;
static_cast<Relocation*>(frag)->apply(*m_Backend.getRelocFactory(), m_LDInfo);
}
return true;
}
void MCLinker::syncRelocationResult()
{
MemoryRegion* region = m_LDInfo.output().memArea()->request(0,
m_LDInfo.output().memArea()->handler()->size());
uint8_t* data = region->getBuffer();
RelocationListType::iterator relocIter, relocEnd = m_RelocationList.end();
for (relocIter = m_RelocationList.begin(); relocIter != relocEnd; ++relocIter) {
Fragment* frag = (Fragment*)relocIter;
Relocation* reloc = static_cast<Relocation*>(frag);
// get output file offset
size_t out_offset = m_Layout.getOutputLDSection(*reloc->targetRef().frag())->offset() +
m_Layout.getOutputOffset(reloc->targetRef());
uint8_t* target_addr = data + out_offset;
// byte swapping if target and host has different endian, and then write back
if(llvm::sys::isLittleEndianHost() != m_Backend.isLittleEndian()) {
uint64_t tmp_data = 0;
switch(m_Backend.bitclass()) {
case 32u:
tmp_data = bswap32(reloc->target());
std::memcpy(target_addr, &tmp_data, 4);
break;
case 64u:
tmp_data = bswap64(reloc->target());
std::memcpy(target_addr, &tmp_data, 8);
break;
default:
break;
}
}
else {
std::memcpy(target_addr, &reloc->target(), m_Backend.bitclass()/8);
}
} // end of for
m_LDInfo.output().memArea()->clear();
}
//===----------------------------------------------------------------------===//
// Exception Handling Operations
//===----------------------------------------------------------------------===//
/// addEhFrame - add an exception handling section
/// @param pSection - the input section
/// @param pArea - the memory area which pSection is within.
uint64_t MCLinker::addEhFrame(const Input& pInput,
LDSection& pSection,
MemoryArea& pArea)
{
uint64_t size = 0;
// get the SectionData of this eh_frame
SectionData& sect_data = getOrCreateSectData(pSection);
// parse the eh_frame if the option --eh-frame-hdr is given
if (m_LDInfo.options().hasEhFrameHdr()) {
EhFrame* ehframe = m_Backend.getEhFrame();
assert(NULL != ehframe);
if (ehframe->canRecognizeAllEhFrame()) {
size = ehframe->readEhFrame(m_Layout, m_Backend, sect_data, pInput,
pSection, pArea);
// zero size indicate that this is an empty section or we can't recognize
// this eh_frame, handle it as a regular section.
if (0 != size)
return size;
}
}
// handle eh_frame as a regular section
MemoryRegion* region = pArea.request(pInput.fileOffset() + pSection.offset(),
pSection.size());
Fragment* frag = NULL;
if (NULL == region) {
// If the input section's size is zero, we got a NULL region.
// use a virtual fill fragment
frag = new FillFragment(0x0, 0, 0);
}
else
frag = new RegionFragment(*region);
size = m_Layout.appendFragment(*frag, sect_data, pSection.align());
return size;
}