blob: 1df7817e74a4ece68321ba2bcf42f16ac056df15 [file] [log] [blame]
//===- 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