| //===- 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/Script/RpnExpr.h> |
| #include <mcld/Script/Operand.h> |
| #include <mcld/Script/Operator.h> |
| #include <mcld/Script/RpnEvaluator.h> |
| #include <mcld/Support/raw_ostream.h> |
| #include <mcld/LinkerScript.h> |
| #include <mcld/LD/LDSection.h> |
| #include <mcld/LD/SectionData.h> |
| #include <mcld/Module.h> |
| #include <llvm/Support/Casting.h> |
| #include <cassert> |
| |
| using 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((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((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((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((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; |
| } |