StaticResolver.cpp revision 0dea6bc96bb52346737966839ac68644f7939f58
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
14using namespace mcld;
15
16//==========================
17// StaticResolver
18StaticResolver::~StaticResolver()
19{
20}
21
22bool 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