| //===- 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(nullptr, nullptr); |
| } |
| |
| 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 |