//===- IRBuilder.cpp ------------------------------------------------------===//
//
// The MCLinker Project
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include <mcld/IRBuilder.h>
#include <mcld/LD/ELFReader.h>
#include <mcld/Object/ObjectBuilder.h>
#include <mcld/LD/SectionData.h>
#include <mcld/LD/EhFrame.h>
#include <mcld/LD/RelocData.h>
#include <mcld/Support/MsgHandling.h>
#include <mcld/Fragment/FragmentRef.h>
using namespace mcld;
//===----------------------------------------------------------------------===//
// Helper Functions
//===----------------------------------------------------------------------===//
LDFileFormat::Kind GetELFSectionKind(uint32_t pType, const char* pName)
{
// name rules
llvm::StringRef name(pName);
if (name.startswith(".debug") ||
name.startswith(".zdebug") ||
name.startswith(".gnu.linkonce.wi.") ||
name.startswith(".line") ||
name.startswith(".stab"))
return LDFileFormat::Debug;
if (name.startswith(".comment"))
return LDFileFormat::MetaData;
if (name.startswith(".interp") || name.startswith(".dynamic"))
return LDFileFormat::Note;
if (name.startswith(".eh_frame"))
return LDFileFormat::EhFrame;
if (name.startswith(".eh_frame_hdr"))
return LDFileFormat::EhFrameHdr;
if (name.startswith(".gcc_except_table"))
return LDFileFormat::GCCExceptTable;
if (name.startswith(".note.GNU-stack"))
return LDFileFormat::StackNote;
// type rules
switch(pType) {
case llvm::ELF::SHT_NULL:
return LDFileFormat::Null;
case llvm::ELF::SHT_INIT_ARRAY:
case llvm::ELF::SHT_FINI_ARRAY:
case llvm::ELF::SHT_PREINIT_ARRAY:
case llvm::ELF::SHT_PROGBITS:
return LDFileFormat::Regular;
case llvm::ELF::SHT_SYMTAB:
case llvm::ELF::SHT_DYNSYM:
case llvm::ELF::SHT_STRTAB:
case llvm::ELF::SHT_HASH:
case llvm::ELF::SHT_DYNAMIC:
return LDFileFormat::NamePool;
case llvm::ELF::SHT_RELA:
case llvm::ELF::SHT_REL:
return LDFileFormat::Relocation;
case llvm::ELF::SHT_NOBITS:
return LDFileFormat::BSS;
case llvm::ELF::SHT_NOTE:
return LDFileFormat::Note;
case llvm::ELF::SHT_GROUP:
return LDFileFormat::Group;
case llvm::ELF::SHT_GNU_versym:
case llvm::ELF::SHT_GNU_verdef:
case llvm::ELF::SHT_GNU_verneed:
return LDFileFormat::Version;
case llvm::ELF::SHT_SHLIB:
return LDFileFormat::Target;
default:
if ((pType >= llvm::ELF::SHT_LOPROC && pType <= llvm::ELF::SHT_HIPROC) ||
(pType >= llvm::ELF::SHT_LOOS && pType <= llvm::ELF::SHT_HIOS) ||
(pType >= llvm::ELF::SHT_LOUSER && pType <= llvm::ELF::SHT_HIUSER))
return LDFileFormat::Target;
fatal(diag::err_unsupported_section) << pName << pType;
}
return LDFileFormat::MetaData;
}
bool ShouldForceLocal(const ResolveInfo& pInfo, const LinkerConfig& pConfig)
{
// 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 (LinkerConfig::Object != pConfig.codeGenType() &&
(pInfo.visibility() == ResolveInfo::Hidden ||
pInfo.visibility() == ResolveInfo::Internal) &&
(pInfo.isGlobal() || pInfo.isWeak()) &&
(pInfo.isDefine() || pInfo.isCommon()))
return true;
return false;
}
//===----------------------------------------------------------------------===//
// IRBuilder
//===----------------------------------------------------------------------===//
IRBuilder::IRBuilder(Module& pModule, const LinkerConfig& pConfig)
: m_Module(pModule), m_Config(pConfig), m_InputBuilder(pConfig) {
m_InputBuilder.setCurrentTree(m_Module.getInputTree());
}
IRBuilder::~IRBuilder()
{
}
/// CreateInput - To create an input file and append it to the input tree.
Input* IRBuilder::CreateInput(const std::string& pName,
const sys::fs::Path& pPath, Input::Type pType)
{
if (Input::Unknown == pType)
return ReadInput(pName, pPath);
m_InputBuilder.createNode<InputTree::Positional>(pName, pPath, pType);
Input* input = *m_InputBuilder.getCurrentNode();
if (!input->hasContext())
m_InputBuilder.setContext(*input, false);
return input;
}
/// ReadInput - To read an input file and append it to the input tree.
Input*
IRBuilder::ReadInput(const std::string& pName, const sys::fs::Path& pPath)
{
m_InputBuilder.createNode<InputTree::Positional>(pName, pPath, Input::Unknown);
Input* input = *m_InputBuilder.getCurrentNode();
if (!input->hasContext())
m_InputBuilder.setContext(*input);
if (!input->hasMemArea())
m_InputBuilder.setMemory(*input, FileHandle::ReadOnly, FileHandle::System);
return input;
}
/// ReadInput - To read an input file and append it to the input tree.
Input* IRBuilder::ReadInput(const std::string& pNameSpec)
{
const sys::fs::Path* path = NULL;
// find out the real path of the namespec.
if (m_InputBuilder.getConstraint().isSharedSystem()) {
// In the system with shared object support, we can find both archive
// and shared object.
if (m_InputBuilder.getAttributes().isStatic()) {
// with --static, we must search an archive.
path = m_Config.options().directories().find(pNameSpec, Input::Archive);
}
else {
// otherwise, with --Bdynamic, we can find either an archive or a
// shared object.
path = m_Config.options().directories().find(pNameSpec, Input::DynObj);
}
}
else {
// In the system without shared object support, we only look for an archive
path = m_Config.options().directories().find(pNameSpec, Input::Archive);
}
if (NULL == path) {
fatal(diag::err_cannot_find_namespec) << pNameSpec;
return NULL;
}
m_InputBuilder.createNode<InputTree::Positional>(pNameSpec, *path);
Input* input = *m_InputBuilder.getCurrentNode();
if (!input->hasContext())
m_InputBuilder.setContext(*input);
if (!input->hasMemArea())
m_InputBuilder.setMemory(*input, FileHandle::ReadOnly, FileHandle::System);
return input;
}
/// ReadInput - To read an input file and append it to the input tree.
Input* IRBuilder::ReadInput(raw_mem_ostream& pMemOStream)
{
Input* input = NULL;
if (pMemOStream.getMemoryArea().hasHandler()) {
m_InputBuilder.createNode<InputTree::Positional>(
"memory ostream",
pMemOStream.getMemoryArea().handler()->path());
input = *m_InputBuilder.getCurrentNode();
m_InputBuilder.setContext(*input);
input->setMemArea(&pMemOStream.getMemoryArea());
}
else {
m_InputBuilder.createNode<InputTree::Positional>("memory ostream", "NAN");
input = *m_InputBuilder.getCurrentNode();
m_InputBuilder.setContext(*input, false);
input->setMemArea(&pMemOStream.getMemoryArea());
}
return input;
}
/// ReadInput - To read an input file and append it to the input tree.
Input* IRBuilder::ReadInput(FileHandle& pFileHandle)
{
m_InputBuilder.createNode<InputTree::Positional>("file handler",
pFileHandle.path());
Input* input = *m_InputBuilder.getCurrentNode();
if (pFileHandle.path().empty()) {
m_InputBuilder.setContext(*input, false);
m_InputBuilder.setMemory(*input, pFileHandle.handler(), FileHandle::ReadOnly);
}
else {
m_InputBuilder.setContext(*input, true);
m_InputBuilder.setMemory(*input, FileHandle::ReadOnly, FileHandle::System);
}
return input;
}
/// ReadInput - To read an input file and append it to the input tree.
Input* IRBuilder::ReadInput(const std::string& pName, void* pRawMemory, size_t pSize)
{
m_InputBuilder.createNode<InputTree::Positional>(pName, "NAN");
Input* input = *m_InputBuilder.getCurrentNode();
m_InputBuilder.setContext(*input, false);
m_InputBuilder.setMemory(*input, pRawMemory, pSize);
return input;
}
bool IRBuilder::StartGroup()
{
if (m_InputBuilder.isInGroup()) {
fatal(diag::fatal_forbid_nest_group);
return false;
}
m_InputBuilder.enterGroup();
return true;
}
bool IRBuilder::EndGroup()
{
m_InputBuilder.exitGroup();
return true;
}
void IRBuilder::WholeArchive()
{
m_InputBuilder.getAttributes().setWholeArchive();
}
void IRBuilder::NoWholeArchive()
{
m_InputBuilder.getAttributes().unsetWholeArchive();
}
void IRBuilder::AsNeeded()
{
m_InputBuilder.getAttributes().setAsNeeded();
}
void IRBuilder::NoAsNeeded()
{
m_InputBuilder.getAttributes().unsetAsNeeded();
}
void IRBuilder::CopyDTNeeded()
{
m_InputBuilder.getAttributes().setAddNeeded();
}
void IRBuilder::NoCopyDTNeeded()
{
m_InputBuilder.getAttributes().unsetAddNeeded();
}
void IRBuilder::AgainstShared()
{
m_InputBuilder.getAttributes().setDynamic();
}
void IRBuilder::AgainstStatic()
{
m_InputBuilder.getAttributes().setStatic();
}
LDSection* IRBuilder::CreateELFHeader(Input& pInput,
const std::string& pName,
uint32_t pType,
uint32_t pFlag,
uint32_t pAlign)
{
// Create section header
LDFileFormat::Kind kind = GetELFSectionKind(pType, pName.c_str());
LDSection* header = LDSection::Create(pName, kind, pType, pFlag);
header->setAlign(pAlign);
// Append section header in input
pInput.context()->appendSection(*header);
return header;
}
/// CreateSectionData - To create a section data for given pSection.
SectionData* IRBuilder::CreateSectionData(LDSection& pSection)
{
assert(!pSection.hasSectionData() && "pSection already has section data.");
SectionData* sect_data = SectionData::Create(pSection);
pSection.setSectionData(sect_data);
return sect_data;
}
/// CreateRelocData - To create a relocation data for given pSection.
RelocData* IRBuilder::CreateRelocData(LDSection &pSection)
{
assert(!pSection.hasRelocData() && "pSection already has relocation data.");
RelocData* reloc_data = RelocData::Create(pSection);
pSection.setRelocData(reloc_data);
return reloc_data;
}
/// CreateEhFrame - To create a eh_frame for given pSection
EhFrame* IRBuilder::CreateEhFrame(LDSection& pSection)
{
assert(!pSection.hasEhFrame() && "pSection already has eh_frame.");
EhFrame* eh_frame = EhFrame::Create(pSection);
pSection.setEhFrame(eh_frame);
return eh_frame;
}
/// CreateBSS - To create a bss section for given pSection
SectionData* IRBuilder::CreateBSS(LDSection& pSection)
{
assert(!pSection.hasSectionData() && "pSection already has section data.");
assert((pSection.kind() == LDFileFormat::BSS) && "pSection is not a BSS section.");
SectionData* sect_data = SectionData::Create(pSection);
pSection.setSectionData(sect_data);
/* value, valsize, size*/
FillFragment* frag = new FillFragment(0x0, 1, pSection.size());
ObjectBuilder::AppendFragment(*frag, *sect_data);
return sect_data;
}
/// CreateRegion - To create a region fragment in the input file.
Fragment* IRBuilder::CreateRegion(Input& pInput, size_t pOffset, size_t pLength)
{
if (!pInput.hasMemArea()) {
fatal(diag::fatal_cannot_read_input) << pInput.path();
return NULL;
}
if (0 == pLength)
return new FillFragment(0x0, 0, 0);
MemoryRegion* region = pInput.memArea()->request(pOffset, pLength);
if (NULL == region)
return new FillFragment(0x0, 0, 0);
return new RegionFragment(*region);
}
/// CreateRegion - To create a region fragment wrapping the given memory
Fragment* IRBuilder::CreateRegion(void* pMemory, size_t pLength)
{
if (0 == pLength)
return new FillFragment(0x0, 0, 0);
MemoryRegion* region = MemoryRegion::Create(pMemory, pLength);
if (NULL == region)
return new FillFragment(0x0, 0, 0);
return new RegionFragment(*region);
}
/// AppendFragment - To append pFrag to the given SectionData pSD
uint64_t IRBuilder::AppendFragment(Fragment& pFrag, SectionData& pSD)
{
uint64_t size = ObjectBuilder::AppendFragment(pFrag,
pSD,
pSD.getSection().align());
pSD.getSection().setSize(pSD.getSection().size() + size);
return size;
}
/// AppendRelocation - To append an relocation to the given RelocData pRD.
void IRBuilder::AppendRelocation(Relocation& pRelocation, RelocData& pRD)
{
pRD.append(pRelocation);
}
/// AppendEhFrame - To append a fragment to EhFrame.
uint64_t IRBuilder::AppendEhFrame(Fragment& pFrag, EhFrame& pEhFrame)
{
uint64_t size = ObjectBuilder::AppendFragment(pFrag,
pEhFrame.getSectionData(),
pEhFrame.getSection().align());
pEhFrame.getSection().setSize(pEhFrame.getSection().size() + size);
return size;
}
/// AppendEhFrame - To append a FDE to the given EhFrame pEhFram.
uint64_t IRBuilder::AppendEhFrame(EhFrame::FDE& pFDE, EhFrame& pEhFrame)
{
pEhFrame.addFDE(pFDE);
pEhFrame.getSection().setSize(pEhFrame.getSection().size() + pFDE.size());
return pFDE.size();
}
/// AppendEhFrame - To append a CIE to the given EhFrame pEhFram.
uint64_t IRBuilder::AppendEhFrame(EhFrame::CIE& pCIE, EhFrame& pEhFrame)
{
pEhFrame.addCIE(pCIE);
pEhFrame.getSection().setSize(pEhFrame.getSection().size() + pCIE.size());
return pCIE.size();
}
/// AddSymbol - To add a symbol in the input file and resolve the symbol
/// immediately
LDSymbol* IRBuilder::AddSymbol(Input& pInput,
const std::string& pName,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBind,
ResolveInfo::SizeType pSize,
LDSymbol::ValueType pValue,
LDSection* pSection,
ResolveInfo::Visibility pVis)
{
// rename symbols
std::string name = pName;
if (!m_Config.scripts().renameMap().empty() &&
ResolveInfo::Undefined == pDesc) {
// If the renameMap is not empty, some symbols should be renamed.
// --wrap and --portable defines the symbol rename map.
ScriptOptions::SymbolRenameMap::const_iterator renameSym =
m_Config.scripts().renameMap().find(pName);
if (renameSym != m_Config.scripts().renameMap().end())
name = renameSym.getEntry()->value();
}
switch (pInput.type()) {
case Input::Object: {
FragmentRef* frag = NULL;
if (NULL == pSection ||
ResolveInfo::Undefined == pDesc ||
ResolveInfo::Common == pDesc ||
ResolveInfo::Absolute == pBind ||
LDFileFormat::Ignore == pSection->kind() ||
LDFileFormat::Group == pSection->kind())
frag = FragmentRef::Null();
else
frag = FragmentRef::Create(*pSection, pValue);
LDSymbol* input_sym = addSymbolFromObject(name, pType, pDesc, pBind, pSize, pValue, frag, pVis);
pInput.context()->addSymbol(input_sym);
return input_sym;
}
case Input::DynObj: {
return addSymbolFromDynObj(pInput, name, pType, pDesc, pBind, pSize, pValue, pVis);
}
default: {
return NULL;
break;
}
}
return NULL;
}
LDSymbol* IRBuilder::addSymbolFromObject(const std::string& pName,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
ResolveInfo::SizeType pSize,
LDSymbol::ValueType pValue,
FragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
// Step 1. calculate a Resolver::Result
// 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_Module.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_Module.getNamePool().insertSymbol(pName, false, pType, pDesc, pBinding,
pSize, pVisibility,
&old_info, resolved_result);
}
// the return ResolveInfo should not NULL
assert(NULL != resolved_result.info);
/// Step 2. create an input LDSymbol.
// create a LDSymbol for the input file.
LDSymbol* input_sym = LDSymbol::Create(*resolved_result.info);
input_sym->setFragmentRef(pFragmentRef);
input_sym->setValue(pValue);
// Step 3. Set up corresponding output LDSymbol
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 (pType == ResolveInfo::Section) {
// if it is a section symbol, its output LDSymbol is the input LDSymbol.
output_sym = input_sym;
}
else {
// if it is a new symbol, create a LDSymbol for the output
output_sym = LDSymbol::Create(*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);
}
// Step 4. Adjust the position of output LDSymbol.
// After symbol resolution, visibility is changed to the most restrict one.
// we need to arrange its position in the output symbol. We arrange the
// positions by sorting symbols in SymbolCategory.
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_Config))
m_Module.getSymbolTable().forceLocal(*output_sym);
else {
// the symbol should not be forcefully local.
m_Module.getSymbolTable().add(*output_sym);
}
}
else if (resolved_result.overriden) {
if (!ShouldForceLocal(old_info, m_Config) ||
!ShouldForceLocal(*resolved_result.info, m_Config)) {
// 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_Module.getSymbolTable().arrange(*output_sym, old_info);
}
}
}
return input_sym;
}
LDSymbol* IRBuilder::addSymbolFromDynObj(Input& pInput,
const std::string& pName,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
ResolveInfo::SizeType pSize,
LDSymbol::ValueType pValue,
ResolveInfo::Visibility pVisibility)
{
// We don't need sections of dynamic objects. So we ignore section symbols.
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_Module.getNamePool().insertSymbol(pName, true, pType, pDesc,
pBinding, pSize, pVisibility,
NULL, resolved_result);
// the return ResolveInfo should not NULL
assert(NULL != resolved_result.info);
if (resolved_result.overriden || !resolved_result.existent)
pInput.setNeeded();
// create a LDSymbol for the input file.
LDSymbol* input_sym = LDSymbol::Create(*resolved_result.info);
input_sym->setFragmentRef(FragmentRef::Null());
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_Config)) {
m_Module.getSymbolTable().forceLocal(*output_sym);
}
}
return input_sym;
}
/// AddRelocation - add a relocation entry
///
/// All symbols should be read and resolved before calling this function.
Relocation* IRBuilder::AddRelocation(LDSection& pSection,
Relocation::Type pType,
LDSymbol& pSym,
uint32_t pOffset,
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.
ResolveInfo* resolve_info = pSym.resolveInfo();
if (!pSym.hasFragRef() &&
ResolveInfo::Section == resolve_info->type() &&
ResolveInfo::Undefined == resolve_info->desc())
return NULL;
FragmentRef* frag_ref = FragmentRef::Create(*pSection.getLink(), pOffset);
Relocation* relocation = Relocation::Create(pType, *frag_ref, pAddend);
relocation->setSymInfo(resolve_info);
pSection.getRelocData()->append(*relocation);
return relocation;
}
/// AddSymbol - define an output symbol and override it immediately
template<> LDSymbol*
IRBuilder::AddSymbol<IRBuilder::Force, IRBuilder::Unresolve>(
const llvm::StringRef& pName,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
ResolveInfo::SizeType pSize,
LDSymbol::ValueType pValue,
FragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
ResolveInfo* info = m_Module.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_Module.getNamePool().insertSymbol(pName, false, pType, pDesc,
pBinding, pSize, pVisibility,
NULL, result);
assert(!result.existent);
// create a output LDSymbol
output_sym = LDSymbol::Create(*result.info);
result.info->setSymPtr(output_sym);
if (ShouldForceLocal(*result.info, m_Config))
m_Module.getSymbolTable().forceLocal(*output_sym);
else
m_Module.getSymbolTable().add(*output_sym);
}
else {
// the symbol is already in the pool, override it
ResolveInfo old_info;
old_info.override(*info);
info->setRegular();
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_Module.getSymbolTable().arrange(*output_sym, old_info);
else {
// create a output LDSymbol
output_sym = LDSymbol::Create(*info);
info->setSymPtr(output_sym);
m_Module.getSymbolTable().add(*output_sym);
}
}
if (NULL != output_sym) {
output_sym->setFragmentRef(pFragmentRef);
output_sym->setValue(pValue);
}
return output_sym;
}
/// AddSymbol - define an output symbol and override it immediately
template<> LDSymbol*
IRBuilder::AddSymbol<IRBuilder::AsReferred, IRBuilder::Unresolve>(
const llvm::StringRef& pName,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
ResolveInfo::SizeType pSize,
LDSymbol::ValueType pValue,
FragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
ResolveInfo* info = m_Module.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->setRegular();
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_Module.getSymbolTable().arrange(*output_sym, old_info);
}
else {
// create a output LDSymbol
output_sym = LDSymbol::Create(*info);
info->setSymPtr(output_sym);
m_Module.getSymbolTable().add(*output_sym);
}
return output_sym;
}
/// AddSymbol - define an output symbol and resolve it
/// immediately
template<> LDSymbol*
IRBuilder::AddSymbol<IRBuilder::Force, IRBuilder::Resolve>(
const llvm::StringRef& pName,
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_Module.getNamePool().insertSymbol(pName, false, 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 = LDSymbol::Create(*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_Config))
m_Module.getSymbolTable().forceLocal(*output_sym);
else if (has_output_sym)
m_Module.getSymbolTable().arrange(*output_sym, old_info);
else
m_Module.getSymbolTable().add(*output_sym);
return output_sym;
}
/// defineSymbol - define an output symbol and resolve it immediately.
template<> LDSymbol*
IRBuilder::AddSymbol<IRBuilder::AsReferred, IRBuilder::Resolve>(
const llvm::StringRef& pName,
ResolveInfo::Type pType,
ResolveInfo::Desc pDesc,
ResolveInfo::Binding pBinding,
ResolveInfo::SizeType pSize,
LDSymbol::ValueType pValue,
FragmentRef* pFragmentRef,
ResolveInfo::Visibility pVisibility)
{
ResolveInfo* info = m_Module.getNamePool().findInfo(pName);
if (NULL == info || !(info->isUndef() || info->isDyn())) {
// only undefined symbol and dynamic symbol can make a reference.
return NULL;
}
return AddSymbol<Force, Resolve>(pName,
pType,
pDesc,
pBinding,
pSize,
pValue,
pFragmentRef,
pVisibility);
}