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