You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
213 lines
8.1 KiB
213 lines
8.1 KiB
//===- StaticResolver.cpp -------------------------------------------------===//
|
|
//
|
|
// The MCLinker Project
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
#include "mcld/LD/StaticResolver.h"
|
|
|
|
#include "mcld/LD/LDSymbol.h"
|
|
#include "mcld/Support/Demangle.h"
|
|
#include "mcld/Support/MsgHandling.h"
|
|
|
|
namespace mcld {
|
|
|
|
//==========================
|
|
// StaticResolver
|
|
StaticResolver::~StaticResolver() {
|
|
}
|
|
|
|
bool StaticResolver::resolve(ResolveInfo& __restrict__ pOld,
|
|
const ResolveInfo& __restrict__ pNew,
|
|
bool& pOverride,
|
|
LDSymbol::ValueType pValue) const {
|
|
/* The state table itself.
|
|
* The first index is a link_row and the second index is a bfd_link_hash_type.
|
|
*
|
|
* Cs -> all rest kind of common (d_C, wd_C)
|
|
* Is -> all kind of indirect
|
|
*/
|
|
static const enum LinkAction link_action[LAST_ORD][LAST_ORD] = {
|
|
/* new\old U w_U d_U wd_U D w_D d_D wd_D C w_C, Cs, Is */ // NOLINT
|
|
/* U */ {NOACT, UND, UND, UND, NOACT, NOACT, DUND, DUND, NOACT, NOACT, NOACT, REFC }, // NOLINT
|
|
/* w_U */ {NOACT, NOACT, NOACT, WEAK, NOACT, NOACT, DUNDW, DUNDW, NOACT, NOACT, NOACT, REFC }, // NOLINT
|
|
/* d_U */ {NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC }, // NOLINT
|
|
/* wd_U */ {NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC }, // NOLINT
|
|
/* D */ {DEF, DEF, DEF, DEF, MDEF, DEF, DEF, DEF, CDEF, CDEF, CDEF, MDEF }, // NOLINT
|
|
/* w_D */ {DEFW, DEFW, DEFW, DEFW, NOACT, NOACT, DEFW, DEFW, NOACT, NOACT, NOACT, NOACT}, // NOLINT
|
|
/* d_D */ {MDEFD, MDEFD, DEFD, DEFD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, MDEF }, // NOLINT
|
|
/* wd_D */ {MDEFWD, MDEFWD, DEFWD, DEFWD, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT}, // NOLINT
|
|
/* C */ {COM, COM, COM, COM, CREF, COM, COM, COM, MBIG, COM, BIG, REFC }, // NOLINT
|
|
/* w_C */ {COM, COM, COM, COM, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, NOACT, REFC }, // NOLINT
|
|
/* Cs */ {COM, COM, COM, COM, NOACT, NOACT, NOACT, NOACT, MBIG, MBIG, MBIG, REFC }, // NOLINT
|
|
/* Is */ {IND, IND, IND, IND, MDEF, IND, IND, IND, CIND, CIND, CIND, MIND } // NOLINT
|
|
};
|
|
|
|
// Special cases:
|
|
// * when a dynamic defined symbol meets a dynamic weak defined symbol, act
|
|
// noting.
|
|
// * when a undefined symbol meets a dynamic defined symbol, override by
|
|
// dynamic defined first, then recover back to undefined symbol later.
|
|
// * when a dynamic defined symbol meets a undefined symbol or a weak
|
|
// undefined symbol, do not override, instead of marking.
|
|
// * When a undefined symbol meets a dynamic defined symbol or a weak
|
|
// undefined symbol meets a dynamic defined symbol, should override.
|
|
// * When a common symbol meets a weak common symbol, adjust the size of
|
|
// common symbol.
|
|
|
|
unsigned int row = getOrdinate(pNew);
|
|
unsigned int col = getOrdinate(pOld);
|
|
|
|
bool cycle = false;
|
|
pOverride = false;
|
|
ResolveInfo* old = &pOld;
|
|
LinkAction action;
|
|
do {
|
|
cycle = false;
|
|
action = link_action[row][col];
|
|
|
|
switch (action) {
|
|
case FAIL: { /* abort. */
|
|
fatal(diag::fail_sym_resolution) << __FILE__ << __LINE__
|
|
<< "mclinker@googlegroups.com";
|
|
return false;
|
|
}
|
|
case NOACT: { /* no action. */
|
|
pOverride = false;
|
|
old->overrideVisibility(pNew);
|
|
break;
|
|
}
|
|
case UND: /* override by symbol undefined symbol. */
|
|
case WEAK: /* override by symbol weak undefined. */
|
|
case DEF: /* override by symbol defined. */
|
|
case DEFW: /* override by symbol weak defined. */
|
|
case DEFD: /* override by symbol dynamic defined. */
|
|
case DEFWD: /* override by symbol dynamic weak defined. */
|
|
case COM: { /* override by symbol common defined. */
|
|
pOverride = true;
|
|
old->override(pNew);
|
|
break;
|
|
}
|
|
case MDEFD: /* mark symbol dynamic defined. */
|
|
case MDEFWD: { /* mark symbol dynamic weak defined. */
|
|
uint32_t binding = old->binding();
|
|
old->override(pNew);
|
|
old->setBinding(binding);
|
|
ignore(diag::mark_dynamic_defined) << old->name();
|
|
pOverride = true;
|
|
break;
|
|
}
|
|
case DUND:
|
|
case DUNDW: {
|
|
old->overrideVisibility(pNew);
|
|
old->setDynamic();
|
|
pOverride = false;
|
|
break;
|
|
}
|
|
case CREF: { /* Possibly warn about common reference to defined symbol. */
|
|
// A common symbol does not override a definition.
|
|
ignore(diag::comm_refer_to_define) << old->name();
|
|
pOverride = false;
|
|
break;
|
|
}
|
|
case CDEF: { /* redefine existing common symbol. */
|
|
// We've seen a common symbol and now we see a definition. The
|
|
// definition overrides.
|
|
//
|
|
// NOTE: m_Mesg uses 'name' instead of `name' for being compatible to
|
|
// GNU ld.
|
|
ignore(diag::redefine_common) << old->name();
|
|
old->override(pNew);
|
|
pOverride = true;
|
|
break;
|
|
}
|
|
case BIG: { /* override by symbol common using largest size. */
|
|
if (old->size() < pNew.size())
|
|
old->setSize(pNew.size());
|
|
old->overrideAttributes(pNew);
|
|
old->overrideVisibility(pNew);
|
|
pOverride = true;
|
|
break;
|
|
}
|
|
case MBIG: { /* mark common symbol by larger size. */
|
|
if (old->size() < pNew.size())
|
|
old->setSize(pNew.size());
|
|
old->overrideVisibility(pNew);
|
|
pOverride = false;
|
|
break;
|
|
}
|
|
case CIND: { /* mark indirect symbol from existing common symbol. */
|
|
ignore(diag::indirect_refer_to_common) << old->name();
|
|
}
|
|
/* Fall through */
|
|
case IND: { /* override by indirect symbol. */
|
|
if (pNew.link() == NULL) {
|
|
fatal(diag::indirect_refer_to_inexist) << pNew.name();
|
|
break;
|
|
}
|
|
|
|
/** Should detect the loop of indirect symbol during file reading **/
|
|
// if (pNew.link()->isIndirect() && pNew.link()->link() == &pNew) {
|
|
// m_Mesg = "indirect symbol `"+pNew.name()+"' to
|
|
// `"+pNew.link()->name()+"' is a loop.";
|
|
// return Resolver::Abort;
|
|
//}
|
|
|
|
// change the old symbol to the indirect symbol
|
|
old->setLink(pNew.link());
|
|
pOverride = true;
|
|
break;
|
|
}
|
|
case MIND: { /* multiple indirect symbols. */
|
|
// it is OK if they both point to the same symbol
|
|
if (old->link() == pNew.link()) {
|
|
pOverride = false;
|
|
break;
|
|
}
|
|
}
|
|
/* Fall through */
|
|
case MDEF: { /* multiple definition error. */
|
|
if (pOld.isDefine() && pNew.isDefine() && pOld.isAbsolute() &&
|
|
pNew.isAbsolute() &&
|
|
(pOld.desc() == pNew.desc() || pOld.desc() == ResolveInfo::NoType ||
|
|
pNew.desc() == ResolveInfo::NoType)) {
|
|
if (pOld.outSymbol()->value() == pValue) {
|
|
pOverride = true;
|
|
old->override(pNew);
|
|
break;
|
|
} else {
|
|
error(diag::multiple_absolute_definitions)
|
|
<< demangleName(pNew.name()) << pOld.outSymbol()->value()
|
|
<< pValue;
|
|
break;
|
|
}
|
|
}
|
|
|
|
error(diag::multiple_definitions) << demangleName(pNew.name());
|
|
break;
|
|
}
|
|
case REFC: { /* Mark indirect symbol referenced and then CYCLE. */
|
|
if (old->link() == NULL) {
|
|
fatal(diag::indirect_refer_to_inexist) << old->name();
|
|
break;
|
|
}
|
|
|
|
old = old->link();
|
|
col = getOrdinate(*old);
|
|
cycle = true;
|
|
break;
|
|
}
|
|
default: {
|
|
error(diag::undefined_situation) << action << old->name()
|
|
<< pNew.name();
|
|
return false;
|
|
}
|
|
} // end of the big switch (action)
|
|
} while (cycle);
|
|
return true;
|
|
}
|
|
|
|
} // namespace mcld
|