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