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