diff options
Diffstat (limited to 'bfd/elflink.c')
-rw-r--r-- | bfd/elflink.c | 148 |
1 files changed, 84 insertions, 64 deletions
diff --git a/bfd/elflink.c b/bfd/elflink.c index 666399b..53ec792 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -27,10 +27,7 @@ #include "safe-ctype.h" #include "libiberty.h" #include "objalloc.h" -#if BFD_SUPPORTS_PLUGINS -#include "plugin-api.h" #include "plugin.h" -#endif #include <limits.h> #ifndef CHAR_BIT @@ -2284,68 +2281,85 @@ _bfd_elf_export_symbol (struct elf_link_hash_entry *h, void *data) return true; } -/* Return the glibc version reference if VERSION_DEP is added to the - list of glibc version dependencies successfully. VERSION_DEP will - be put into the .gnu.version_r section. GLIBC_MINOR_BASE is the - pointer to the glibc minor base version. */ +/* Return true if linked against glibc. Otherwise return false. If + linked against glibc, add VERSION_DEP to the list of glibc version + dependencies and set *AUTO_VERSION to true. If *AUTO_VERSION is + true, add VERSION_DEP to the version dependency list only if libc.so + defines VERSION_DEP. GLIBC_MINOR_BASE is the pointer to the glibc + minor base version. */ -static Elf_Internal_Verneed * +static bool elf_link_add_glibc_verneed (struct elf_find_verdep_info *rinfo, - Elf_Internal_Verneed *glibc_verref, const char *version_dep, - int *glibc_minor_base) + int *glibc_minor_base, + bool *auto_version) { Elf_Internal_Verneed *t; Elf_Internal_Vernaux *a; size_t amt; int minor_version = -1; + bool added = false; + bool glibc = false; - if (glibc_verref != NULL) + for (t = elf_tdata (rinfo->info->output_bfd)->verref; + t != NULL; + t = t->vn_nextref) { - t = glibc_verref; + const char *soname = bfd_elf_get_dt_soname (t->vn_bfd); + if (soname != NULL && startswith (soname, "libc.so.")) + break; + } - for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) + /* Skip the shared library if it isn't libc.so. */ + if (t == NULL) + goto update_auto_version_and_return; + + for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) + { + /* Return if VERSION_DEP dependency has been added. */ + if (a->vna_nodename == version_dep + || strcmp (a->vna_nodename, version_dep) == 0) { - /* Return if VERSION_DEP dependency has been added. */ - if (a->vna_nodename == version_dep - || strcmp (a->vna_nodename, version_dep) == 0) - return t; + glibc = true; + goto update_auto_version_and_return; } - } - else - { - for (t = elf_tdata (rinfo->info->output_bfd)->verref; - t != NULL; - t = t->vn_nextref) + + /* Check if libc.so provides GLIBC_2.XX version. */ + if (startswith (a->vna_nodename, "GLIBC_2.")) { - const char *soname = bfd_elf_get_dt_soname (t->vn_bfd); - if (soname != NULL && startswith (soname, "libc.so.")) - break; + minor_version = strtol (a->vna_nodename + 8, NULL, 10); + if (minor_version < *glibc_minor_base) + *glibc_minor_base = minor_version; } + } - /* Skip the shared library if it isn't libc.so. */ - if (t == NULL) - return t; + /* Skip if it isn't linked against glibc. */ + if (minor_version < 0) + goto update_auto_version_and_return; - for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) - { - /* Return if VERSION_DEP dependency has been added. */ - if (a->vna_nodename == version_dep - || strcmp (a->vna_nodename, version_dep) == 0) - return t; + glibc = true; - /* Check if libc.so provides GLIBC_2.XX version. */ - if (startswith (a->vna_nodename, "GLIBC_2.")) - { - minor_version = strtol (a->vna_nodename + 8, NULL, 10); - if (minor_version < *glibc_minor_base) - *glibc_minor_base = minor_version; - } - } + if (auto_version && *auto_version) + { + /* Add VERSION_DEP to the version dependency list only if + libc.so defines VERSION_DEP. */ - /* Skip if it isn't linked against glibc. */ - if (minor_version < 0) - return NULL; + bool defined = false; + Elf_Internal_Verdef *d; + + for (d = elf_tdata (t->vn_bfd)->verdef; + d != NULL; + d = d->vd_nextdef) + if (strcmp (d->vd_nodename, version_dep) == 0) + { + defined = true; + break; + } + + /* Set *AUTO_VERSION to false and return true to indicate that + libc.so doesn't define VERSION_DEP. */ + if (!defined) + goto update_auto_version_and_return; } /* Skip if 2.GLIBC_MINOR_BASE includes VERSION_DEP. */ @@ -2353,7 +2367,7 @@ elf_link_add_glibc_verneed (struct elf_find_verdep_info *rinfo, { minor_version = strtol (version_dep + 8, NULL, 10); if (minor_version <= *glibc_minor_base) - return NULL; + goto update_auto_version_and_return; } amt = sizeof *a; @@ -2361,7 +2375,8 @@ elf_link_add_glibc_verneed (struct elf_find_verdep_info *rinfo, if (a == NULL) { rinfo->failed = true; - return NULL; + glibc = false; + goto update_auto_version_and_return; } a->vna_nodename = version_dep; @@ -2372,30 +2387,38 @@ elf_link_add_glibc_verneed (struct elf_find_verdep_info *rinfo, t->vn_auxptr = a; - return t; + added = true; + + update_auto_version_and_return: + if (auto_version) + *auto_version = added; + + return glibc; } /* Add VERSION_DEP to the list of version dependencies when linked against glibc. */ -void +bool _bfd_elf_link_add_glibc_version_dependency (struct elf_find_verdep_info *rinfo, - const char *version_dep[]) + const char *const version_dep[], + bool *auto_version) { - Elf_Internal_Verneed *t = NULL; int glibc_minor_base = INT_MAX; do { - t = elf_link_add_glibc_verneed (rinfo, t, *version_dep, - &glibc_minor_base); - /* Return if there is no glibc version reference. */ - if (t == NULL) - return; + /* Return if not linked against glibc. */ + if (!elf_link_add_glibc_verneed (rinfo, *version_dep, + &glibc_minor_base, auto_version)) + return false; version_dep++; + auto_version++; } while (*version_dep != NULL); + + return true; } /* Add GLIBC_ABI_DT_RELR to the list of version dependencies when @@ -2406,12 +2429,12 @@ _bfd_elf_link_add_dt_relr_dependency (struct elf_find_verdep_info *rinfo) { if (rinfo->info->enable_dt_relr) { - const char *version[] = + static const char *const version[] = { "GLIBC_ABI_DT_RELR", NULL }; - _bfd_elf_link_add_glibc_version_dependency (rinfo, version); + _bfd_elf_link_add_glibc_version_dependency (rinfo, version, NULL); } } @@ -3679,11 +3702,8 @@ elf_link_is_defined_archive_symbol (bfd * abfd, carsym * symdef) get the correct symbol table. */ if (abfd->plugin_format == bfd_plugin_yes || abfd->plugin_format == bfd_plugin_yes_unused -#if BFD_SUPPORTS_PLUGINS || (abfd->plugin_format == bfd_plugin_unknown - && bfd_link_plugin_object_p (abfd)) -#endif - ) + && bfd_link_plugin_object_p (abfd))) { /* Use the IR symbol table if the object has been claimed by plugin. */ @@ -11293,7 +11313,7 @@ _bfd_elf_default_action_discarded (asection *sec) && strncmp (sec->name, ".eh_frame.", 10) == 0) return 0; - if (strcmp (".sframe", sec->name) == 0) + if (elf_section_type (sec) == SHT_GNU_SFRAME) return 0; if (strcmp (".gcc_except_table", sec->name) == 0) |