X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=bfd%2Felflink.h;h=ce71d948c43f894a8357428221f3422d004899f4;hb=7f8d5fc90bf3c799976edffa902e03edf1455061;hp=b20390853871a390e4c237aa83690ab3705f055e;hpb=23bc299bd87439c2bc1c2a7969b427b06831bfed;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elflink.h b/bfd/elflink.h index b203908538..ce71d948c4 100644 --- a/bfd/elflink.h +++ b/bfd/elflink.h @@ -48,18 +48,17 @@ static boolean elf_link_find_version_dependencies PARAMS ((struct elf_link_hash_entry *, PTR)); static boolean elf_link_assign_sym_version PARAMS ((struct elf_link_hash_entry *, PTR)); -static boolean elf_link_renumber_dynsyms - PARAMS ((struct elf_link_hash_entry *, PTR)); static boolean elf_collect_hash_codes PARAMS ((struct elf_link_hash_entry *, PTR)); static boolean elf_link_read_relocs_from_section PARAMS ((bfd *, Elf_Internal_Shdr *, PTR, Elf_Internal_Rela *)); -static void elf_link_remove_section_and_adjust_dynindices - PARAMS ((struct bfd_link_info *, asection *)); static void elf_link_output_relocs PARAMS ((bfd *, asection *, Elf_Internal_Shdr *, Elf_Internal_Rela *)); static boolean elf_link_size_reloc_section PARAMS ((bfd *, Elf_Internal_Shdr *, asection *)); +static void elf_link_adjust_relocs + PARAMS ((bfd *, Elf_Internal_Shdr *, unsigned int, + struct elf_link_hash_entry **)); /* Given an ELF BFD, add symbols to the global hash table as appropriate. */ @@ -81,6 +80,138 @@ elf_bfd_link_add_symbols (abfd, info) } } +/* Return true iff this is a non-common definition of a symbol. */ +static boolean +is_global_symbol_definition (abfd, sym) + bfd * abfd; + Elf_Internal_Sym * sym; +{ + /* Local symbols do not count, but target specific ones might. */ + if (ELF_ST_BIND (sym->st_info) != STB_GLOBAL + && ELF_ST_BIND (sym->st_info) < STB_LOOS) + return false; + + /* If the section is undefined, then so is the symbol. */ + if (sym->st_shndx == SHN_UNDEF) + return false; + + /* If the symbol is defined in the common section, then + it is a common definition and so does not count. */ + if (sym->st_shndx == SHN_COMMON) + return false; + + /* If the symbol is in a target specific section then we + must rely upon the backend to tell us what it is. */ + if (sym->st_shndx >= SHN_LORESERVE && sym->st_shndx < SHN_ABS) + /* FIXME - this function is not coded yet: + + return _bfd_is_global_symbol_definition (abfd, sym); + + Instead for now assume that the definition is not global, + Even if this is wrong, at least the linker will behave + in the same way that it used to do. */ + return false; + + return true; +} + + +/* Search the symbol table of the archive element of the archive ABFD + whoes archove map contains a mention of SYMDEF, and determine if + the symbol is defined in this element. */ +static boolean +elf_link_is_defined_archive_symbol (abfd, symdef) + bfd * abfd; + carsym * symdef; +{ + Elf_Internal_Shdr * hdr; + Elf_External_Sym * esym; + Elf_External_Sym * esymend; + Elf_External_Sym * buf = NULL; + size_t symcount; + size_t extsymcount; + size_t extsymoff; + boolean result = false; + + abfd = _bfd_get_elt_at_filepos (abfd, symdef->file_offset); + if (abfd == (bfd *) NULL) + return false; + + if (! bfd_check_format (abfd, bfd_object)) + return false; + + /* If we have already included the element containing this symbol in the + link then we do not need to include it again. Just claim that any symbol + it contains is not a definition, so that our caller will not decide to + (re)include this element. */ + if (abfd->archive_pass) + return false; + + /* Select the appropriate symbol table. */ + if ((abfd->flags & DYNAMIC) == 0 || elf_dynsymtab (abfd) == 0) + hdr = &elf_tdata (abfd)->symtab_hdr; + else + hdr = &elf_tdata (abfd)->dynsymtab_hdr; + + symcount = hdr->sh_size / sizeof (Elf_External_Sym); + + /* The sh_info field of the symtab header tells us where the + external symbols start. We don't care about the local symbols. */ + if (elf_bad_symtab (abfd)) + { + extsymcount = symcount; + extsymoff = 0; + } + else + { + extsymcount = symcount - hdr->sh_info; + extsymoff = hdr->sh_info; + } + + buf = ((Elf_External_Sym *) + bfd_malloc (extsymcount * sizeof (Elf_External_Sym))); + if (buf == NULL && extsymcount != 0) + return false; + + /* Read in the symbol table. + FIXME: This ought to be cached somewhere. */ + if (bfd_seek (abfd, + hdr->sh_offset + extsymoff * sizeof (Elf_External_Sym), + SEEK_SET) != 0 + || (bfd_read ((PTR) buf, sizeof (Elf_External_Sym), extsymcount, abfd) + != extsymcount * sizeof (Elf_External_Sym))) + { + free (buf); + return false; + } + + /* Scan the symbol table looking for SYMDEF. */ + esymend = buf + extsymcount; + for (esym = buf; + esym < esymend; + esym++) + { + Elf_Internal_Sym sym; + const char * name; + + elf_swap_symbol_in (abfd, esym, & sym); + + name = bfd_elf_string_from_elf_section (abfd, hdr->sh_link, sym.st_name); + if (name == (const char *) NULL) + break; + + if (strcmp (name, symdef->name) == 0) + { + result = is_global_symbol_definition (abfd, & sym); + break; + } + } + + free (buf); + + return result; +} + /* Add symbols from an ELF archive file to the linker hash table. We don't use _bfd_generic_link_add_archive_symbols because of a @@ -201,7 +332,24 @@ elf_link_add_archive_symbols (abfd, info) if (h == NULL) continue; - if (h->root.type != bfd_link_hash_undefined) + if (h->root.type == bfd_link_hash_common) + { + /* We currently have a common symbol. The archive map contains + a reference to this symbol, so we may want to include it. We + only want to include it however, if this archive element + contains a definition of the symbol, not just another common + declaration of it. + + Unfortunately some archivers (including GNU ar) will put + declarations of common symbols into their archive maps, as + well as real definitions, so we cannot just go by the archive + map alone. Instead we must read in the element's symbol + table and check that to see what kind of symbol definition + this is. */ + if (! elf_link_is_defined_archive_symbol (abfd, symdef)) + continue; + } + else if (h->root.type != bfd_link_hash_undefined) { if (h->root.type != bfd_link_hash_undefweak) defined[i] = true; @@ -366,6 +514,17 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash, break; } + /* In cases involving weak versioned symbols, we may wind up trying + to merge a symbol with itself. Catch that here, to avoid the + confusion that results if we try to override a symbol with + itself. The additional tests catch cases like + _GLOBAL_OFFSET_TABLE_, which are regular symbols defined in a + dynamic object, which we do want to handle here. */ + if (abfd == oldbfd + && ((abfd->flags & DYNAMIC) == 0 + || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)) + return true; + /* NEWDYN and OLDDYN indicate whether the new or old symbol, respectively, is from a dynamic object. */ @@ -374,10 +533,35 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash, else newdyn = false; - if (oldbfd == NULL || (oldbfd->flags & DYNAMIC) == 0) - olddyn = false; + if (oldbfd != NULL) + olddyn = (oldbfd->flags & DYNAMIC) != 0; else - olddyn = true; + { + asection *hsec; + + /* This code handles the special SHN_MIPS_{TEXT,DATA} section + indices used by MIPS ELF. */ + switch (h->root.type) + { + default: + hsec = NULL; + break; + + case bfd_link_hash_defined: + case bfd_link_hash_defweak: + hsec = h->root.u.def.section; + break; + + case bfd_link_hash_common: + hsec = h->root.u.c.p->section; + break; + } + + if (hsec == NULL) + olddyn = false; + else + olddyn = (hsec->symbol->flags & BSF_DYNAMIC) != 0; + } /* NEWDEF and OLDDEF indicate whether the new or old symbol, respectively, appear to be a definition rather than reference. */ @@ -492,14 +676,19 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash, represent variables; this can cause confusion in principle, but any such confusion would seem to indicate an erroneous program or shared library. We also permit a common symbol in a regular - object to override a weak symbol in a shared object. */ + object to override a weak symbol in a shared object. + + We prefer a non-weak definition in a shared library to a weak + definition in the executable. */ if (newdyn && newdef && (olddef || (h->root.type == bfd_link_hash_common && (bind == STB_WEAK - || ELF_ST_TYPE (sym->st_info) == STT_FUNC)))) + || ELF_ST_TYPE (sym->st_info) == STT_FUNC))) + && (h->root.type != bfd_link_hash_defweak + || bind == STB_WEAK)) { *override = true; newdef = false; @@ -543,7 +732,10 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash, As above, we again permit a common symbol in a regular object to override a definition in a shared object if the shared object - symbol is a function or is weak. */ + symbol is a function or is weak. + + As above, we permit a non-weak definition in a shared object to + override a weak definition in a regular object. */ if (! newdyn && (newdef @@ -552,7 +744,9 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash, || h->type == STT_FUNC))) && olddyn && olddef - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + && (bind != STB_WEAK + || h->root.type == bfd_link_hash_defweak)) { /* Change the hash table entry to undefined, and let _bfd_generic_link_add_one_symbol do the right thing with the @@ -626,6 +820,45 @@ elf_merge_symbol (abfd, info, name, sym, psec, pvalue, sym_hash, h->verinfo.vertree = NULL; } + /* Handle the special case of a weak definition in a regular object + followed by a non-weak definition in a shared object. In this + case, we prefer the definition in the shared object. */ + if (olddef + && h->root.type == bfd_link_hash_defweak + && newdef + && newdyn + && bind != STB_WEAK) + { + /* To make this work we have to frob the flags so that the rest + of the code does not think we are using the regular + definition. */ + if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) + h->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; + else if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0) + h->elf_link_hash_flags |= ELF_LINK_HASH_REF_DYNAMIC; + h->elf_link_hash_flags &= ~ (ELF_LINK_HASH_DEF_REGULAR + | ELF_LINK_HASH_DEF_DYNAMIC); + + /* If H is the target of an indirection, we want the caller to + use H rather than the indirect symbol. Otherwise if we are + defining a new indirect symbol we will wind up attaching it + to the entry we are overriding. */ + *sym_hash = h; + } + + /* Handle the special case of a non-weak definition in a shared + object followed by a weak definition in a regular object. In + this case we prefer to definition in the shared object. To make + this work we have to tell the caller to not treat the new symbol + as a definition. */ + if (olddef + && olddyn + && h->root.type != bfd_link_hash_defweak + && newdef + && ! newdyn + && bind == STB_WEAK) + *override = true; + return true; } @@ -874,6 +1107,23 @@ elf_link_add_object_symbols (abfd, info) goto error_return; link = elf_elfsections (abfd)[elfsec]->sh_link; + { + /* The shared libraries distributed with hpux11 have a bogus + sh_link field for the ".dynamic" section. This code detects + when LINK refers to a section that is not a string table and + tries to find the string table for the ".dynsym" section + instead. */ + Elf_Internal_Shdr *hdr = elf_elfsections (abfd)[link]; + if (hdr->sh_type != SHT_STRTAB) + { + asection *s = bfd_get_section_by_name (abfd, ".dynsym"); + int elfsec = _bfd_elf_section_from_bfd_section (abfd, s); + if (elfsec == -1) + goto error_return; + link = elf_elfsections (abfd)[elfsec]->sh_link; + } + } + extdyn = dynbuf; extdynend = extdyn + s->_raw_size / sizeof (Elf_External_Dyn); for (; extdyn < extdynend; extdyn++) @@ -1316,9 +1566,24 @@ elf_link_add_object_symbols (abfd, info) h->type = ELF_ST_TYPE (sym.st_info); } - if (sym.st_other != 0 - && (definition || h->other == 0)) - h->other = sym.st_other; + /* If st_other has a processor-specific meaning, specific code + might be needed here. */ + if (sym.st_other != 0) + { + /* Combine visibilities, using the most constraining one. */ + unsigned char hvis = ELF_ST_VISIBILITY (h->other); + unsigned char symvis = ELF_ST_VISIBILITY (sym.st_other); + + if (symvis && (hvis > symvis || hvis == 0)) + h->other = sym.st_other; + + /* If neither has visibility, use the st_other of the + definition. This is an arbitrary choice, since the + other bits have no general meaning. */ + if (!symvis && !hvis + && (definition || h->other == 0)) + h->other = sym.st_other; + } /* Set a flag in the hash table entry indicating the type of reference or definition we just found. Keep a count of @@ -1477,7 +1742,8 @@ elf_link_add_object_symbols (abfd, info) (hi->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR - | ELF_LINK_HASH_REF_REGULAR_NONWEAK)); + | ELF_LINK_HASH_REF_REGULAR_NONWEAK + | ELF_LINK_NON_GOT_REF)); /* Copy over the global and procedure linkage table offset entries. These may have been already set @@ -1586,7 +1852,8 @@ elf_link_add_object_symbols (abfd, info) (hi->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC | ELF_LINK_HASH_REF_REGULAR - | ELF_LINK_HASH_REF_REGULAR_NONWEAK)); + | ELF_LINK_HASH_REF_REGULAR_NONWEAK + | ELF_LINK_NON_GOT_REF)); /* Copy over the global and procedure linkage table offset entries. These may have been @@ -1945,16 +2212,18 @@ elf_link_create_dynamic_sections (abfd, info) && ! _bfd_elf_link_record_dynamic_symbol (info, h)) return false; + bed = get_elf_backend_data (abfd); + s = bfd_make_section (abfd, ".hash"); if (s == NULL || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) || ! bfd_set_section_alignment (abfd, s, LOG_FILE_ALIGN)) return false; + elf_section_data (s)->this_hdr.sh_entsize = bed->s->sizeof_hash_entry; /* Let the backend create the rest of the sections. This lets the backend set the right flags. The backend will normally create the .got and .plt sections. */ - bed = get_elf_backend_data (abfd); if (! (*bed->elf_backend_create_dynamic_sections) (abfd, info)) return false; @@ -1997,6 +2266,76 @@ elf_add_dynamic_entry (info, tag, val) return true; } + +/* Record a new local dynamic symbol. */ + +boolean +elf_link_record_local_dynamic_symbol (info, input_bfd, input_indx) + struct bfd_link_info *info; + bfd *input_bfd; + long input_indx; +{ + struct elf_link_local_dynamic_entry *entry; + struct elf_link_hash_table *eht; + struct bfd_strtab_hash *dynstr; + Elf_External_Sym esym; + unsigned long dynstr_index; + char *name; + + /* See if the entry exists already. */ + for (entry = elf_hash_table (info)->dynlocal; entry ; entry = entry->next) + if (entry->input_bfd == input_bfd && entry->input_indx == input_indx) + return true; + + entry = (struct elf_link_local_dynamic_entry *) + bfd_alloc (input_bfd, sizeof (*entry)); + if (entry == NULL) + return false; + + /* Go find the symbol, so that we can find it's name. */ + if (bfd_seek (input_bfd, + (elf_tdata (input_bfd)->symtab_hdr.sh_offset + + input_indx * sizeof (Elf_External_Sym)), + SEEK_SET) != 0 + || (bfd_read (&esym, sizeof (Elf_External_Sym), 1, input_bfd) + != sizeof (Elf_External_Sym))) + return false; + elf_swap_symbol_in (input_bfd, &esym, &entry->isym); + + name = (bfd_elf_string_from_elf_section + (input_bfd, elf_tdata (input_bfd)->symtab_hdr.sh_link, + entry->isym.st_name)); + + dynstr = elf_hash_table (info)->dynstr; + if (dynstr == NULL) + { + /* Create a strtab to hold the dynamic symbol names. */ + elf_hash_table (info)->dynstr = dynstr = _bfd_elf_stringtab_init (); + if (dynstr == NULL) + return false; + } + + dynstr_index = _bfd_stringtab_add (dynstr, name, true, false); + if (dynstr_index == (unsigned long) -1) + return false; + entry->isym.st_name = dynstr_index; + + eht = elf_hash_table (info); + + entry->next = eht->dynlocal; + eht->dynlocal = entry; + entry->input_bfd = input_bfd; + entry->input_indx = input_indx; + eht->dynsymcount++; + + /* Whatever binding the symbol had before, it's now local. */ + entry->isym.st_info + = ELF_ST_INFO (STB_LOCAL, ELF_ST_TYPE (entry->isym.st_info)); + + /* The dynindx will be set at the end of size_dynamic_sections. */ + + return true; +} /* Read and swap the relocs from the section indicated by SHDR. This @@ -2016,6 +2355,8 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs, PTR external_relocs; Elf_Internal_Rela *internal_relocs; { + struct elf_backend_data *bed; + /* If there aren't any relocations, that's OK. */ if (!shdr) return true; @@ -2029,24 +2370,36 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs, != shdr->sh_size) return false; + bed = get_elf_backend_data (abfd); + /* Convert the external relocations to the internal format. */ if (shdr->sh_entsize == sizeof (Elf_External_Rel)) { Elf_External_Rel *erel; Elf_External_Rel *erelend; Elf_Internal_Rela *irela; + Elf_Internal_Rel *irel; erel = (Elf_External_Rel *) external_relocs; erelend = erel + shdr->sh_size / shdr->sh_entsize; irela = internal_relocs; - for (; erel < erelend; erel++, irela++) + irel = bfd_alloc (abfd, (bed->s->int_rels_per_ext_rel + * sizeof (Elf_Internal_Rel))); + for (; erel < erelend; erel++, irela += bed->s->int_rels_per_ext_rel) { - Elf_Internal_Rel irel; + unsigned char i; - elf_swap_reloc_in (abfd, erel, &irel); - irela->r_offset = irel.r_offset; - irela->r_info = irel.r_info; - irela->r_addend = 0; + if (bed->s->swap_reloc_in) + (*bed->s->swap_reloc_in) (abfd, (bfd_byte *) erel, irel); + else + elf_swap_reloc_in (abfd, erel, irel); + + for (i = 0; i < bed->s->int_rels_per_ext_rel; ++i) + { + irela[i].r_offset = irel[i].r_offset; + irela[i].r_info = irel[i].r_info; + irela[i].r_addend = 0; + } } } else @@ -2060,8 +2413,13 @@ elf_link_read_relocs_from_section (abfd, shdr, external_relocs, erela = (Elf_External_Rela *) external_relocs; erelaend = erela + shdr->sh_size / shdr->sh_entsize; irela = internal_relocs; - for (; erela < erelaend; erela++, irela++) - elf_swap_reloca_in (abfd, erela, irela); + for (; erela < erelaend; erela++, irela += bed->s->int_rels_per_ext_rel) + { + if (bed->s->swap_reloca_in) + (*bed->s->swap_reloca_in) (abfd, (bfd_byte *) erela, irela); + else + elf_swap_reloca_in (abfd, erela, irela); + } } return true; @@ -2089,6 +2447,7 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs, Elf_Internal_Shdr *rel_hdr; PTR alloc1 = NULL; Elf_Internal_Rela *alloc2 = NULL; + struct elf_backend_data *bed = get_elf_backend_data (abfd); if (elf_section_data (o)->relocs != NULL) return elf_section_data (o)->relocs; @@ -2102,7 +2461,8 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs, { size_t size; - size = o->reloc_count * sizeof (Elf_Internal_Rela); + size = (o->reloc_count * bed->s->int_rels_per_ext_rel + * sizeof (Elf_Internal_Rela)); if (keep_memory) internal_relocs = (Elf_Internal_Rela *) bfd_alloc (abfd, size); else @@ -2131,7 +2491,8 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs, (abfd, elf_section_data (o)->rel_hdr2, ((bfd_byte *) external_relocs) + rel_hdr->sh_size, - internal_relocs + rel_hdr->sh_size / rel_hdr->sh_entsize)) + internal_relocs + (rel_hdr->sh_size / rel_hdr->sh_entsize + * bed->s->int_rels_per_ext_rel))) goto error_return; /* Cache the results for next time, if we can. */ @@ -2161,7 +2522,7 @@ NAME(_bfd_elf,link_read_relocs) (abfd, o, external_relocs, internal_relocs, /*ARGSUSED*/ boolean NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide) - bfd *output_bfd; + bfd *output_bfd ATTRIBUTE_UNUSED; struct bfd_link_info *info; const char *name; boolean provide; @@ -2197,7 +2558,10 @@ NAME(bfd_elf,record_link_assignment) (output_bfd, info, name, provide) h->verinfo.verdef = NULL; h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; - h->type = STT_OBJECT; + + /* When possible, keep the original type of the symbol */ + if (h->type == STT_NOTYPE) + h->type = STT_OBJECT; if (((h->elf_link_hash_flags & (ELF_LINK_HASH_DEF_DYNAMIC | ELF_LINK_HASH_REF_DYNAMIC)) != 0 @@ -2234,8 +2598,6 @@ struct elf_assign_sym_version_info struct bfd_elf_version_tree *verdefs; /* Whether we are exporting all dynamic symbols. */ boolean export_dynamic; - /* Whether we removed any symbols from the dynamic symbol table. */ - boolean removed_dynamic; /* Whether we had a failure. */ boolean failed; }; @@ -2280,7 +2642,7 @@ compute_bucket_count (info) struct bfd_link_info *info; { size_t dynsymcount = elf_hash_table (info)->dynsymcount; - size_t best_size; + size_t best_size = 0; unsigned long int *hashcodes; unsigned long int *hashcodesp; unsigned long int i; @@ -2410,42 +2772,6 @@ compute_bucket_count (info) return best_size; } -/* Remove SECTION from the BFD. If a symbol for SECTION was going to - be put into the dynamic symbol table, remove it, and renumber - subsequent entries. */ - -static void -elf_link_remove_section_and_adjust_dynindices (info, section) - struct bfd_link_info *info; - asection *section; -{ - /* Remove the section from the output list. */ - _bfd_strip_section_from_output (section); - - if (elf_section_data (section->output_section)->dynindx) - { - asection *s; - int increment = -1; - - /* We were going to output an entry in the dynamic symbol table - for the symbol corresponding to this section. Now, the - section is gone. So, we must renumber the dynamic indices of - all subsequent sections and all other entries in the dynamic - symbol table. */ - elf_section_data (section->output_section)->dynindx = 0; - for (s = section->output_section->next; s; s = s->next) - if (elf_section_data (s)->dynindx) - --elf_section_data (s)->dynindx; - - elf_link_hash_traverse (elf_hash_table (info), - _bfd_elf_link_adjust_dynindx, - &increment); - - /* There is one less dynamic symbol than there was before. */ - --elf_hash_table (info)->dynsymcount; - } -} - /* Set up the sizes and contents of the ELF dynamic sections. This is called by the ELF linker emulation before_allocation routine. We must set the sizes of the sections before the linker sets the @@ -2469,7 +2795,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, bfd_size_type soname_indx; bfd *dynobj; struct elf_backend_data *bed; - bfd_size_type old_dynsymcount; struct elf_assign_sym_version_info asvinfo; *sinterpptr = NULL; @@ -2493,20 +2818,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, if (dynobj == NULL) return true; - /* If we are supposed to export all symbols into the dynamic symbol - table (this is not the normal case), then do so. */ - if (export_dynamic) - { - struct elf_info_failed eif; - - eif.failed = false; - eif.info = info; - elf_link_hash_traverse (elf_hash_table (info), elf_export_symbol, - (PTR) &eif); - if (eif.failed) - return false; - } - if (elf_hash_table (info)->dynamic_sections_created) { struct elf_info_failed eif; @@ -2569,12 +2880,25 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, } } + /* If we are supposed to export all symbols into the dynamic symbol + table (this is not the normal case), then do so. */ + if (export_dynamic) + { + struct elf_info_failed eif; + + eif.failed = false; + eif.info = info; + elf_link_hash_traverse (elf_hash_table (info), elf_export_symbol, + (PTR) &eif); + if (eif.failed) + return false; + } + /* Attach all the symbols to their version information. */ asvinfo.output_bfd = output_bfd; asvinfo.info = info; asvinfo.verdefs = verdefs; asvinfo.export_dynamic = export_dynamic; - asvinfo.removed_dynamic = false; asvinfo.failed = false; elf_link_hash_traverse (elf_hash_table (info), @@ -2636,7 +2960,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, /* The backend must work out the sizes of all the other dynamic sections. */ - old_dynsymcount = elf_hash_table (info)->dynsymcount; if (bed->elf_backend_size_dynamic_sections && ! (*bed->elf_backend_size_dynamic_sections) (output_bfd, info)) return false; @@ -2647,6 +2970,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, asection *s; size_t bucketcount = 0; Elf_Internal_Sym isym; + size_t hash_entry_size; /* Set up the version definition section. */ s = bfd_get_section_by_name (dynobj, ".gnu.version_d"); @@ -2657,7 +2981,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, verdefs = asvinfo.verdefs; if (verdefs == NULL) - elf_link_remove_section_and_adjust_dynindices (info, s); + _bfd_strip_section_from_output (info, s); else { unsigned int cdefs; @@ -2667,23 +2991,6 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, Elf_Internal_Verdef def; Elf_Internal_Verdaux defaux; - if (asvinfo.removed_dynamic) - { - /* Some dynamic symbols were changed to be local - symbols. In this case, we renumber all of the - dynamic symbols, so that we don't have a hole. If - the backend changed dynsymcount, then assume that the - new symbols are at the start. This is the case on - the MIPS. FIXME: The names of the removed symbols - will still be in the dynamic string table, wasting - space. */ - elf_hash_table (info)->dynsymcount = - 1 + (elf_hash_table (info)->dynsymcount - old_dynsymcount); - elf_link_hash_traverse (elf_hash_table (info), - elf_link_renumber_dynsyms, - (PTR) info); - } - cdefs = 0; size = 0; @@ -2723,7 +3030,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, if (soname_indx != (bfd_size_type) -1) { - def.vd_hash = bfd_elf_hash ((const unsigned char *) soname); + def.vd_hash = bfd_elf_hash (soname); defaux.vda_name = soname_indx; } else @@ -2732,7 +3039,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, bfd_size_type indx; name = output_bfd->filename; - def.vd_hash = bfd_elf_hash ((const unsigned char *) name); + def.vd_hash = bfd_elf_hash (name); indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr, name, true, false); if (indx == (bfd_size_type) -1) @@ -2780,7 +3087,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, def.vd_flags |= VER_FLG_WEAK; def.vd_ndx = t->vernum + 1; def.vd_cnt = cdeps + 1; - def.vd_hash = bfd_elf_hash ((const unsigned char *) t->name); + def.vd_hash = bfd_elf_hash (t->name); def.vd_aux = sizeof (Elf_External_Verdef); if (t->next != NULL) def.vd_next = (sizeof (Elf_External_Verdef) @@ -2850,7 +3157,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, (PTR) &sinfo); if (elf_tdata (output_bfd)->verref == NULL) - elf_link_remove_section_and_adjust_dynindices (info, s); + _bfd_strip_section_from_output (info, s); else { Elf_Internal_Verneed *t; @@ -2916,8 +3223,7 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, for (a = t->vn_auxptr; a != NULL; a = a->vna_nextptr) { - a->vna_hash = bfd_elf_hash ((const unsigned char *) - a->vna_nodename); + a->vna_hash = bfd_elf_hash (a->vna_nodename); indx = _bfd_stringtab_add (elf_hash_table (info)->dynstr, a->vna_nodename, true, false); if (indx == (bfd_size_type) -1) @@ -2942,7 +3248,12 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, } } - dynsymcount = elf_hash_table (info)->dynsymcount; + /* Assign dynsym indicies. In a shared library we generate a + section symbol for each output section, which come first. + Next come all of the back-end allocated local dynamic syms, + followed by the rest of the global symbols. */ + + dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info); /* Work out the size of the symbol version section. */ s = bfd_get_section_by_name (dynobj, ".gnu.version"); @@ -2950,10 +3261,10 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, if (dynsymcount == 0 || (verdefs == NULL && elf_tdata (output_bfd)->verref == NULL)) { - elf_link_remove_section_and_adjust_dynindices (info, s); + _bfd_strip_section_from_output (info, s); /* The DYNSYMCOUNT might have changed if we were going to output a dynamic symbol table entry for S. */ - dynsymcount = elf_hash_table (info)->dynsymcount; + dynsymcount = _bfd_elf_link_renumber_dynsyms (output_bfd, info); } else { @@ -2995,14 +3306,16 @@ NAME(bfd_elf,size_dynamic_sections) (output_bfd, soname, rpath, s = bfd_get_section_by_name (dynobj, ".hash"); BFD_ASSERT (s != NULL); - s->_raw_size = (2 + bucketcount + dynsymcount) * (ARCH_SIZE / 8); + hash_entry_size = elf_section_data (s)->this_hdr.sh_entsize; + s->_raw_size = ((2 + bucketcount + dynsymcount) * hash_entry_size); s->contents = (bfd_byte *) bfd_alloc (output_bfd, s->_raw_size); if (s->contents == NULL) return false; memset (s->contents, 0, (size_t) s->_raw_size); - put_word (output_bfd, bucketcount, s->contents); - put_word (output_bfd, dynsymcount, s->contents + (ARCH_SIZE / 8)); + bfd_put (8 * hash_entry_size, output_bfd, bucketcount, s->contents); + bfd_put (8 * hash_entry_size, output_bfd, dynsymcount, + s->contents + hash_entry_size); elf_hash_table (info)->bucketcount = bucketcount; @@ -3105,6 +3418,33 @@ elf_fix_symbol_flags (h, eif) h->plt.offset = (bfd_vma) -1; } + /* If this is a weak defined symbol in a dynamic object, and we know + the real definition in the dynamic object, copy interesting flags + over to the real definition. */ + if (h->weakdef != NULL) + { + struct elf_link_hash_entry *weakdef; + + BFD_ASSERT (h->root.type == bfd_link_hash_defined + || h->root.type == bfd_link_hash_defweak); + weakdef = h->weakdef; + BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined + || weakdef->root.type == bfd_link_hash_defweak); + BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC); + + /* If the real definition is defined by a regular object file, + don't do anything special. See the longer description in + elf_adjust_dynamic_symbol, below. */ + if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) + h->weakdef = NULL; + else + weakdef->elf_link_hash_flags |= + (h->elf_link_hash_flags + & (ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_REF_REGULAR_NONWEAK + | ELF_LINK_NON_GOT_REF)); + } + return true; } @@ -3187,32 +3527,14 @@ elf_adjust_dynamic_symbol (h, data) if (h->weakdef != NULL) { - struct elf_link_hash_entry *weakdef; + /* If we get to this point, we know there is an implicit + reference by a regular object file via the weak symbol H. + FIXME: Is this really true? What if the traversal finds + H->WEAKDEF before it finds H? */ + h->weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; - BFD_ASSERT (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak); - weakdef = h->weakdef; - BFD_ASSERT (weakdef->root.type == bfd_link_hash_defined - || weakdef->root.type == bfd_link_hash_defweak); - BFD_ASSERT (weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC); - if ((weakdef->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0) - { - /* This symbol is defined by a regular object file, so we - will not do anything special. Clear weakdef for the - convenience of the processor backend. */ - h->weakdef = NULL; - } - else - { - /* There is an implicit reference by a regular object file - via the weak symbol. */ - weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR; - if (h->weakdef->elf_link_hash_flags - & ELF_LINK_HASH_REF_REGULAR_NONWEAK) - weakdef->elf_link_hash_flags |= ELF_LINK_HASH_REF_REGULAR_NONWEAK; - if (! elf_adjust_dynamic_symbol (weakdef, (PTR) eif)) - return false; - } + if (! elf_adjust_dynamic_symbol (h->weakdef, (PTR) eif)) + return false; } /* If a symbol has no type and no size and does not require a PLT @@ -3435,7 +3757,6 @@ elf_link_assign_sym_version (h, data) && info->shared && ! sinfo->export_dynamic) { - sinfo->removed_dynamic = true; h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL; h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT; @@ -3551,7 +3872,6 @@ elf_link_assign_sym_version (h, data) && info->shared && ! sinfo->export_dynamic) { - sinfo->removed_dynamic = true; h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL; h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT; h->dynindx = -1; @@ -3576,7 +3896,6 @@ elf_link_assign_sym_version (h, data) && info->shared && ! sinfo->export_dynamic) { - sinfo->removed_dynamic = true; h->elf_link_hash_flags |= ELF_LINK_FORCED_LOCAL; h->elf_link_hash_flags &=~ ELF_LINK_HASH_NEEDS_PLT; h->dynindx = -1; @@ -3589,26 +3908,6 @@ elf_link_assign_sym_version (h, data) return true; } - -/* This function is used to renumber the dynamic symbols, if some of - them are removed because they are marked as local. This is called - via elf_link_hash_traverse. */ - -static boolean -elf_link_renumber_dynsyms (h, data) - struct elf_link_hash_entry *h; - PTR data; -{ - struct bfd_link_info *info = (struct bfd_link_info *) data; - - if (h->dynindx != -1) - { - h->dynindx = elf_hash_table (info)->dynsymcount; - ++elf_hash_table (info)->dynsymcount; - } - - return true; -} /* Final phase of ELF linker. */ @@ -3686,38 +3985,91 @@ elf_link_size_reloc_section (abfd, rel_hdr, o) asection *o; { register struct elf_link_hash_entry **p, **pend; + unsigned reloc_count; - /* We are overestimating the size required for the relocation - sections, in the case that we are using both REL and RELA - relocations for a single section. In that case, RELOC_COUNT will - be the total number of relocations required, and we allocate - space for that many REL relocations as well as that many RELA - relocations. This approximation is wasteful of disk space. - However, until we keep track of how many of each kind of - relocation is required, it's difficult to calculate the right - value. */ - rel_hdr->sh_size = rel_hdr->sh_entsize * o->reloc_count; + /* Figure out how many relocations there will be. */ + if (rel_hdr == &elf_section_data (o)->rel_hdr) + reloc_count = elf_section_data (o)->rel_count; + else + reloc_count = elf_section_data (o)->rel_count2; + + /* That allows us to calculate the size of the section. */ + rel_hdr->sh_size = rel_hdr->sh_entsize * reloc_count; /* The contents field must last into write_object_contents, so we allocate it with bfd_alloc rather than malloc. */ rel_hdr->contents = (PTR) bfd_alloc (abfd, rel_hdr->sh_size); if (rel_hdr->contents == NULL && rel_hdr->sh_size != 0) return false; + + /* We only allocate one set of hash entries, so we only do it the + first time we are called. */ + if (elf_section_data (o)->rel_hashes == NULL) + { + p = ((struct elf_link_hash_entry **) + bfd_malloc (o->reloc_count + * sizeof (struct elf_link_hash_entry *))); + if (p == NULL && o->reloc_count != 0) + return false; - p = ((struct elf_link_hash_entry **) - bfd_malloc (o->reloc_count - * sizeof (struct elf_link_hash_entry *))); - if (p == NULL && o->reloc_count != 0) - return false; - - elf_section_data (o)->rel_hashes = p; - pend = p + o->reloc_count; - for (; p < pend; p++) - *p = NULL; + elf_section_data (o)->rel_hashes = p; + pend = p + o->reloc_count; + for (; p < pend; p++) + *p = NULL; + } return true; } +/* When performing a relocateable link, the input relocations are + preserved. But, if they reference global symbols, the indices + referenced must be updated. Update all the relocations in + REL_HDR (there are COUNT of them), using the data in REL_HASH. */ + +static void +elf_link_adjust_relocs (abfd, rel_hdr, count, rel_hash) + bfd *abfd; + Elf_Internal_Shdr *rel_hdr; + unsigned int count; + struct elf_link_hash_entry **rel_hash; +{ + unsigned int i; + + for (i = 0; i < count; i++, rel_hash++) + { + if (*rel_hash == NULL) + continue; + + BFD_ASSERT ((*rel_hash)->indx >= 0); + + if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) + { + Elf_External_Rel *erel; + Elf_Internal_Rel irel; + + erel = (Elf_External_Rel *) rel_hdr->contents + i; + elf_swap_reloc_in (abfd, erel, &irel); + irel.r_info = ELF_R_INFO ((*rel_hash)->indx, + ELF_R_TYPE (irel.r_info)); + elf_swap_reloc_out (abfd, &irel, erel); + } + else + { + Elf_External_Rela *erela; + Elf_Internal_Rela irela; + + BFD_ASSERT (rel_hdr->sh_entsize + == sizeof (Elf_External_Rela)); + + erela = (Elf_External_Rela *) rel_hdr->contents + i; + elf_swap_reloca_in (abfd, erela, &irela); + irela.r_info = ELF_R_INFO ((*rel_hash)->indx, + ELF_R_TYPE (irela.r_info)); + elf_swap_reloca_out (abfd, &irela, erela); + } + } +} + /* Do the final step of an ELF link. */ boolean @@ -3873,6 +4225,54 @@ elf_bfd_final_link (abfd, info) if (! _bfd_elf_compute_section_file_positions (abfd, info)) goto error_return; + /* Figure out how many relocations we will have in each section. + Just using RELOC_COUNT isn't good enough since that doesn't + maintain a separate value for REL vs. RELA relocations. */ + if (info->relocateable) + for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) + for (o = sub->sections; o != NULL; o = o->next) + { + asection *output_section; + + if (! o->linker_mark) + { + /* This section was omitted from the link. */ + continue; + } + + output_section = o->output_section; + + if (output_section != NULL + && (o->flags & SEC_RELOC) != 0) + { + struct bfd_elf_section_data *esdi + = elf_section_data (o); + struct bfd_elf_section_data *esdo + = elf_section_data (output_section); + unsigned int *rel_count; + unsigned int *rel_count2; + + /* We must be careful to add the relocation froms the + input section to the right output count. */ + if (esdi->rel_hdr.sh_entsize == esdo->rel_hdr.sh_entsize) + { + rel_count = &esdo->rel_count; + rel_count2 = &esdo->rel_count2; + } + else + { + rel_count = &esdo->rel_count2; + rel_count2 = &esdo->rel_count; + } + + *rel_count += (esdi->rel_hdr.sh_size + / esdi->rel_hdr.sh_entsize); + if (esdi->rel_hdr2) + *rel_count2 += (esdi->rel_hdr2->sh_size + / esdi->rel_hdr2->sh_entsize); + } + } + /* That created the reloc sections. Set their sizes, and assign them file positions, and allocate some buffers. */ for (o = abfd->sections; o != NULL; o = o->next) @@ -3890,6 +4290,11 @@ elf_bfd_final_link (abfd, info) o)) goto error_return; } + + /* Now, reset REL_COUNT and REL_COUNT2 so that we can use them + to count upwards while actually outputting the relocations. */ + elf_section_data (o)->rel_count = 0; + elf_section_data (o)->rel_count2 = 0; } _bfd_elf_assign_file_positions_for_relocs (abfd); @@ -3991,7 +4396,8 @@ elf_bfd_final_link (abfd, info) finfo.external_relocs = (PTR) bfd_malloc (max_external_reloc_size); finfo.internal_relocs = ((Elf_Internal_Rela *) bfd_malloc (max_internal_reloc_count - * sizeof (Elf_Internal_Rela))); + * sizeof (Elf_Internal_Rela) + * bed->s->int_rels_per_ext_rel)); finfo.external_syms = ((Elf_External_Sym *) bfd_malloc (max_sym_count * sizeof (Elf_External_Sym))); @@ -4082,11 +4488,79 @@ elf_bfd_final_link (abfd, info) return false; } - /* The sh_info field records the index of the first non local - symbol. */ + /* The sh_info field records the index of the first non local symbol. */ symtab_hdr->sh_info = bfd_get_symcount (abfd); + if (dynamic) - elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = 1; + { + Elf_Internal_Sym sym; + Elf_External_Sym *dynsym = + (Elf_External_Sym *)finfo.dynsym_sec->contents; + long last_local = 0; + + /* Write out the section symbols for the output sections. */ + if (info->shared) + { + asection *s; + + sym.st_size = 0; + sym.st_name = 0; + sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_SECTION); + sym.st_other = 0; + + for (s = abfd->sections; s != NULL; s = s->next) + { + int indx; + indx = elf_section_data (s)->this_idx; + BFD_ASSERT (indx > 0); + sym.st_shndx = indx; + sym.st_value = s->vma; + + elf_swap_symbol_out (abfd, &sym, + dynsym + elf_section_data (s)->dynindx); + } + + last_local = bfd_count_sections (abfd); + } + + /* Write out the local dynsyms. */ + if (elf_hash_table (info)->dynlocal) + { + struct elf_link_local_dynamic_entry *e; + for (e = elf_hash_table (info)->dynlocal; e ; e = e->next) + { + asection *s; + + sym.st_size = e->isym.st_size; + sym.st_other = e->isym.st_other; + + /* Copy the internal symbol as is. + Note that we saved a word of storage and overwrote + the original st_name with the dynstr_index. */ + sym = e->isym; + + if (e->isym.st_shndx > 0 && e->isym.st_shndx < SHN_LORESERVE) + { + s = bfd_section_from_elf_index (e->input_bfd, + e->isym.st_shndx); + + sym.st_shndx = + elf_section_data (s->output_section)->this_idx; + sym.st_value = (s->output_section->vma + + s->output_offset + + e->isym.st_value); + } + + if (last_local < e->dynindx) + last_local = e->dynindx; + + elf_swap_symbol_out (abfd, &sym, dynsym + e->dynindx); + } + } + + elf_section_data (finfo.dynsym_sec->output_section)->this_hdr.sh_info = + last_local + 1; + } /* We get the global symbols from the hash table. */ eoinfo.failed = false; @@ -4097,6 +4571,18 @@ elf_bfd_final_link (abfd, info) if (eoinfo.failed) return false; + /* If backend needs to output some symbols not present in the hash + table, do it now. */ + if (bed->elf_backend_output_arch_syms) + { + if (! (*bed->elf_backend_output_arch_syms) + (abfd, info, (PTR) &finfo, + (boolean (*) PARAMS ((PTR, const char *, + Elf_Internal_Sym *, asection *))) + elf_link_output_sym)) + return false; + } + /* Flush all symbols to the file. */ if (! elf_link_flush_output_syms (&finfo)) return false; @@ -4131,47 +4617,17 @@ elf_bfd_final_link (abfd, info) /* Adjust the relocs to have the correct symbol indices. */ for (o = abfd->sections; o != NULL; o = o->next) { - struct elf_link_hash_entry **rel_hash; - Elf_Internal_Shdr *rel_hdr; - if ((o->flags & SEC_RELOC) == 0) continue; - rel_hash = elf_section_data (o)->rel_hashes; - rel_hdr = &elf_section_data (o)->rel_hdr; - for (i = 0; i < o->reloc_count; i++, rel_hash++) - { - if (*rel_hash == NULL) - continue; - - BFD_ASSERT ((*rel_hash)->indx >= 0); - - if (rel_hdr->sh_entsize == sizeof (Elf_External_Rel)) - { - Elf_External_Rel *erel; - Elf_Internal_Rel irel; - - erel = (Elf_External_Rel *) rel_hdr->contents + i; - elf_swap_reloc_in (abfd, erel, &irel); - irel.r_info = ELF_R_INFO ((*rel_hash)->indx, - ELF_R_TYPE (irel.r_info)); - elf_swap_reloc_out (abfd, &irel, erel); - } - else - { - Elf_External_Rela *erela; - Elf_Internal_Rela irela; - - BFD_ASSERT (rel_hdr->sh_entsize - == sizeof (Elf_External_Rela)); - - erela = (Elf_External_Rela *) rel_hdr->contents + i; - elf_swap_reloca_in (abfd, erela, &irela); - irela.r_info = ELF_R_INFO ((*rel_hash)->indx, - ELF_R_TYPE (irela.r_info)); - elf_swap_reloca_out (abfd, &irela, erela); - } - } + elf_link_adjust_relocs (abfd, &elf_section_data (o)->rel_hdr, + elf_section_data (o)->rel_count, + elf_section_data (o)->rel_hashes); + if (elf_section_data (o)->rel_hdr2 != NULL) + elf_link_adjust_relocs (abfd, elf_section_data (o)->rel_hdr2, + elf_section_data (o)->rel_count2, + (elf_section_data (o)->rel_hashes + + elf_section_data (o)->rel_count)); /* Set the reloc_count field to 0 to prevent write_relocs from trying to swap the relocs out itself. */ @@ -4668,14 +5124,23 @@ elf_link_output_extsym (h, data) /* If we are marking the symbol as undefined, and there are no non-weak references to this symbol from a regular object, then - mark the symbol as weak undefined. We can't do this earlier, + mark the symbol as weak undefined; if there are non-weak + references, mark the symbol as strong. We can't do this earlier, because it might not be marked as undefined until the finish_dynamic_symbol routine gets through with it. */ if (sym.st_shndx == SHN_UNDEF - && sym.st_info == ELF_ST_INFO (STB_GLOBAL, h->type) && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR) != 0 - && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) == 0) - sym.st_info = ELF_ST_INFO (STB_WEAK, h->type); + && (ELF_ST_BIND(sym.st_info) == STB_GLOBAL + || ELF_ST_BIND(sym.st_info) == STB_WEAK)) + { + int bindtype; + + if ((h->elf_link_hash_flags & ELF_LINK_HASH_REF_REGULAR_NONWEAK) != 0) + bindtype = STB_GLOBAL; + else + bindtype = STB_WEAK; + sym.st_info = ELF_ST_INFO (bindtype, ELF_ST_TYPE (sym.st_info)); + } /* If this symbol should be put in the .dynsym section, then put it there now. We have already know the symbol index. We also fill @@ -4685,6 +5150,7 @@ elf_link_output_extsym (h, data) { size_t bucketcount; size_t bucket; + size_t hash_entry_size; bfd_byte *bucketpos; bfd_vma chain; @@ -4697,13 +5163,15 @@ elf_link_output_extsym (h, data) bucketcount = elf_hash_table (finfo->info)->bucketcount; bucket = h->elf_hash_value % bucketcount; + hash_entry_size + = elf_section_data (finfo->hash_sec)->this_hdr.sh_entsize; bucketpos = ((bfd_byte *) finfo->hash_sec->contents - + (bucket + 2) * (ARCH_SIZE / 8)); - chain = get_word (finfo->output_bfd, bucketpos); - put_word (finfo->output_bfd, h->dynindx, bucketpos); - put_word (finfo->output_bfd, chain, - ((bfd_byte *) finfo->hash_sec->contents - + (bucketcount + 2 + h->dynindx) * (ARCH_SIZE / 8))); + + (bucket + 2) * hash_entry_size); + chain = bfd_get (8 * hash_entry_size, finfo->output_bfd, bucketpos); + bfd_put (8 * hash_entry_size, finfo->output_bfd, h->dynindx, bucketpos); + bfd_put (8 * hash_entry_size, finfo->output_bfd, chain, + ((bfd_byte *) finfo->hash_sec->contents + + (bucketcount + 2 + h->dynindx) * hash_entry_size)); if (finfo->symver_sec != NULL && finfo->symver_sec->contents != NULL) { @@ -4766,7 +5234,7 @@ elf_link_output_relocs (output_bfd, input_section, input_rel_hdr, Elf_Internal_Rela *irelaend; Elf_Internal_Shdr *output_rel_hdr; asection *output_section; - unsigned int *rel_countp; + unsigned int *rel_countp = NULL; output_section = input_section->output_section; output_rel_hdr = NULL; @@ -4845,10 +5313,11 @@ elf_link_input_bfd (finfo, input_bfd) long *pindex; asection **ppsection; asection *o; + struct elf_backend_data *bed; output_bfd = finfo->output_bfd; - relocate_section = - get_elf_backend_data (output_bfd)->elf_backend_relocate_section; + bed = get_elf_backend_data (output_bfd); + relocate_section = bed->elf_backend_relocate_section; /* If this is a dynamic object, we don't want to do anything here: we don't want the local symbols, and we don't want the section @@ -5085,9 +5554,11 @@ elf_link_input_bfd (finfo, input_bfd) /* Adjust the reloc addresses and symbol indices. */ irela = internal_relocs; - irelaend = irela + o->reloc_count; + irelaend = + irela + o->reloc_count * bed->s->int_rels_per_ext_rel; rel_hash = (elf_section_data (o->output_section)->rel_hashes - + o->output_section->reloc_count); + + elf_section_data (o->output_section)->rel_count + + elf_section_data (o->output_section)->rel_count2); for (; irela < irelaend; irela++, rel_hash++) { unsigned long r_symndx; @@ -5277,7 +5748,8 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order) /* Figure out the symbol index. */ rel_hash_ptr = (elf_section_data (output_section)->rel_hashes - + output_section->reloc_count); + + elf_section_data (output_section)->rel_count + + elf_section_data (output_section)->rel_count2); if (link_order->type == bfd_section_reloc_link_order) { indx = link_order->u.reloc.p->u.section->target_index; @@ -5386,7 +5858,7 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order) irel.r_offset = offset; irel.r_info = ELF_R_INFO (indx, howto->type); erel = ((Elf_External_Rel *) rel_hdr->contents - + output_section->reloc_count); + + elf_section_data (output_section)->rel_count); elf_swap_reloc_out (output_bfd, &irel, erel); } else @@ -5398,11 +5870,11 @@ elf_reloc_link_order (output_bfd, info, output_section, link_order) irela.r_info = ELF_R_INFO (indx, howto->type); irela.r_addend = addend; erela = ((Elf_External_Rela *) rel_hdr->contents - + output_section->reloc_count); + + elf_section_data (output_section)->rel_count); elf_swap_reloca_out (output_bfd, &irela, erela); } - ++output_section->reloc_count; + ++elf_section_data (output_section)->rel_count; return true; } @@ -5622,8 +6094,8 @@ elf_finish_pointer_linker_section (output_bfd, input_bfd, info, lsect, h, reloca elf_swap_reloca_out (output_bfd, &outrel, (((Elf_External_Rela *) lsect->section->contents) - + lsect->section->reloc_count)); - ++lsect->section->reloc_count; + + elf_section_data (lsect->section)->rel_count)); + ++elf_section_data (lsect->section)->rel_count; } } } @@ -5695,6 +6167,7 @@ elf_gc_mark (info, sec, gc_mark_hook) size_t extsymoff; Elf_External_Sym *locsyms, *freesyms = NULL; bfd *input_bfd = sec->owner; + struct elf_backend_data *bed = get_elf_backend_data (input_bfd); /* GCFIXME: how to arrange so that relocs and symbols are not reread continually? */ @@ -5738,7 +6211,7 @@ elf_gc_mark (info, sec, gc_mark_hook) ret = false; goto out1; } - relend = relstart + sec->reloc_count; + relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel; for (rel = relstart; rel < relend; rel++) { @@ -5944,6 +6417,7 @@ elf_gc_smash_unused_vtentry_relocs (h, okp) asection *sec; bfd_vma hstart, hend; Elf_Internal_Rela *relstart, *relend, *rel; + struct elf_backend_data *bed; /* Take care of both those symbols that do not describe vtables as well as those that are not loaded. */ @@ -5961,7 +6435,8 @@ elf_gc_smash_unused_vtentry_relocs (h, okp) (sec->owner, sec, NULL, (Elf_Internal_Rela *) NULL, true)); if (!relstart) return *(boolean *)okp = false; - relend = relstart + sec->reloc_count; + bed = get_elf_backend_data (sec->owner); + relend = relstart + sec->reloc_count * bed->s->int_rels_per_ext_rel; for (rel = relstart; rel < relend; ++rel) if (rel->r_offset >= hstart && rel->r_offset < hend) @@ -6095,8 +6570,8 @@ win: boolean elf_gc_record_vtentry (abfd, sec, h, addend) - bfd *abfd; - asection *sec; + bfd *abfd ATTRIBUTE_UNUSED; + asection *sec ATTRIBUTE_UNUSED; struct elf_link_hash_entry *h; bfd_vma addend; { @@ -6122,30 +6597,31 @@ elf_gc_record_vtentry (abfd, sec, h, addend) /* Allocate one extra entry for use as a "done" flag for the consolidation pass. */ - bytes = (size / FILE_ALIGN + 1) * sizeof(boolean); + bytes = (size / FILE_ALIGN + 1) * sizeof (boolean); if (ptr) { - size_t oldbytes; - - ptr = realloc (ptr-1, bytes); - if (ptr == NULL) - return false; + ptr = bfd_realloc (ptr - 1, bytes); + + if (ptr != NULL) + { + size_t oldbytes; - oldbytes = (h->vtable_entries_size/FILE_ALIGN + 1) * sizeof(boolean); - memset (ptr + oldbytes, 0, bytes - oldbytes); + oldbytes = (h->vtable_entries_size/FILE_ALIGN + 1) * sizeof (boolean); + memset (((char *)ptr) + oldbytes, 0, bytes - oldbytes); + } } else - { - ptr = calloc (1, bytes); - if (ptr == NULL) - return false; - } + ptr = bfd_zmalloc (bytes); + if (ptr == NULL) + return false; + /* And arrange for that done flag to be at index -1. */ - h->vtable_entries_used = ptr+1; + h->vtable_entries_used = ptr + 1; h->vtable_entries_size = size; } + h->vtable_entries_used[addend / FILE_ALIGN] = true; return true;