1//===- Assignment.cpp -----------------------------------------------------===//
2//
3//                     The MCLinker Project
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include <mcld/Script/Assignment.h>
10#include <mcld/Script/RpnExpr.h>
11#include <mcld/Script/Operand.h>
12#include <mcld/Script/Operator.h>
13#include <mcld/Script/RpnEvaluator.h>
14#include <mcld/Support/raw_ostream.h>
15#include <mcld/LinkerScript.h>
16#include <mcld/LD/LDSection.h>
17#include <mcld/LD/SectionData.h>
18#include <mcld/Module.h>
19#include <llvm/Support/Casting.h>
20#include <cassert>
21
22using namespace mcld;
23
24//===----------------------------------------------------------------------===//
25// Assignment
26//===----------------------------------------------------------------------===//
27Assignment::Assignment(Level pLevel,
28                       Type pType,
29                       SymOperand& pSymbol,
30                       RpnExpr& pRpnExpr)
31  : ScriptCommand(ScriptCommand::ASSIGNMENT),
32    m_Level(pLevel),
33    m_Type(pType),
34    m_Symbol(pSymbol),
35    m_RpnExpr(pRpnExpr)
36{
37}
38
39Assignment::~Assignment()
40{
41}
42
43Assignment& Assignment::operator=(const Assignment& pAssignment)
44{
45  return *this;
46}
47
48void Assignment::dump() const
49{
50  switch (type()) {
51  case DEFAULT:
52    break;
53  case HIDDEN:
54    mcld::outs() << "HIDDEN ( ";
55    break;
56  case PROVIDE:
57    mcld::outs() << "PROVIDE ( ";
58    break;
59  case PROVIDE_HIDDEN:
60    mcld::outs() << "PROVIDE_HIDDEN ( ";
61    break;
62  default:
63    break;
64  }
65
66  m_Symbol.dump();
67
68  mcld::outs() << " = ";
69
70  m_RpnExpr.dump();
71
72  if (type() != DEFAULT)
73    mcld::outs() << " )";
74
75  mcld::outs() << ";\n";
76}
77
78void Assignment::activate(Module& pModule)
79{
80  bool isLhsDot = m_Symbol.isDot();
81  LinkerScript& script = pModule.getScript();
82  switch (m_Level) {
83  case OUTSIDE_SECTIONS:
84    assert(!isLhsDot);
85    script.assignments().push_back(std::make_pair((LDSymbol*)NULL, *this));
86    break;
87
88  case OUTPUT_SECTION: {
89    bool hasDotInRhs = m_RpnExpr.hasDot();
90    SectionMap::reference out = script.sectionMap().back();
91    if (hasDotInRhs) {
92      if (!isLhsDot && out->dotAssignments().empty()) {
93        // . = ADDR ( `prev_output_sect' ) + SIZEOF ( `prev_output_sect' )
94        SectionMap::iterator prev = script.sectionMap().begin() +
95                                    script.sectionMap().size() - 2;
96        Assignment assign(OUTPUT_SECTION,
97                          HIDDEN,
98                          *SymOperand::create("."),
99                          *RpnExpr::buildHelperExpr(prev));
100        out->dotAssignments().push_back(assign);
101      }
102
103      if (!out->dotAssignments().empty()) {
104        Assignment& prevDotAssign = out->dotAssignments().back();
105        // If this is the 1st explicit assignment that includes both lhs dot and
106        // rhs dot, then because of possible orphan sections, we are unable to
107        // substitute the rhs dot now.
108        if (!isLhsDot || prevDotAssign.type() == DEFAULT) {
109          for (RpnExpr::iterator it = m_RpnExpr.begin(), ie = m_RpnExpr.end();
110            it != ie; ++it) {
111            // substitute the rhs dot with the appropriate helper expr
112            if ((*it)->kind() == ExprToken::OPERAND &&
113                llvm::cast<Operand>(*it)->isDot())
114              *it = &(prevDotAssign.symbol());
115          } // for each expression token
116        }
117      }
118    }
119
120    if (isLhsDot) {
121      out->dotAssignments().push_back(*this);
122    } else {
123      script.assignments().push_back(std::make_pair((LDSymbol*)NULL, *this));
124    }
125
126    break;
127  }
128
129  case INPUT_SECTION: {
130    bool hasDotInRhs = m_RpnExpr.hasDot();
131    SectionMap::Output::reference in = script.sectionMap().back()->back();
132    if (hasDotInRhs) {
133      if (in->dotAssignments().empty()) {
134        // . = `frag'
135        RpnExpr* expr =
136          RpnExpr::buildHelperExpr(in->getSection()->getSectionData()->front());
137        Assignment assign(INPUT_SECTION,
138                          HIDDEN,
139                          *SymOperand::create("."),
140                          *expr);
141        in->dotAssignments().push_back(std::make_pair((Fragment*)NULL, assign));
142      }
143
144      Assignment& prevDotAssign = in->dotAssignments().back().second;
145      for (RpnExpr::iterator it = m_RpnExpr.begin(), ie = m_RpnExpr.end();
146        it != ie; ++it) {
147        // substitute the rhs dot with the appropriate helper expr
148        if ((*it)->kind() == ExprToken::OPERAND &&
149            llvm::cast<Operand>(*it)->isDot())
150          *it = &(prevDotAssign.symbol());
151      } // end of for
152    }
153
154    if (isLhsDot) {
155      in->dotAssignments().push_back(
156        std::make_pair(in->getSection()->getSectionData()->front().getNextNode(),
157                       *this));
158    } else {
159      script.assignments().push_back(std::make_pair((LDSymbol*)NULL, *this));
160    }
161
162    break;
163  }
164
165  } // end of switch
166}
167
168bool Assignment::assign(RpnEvaluator& pEvaluator)
169{
170  uint64_t result = 0;
171  bool success = pEvaluator.eval(m_RpnExpr, result);
172  if (success)
173    m_Symbol.setValue(result);
174  return success;
175}
176