//===- Assignment.cpp -----------------------------------------------------===// // // The MCLinker Project // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "mcld/Script/Assignment.h" #include "mcld/LinkerScript.h" #include "mcld/Module.h" #include "mcld/LD/LDSection.h" #include "mcld/LD/SectionData.h" #include "mcld/Script/Operand.h" #include "mcld/Script/Operator.h" #include "mcld/Script/RpnEvaluator.h" #include "mcld/Script/RpnExpr.h" #include "mcld/Support/raw_ostream.h" #include <llvm/Support/Casting.h> #include <cassert> namespace mcld { //===----------------------------------------------------------------------===// // Assignment //===----------------------------------------------------------------------===// Assignment::Assignment(Level pLevel, Type pType, SymOperand& pSymbol, RpnExpr& pRpnExpr) : ScriptCommand(ScriptCommand::ASSIGNMENT), m_Level(pLevel), m_Type(pType), m_Symbol(pSymbol), m_RpnExpr(pRpnExpr) { } Assignment::~Assignment() { } Assignment& Assignment::operator=(const Assignment& pAssignment) { return *this; } void Assignment::dump() const { switch (type()) { case DEFAULT: break; case HIDDEN: mcld::outs() << "HIDDEN ( "; break; case PROVIDE: mcld::outs() << "PROVIDE ( "; break; case PROVIDE_HIDDEN: mcld::outs() << "PROVIDE_HIDDEN ( "; break; default: break; } m_Symbol.dump(); mcld::outs() << " = "; m_RpnExpr.dump(); if (type() != DEFAULT) mcld::outs() << " )"; mcld::outs() << ";\n"; } void Assignment::activate(Module& pModule) { bool isLhsDot = m_Symbol.isDot(); LinkerScript& script = pModule.getScript(); switch (m_Level) { case OUTSIDE_SECTIONS: assert(!isLhsDot); script.assignments().push_back( std::make_pair(reinterpret_cast<LDSymbol*>(NULL), *this)); break; case OUTPUT_SECTION: { bool hasDotInRhs = m_RpnExpr.hasDot(); SectionMap::reference out = script.sectionMap().back(); if (hasDotInRhs) { if (!isLhsDot && out->dotAssignments().empty()) { // . = ADDR ( `prev_output_sect' ) + SIZEOF ( `prev_output_sect' ) SectionMap::iterator prev = script.sectionMap().begin() + script.sectionMap().size() - 2; Assignment assign(OUTPUT_SECTION, HIDDEN, *SymOperand::create("."), *RpnExpr::buildHelperExpr(prev)); out->dotAssignments().push_back(assign); } if (!out->dotAssignments().empty()) { Assignment& prevDotAssign = out->dotAssignments().back(); // If this is the 1st explicit assignment that includes both lhs dot // and // rhs dot, then because of possible orphan sections, we are unable to // substitute the rhs dot now. if (!isLhsDot || prevDotAssign.type() == DEFAULT) { for (RpnExpr::iterator it = m_RpnExpr.begin(), ie = m_RpnExpr.end(); it != ie; ++it) { // substitute the rhs dot with the appropriate helper expr if ((*it)->kind() == ExprToken::OPERAND && llvm::cast<Operand>(*it)->isDot()) { *it = &(prevDotAssign.symbol()); } } // for each expression token } } } if (isLhsDot) { out->dotAssignments().push_back(*this); } else { script.assignments().push_back( std::make_pair(reinterpret_cast<LDSymbol*>(NULL), *this)); } break; } case INPUT_SECTION: { bool hasDotInRhs = m_RpnExpr.hasDot(); SectionMap::Output::reference in = script.sectionMap().back()->back(); if (hasDotInRhs) { if (in->dotAssignments().empty()) { // . = `frag' RpnExpr* expr = RpnExpr::buildHelperExpr( in->getSection()->getSectionData()->front()); Assignment assign( INPUT_SECTION, HIDDEN, *SymOperand::create("."), *expr); in->dotAssignments().push_back( std::make_pair(reinterpret_cast<Fragment*>(NULL), assign)); } Assignment& prevDotAssign = in->dotAssignments().back().second; for (RpnExpr::iterator it = m_RpnExpr.begin(), ie = m_RpnExpr.end(); it != ie; ++it) { // substitute the rhs dot with the appropriate helper expr if ((*it)->kind() == ExprToken::OPERAND && llvm::cast<Operand>(*it)->isDot()) { *it = &(prevDotAssign.symbol()); } } // end of for } if (isLhsDot) { in->dotAssignments().push_back(std::make_pair( in->getSection()->getSectionData()->front().getNextNode(), *this)); } else { script.assignments().push_back( std::make_pair(reinterpret_cast<LDSymbol*>(NULL), *this)); } break; } } // end of switch } bool Assignment::assign(RpnEvaluator& pEvaluator) { uint64_t result = 0; bool success = pEvaluator.eval(m_RpnExpr, result); if (success) m_Symbol.setValue(result); return success; } } // namespace mcld