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