blob: 58c13609d441fbc354012ef50313af1e3d491a60 [file] [log] [blame]
//===- 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>
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;
}
//===----------------------------------------------------------------------===//
// 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 = new EhFrame(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.getFragmentList().push_back(&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();
}