You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
13 KiB
381 lines
13 KiB
//===- SectionMap.cpp -----------------------------------------------------===//
|
|
//
|
|
// The MCLinker Project
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "mcld/Object/SectionMap.h"
|
|
|
|
#include "mcld/Fragment/NullFragment.h"
|
|
#include "mcld/LD/LDSection.h"
|
|
#include "mcld/LD/SectionData.h"
|
|
#include "mcld/Script/Assignment.h"
|
|
#include "mcld/Script/Operand.h"
|
|
#include "mcld/Script/Operator.h"
|
|
#include "mcld/Script/RpnExpr.h"
|
|
#include "mcld/Script/StringList.h"
|
|
#include "mcld/Script/WildcardPattern.h"
|
|
|
|
#include <llvm/Support/Casting.h>
|
|
|
|
#include <cassert>
|
|
#include <cstring>
|
|
#include <climits>
|
|
#if !defined(MCLD_ON_WIN32)
|
|
#include <fnmatch.h>
|
|
#define fnmatch0(pattern, string) (fnmatch(pattern, string, 0) == 0)
|
|
#else
|
|
#include <windows.h>
|
|
#include <shlwapi.h>
|
|
#define fnmatch0(pattern, string) (PathMatchSpec(string, pattern) == true)
|
|
#endif
|
|
|
|
namespace mcld {
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SectionMap::Input
|
|
//===----------------------------------------------------------------------===//
|
|
SectionMap::Input::Input(const std::string& pName,
|
|
InputSectDesc::KeepPolicy pPolicy)
|
|
: m_Policy(pPolicy) {
|
|
m_Spec.m_pWildcardFile =
|
|
WildcardPattern::create("*", WildcardPattern::SORT_NONE);
|
|
m_Spec.m_pExcludeFiles = NULL;
|
|
|
|
StringList* sections = StringList::create();
|
|
sections->push_back(
|
|
WildcardPattern::create(pName, WildcardPattern::SORT_NONE));
|
|
m_Spec.m_pWildcardSections = sections;
|
|
|
|
m_pSection = LDSection::Create(pName, LDFileFormat::TEXT, 0, 0);
|
|
SectionData* sd = SectionData::Create(*m_pSection);
|
|
m_pSection->setSectionData(sd);
|
|
new NullFragment(sd);
|
|
new NullFragment(sd);
|
|
}
|
|
|
|
SectionMap::Input::Input(const InputSectDesc& pInputDesc)
|
|
: m_Policy(pInputDesc.policy()) {
|
|
m_Spec.m_pWildcardFile = pInputDesc.spec().m_pWildcardFile;
|
|
m_Spec.m_pExcludeFiles = pInputDesc.spec().m_pExcludeFiles;
|
|
m_Spec.m_pWildcardSections = pInputDesc.spec().m_pWildcardSections;
|
|
m_pSection = LDSection::Create("", LDFileFormat::TEXT, 0, 0);
|
|
SectionData* sd = SectionData::Create(*m_pSection);
|
|
m_pSection->setSectionData(sd);
|
|
new NullFragment(sd);
|
|
new NullFragment(sd);
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SectionMap::Output
|
|
//===----------------------------------------------------------------------===//
|
|
SectionMap::Output::Output(const std::string& pName)
|
|
: m_Name(pName), m_Order(UINT_MAX) {
|
|
m_Prolog.m_pVMA = NULL;
|
|
m_Prolog.m_Type = OutputSectDesc::LOAD;
|
|
m_Prolog.m_pLMA = NULL;
|
|
m_Prolog.m_pAlign = NULL;
|
|
m_Prolog.m_pSubAlign = NULL;
|
|
m_Prolog.m_Constraint = OutputSectDesc::NO_CONSTRAINT;
|
|
|
|
m_Epilog.m_pRegion = NULL;
|
|
m_Epilog.m_pLMARegion = NULL;
|
|
m_Epilog.m_pPhdrs = NULL;
|
|
m_Epilog.m_pFillExp = NULL;
|
|
|
|
m_pSection = LDSection::Create(pName, LDFileFormat::TEXT, 0, 0);
|
|
SectionData* sd = SectionData::Create(*m_pSection);
|
|
m_pSection->setSectionData(sd);
|
|
|
|
m_bIsDiscard = pName.compare("/DISCARD/") == 0;
|
|
}
|
|
|
|
SectionMap::Output::Output(const OutputSectDesc& pOutputDesc)
|
|
: m_Name(pOutputDesc.name()),
|
|
m_Prolog(pOutputDesc.prolog()),
|
|
m_Epilog(pOutputDesc.epilog()),
|
|
m_Order(UINT_MAX) {
|
|
m_pSection = LDSection::Create(m_Name, LDFileFormat::TEXT, 0, 0);
|
|
SectionData* sd = SectionData::Create(*m_pSection);
|
|
m_pSection->setSectionData(sd);
|
|
|
|
m_bIsDiscard = m_Name.compare("/DISCARD/") == 0;
|
|
}
|
|
|
|
bool SectionMap::Output::hasContent() const {
|
|
return m_pSection != NULL && m_pSection->size() != 0;
|
|
}
|
|
|
|
SectionMap::Output::const_dot_iterator
|
|
SectionMap::Output::find_first_explicit_dot() const {
|
|
for (const_dot_iterator it = dot_begin(), ie = dot_end(); it != ie; ++it) {
|
|
if ((*it).type() == Assignment::DEFAULT)
|
|
return it;
|
|
}
|
|
return dot_end();
|
|
}
|
|
|
|
SectionMap::Output::dot_iterator SectionMap::Output::find_first_explicit_dot() {
|
|
for (dot_iterator it = dot_begin(), ie = dot_end(); it != ie; ++it) {
|
|
if ((*it).type() == Assignment::DEFAULT)
|
|
return it;
|
|
}
|
|
return dot_end();
|
|
}
|
|
|
|
SectionMap::Output::const_dot_iterator
|
|
SectionMap::Output::find_last_explicit_dot() const {
|
|
typedef DotAssignments::const_reverse_iterator CONST_RIT;
|
|
for (CONST_RIT rit = dotAssignments().rbegin(), rie = dotAssignments().rend();
|
|
rit != rie;
|
|
++rit) {
|
|
if ((*rit).type() == Assignment::DEFAULT) {
|
|
return dot_begin() +
|
|
(dotAssignments().size() - (rit - dotAssignments().rbegin()) - 1);
|
|
}
|
|
}
|
|
return dot_end();
|
|
}
|
|
|
|
SectionMap::Output::dot_iterator SectionMap::Output::find_last_explicit_dot() {
|
|
typedef DotAssignments::reverse_iterator RIT;
|
|
for (RIT rit = dotAssignments().rbegin(), rie = dotAssignments().rend();
|
|
rit != rie;
|
|
++rit) {
|
|
if ((*rit).type() == Assignment::DEFAULT) {
|
|
return dot_begin() +
|
|
(dotAssignments().size() - (rit - dotAssignments().rbegin()) - 1);
|
|
}
|
|
}
|
|
return dot_end();
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// SectionMap
|
|
//===----------------------------------------------------------------------===//
|
|
SectionMap::~SectionMap() {
|
|
iterator out, outBegin = begin(), outEnd = end();
|
|
for (out = outBegin; out != outEnd; ++out) {
|
|
if (*out != NULL) {
|
|
Output::iterator in, inBegin = (*out)->begin(), inEnd = (*out)->end();
|
|
for (in = inBegin; in != inEnd; ++in) {
|
|
if (*in != NULL)
|
|
delete *in;
|
|
}
|
|
delete *out;
|
|
}
|
|
}
|
|
}
|
|
|
|
SectionMap::const_mapping SectionMap::find(
|
|
const std::string& pInputFile,
|
|
const std::string& pInputSection) const {
|
|
const_iterator out, outBegin = begin(), outEnd = end();
|
|
for (out = outBegin; out != outEnd; ++out) {
|
|
Output::const_iterator in, inBegin = (*out)->begin(), inEnd = (*out)->end();
|
|
for (in = inBegin; in != inEnd; ++in) {
|
|
if (matched(**in, pInputFile, pInputSection))
|
|
return std::make_pair(*out, *in);
|
|
}
|
|
}
|
|
return std::make_pair((const Output*)NULL, (const Input*)NULL);
|
|
}
|
|
|
|
SectionMap::mapping SectionMap::find(const std::string& pInputFile,
|
|
const std::string& pInputSection) {
|
|
iterator out, outBegin = begin(), outEnd = end();
|
|
for (out = outBegin; out != outEnd; ++out) {
|
|
Output::iterator in, inBegin = (*out)->begin(), inEnd = (*out)->end();
|
|
for (in = inBegin; in != inEnd; ++in) {
|
|
if (matched(**in, pInputFile, pInputSection))
|
|
return std::make_pair(*out, *in);
|
|
}
|
|
}
|
|
return std::make_pair(reinterpret_cast<Output*>(NULL),
|
|
reinterpret_cast<Input*>(NULL));
|
|
}
|
|
|
|
SectionMap::const_iterator SectionMap::find(
|
|
const std::string& pOutputSection) const {
|
|
const_iterator out, outBegin = begin(), outEnd = end();
|
|
for (out = outBegin; out != outEnd; ++out) {
|
|
if ((*out)->name().compare(pOutputSection) == 0)
|
|
return out;
|
|
}
|
|
return outEnd;
|
|
}
|
|
|
|
SectionMap::iterator SectionMap::find(const std::string& pOutputSection) {
|
|
iterator out, outBegin = begin(), outEnd = end();
|
|
for (out = outBegin; out != outEnd; ++out) {
|
|
if ((*out)->name().compare(pOutputSection) == 0)
|
|
return out;
|
|
}
|
|
return outEnd;
|
|
}
|
|
|
|
std::pair<SectionMap::mapping, bool> SectionMap::insert(
|
|
const std::string& pInputSection,
|
|
const std::string& pOutputSection,
|
|
InputSectDesc::KeepPolicy pPolicy) {
|
|
iterator out, outBegin = begin(), outEnd = end();
|
|
for (out = outBegin; out != outEnd; ++out) {
|
|
if ((*out)->name().compare(pOutputSection) == 0)
|
|
break;
|
|
}
|
|
if (out != end()) {
|
|
Output::iterator in, inBegin = (*out)->begin(), inEnd = (*out)->end();
|
|
for (in = inBegin; in != inEnd; ++in) {
|
|
if ((*in)->getSection()->name().compare(pInputSection) == 0)
|
|
break;
|
|
}
|
|
|
|
if (in != (*out)->end()) {
|
|
return std::make_pair(std::make_pair(*out, *in), false);
|
|
} else {
|
|
Input* input = new Input(pInputSection, pPolicy);
|
|
(*out)->append(input);
|
|
return std::make_pair(std::make_pair(*out, input), true);
|
|
}
|
|
}
|
|
|
|
Output* output = new Output(pOutputSection);
|
|
m_OutputDescList.push_back(output);
|
|
Input* input = new Input(pInputSection, pPolicy);
|
|
output->append(input);
|
|
|
|
return std::make_pair(std::make_pair(output, input), true);
|
|
}
|
|
|
|
std::pair<SectionMap::mapping, bool> SectionMap::insert(
|
|
const InputSectDesc& pInputDesc,
|
|
const OutputSectDesc& pOutputDesc) {
|
|
iterator out, outBegin = begin(), outEnd = end();
|
|
for (out = outBegin; out != outEnd; ++out) {
|
|
if ((*out)->name().compare(pOutputDesc.name()) == 0 &&
|
|
(*out)->prolog() == pOutputDesc.prolog() &&
|
|
(*out)->epilog() == pOutputDesc.epilog())
|
|
break;
|
|
}
|
|
|
|
if (out != end()) {
|
|
Output::iterator in, inBegin = (*out)->begin(), inEnd = (*out)->end();
|
|
for (in = inBegin; in != inEnd; ++in) {
|
|
if ((*in)->policy() == pInputDesc.policy() &&
|
|
(*in)->spec() == pInputDesc.spec())
|
|
break;
|
|
}
|
|
|
|
if (in != (*out)->end()) {
|
|
return std::make_pair(std::make_pair(*out, *in), false);
|
|
} else {
|
|
Input* input = new Input(pInputDesc);
|
|
(*out)->append(input);
|
|
return std::make_pair(std::make_pair(*out, input), true);
|
|
}
|
|
}
|
|
|
|
Output* output = new Output(pOutputDesc);
|
|
m_OutputDescList.push_back(output);
|
|
Input* input = new Input(pInputDesc);
|
|
output->append(input);
|
|
|
|
return std::make_pair(std::make_pair(output, input), true);
|
|
}
|
|
|
|
SectionMap::iterator SectionMap::insert(iterator pPosition,
|
|
LDSection* pSection) {
|
|
Output* output = new Output(pSection->name());
|
|
output->append(new Input(pSection->name(), InputSectDesc::NoKeep));
|
|
output->setSection(pSection);
|
|
return m_OutputDescList.insert(pPosition, output);
|
|
}
|
|
|
|
bool SectionMap::matched(const SectionMap::Input& pInput,
|
|
const std::string& pInputFile,
|
|
const std::string& pInputSection) const {
|
|
if (pInput.spec().hasFile() && !matched(pInput.spec().file(), pInputFile))
|
|
return false;
|
|
|
|
if (pInput.spec().hasExcludeFiles()) {
|
|
StringList::const_iterator file, fileEnd;
|
|
fileEnd = pInput.spec().excludeFiles().end();
|
|
for (file = pInput.spec().excludeFiles().begin(); file != fileEnd; ++file) {
|
|
if (matched(llvm::cast<WildcardPattern>(**file), pInputFile)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pInput.spec().hasSections()) {
|
|
StringList::const_iterator sect, sectEnd = pInput.spec().sections().end();
|
|
for (sect = pInput.spec().sections().begin(); sect != sectEnd; ++sect) {
|
|
if (matched(llvm::cast<WildcardPattern>(**sect), pInputSection)) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool SectionMap::matched(const WildcardPattern& pPattern,
|
|
const std::string& pName) const {
|
|
if (pPattern.isPrefix()) {
|
|
llvm::StringRef name(pName);
|
|
return name.startswith(pPattern.prefix());
|
|
} else {
|
|
return fnmatch0(pPattern.name().c_str(), pName.c_str());
|
|
}
|
|
}
|
|
|
|
// fixupDotSymbols - ensure the dot symbols are valid
|
|
void SectionMap::fixupDotSymbols() {
|
|
for (iterator it = begin() + 1, ie = end(); it != ie; ++it) {
|
|
// fixup the 1st explicit dot assignment if needed
|
|
if (!(*it)->dotAssignments().empty()) {
|
|
Output::dot_iterator dot = (*it)->find_first_explicit_dot();
|
|
if (dot != (*it)->dot_end() && (*dot).symbol().isDot() &&
|
|
(*dot).getRpnExpr().hasDot()) {
|
|
Assignment assign(Assignment::OUTPUT_SECTION,
|
|
Assignment::DEFAULT,
|
|
*SymOperand::create("."),
|
|
*RpnExpr::buildHelperExpr(it - 1));
|
|
Output::dot_iterator ref = (*it)->dotAssignments().insert(dot, assign);
|
|
for (RpnExpr::iterator tok = (*dot).getRpnExpr().begin(),
|
|
tokEnd = (*dot).getRpnExpr().end();
|
|
tok != tokEnd;
|
|
++tok) {
|
|
if ((*tok)->kind() == ExprToken::OPERAND &&
|
|
llvm::cast<Operand>(*tok)->isDot())
|
|
*tok = &((*ref).symbol());
|
|
} // for each token in the RHS expr of the dot assignment
|
|
}
|
|
}
|
|
|
|
// fixup dot in output VMA if needed
|
|
if ((*it)->prolog().hasVMA() && (*it)->prolog().vma().hasDot()) {
|
|
Output::dot_iterator dot = (*it)->find_last_explicit_dot();
|
|
if (dot == (*it)->dot_end()) {
|
|
Assignment assign(Assignment::OUTPUT_SECTION,
|
|
Assignment::DEFAULT,
|
|
*SymOperand::create("."),
|
|
*RpnExpr::buildHelperExpr(it - 1));
|
|
dot = (*it)->dotAssignments().insert(dot, assign);
|
|
}
|
|
for (RpnExpr::iterator tok = (*it)->prolog().vma().begin(),
|
|
tokEnd = (*it)->prolog().vma().end();
|
|
tok != tokEnd;
|
|
++tok) {
|
|
if ((*tok)->kind() == ExprToken::OPERAND &&
|
|
llvm::cast<Operand>(*tok)->isDot())
|
|
*tok = &((*dot).symbol());
|
|
} // for each token in the RHS expr of the dot assignment
|
|
}
|
|
} // for each output section
|
|
}
|
|
|
|
} // namespace mcld
|