diff options
Diffstat (limited to 'bfd/elflink.c')
-rw-r--r-- | bfd/elflink.c | 178 |
1 files changed, 108 insertions, 70 deletions
diff --git a/bfd/elflink.c b/bfd/elflink.c index cdd58b2..5c8b822 100644 --- a/bfd/elflink.c +++ b/bfd/elflink.c @@ -27,9 +27,7 @@ #include "safe-ctype.h" #include "libiberty.h" #include "objalloc.h" -#if BFD_SUPPORTS_PLUGINS #include "plugin.h" -#endif #include <limits.h> #ifndef CHAR_BIT @@ -356,6 +354,7 @@ _bfd_elf_link_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) flags | SEC_READONLY); if (s == NULL) return false; + elf_hash_table (info)->interp = s; } /* Create sections to hold version informations. These are removed @@ -2283,68 +2282,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. */ @@ -2352,7 +2368,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; @@ -2360,7 +2376,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; @@ -2371,30 +2388,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 @@ -2405,12 +2430,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); } } @@ -3678,11 +3703,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. */ @@ -5117,6 +5139,13 @@ elf_link_add_object_symbols (bfd *abfd, struct bfd_link_info *info) continue; } + if (name[0] == '\0') + { + _bfd_error_handler (_("%pB: corrupt symbol table"), abfd); + bfd_set_error (bfd_error_bad_value); + goto error_free_vers; + } + /* Sanity check that all possibilities were handled. */ if (sec == NULL) abort (); @@ -7526,7 +7555,7 @@ NOTE: This behaviour is deprecated and will be removed in a future version of th asection *dynstr; asection *s; - *sinterpptr = bfd_get_linker_section (dynobj, ".interp"); + *sinterpptr = elf_hash_table (info)->interp; BFD_ASSERT (*sinterpptr != NULL || !bfd_link_executable (info) || info->nointerp); if (info->symbolic) @@ -9126,7 +9155,7 @@ struct elf_outext_info <binary-operator> := as in C <unary-operator> := as in C, plus "0-" for unambiguous negation. */ -static void +static bool set_symbol_value (bfd *bfd_with_globals, Elf_Internal_Sym *isymbuf, size_t locsymcount, @@ -9147,9 +9176,15 @@ set_symbol_value (bfd *bfd_with_globals, "absolute" section and give it a value. */ sym->st_shndx = SHN_ABS; sym->st_value = val; - return; + return true; + } + if (!elf_bad_symtab (bfd_with_globals)) + { + _bfd_error_handler (_("%pB: corrupt symbol table"), + bfd_with_globals); + bfd_set_error (bfd_error_bad_value); + return false; } - BFD_ASSERT (elf_bad_symtab (bfd_with_globals)); extsymoff = 0; } @@ -9159,11 +9194,12 @@ set_symbol_value (bfd *bfd_with_globals, if (h == NULL) { /* FIXMEL What should we do ? */ - return; + return false; } h->root.type = bfd_link_hash_defined; h->root.u.def.value = val; h->root.u.def.section = bfd_abs_section_ptr; + return true; } static bool @@ -11861,8 +11897,10 @@ elf_link_input_bfd (struct elf_final_link_info *flinfo, bfd *input_bfd) return false; /* Symbol evaluated OK. Update to absolute value. */ - set_symbol_value (input_bfd, isymbuf, locsymcount, - r_symndx, val); + if (!set_symbol_value (input_bfd, isymbuf, locsymcount, r_symndx, + val)) + return false; + continue; } @@ -14827,7 +14865,7 @@ bfd_elf_gc_record_vtentry (bfd *abfd, asection *sec, const struct elf_backend_data *bed = get_elf_backend_data (abfd); unsigned int log_file_align = bed->s->log_file_align; - if (!h) + if (!h || addend > 1u << 28) { /* xgettext:c-format */ _bfd_error_handler (_("%pB: section '%pA': corrupt VTENTRY entry"), |