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