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 
25 namespace mcld {
26 
27 //===----------------------------------------------------------------------===//
28 // Assignment
29 //===----------------------------------------------------------------------===//
Assignment(Level pLevel,Type pType,SymOperand & pSymbol,RpnExpr & pRpnExpr)30 Assignment::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 
~Assignment()41 Assignment::~Assignment() {
42 }
43 
operator =(const Assignment & pAssignment)44 Assignment& Assignment::operator=(const Assignment& pAssignment) {
45   return *this;
46 }
47 
dump() const48 void 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 
activate(Module & pModule)77 void 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 
assign(RpnEvaluator & pEvaluator)169 bool 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