Line 114... |
Line 114... |
LDPT_REGISTER_CLEANUP_HOOK,
|
LDPT_REGISTER_CLEANUP_HOOK,
|
LDPT_ADD_SYMBOLS,
|
LDPT_ADD_SYMBOLS,
|
LDPT_GET_INPUT_FILE,
|
LDPT_GET_INPUT_FILE,
|
LDPT_RELEASE_INPUT_FILE,
|
LDPT_RELEASE_INPUT_FILE,
|
LDPT_GET_SYMBOLS,
|
LDPT_GET_SYMBOLS,
|
|
LDPT_GET_SYMBOLS_V2,
|
LDPT_ADD_INPUT_FILE,
|
LDPT_ADD_INPUT_FILE,
|
LDPT_ADD_INPUT_LIBRARY,
|
LDPT_ADD_INPUT_LIBRARY,
|
LDPT_SET_EXTRA_LIBRARY_PATH
|
LDPT_SET_EXTRA_LIBRARY_PATH
|
};
|
};
|
|
|
Line 439... |
Line 440... |
}
|
}
|
|
|
/* Return TRUE if a defined symbol might be reachable from outside the
|
/* Return TRUE if a defined symbol might be reachable from outside the
|
universe of claimed objects. */
|
universe of claimed objects. */
|
static inline bfd_boolean
|
static inline bfd_boolean
|
is_visible_from_outside (struct ld_plugin_symbol *lsym, asection *section,
|
is_visible_from_outside (struct ld_plugin_symbol *lsym,
|
struct bfd_link_hash_entry *blhe)
|
struct bfd_link_hash_entry *blhe)
|
{
|
{
|
struct bfd_sym_chain *sym;
|
struct bfd_sym_chain *sym;
|
|
|
/* Section's owner may be NULL if it is the absolute
|
|
section, fortunately is_ir_dummy_bfd handles that. */
|
|
if (!is_ir_dummy_bfd (section->owner))
|
|
return TRUE;
|
|
if (link_info.relocatable)
|
if (link_info.relocatable)
|
return TRUE;
|
return TRUE;
|
if (link_info.export_dynamic || link_info.shared)
|
if (link_info.export_dynamic || !link_info.executable)
|
{
|
{
|
|
/* Check if symbol is hidden by version script. */
|
|
if (bfd_hide_sym_by_version (link_info.version_info,
|
|
blhe->root.string))
|
|
return FALSE;
|
/* Only ELF symbols really have visibility. */
|
/* Only ELF symbols really have visibility. */
|
if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour)
|
if (bfd_get_flavour (link_info.output_bfd) == bfd_target_elf_flavour)
|
{
|
{
|
struct elf_link_hash_entry *el = (struct elf_link_hash_entry *)blhe;
|
struct elf_link_hash_entry *el = (struct elf_link_hash_entry *)blhe;
|
int vis = ELF_ST_VISIBILITY (el->other);
|
int vis = ELF_ST_VISIBILITY (el->other);
|
Line 483... |
Line 484... |
return FALSE;
|
return FALSE;
|
}
|
}
|
|
|
/* Get the symbol resolution info for a plugin-claimed input file. */
|
/* Get the symbol resolution info for a plugin-claimed input file. */
|
static enum ld_plugin_status
|
static enum ld_plugin_status
|
get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
|
get_symbols (const void *handle, int nsyms, struct ld_plugin_symbol *syms,
|
|
int def_ironly_exp)
|
{
|
{
|
const bfd *abfd = handle;
|
const bfd *abfd = handle;
|
int n;
|
int n;
|
|
|
ASSERT (called_plugin);
|
ASSERT (called_plugin);
|
for (n = 0; n < nsyms; n++)
|
for (n = 0; n < nsyms; n++)
|
{
|
{
|
struct bfd_link_hash_entry *blhe;
|
struct bfd_link_hash_entry *blhe;
|
bfd_boolean ironly;
|
|
asection *owner_sec;
|
asection *owner_sec;
|
|
int res;
|
|
|
if (syms[n].def != LDPK_UNDEF)
|
if (syms[n].def != LDPK_UNDEF)
|
blhe = bfd_link_hash_lookup (link_info.hash, syms[n].name,
|
blhe = bfd_link_hash_lookup (link_info.hash, syms[n].name,
|
FALSE, FALSE, TRUE);
|
FALSE, FALSE, TRUE);
|
else
|
else
|
blhe = bfd_wrapped_link_hash_lookup (link_info.output_bfd, &link_info,
|
blhe = bfd_wrapped_link_hash_lookup (link_info.output_bfd, &link_info,
|
syms[n].name, FALSE, FALSE, TRUE);
|
syms[n].name, FALSE, FALSE, TRUE);
|
if (!blhe)
|
if (!blhe)
|
{
|
{
|
syms[n].resolution = LDPR_UNKNOWN;
|
res = LDPR_UNKNOWN;
|
goto report_symbol;
|
goto report_symbol;
|
}
|
}
|
|
|
/* Determine resolution from blhe type and symbol's original type. */
|
/* Determine resolution from blhe type and symbol's original type. */
|
if (blhe->type == bfd_link_hash_undefined
|
if (blhe->type == bfd_link_hash_undefined
|
|| blhe->type == bfd_link_hash_undefweak)
|
|| blhe->type == bfd_link_hash_undefweak)
|
{
|
{
|
syms[n].resolution = LDPR_UNDEF;
|
res = LDPR_UNDEF;
|
goto report_symbol;
|
goto report_symbol;
|
}
|
}
|
if (blhe->type != bfd_link_hash_defined
|
if (blhe->type != bfd_link_hash_defined
|
&& blhe->type != bfd_link_hash_defweak
|
&& blhe->type != bfd_link_hash_defweak
|
&& blhe->type != bfd_link_hash_common)
|
&& blhe->type != bfd_link_hash_common)
|
Line 528... |
Line 532... |
and weakdefs keep it in the same place. */
|
and weakdefs keep it in the same place. */
|
owner_sec = (blhe->type == bfd_link_hash_common
|
owner_sec = (blhe->type == bfd_link_hash_common
|
? blhe->u.c.p->section
|
? blhe->u.c.p->section
|
: blhe->u.def.section);
|
: blhe->u.def.section);
|
|
|
/* We need to know if the sym is referenced from non-IR files. Or
|
|
even potentially-referenced, perhaps in a future final link if
|
|
this is a partial one, perhaps dynamically at load-time if the
|
|
symbol is externally visible. */
|
|
ironly = !(blhe->non_ir_ref
|
|
|| is_visible_from_outside (&syms[n], owner_sec, blhe));
|
|
|
|
/* If it was originally undefined or common, then it has been
|
/* If it was originally undefined or common, then it has been
|
resolved; determine how. */
|
resolved; determine how. */
|
if (syms[n].def == LDPK_UNDEF
|
if (syms[n].def == LDPK_UNDEF
|
|| syms[n].def == LDPK_WEAKUNDEF
|
|| syms[n].def == LDPK_WEAKUNDEF
|
|| syms[n].def == LDPK_COMMON)
|
|| syms[n].def == LDPK_COMMON)
|
{
|
{
|
if (owner_sec->owner == link_info.output_bfd)
|
if (owner_sec->owner == link_info.output_bfd)
|
syms[n].resolution = LDPR_RESOLVED_EXEC;
|
res = LDPR_RESOLVED_EXEC;
|
else if (owner_sec->owner == abfd)
|
else if (owner_sec->owner == abfd)
|
syms[n].resolution = (ironly
|
res = LDPR_PREVAILING_DEF_IRONLY;
|
? LDPR_PREVAILING_DEF_IRONLY
|
|
: LDPR_PREVAILING_DEF);
|
|
else if (is_ir_dummy_bfd (owner_sec->owner))
|
else if (is_ir_dummy_bfd (owner_sec->owner))
|
syms[n].resolution = LDPR_RESOLVED_IR;
|
res = LDPR_RESOLVED_IR;
|
else if (owner_sec->owner != NULL
|
else if (owner_sec->owner != NULL
|
&& (owner_sec->owner->flags & DYNAMIC) != 0)
|
&& (owner_sec->owner->flags & DYNAMIC) != 0)
|
syms[n].resolution = LDPR_RESOLVED_DYN;
|
res = LDPR_RESOLVED_DYN;
|
else
|
else
|
syms[n].resolution = LDPR_RESOLVED_EXEC;
|
res = LDPR_RESOLVED_EXEC;
|
goto report_symbol;
|
|
}
|
}
|
|
|
/* Was originally def, or weakdef. Does it prevail? If the
|
/* Was originally def, or weakdef. Does it prevail? If the
|
owner is the original dummy bfd that supplied it, then this
|
owner is the original dummy bfd that supplied it, then this
|
is the definition that has prevailed. */
|
is the definition that has prevailed. */
|
if (owner_sec->owner == link_info.output_bfd)
|
else if (owner_sec->owner == link_info.output_bfd)
|
syms[n].resolution = LDPR_PREEMPTED_REG;
|
res = LDPR_PREEMPTED_REG;
|
else if (owner_sec->owner == abfd)
|
else if (owner_sec->owner == abfd)
|
{
|
res = LDPR_PREVAILING_DEF_IRONLY;
|
syms[n].resolution = (ironly
|
|
? LDPR_PREVAILING_DEF_IRONLY
|
|
: LDPR_PREVAILING_DEF);
|
|
goto report_symbol;
|
|
}
|
|
|
|
/* Was originally def, weakdef, or common, but has been pre-empted. */
|
/* Was originally def, weakdef, or common, but has been pre-empted. */
|
syms[n].resolution = (is_ir_dummy_bfd (owner_sec->owner)
|
else if (is_ir_dummy_bfd (owner_sec->owner))
|
? LDPR_PREEMPTED_IR
|
res = LDPR_PREEMPTED_IR;
|
: LDPR_PREEMPTED_REG);
|
else
|
|
res = LDPR_PREEMPTED_REG;
|
|
|
|
if (res == LDPR_PREVAILING_DEF_IRONLY)
|
|
{
|
|
/* We need to know if the sym is referenced from non-IR files. Or
|
|
even potentially-referenced, perhaps in a future final link if
|
|
this is a partial one, perhaps dynamically at load-time if the
|
|
symbol is externally visible. */
|
|
if (blhe->non_ir_ref)
|
|
res = LDPR_PREVAILING_DEF;
|
|
else if (is_visible_from_outside (&syms[n], blhe))
|
|
res = def_ironly_exp;
|
|
}
|
|
|
report_symbol:
|
report_symbol:
|
|
syms[n].resolution = res;
|
if (report_plugin_symbols)
|
if (report_plugin_symbols)
|
einfo (_("%P: %B: symbol `%s' "
|
einfo (_("%P: %B: symbol `%s' "
|
"definition: %d, visibility: %d, resolution: %d\n"),
|
"definition: %d, visibility: %d, resolution: %d\n"),
|
abfd, syms[n].name,
|
abfd, syms[n].name,
|
syms[n].def, syms[n].visibility, syms[n].resolution);
|
syms[n].def, syms[n].visibility, res);
|
}
|
}
|
return LDPS_OK;
|
return LDPS_OK;
|
}
|
}
|
|
|
|
static enum ld_plugin_status
|
|
get_symbols_v1 (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
|
|
{
|
|
return get_symbols (handle, nsyms, syms, LDPR_PREVAILING_DEF);
|
|
}
|
|
|
|
static enum ld_plugin_status
|
|
get_symbols_v2 (const void *handle, int nsyms, struct ld_plugin_symbol *syms)
|
|
{
|
|
return get_symbols (handle, nsyms, syms, LDPR_PREVAILING_DEF_IRONLY_EXP);
|
|
}
|
|
|
/* Add a new (real) input file generated by a plugin. */
|
/* Add a new (real) input file generated by a plugin. */
|
static enum ld_plugin_status
|
static enum ld_plugin_status
|
add_input_file (const char *pathname)
|
add_input_file (const char *pathname)
|
{
|
{
|
ASSERT (called_plugin);
|
ASSERT (called_plugin);
|
Line 652... |
Line 668... |
va_end (args);
|
va_end (args);
|
return LDPS_OK;
|
return LDPS_OK;
|
}
|
}
|
|
|
/* Helper to size leading part of tv array and set it up. */
|
/* Helper to size leading part of tv array and set it up. */
|
static size_t
|
static void
|
set_tv_header (struct ld_plugin_tv *tv)
|
set_tv_header (struct ld_plugin_tv *tv)
|
{
|
{
|
size_t i;
|
size_t i;
|
|
|
/* Version info. */
|
/* Version info. */
|
static const unsigned int major = (unsigned)(BFD_VERSION / 100000000UL);
|
static const unsigned int major = (unsigned)(BFD_VERSION / 100000000UL);
|
static const unsigned int minor = (unsigned)(BFD_VERSION / 1000000UL) % 100;
|
static const unsigned int minor = (unsigned)(BFD_VERSION / 1000000UL) % 100;
|
|
|
if (!tv)
|
|
return tv_header_size;
|
|
|
|
for (i = 0; i < tv_header_size; i++)
|
for (i = 0; i < tv_header_size; i++)
|
{
|
{
|
tv[i].tv_tag = tv_header_tags[i];
|
tv[i].tv_tag = tv_header_tags[i];
|
#define TVU(x) tv[i].tv_u.tv_ ## x
|
#define TVU(x) tv[i].tv_u.tv_ ## x
|
switch (tv[i].tv_tag)
|
switch (tv[i].tv_tag)
|
Line 682... |
Line 695... |
TVU(val) = major * 100 + minor;
|
TVU(val) = major * 100 + minor;
|
break;
|
break;
|
case LDPT_LINKER_OUTPUT:
|
case LDPT_LINKER_OUTPUT:
|
TVU(val) = (link_info.relocatable
|
TVU(val) = (link_info.relocatable
|
? LDPO_REL
|
? LDPO_REL
|
: (link_info.shared ? LDPO_DYN : LDPO_EXEC));
|
: link_info.executable ? LDPO_EXEC : LDPO_DYN);
|
break;
|
break;
|
case LDPT_OUTPUT_NAME:
|
case LDPT_OUTPUT_NAME:
|
TVU(string) = output_filename;
|
TVU(string) = output_filename;
|
break;
|
break;
|
case LDPT_REGISTER_CLAIM_FILE_HOOK:
|
case LDPT_REGISTER_CLAIM_FILE_HOOK:
|
Line 706... |
Line 719... |
break;
|
break;
|
case LDPT_RELEASE_INPUT_FILE:
|
case LDPT_RELEASE_INPUT_FILE:
|
TVU(release_input_file) = release_input_file;
|
TVU(release_input_file) = release_input_file;
|
break;
|
break;
|
case LDPT_GET_SYMBOLS:
|
case LDPT_GET_SYMBOLS:
|
TVU(get_symbols) = get_symbols;
|
TVU(get_symbols) = get_symbols_v1;
|
|
break;
|
|
case LDPT_GET_SYMBOLS_V2:
|
|
TVU(get_symbols) = get_symbols_v2;
|
break;
|
break;
|
case LDPT_ADD_INPUT_FILE:
|
case LDPT_ADD_INPUT_FILE:
|
TVU(add_input_file) = add_input_file;
|
TVU(add_input_file) = add_input_file;
|
break;
|
break;
|
case LDPT_ADD_INPUT_LIBRARY:
|
case LDPT_ADD_INPUT_LIBRARY:
|
Line 724... |
Line 740... |
a new case to set up its value is a bug. */
|
a new case to set up its value is a bug. */
|
FAIL ();
|
FAIL ();
|
}
|
}
|
#undef TVU
|
#undef TVU
|
}
|
}
|
return tv_header_size;
|
|
}
|
}
|
|
|
/* Append the per-plugin args list and trailing LDPT_NULL to tv. */
|
/* Append the per-plugin args list and trailing LDPT_NULL to tv. */
|
static void
|
static void
|
set_tv_plugin_args (plugin_t *plugin, struct ld_plugin_tv *tv)
|
set_tv_plugin_args (plugin_t *plugin, struct ld_plugin_tv *tv)
|
Line 998... |
Line 1013... |
return (*orig_callbacks->notice) (info, h,
|
return (*orig_callbacks->notice) (info, h,
|
abfd, section, value, flags, string);
|
abfd, section, value, flags, string);
|
return TRUE;
|
return TRUE;
|
}
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|
|
/* Return true if bfd is a dynamic library that should be reloaded. */
|
|
|
|
bfd_boolean
|
|
plugin_should_reload (bfd *abfd)
|
|
{
|
|
return ((abfd->flags & DYNAMIC) != 0
|
|
&& bfd_get_flavour (abfd) == bfd_target_elf_flavour
|
|
&& bfd_get_format (abfd) == bfd_object
|
|
&& (elf_dyn_lib_class (abfd) & DYN_AS_NEEDED) != 0);
|
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|