| //===- 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(nullptr, *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(nullptr, *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(nullptr, 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(nullptr, *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 |