C++程序  |  176行  |  5.04 KB

//===- 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;
}