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