1 //===- StaticResolver.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/LD/StaticResolver.h>
10 #include <mcld/LD/LDSymbol.h>
11 #include <mcld/Support/Demangle.h>
12 #include <mcld/Support/MsgHandling.h>
13
14 using namespace mcld;
15
16 //==========================
17 // StaticResolver
~StaticResolver()18 StaticResolver::~StaticResolver()
19 {
20 }
21
resolve(ResolveInfo & __restrict__ pOld,const ResolveInfo & __restrict__ pNew,bool & pOverride,LDSymbol::ValueType pValue) const22 bool StaticResolver::resolve(ResolveInfo& __restrict__ pOld,
23 const ResolveInfo& __restrict__ pNew,
24 bool &pOverride, LDSymbol::ValueType pValue) const
25 {
26
27 /* The state table itself.
28 * The first index is a link_row and the second index is a bfd_link_hash_type.
29 *
30 * Cs -> all rest kind of common (d_C, wd_C)
31 * Is -> all kind of indirect
32 */
33 static const enum LinkAction link_action[LAST_ORD][LAST_ORD] =
34 {
35 /* new\old U w_U d_U wd_U D w_D d_D wd_D C w_C, Cs, Is */
36 /* U */ {NOACT, UND, UND, UND, NOACT, NOACT, DUND, DUND, NOACT, NOACT, NOACT, REFC },
37 /* w_U */ {NOACT, NOACT, NOACT, WEAK, NOACT, NOACT, DUNDW, DUNDW, NOACT, NOACT, NOACT, REFC },
38 /* d_U */ {NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC },
39 /* wd_U */ {NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC },
40 /* D */ {DEF, DEF, DEF, DEF, MDEF, DEF, DEF, DEF, CDEF, CDEF, CDEF, MDEF },
41 /* w_D */ {DEFW, DEFW, DEFW, DEFW, NOACT, NOACT, DEFW, DEFW, NOACT, NOACT, NOACT, NOACT},
42 /* d_D */ {MDEFD, MDEFD, DEFD, DEFD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, MDEF },
43 /* wd_D */ {MDEFWD, MDEFWD, DEFWD, DEFWD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT},
44 /* C */ {COM, COM, COM, COM, CREF, COM, COM, COM, MBIG, COM, BIG, REFC },
45 /* w_C */ {COM, COM, COM, COM, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC },
46 /* Cs */ {COM, COM, COM, COM, NOACT, NOACT, NOACT, NOACT, MBIG, MBIG, MBIG, REFC },
47 /* Is */ {IND, IND, IND, IND, MDEF, IND, IND, IND, CIND, CIND, CIND, MIND }
48 };
49
50 // Special cases:
51 // * when a dynamic defined symbol meets a dynamic weak defined symbol, act
52 // noting.
53 // * when a undefined symbol meets a dynamic defined symbol, override by
54 // dynamic defined first, then recover back to undefined symbol later.
55 // * when a dynamic defined symbol meets a undefined symbol or a weak
56 // undefined symbol, do not override, instead of marking.
57 // * When a undefined symbol meets a dynamic defined symbol or a weak
58 // undefined symbol meets a dynamic defined symbol, should override.
59 // * When a common symbol meets a weak common symbol, adjust the size of
60 // common symbol (ref: Google gold linker: resolve.cc)
61
62 unsigned int row = getOrdinate(pNew);
63 unsigned int col = getOrdinate(pOld);
64
65 bool cycle = false;
66 pOverride = false;
67 ResolveInfo* old = &pOld;
68 LinkAction action;
69 do {
70 cycle = false;
71 action = link_action[row][col];
72
73 switch(action) {
74 case FAIL: { /* abort. */
75 fatal(diag::fail_sym_resolution)
76 << __FILE__ << __LINE__
77 << "mclinker@googlegroups.com";
78 return false;
79 }
80 case NOACT: { /* no action. */
81 pOverride = false;
82 old->overrideVisibility(pNew);
83 break;
84 }
85 case UND: /* override by symbol undefined symbol. */
86 case WEAK: /* override by symbol weak undefined. */
87 case DEF: /* override by symbol defined. */
88 case DEFW: /* override by symbol weak defined. */
89 case DEFD: /* override by symbol dynamic defined. */
90 case DEFWD: /* override by symbol dynamic weak defined. */
91 case COM: { /* override by symbol common defined. */
92 pOverride = true;
93 old->override(pNew);
94 break;
95 }
96 case MDEFD: /* mark symbol dynamic defined. */
97 case MDEFWD: { /* mark symbol dynamic weak defined. */
98 uint32_t binding = old->binding();
99 old->override(pNew);
100 old->setBinding(binding);
101 ignore(diag::mark_dynamic_defined) << old->name();
102 pOverride = true;
103 break;
104 }
105 case DUND:
106 case DUNDW: {
107 old->overrideVisibility(pNew);
108 old->setDynamic();
109 pOverride = false;
110 break;
111 }
112 case CREF: { /* Possibly warn about common reference to defined symbol. */
113 // A common symbol does not override a definition.
114 ignore(diag::comm_refer_to_define) << old->name();
115 pOverride = false;
116 break;
117 }
118 case CDEF: { /* redefine existing common symbol. */
119 // We've seen a common symbol and now we see a definition. The
120 // definition overrides.
121 //
122 // NOTE: m_Mesg uses 'name' instead of `name' for being compatible to GNU ld.
123 ignore(diag::redefine_common) << old->name();
124 old->override(pNew);
125 pOverride = true;
126 break;
127 }
128 case BIG: { /* override by symbol common using largest size. */
129 if (old->size() < pNew.size())
130 old->setSize(pNew.size());
131 old->overrideAttributes(pNew);
132 old->overrideVisibility(pNew);
133 pOverride = true;
134 break;
135 }
136 case MBIG: { /* mark common symbol by larger size. */
137 if (old->size() < pNew.size())
138 old->setSize(pNew.size());
139 old->overrideVisibility(pNew);
140 pOverride = false;
141 break;
142 }
143 case CIND: { /* mark indirect symbol from existing common symbol. */
144 ignore(diag::indirect_refer_to_common) << old->name();
145 }
146 /* Fall through */
147 case IND: { /* override by indirect symbol. */
148 if (NULL == pNew.link()) {
149 fatal(diag::indirect_refer_to_inexist) << pNew.name();
150 break;
151 }
152
153 /** Should detect the loop of indirect symbol during file reading **/
154 // if (pNew.link()->isIndirect() && pNew.link()->link() == &pNew) {
155 // m_Mesg = "indirect symbol `"+pNew.name()+"' to `"+pNew.link()->name()+"' is a loop.";
156 // return Resolver::Abort;
157 //}
158
159 // change the old symbol to the indirect symbol
160 old->setLink(pNew.link());
161 pOverride = true;
162 break;
163 }
164 case MIND: { /* multiple indirect symbols. */
165 // it is OK if they both point to the same symbol
166 if (old->link() == pNew.link()) {
167 pOverride = false;
168 break;
169 }
170 }
171 /* Fall through */
172 case MDEF: { /* multiple definition error. */
173 if (pOld.isDefine() && pNew.isDefine() &&
174 pOld.isAbsolute() && pNew.isAbsolute() &&
175 (pOld.desc() == pNew.desc() || pOld.desc() == ResolveInfo::NoType ||
176 pNew.desc() == ResolveInfo::NoType)) {
177 if (pOld.outSymbol()->value() == pValue) {
178 pOverride = true;
179 old->override(pNew);
180 break;
181 } else {
182 error(diag::multiple_absolute_definitions)
183 << demangleName(pNew.name())
184 << pOld.outSymbol()->value()
185 << pValue;
186 break;
187 }
188 }
189
190 error(diag::multiple_definitions) << demangleName(pNew.name());
191 break;
192 }
193 case REFC: { /* Mark indirect symbol referenced and then CYCLE. */
194 if (NULL == old->link()) {
195 fatal(diag::indirect_refer_to_inexist) << old->name();
196 break;
197 }
198
199 old = old->link();
200 col = getOrdinate(*old);
201 cycle = true;
202 break;
203 }
204 default: {
205 error(diag::undefined_situation) << action << old->name() << pNew.name();
206 return false;
207 }
208 } // end of the big switch (action)
209 } while(cycle);
210 return true;
211 }
212
213