X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf32-i386.c;h=e76e75b01312f2680efbf396b288a1ef57c6f2d2;hb=5a15f56fea3090ab5ee971207656453cdf267b86;hp=f43adcd85ebea1888c0ed92a895de75b31d8d488;hpb=d9bc7a4499c25b26971d80e2392a6da6e84cbe21;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index f43adcd85e..e76e75b013 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -35,11 +35,16 @@ static struct bfd_hash_entry *elf_i386_link_hash_newfunc PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); static struct bfd_link_hash_table *elf_i386_link_hash_table_create PARAMS ((bfd *)); +static boolean create_got_section PARAMS((bfd *, struct bfd_link_info *)); +static boolean elf_i386_create_dynamic_sections + PARAMS((bfd *, struct bfd_link_info *)); static boolean elf_i386_check_relocs PARAMS ((bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *)); static boolean elf_i386_adjust_dynamic_symbol PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *)); +static boolean allocate_plt_and_got_and_discard_relocs + PARAMS ((struct elf_link_hash_entry *, PTR)); static boolean elf_i386_size_dynamic_sections PARAMS ((bfd *, struct bfd_link_info *)); static boolean elf_i386_relocate_section @@ -352,18 +357,15 @@ static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = }; /* The i386 linker needs to keep track of the number of relocs that it - decides to copy in check_relocs for each symbol. This is so that - it can discard PC relative relocs if it doesn't need them when - linking with -Bsymbolic. We store the information in a field - extending the regular ELF linker hash table. */ + decides to copy as dynamic relocs in check_relocs for each symbol. + This is so that it can later discard them if they are found to be + unnecessary. We store the information in a field extending the + regular ELF linker hash table. */ -/* This structure keeps track of the number of PC relative relocs we - have copied for a given symbol. */ - -struct elf_i386_pcrel_relocs_copied +struct elf_i386_dyn_relocs { /* Next section. */ - struct elf_i386_pcrel_relocs_copied *next; + struct elf_i386_dyn_relocs *next; /* A section in dynobj. */ asection *section; /* Number of relocs copied in this section. */ @@ -377,7 +379,7 @@ struct elf_i386_link_hash_entry struct elf_link_hash_entry root; /* Number of PC relative relocs copied for this symbol. */ - struct elf_i386_pcrel_relocs_copied *pcrel_relocs_copied; + struct elf_i386_dyn_relocs *dyn_relocs; }; /* i386 ELF linker hash table. */ @@ -385,20 +387,16 @@ struct elf_i386_link_hash_entry struct elf_i386_link_hash_table { struct elf_link_hash_table root; -}; - -/* Declare this now that the above structures are defined. */ - -static boolean elf_i386_discard_copies - PARAMS ((struct elf_i386_link_hash_entry *, PTR)); - -/* Traverse an i386 ELF linker hash table. */ -#define elf_i386_link_hash_traverse(table, func, info) \ - (elf_link_hash_traverse \ - (&(table)->root, \ - (boolean (*) PARAMS ((struct elf_link_hash_entry *, PTR))) (func), \ - (info))) + /* Short-cuts to get to dynamic linker sections. */ + asection *sgot; + asection *sgotplt; + asection *srelgot; + asection *splt; + asection *srelplt; + asection *sdynbss; + asection *srelbss; +}; /* Get the i386 ELF linker hash table from a link_info structure. */ @@ -431,7 +429,7 @@ elf_i386_link_hash_newfunc (entry, table, string) table, string)); if (ret != (struct elf_i386_link_hash_entry *) NULL) { - ret->pcrel_relocs_copied = NULL; + ret->dyn_relocs = NULL; } return (struct bfd_hash_entry *) ret; @@ -457,9 +455,78 @@ elf_i386_link_hash_table_create (abfd) return NULL; } + ret->sgot = NULL; + ret->sgotplt = NULL; + ret->srelgot = NULL; + ret->splt = NULL; + ret->srelplt = NULL; + ret->sdynbss = NULL; + ret->srelbss = NULL; + return &ret->root.root; } +/* Create .got, .gotplt, and .rel.got sections in DYNOBJ, and set up + shortcuts to them in our hash table. */ + +static boolean +create_got_section (dynobj, info) + bfd *dynobj; + struct bfd_link_info *info; +{ + struct elf_i386_link_hash_table *htab; + + if (! _bfd_elf_create_got_section (dynobj, info)) + return false; + + htab = elf_i386_hash_table (info); + htab->sgot = bfd_get_section_by_name (dynobj, ".got"); + htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt"); + if (!htab->sgot || !htab->sgotplt) + abort (); + + htab->srelgot = bfd_make_section (dynobj, ".rel.got"); + if (htab->srelgot == NULL + || ! bfd_set_section_flags (dynobj, htab->srelgot, + (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS + | SEC_IN_MEMORY | SEC_LINKER_CREATED + | SEC_READONLY)) + || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2)) + return false; + return true; +} + +/* Create .plt, .rel.plt, .got, .got.plt, .rel.got, .dynbss, and + .rel.bss sections in DYNOBJ, and set up shortcuts to them in our + hash table. */ + +static boolean +elf_i386_create_dynamic_sections (dynobj, info) + bfd *dynobj; + struct bfd_link_info *info; +{ + struct elf_i386_link_hash_table *htab; + + htab = elf_i386_hash_table (info); + if (!htab->sgot && !create_got_section (dynobj, info)) + return false; + + if (!_bfd_elf_create_dynamic_sections (dynobj, info)) + return false; + + htab->splt = bfd_get_section_by_name (dynobj, ".plt"); + htab->srelplt = bfd_get_section_by_name (dynobj, ".rel.plt"); + htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss"); + if (!info->shared) + htab->srelbss = bfd_get_section_by_name (dynobj, ".rel.bss"); + + if (!htab->splt || !htab->srelplt || !htab->sdynbss + || (!info->shared && !htab->srelbss)) + abort (); + + return true; +} + /* Look through the relocs for a section during the first phase, and allocate space in the global offset table or procedure linkage table. */ @@ -471,26 +538,24 @@ elf_i386_check_relocs (abfd, info, sec, relocs) asection *sec; const Elf_Internal_Rela *relocs; { + struct elf_i386_link_hash_table *htab; bfd *dynobj; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; bfd_signed_vma *local_got_refcounts; const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; - asection *sgot; - asection *srelgot; asection *sreloc; if (info->relocateable) return true; - dynobj = elf_hash_table (info)->dynobj; + htab = elf_i386_hash_table (info); + dynobj = htab->root.dynobj; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; sym_hashes = elf_sym_hashes (abfd); local_got_refcounts = elf_local_got_refcounts (abfd); - sgot = NULL; - srelgot = NULL; sreloc = NULL; rel_end = relocs + sec->reloc_count; @@ -521,15 +586,16 @@ elf_i386_check_relocs (abfd, info, sec, relocs) h = sym_hashes[r_symndx - symtab_hdr->sh_info]; /* Some relocs require a global offset table. */ - if (dynobj == NULL) + if (htab->sgot == NULL) { switch (ELF32_R_TYPE (rel->r_info)) { case R_386_GOT32: case R_386_GOTOFF: case R_386_GOTPC: - elf_hash_table (info)->dynobj = dynobj = abfd; - if (! _bfd_elf_create_got_section (dynobj, info)) + if (dynobj == NULL) + htab->root.dynobj = dynobj = abfd; + if (!create_got_section (dynobj, info)) return false; break; @@ -542,55 +608,16 @@ elf_i386_check_relocs (abfd, info, sec, relocs) { case R_386_GOT32: /* This symbol requires a global offset table entry. */ - - if (sgot == NULL) - { - sgot = bfd_get_section_by_name (dynobj, ".got"); - BFD_ASSERT (sgot != NULL); - } - - if (srelgot == NULL - && (h != NULL || info->shared)) - { - srelgot = bfd_get_section_by_name (dynobj, ".rel.got"); - if (srelgot == NULL) - { - srelgot = bfd_make_section (dynobj, ".rel.got"); - if (srelgot == NULL - || ! bfd_set_section_flags (dynobj, srelgot, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_LINKER_CREATED - | SEC_READONLY)) - || ! bfd_set_section_alignment (dynobj, srelgot, 2)) - return false; - } - } - if (h != NULL) { if (h->got.refcount == -1) - { - h->got.refcount = 1; - - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1) - { - if (! bfd_elf32_link_record_dynamic_symbol (info, h)) - return false; - } - - sgot->_raw_size += 4; - srelgot->_raw_size += sizeof (Elf32_External_Rel); - } + h->got.refcount = 1; else h->got.refcount += 1; } else { - /* This is a global offset table entry for a local symbol. */ + /* This is a global offset table entry for a local symbol. */ if (local_got_refcounts == NULL) { size_t size; @@ -604,18 +631,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs) memset (local_got_refcounts, -1, size); } if (local_got_refcounts[r_symndx] == -1) - { - local_got_refcounts[r_symndx] = 1; - - sgot->_raw_size += 4; - if (info->shared) - { - /* If we are generating a shared object, we need to - output a R_386_RELATIVE reloc so that the dynamic - linker can adjust this GOT entry. */ - srelgot->_raw_size += sizeof (Elf32_External_Rel); - } - } + local_got_refcounts[r_symndx] = 1; else local_got_refcounts[r_symndx] += 1; } @@ -623,21 +639,21 @@ elf_i386_check_relocs (abfd, info, sec, relocs) case R_386_PLT32: /* This symbol requires a procedure linkage table entry. We - actually build the entry in adjust_dynamic_symbol, - because this might be a case of linking PIC code which is - never referenced by a dynamic object, in which case we - don't need to generate a procedure linkage table entry - after all. */ + actually build the entry in adjust_dynamic_symbol, + because this might be a case of linking PIC code which is + never referenced by a dynamic object, in which case we + don't need to generate a procedure linkage table entry + after all. */ /* If this is a local symbol, we resolve it directly without - creating a procedure linkage table entry. */ + creating a procedure linkage table entry. */ if (h == NULL) continue; if (h->plt.refcount == -1) { - h->plt.refcount = 1; h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + h->plt.refcount = 1; } else h->plt.refcount += 1; @@ -645,8 +661,20 @@ elf_i386_check_relocs (abfd, info, sec, relocs) case R_386_32: case R_386_PC32: - if (h != NULL) - h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF; + if (h != NULL && !info->shared) + { + /* If this reloc is in a read-only section, we might + need a copy reloc. */ + if ((sec->flags & SEC_READONLY) != 0) + h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF; + + /* We may need a .plt entry if the function this reloc + refers to is in a shared lib. */ + if (h->plt.refcount == -1) + h->plt.refcount = 1; + else + h->plt.refcount += 1; + } /* If we are creating a shared library, and this is a reloc against a global symbol, or a non PC relative reloc @@ -663,19 +691,33 @@ elf_i386_check_relocs (abfd, info, sec, relocs) storing information in the relocs_copied field of the hash table entry. A similar situation occurs when creating shared libraries and symbol visibility changes render the - symbol local. */ - if (info->shared - && (sec->flags & SEC_ALLOC) != 0 - && (ELF32_R_TYPE (rel->r_info) != R_386_PC32 - || (h != NULL - && (! info->symbolic - || h->root.type == bfd_link_hash_defweak - || (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + symbol local. + If on the other hand, we are creating an executable, we + may need to keep relocations for symbols satisfied by a + dynamic library if we manage to avoid copy relocs for the + symbol. */ + if ((info->shared + && (sec->flags & SEC_ALLOC) != 0 + && (ELF32_R_TYPE (rel->r_info) != R_386_PC32 + || (h != NULL + && (! info->symbolic + || h->root.type == bfd_link_hash_defweak + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + || (!info->shared + && (sec->flags & SEC_ALLOC) != 0 + && h != NULL + && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 + && (h->root.type == bfd_link_hash_defweak + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0))) { - /* When creating a shared object, we must copy these - reloc types into the output file. We create a reloc - section in dynobj and make room for this reloc. */ + /* We must copy these reloc types into the output file. + Create a reloc section in dynobj and make room for + this reloc. */ + if (dynobj == NULL) + htab->root.dynobj = dynobj = abfd; + if (sreloc == NULL) { const char *name; @@ -727,26 +769,27 @@ elf_i386_check_relocs (abfd, info, sec, relocs) that this function is only called if we are using an elf_i386 linker hash table, which means that h is really a pointer to an elf_i386_link_hash_entry. */ - if (h != NULL - && ELF32_R_TYPE (rel->r_info) == R_386_PC32) + if (!info->shared + || (h != NULL + && ELF32_R_TYPE (rel->r_info) == R_386_PC32)) { struct elf_i386_link_hash_entry *eh; - struct elf_i386_pcrel_relocs_copied *p; + struct elf_i386_dyn_relocs *p; eh = (struct elf_i386_link_hash_entry *) h; - for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next) + for (p = eh->dyn_relocs; p != NULL; p = p->next) if (p->section == sreloc) break; if (p == NULL) { - p = ((struct elf_i386_pcrel_relocs_copied *) + p = ((struct elf_i386_dyn_relocs *) bfd_alloc (dynobj, sizeof *p)); if (p == NULL) return false; - p->next = eh->pcrel_relocs_copied; - eh->pcrel_relocs_copied = p; + p->next = eh->dyn_relocs; + eh->dyn_relocs = p; p->section = sreloc; p->count = 0; } @@ -832,7 +875,7 @@ elf_i386_gc_mark_hook (abfd, info, rel, h, sym) static boolean elf_i386_gc_sweep_hook (abfd, info, sec, relocs) bfd *abfd; - struct bfd_link_info *info ATTRIBUTE_UNUSED; + struct bfd_link_info *info; asection *sec; const Elf_Internal_Rela *relocs; { @@ -843,19 +886,14 @@ elf_i386_gc_sweep_hook (abfd, info, sec, relocs) unsigned long r_symndx; struct elf_link_hash_entry *h; bfd *dynobj; - asection *sgot; - asection *srelgot; - - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; - sym_hashes = elf_sym_hashes (abfd); - local_got_refcounts = elf_local_got_refcounts (abfd); dynobj = elf_hash_table (info)->dynobj; if (dynobj == NULL) return true; - sgot = bfd_get_section_by_name (dynobj, ".got"); - srelgot = bfd_get_section_by_name (dynobj, ".rel.got"); + symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + sym_hashes = elf_sym_hashes (abfd); + local_got_refcounts = elf_local_got_refcounts (abfd); relend = relocs + sec->reloc_count; for (rel = relocs; rel < relend; rel++) @@ -869,30 +907,21 @@ elf_i386_gc_sweep_hook (abfd, info, sec, relocs) { h = sym_hashes[r_symndx - symtab_hdr->sh_info]; if (h->got.refcount > 0) - { - h->got.refcount -= 1; - if (h->got.refcount == 0) - { - sgot->_raw_size -= 4; - srelgot->_raw_size -= sizeof (Elf32_External_Rel); - } - } + h->got.refcount -= 1; } else if (local_got_refcounts != NULL) { if (local_got_refcounts[r_symndx] > 0) - { - local_got_refcounts[r_symndx] -= 1; - if (local_got_refcounts[r_symndx] == 0) - { - sgot->_raw_size -= 4; - if (info->shared) - srelgot->_raw_size -= sizeof (Elf32_External_Rel); - } - } + local_got_refcounts[r_symndx] -= 1; } break; + case R_386_32: + case R_386_PC32: + if (info->shared) + break; + /* Fall through. */ + case R_386_PLT32: r_symndx = ELF32_R_SYM (rel->r_info); if (r_symndx >= symtab_hdr->sh_info) @@ -921,22 +950,13 @@ elf_i386_adjust_dynamic_symbol (info, h) struct bfd_link_info *info; struct elf_link_hash_entry *h; { + struct elf_i386_link_hash_table *htab; bfd *dynobj; asection *s; unsigned int power_of_two; - dynobj = elf_hash_table (info)->dynobj; - - /* Make sure we know what is going on here. */ - BFD_ASSERT (dynobj != NULL - && ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) - || h->weakdef != NULL - || ((h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_DYNAMIC) != 0 - && (h->elf_link_hash_flags - & ELF_LINK_HASH_REF_REGULAR) != 0 - && (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0))); + htab = elf_i386_hash_table (info); + dynobj = htab->root.dynobj; /* If this is a function, put it in the procedure linkage table. We will fill in the contents of the procedure linkage table later, @@ -944,66 +964,29 @@ elf_i386_adjust_dynamic_symbol (info, h) if (h->type == STT_FUNC || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) { - if ((! info->shared - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 - && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0) - || (info->shared && h->plt.refcount <= 0)) + if (h->plt.refcount <= 0 + || (! info->shared + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) == 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_REF_DYNAMIC) == 0)) { /* This case can occur if we saw a PLT32 reloc in an input file, but the symbol was never referred to by a dynamic object, or if all references were garbage collected. In such a case, we don't actually need to build a procedure linkage table, and we can just do a PC32 reloc instead. */ - h->plt.offset = (bfd_vma) -1; + h->plt.refcount = (bfd_vma) -1; h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; - return true; - } - - /* Make sure this symbol is output as a dynamic symbol. */ - if (h->dynindx == -1) - { - if (! bfd_elf32_link_record_dynamic_symbol (info, h)) - return false; } - s = bfd_get_section_by_name (dynobj, ".plt"); - BFD_ASSERT (s != NULL); - - /* If this is the first .plt entry, make room for the special - first entry. */ - if (s->_raw_size == 0) - s->_raw_size += PLT_ENTRY_SIZE; - - /* If this symbol is not defined in a regular file, and we are - not generating a shared library, then set the symbol to this - location in the .plt. This is required to make function - pointers compare as equal between the normal executable and - the shared library. */ - if (! info->shared - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) - { - h->root.u.def.section = s; - h->root.u.def.value = s->_raw_size; - } - - h->plt.offset = s->_raw_size; - - /* Make room for this entry. */ - s->_raw_size += PLT_ENTRY_SIZE; - - /* We also need to make an entry in the .got.plt section, which - will be placed in the .got section by the linker script. */ - s = bfd_get_section_by_name (dynobj, ".got.plt"); - BFD_ASSERT (s != NULL); - s->_raw_size += 4; - - /* We also need to make an entry in the .rel.plt section. */ - s = bfd_get_section_by_name (dynobj, ".rel.plt"); - BFD_ASSERT (s != NULL); - s->_raw_size += sizeof (Elf32_External_Rel); - return true; } + else + /* It's possible that we incorrectly decided a .plt reloc was + needed for an R_386_PC32 reloc to a non-function sym in + check_relocs. We can't decide accurately between function and + non-function syms in check-relocs; Objects loaded later in + the link may change h->type. So fix it now. */ + h->plt.refcount = (bfd_vma) -1; /* If this is a weak symbol, and there is a real definition, the processor independent code will have arranged for us to see the @@ -1042,8 +1025,9 @@ elf_i386_adjust_dynamic_symbol (info, h) both the dynamic object and the regular object will refer to the same memory location for the variable. */ - s = bfd_get_section_by_name (dynobj, ".dynbss"); - BFD_ASSERT (s != NULL); + s = htab->sdynbss; + if (s == NULL) + abort (); /* We must generate a R_386_COPY reloc to tell the dynamic linker to copy the initial value out of the dynamic object and into the @@ -1053,8 +1037,9 @@ elf_i386_adjust_dynamic_symbol (info, h) { asection *srel; - srel = bfd_get_section_by_name (dynobj, ".rel.bss"); - BFD_ASSERT (srel != NULL); + srel = htab->srelbss; + if (srel == NULL) + abort (); srel->_raw_size += sizeof (Elf32_External_Rel); h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_COPY; } @@ -1084,6 +1069,167 @@ elf_i386_adjust_dynamic_symbol (info, h) return true; } +/* This is the condition under which elf_i386_finish_dynamic_symbol + will be called from elflink.h. If elflink.h doesn't call our + finish_dynamic_symbol routine, we'll need to do something about + initializing any .plt and .got entries in elf_i386_relocate_section. */ +#define WILL_CALL_FINISH_DYNAMIC_SYMBOL(DYN, INFO, H) \ + ((DYN) \ + && ((INFO)->shared \ + || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) \ + && ((H)->dynindx != -1 \ + || ((H)->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0)) + +/* Allocate space in .plt, .got and associated reloc sections for + global syms. Also discards space allocated for relocs in the + check_relocs function that we subsequently have found to be + unneeded. */ + +static boolean +allocate_plt_and_got_and_discard_relocs (h, inf) + struct elf_link_hash_entry *h; + PTR inf; +{ + struct bfd_link_info *info; + struct elf_i386_link_hash_table *htab; + asection *s; + struct elf_i386_link_hash_entry *eh; + + if (h->root.type == bfd_link_hash_indirect + || h->root.type == bfd_link_hash_warning) + return true; + + info = (struct bfd_link_info *) inf; + htab = elf_i386_hash_table (info); + + if (htab->root.dynamic_sections_created + && h->plt.refcount > 0) + { + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + s = htab->splt; + if (s == NULL) + abort (); + + /* If this is the first .plt entry, make room for the special + first entry. */ + if (s->_raw_size == 0) + s->_raw_size += PLT_ENTRY_SIZE; + + h->plt.offset = s->_raw_size; + + /* If this symbol is not defined in a regular file, and we are + not generating a shared library, then set the symbol to this + location in the .plt. This is required to make function + pointers compare as equal between the normal executable and + the shared library. */ + if (! info->shared + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + { + h->root.u.def.section = s; + h->root.u.def.value = h->plt.offset; + } + + /* Make room for this entry. */ + s->_raw_size += PLT_ENTRY_SIZE; + + /* We also need to make an entry in the .got.plt section, which + will be placed in the .got section by the linker script. */ + s = htab->sgotplt; + if (s == NULL) + abort (); + s->_raw_size += 4; + + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h)) + { + /* We also need to make an entry in the .rel.plt section. */ + s = htab->srelplt; + if (s == NULL) + abort (); + s->_raw_size += sizeof (Elf32_External_Rel); + } + } + else + { + h->plt.offset = (bfd_vma) -1; + h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; + } + + if (h->got.refcount > 0) + { + boolean dyn; + + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + s = htab->sgot; + h->got.offset = s->_raw_size; + s->_raw_size += 4; + dyn = htab->root.dynamic_sections_created; + if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h)) + htab->srelgot->_raw_size += sizeof (Elf32_External_Rel); + } + else + h->got.offset = (bfd_vma) -1; + + /* In the shared -Bsymbolic case, discard space allocated for + dynamic relocs against symbols which turn out to be defined + in regular objects. For the normal shared case, discard space + for relocs that have become local due to symbol visibility + changes. For the non-shared case, discard space for symbols + which turn out to need copy relocs or are not dynamic. */ + + eh = (struct elf_i386_link_hash_entry *) h; + if (eh->dyn_relocs == NULL) + return true; + + if (!info->shared + && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 + && ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + || h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined)) + { + /* Make sure this symbol is output as a dynamic symbol. + Undefined weak syms won't yet be marked as dynamic. */ + if (h->dynindx == -1 + && (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) == 0) + { + if (! bfd_elf32_link_record_dynamic_symbol (info, h)) + return false; + } + + /* If that succeeded, we know we'll be keeping all the relocs. */ + if (h->dynindx != -1) + return true; + } + + if (!info->shared + || ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 + && ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0 + || info->symbolic))) + { + struct elf_i386_dyn_relocs *c; + + for (c = eh->dyn_relocs; c != NULL; c = c->next) + c->section->_raw_size -= c->count * sizeof (Elf32_External_Rel); + } + + return true; +} + /* Set the sizes of the dynamic sections. */ static boolean @@ -1091,82 +1237,89 @@ elf_i386_size_dynamic_sections (output_bfd, info) bfd *output_bfd; struct bfd_link_info *info; { + struct elf_i386_link_hash_table *htab; bfd *dynobj; asection *s; - boolean plt; boolean relocs; boolean reltext; + bfd *i; - dynobj = elf_hash_table (info)->dynobj; - BFD_ASSERT (dynobj != NULL); + htab = elf_i386_hash_table (info); + dynobj = htab->root.dynobj; + if (dynobj == NULL) + abort (); - if (elf_hash_table (info)->dynamic_sections_created) + if (htab->root.dynamic_sections_created) { /* Set the contents of the .interp section to the interpreter. */ if (! info->shared) { s = bfd_get_section_by_name (dynobj, ".interp"); - BFD_ASSERT (s != NULL); + if (s == NULL) + abort (); s->_raw_size = sizeof ELF_DYNAMIC_INTERPRETER; s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; } } - else + + /* Set up .got offsets for local syms. */ + for (i = info->input_bfds; i; i = i->link_next) { - /* We may have created entries in the .rel.got section. - However, if we are not creating the dynamic sections, we will - not actually use these entries. Reset the size of .rel.got, - which will cause it to get stripped from the output file - below. */ - s = bfd_get_section_by_name (dynobj, ".rel.got"); - if (s != NULL) - s->_raw_size = 0; + bfd_signed_vma *local_got; + bfd_signed_vma *end_local_got; + bfd_size_type locsymcount; + Elf_Internal_Shdr *symtab_hdr; + asection *srel; + + if (bfd_get_flavour (i) != bfd_target_elf_flavour) + continue; + + local_got = elf_local_got_refcounts (i); + if (!local_got) + continue; + + symtab_hdr = &elf_tdata (i)->symtab_hdr; + locsymcount = symtab_hdr->sh_info; + end_local_got = local_got + locsymcount; + s = htab->sgot; + srel = htab->srelgot; + for (; local_got < end_local_got; ++local_got) + { + if (*local_got > 0) + { + *local_got = s->_raw_size; + s->_raw_size += 4; + if (info->shared) + srel->_raw_size += sizeof (Elf32_External_Rel); + } + else + *local_got = (bfd_vma) -1; + } } - /* If this is a -Bsymbolic shared link, then we need to discard all - PC relative relocs against symbols defined in a regular object. - We allocated space for them in the check_relocs routine, but we - will not fill them in in the relocate_section routine. */ - if (info->shared) - elf_i386_link_hash_traverse (elf_i386_hash_table (info), - elf_i386_discard_copies, - (PTR) info); - - /* The check_relocs and adjust_dynamic_symbol entry points have - determined the sizes of the various dynamic sections. Allocate - memory for them. */ - plt = false; + /* Allocate global sym .plt and .got entries. Also discard all + unneeded relocs. */ + elf_link_hash_traverse (&htab->root, + allocate_plt_and_got_and_discard_relocs, + (PTR) info); + + /* We now have determined the sizes of the various dynamic sections. + Allocate memory for them. */ relocs = false; reltext = false; for (s = dynobj->sections; s != NULL; s = s->next) { - const char *name; - boolean strip; - if ((s->flags & SEC_LINKER_CREATED) == 0) continue; - /* It's OK to base decisions on the section name, because none - of the dynobj section names depend upon the input files. */ - name = bfd_get_section_name (dynobj, s); - - strip = false; - - if (strcmp (name, ".plt") == 0) + if (s == htab->splt + || s == htab->sgot + || s == htab->sgotplt) { - if (s->_raw_size == 0) - { - /* Strip this section if we don't need it; see the - comment below. */ - strip = true; - } - else - { - /* Remember whether there is a PLT. */ - plt = true; - } + /* Strip this section if we don't need it; see the + comment below. */ } - else if (strncmp (name, ".rel", 4) == 0) + else if (strncmp (bfd_get_section_name (dynobj, s), ".rel", 4) == 0) { if (s->_raw_size == 0) { @@ -1179,15 +1332,14 @@ elf_i386_size_dynamic_sections (output_bfd, info) adjust_dynamic_symbol is called, and it is that function which decides whether anything needs to go into these sections. */ - strip = true; } else { asection *target; /* Remember whether there are any reloc sections other - than .rel.plt. */ - if (strcmp (name, ".rel.plt") != 0) + than .rel.plt. */ + if (s != htab->srelplt) { const char *outname; @@ -1212,13 +1364,13 @@ elf_i386_size_dynamic_sections (output_bfd, info) s->reloc_count = 0; } } - else if (strncmp (name, ".got", 4) != 0) + else { /* It's not one of our sections, so don't allocate space. */ continue; } - if (strip) + if (s->_raw_size == 0) { _bfd_strip_section_from_output (info, s); continue; @@ -1230,11 +1382,11 @@ elf_i386_size_dynamic_sections (output_bfd, info) but this way if it does, we get a R_386_NONE reloc instead of garbage. */ s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->_raw_size); - if (s->contents == NULL && s->_raw_size != 0) + if (s->contents == NULL) return false; } - if (elf_hash_table (info)->dynamic_sections_created) + if (htab->root.dynamic_sections_created) { /* Add some entries to the .dynamic section. We fill in the values later, in elf_i386_finish_dynamic_sections, but we @@ -1247,7 +1399,7 @@ elf_i386_size_dynamic_sections (output_bfd, info) return false; } - if (plt) + if (htab->splt->_raw_size != 0) { if (! bfd_elf32_add_dynamic_entry (info, DT_PLTGOT, 0) || ! bfd_elf32_add_dynamic_entry (info, DT_PLTRELSZ, 0) @@ -1276,37 +1428,6 @@ elf_i386_size_dynamic_sections (output_bfd, info) return true; } -/* This function is called via elf_i386_link_hash_traverse if we are - creating a shared object. In the -Bsymbolic case, it discards the - space allocated to copy PC relative relocs against symbols which - are defined in regular objects. For the normal non-symbolic case, - we also discard space for relocs that have become local due to - symbol visibility changes. We allocated space for them in the - check_relocs routine, but we won't fill them in in the - relocate_section routine. */ - -static boolean -elf_i386_discard_copies (h, inf) - struct elf_i386_link_hash_entry *h; - PTR inf; -{ - struct elf_i386_pcrel_relocs_copied *s; - struct bfd_link_info *info = (struct bfd_link_info *) inf; - - /* If a symbol has been forced local or we have found a regular - definition for the symbolic link case, then we won't be needing - any relocs. */ - if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 - && ((h->root.elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0 - || info->symbolic)) - { - for (s = h->pcrel_relocs_copied; s != NULL; s = s->next) - s->section->_raw_size -= s->count * sizeof (Elf32_External_Rel); - } - - return true; -} - /* Relocate an i386 ELF section. */ static boolean @@ -1321,30 +1442,22 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, Elf_Internal_Sym *local_syms; asection **local_sections; { + struct elf_i386_link_hash_table *htab; bfd *dynobj; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; bfd_vma *local_got_offsets; - asection *sgot; - asection *splt; asection *sreloc; Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; - dynobj = elf_hash_table (info)->dynobj; + htab = elf_i386_hash_table (info); + dynobj = htab->root.dynobj; symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; sym_hashes = elf_sym_hashes (input_bfd); local_got_offsets = elf_local_got_offsets (input_bfd); sreloc = NULL; - splt = NULL; - sgot = NULL; - if (dynobj != NULL) - { - splt = bfd_get_section_by_name (dynobj, ".plt"); - sgot = bfd_get_section_by_name (dynobj, ".got"); - } - rel = relocs; relend = relocs + input_section->reloc_count; for (; rel < relend; rel++) @@ -1355,7 +1468,9 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; asection *sec; + bfd_vma off; bfd_vma relocation; + boolean unresolved_reloc; bfd_reloc_status_type r; unsigned int indx; @@ -1402,6 +1517,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, h = NULL; sym = NULL; sec = NULL; + unresolved_reloc = false; if (r_symndx < symtab_hdr->sh_info) { sym = local_syms + r_symndx; @@ -1416,59 +1532,29 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, while (h->root.type == bfd_link_hash_indirect || h->root.type == bfd_link_hash_warning) h = (struct elf_link_hash_entry *) h->root.u.i.link; + + relocation = 0; if (h->root.type == bfd_link_hash_defined || h->root.type == bfd_link_hash_defweak) { sec = h->root.u.def.section; - if (r_type == R_386_GOTPC - || (r_type == R_386_PLT32 - && splt != NULL - && h->plt.offset != (bfd_vma) -1) - || (r_type == R_386_GOT32 - && elf_hash_table (info)->dynamic_sections_created - && (! info->shared - || (! info->symbolic && h->dynindx != -1) - || (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0)) - || (info->shared - && ((! info->symbolic && h->dynindx != -1) - || (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0) - && (r_type == R_386_32 - || r_type == R_386_PC32) - && ((input_section->flags & SEC_ALLOC) != 0 - /* DWARF will emit R_386_32 relocations in its - sections against symbols defined externally - in shared libraries. We can't do anything - with them here. */ - || ((input_section->flags & SEC_DEBUGGING) != 0 - && (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_DYNAMIC) != 0)))) - { - /* In these cases, we don't need the relocation - value. We check specially because in some - obscure cases sec->output_section will be NULL. */ - relocation = 0; - } - else if (sec->output_section == NULL) - { - (*_bfd_error_handler) - (_("%s: warning: unresolvable relocation against symbol `%s' from %s section"), - bfd_get_filename (input_bfd), h->root.root.string, - bfd_get_section_name (input_bfd, input_section)); - relocation = 0; - } + if (sec->output_section == NULL) + /* Set a flag that will be cleared later if we find a + relocation value for this symbol. output_section + is typically NULL for symbols satisfied by a shared + library. */ + unresolved_reloc = true; else relocation = (h->root.u.def.value + sec->output_section->vma + sec->output_offset); } else if (h->root.type == bfd_link_hash_undefweak) - relocation = 0; + ; else if (info->shared && !info->symbolic && !info->no_undefined && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) - relocation = 0; + ; else { if (! ((*info->callbacks->undefined_symbol) @@ -1477,7 +1563,6 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, (!info->shared || info->no_undefined || ELF_ST_VISIBILITY (h->other))))) return false; - relocation = 0; } } @@ -1486,18 +1571,20 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, case R_386_GOT32: /* Relocation is to the entry for this symbol in the global offset table. */ - BFD_ASSERT (sgot != NULL); + if (htab->sgot == NULL) + abort (); if (h != NULL) { - bfd_vma off; + boolean dyn; off = h->got.offset; - BFD_ASSERT (off != (bfd_vma) -1); - - if (! elf_hash_table (info)->dynamic_sections_created + dyn = htab->root.dynamic_sections_created; + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h) || (info->shared - && (info->symbolic || h->dynindx == -1) + && (info->symbolic + || h->dynindx == -1 + || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)) && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) { /* This is actually a static link, or it is a @@ -1517,41 +1604,41 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, else { bfd_put_32 (output_bfd, relocation, - sgot->contents + off); + htab->sgot->contents + off); h->got.offset |= 1; } } - - relocation = sgot->output_offset + off; + else + unresolved_reloc = false; } else { - bfd_vma off; - - BFD_ASSERT (local_got_offsets != NULL - && local_got_offsets[r_symndx] != (bfd_vma) -1); + if (local_got_offsets == NULL) + abort (); off = local_got_offsets[r_symndx]; /* The offset must always be a multiple of 4. We use - the least significant bit to record whether we have - already generated the necessary reloc. */ + the least significant bit to record whether we have + already generated the necessary reloc. */ if ((off & 1) != 0) off &= ~1; else { - bfd_put_32 (output_bfd, relocation, sgot->contents + off); + bfd_put_32 (output_bfd, relocation, + htab->sgot->contents + off); if (info->shared) { asection *srelgot; Elf_Internal_Rel outrel; - srelgot = bfd_get_section_by_name (dynobj, ".rel.got"); - BFD_ASSERT (srelgot != NULL); + srelgot = htab->srelgot; + if (srelgot == NULL) + abort (); - outrel.r_offset = (sgot->output_section->vma - + sgot->output_offset + outrel.r_offset = (htab->sgot->output_section->vma + + htab->sgot->output_offset + off); outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); bfd_elf32_swap_reloc_out (output_bfd, &outrel, @@ -1563,42 +1650,30 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, local_got_offsets[r_symndx] |= 1; } - - relocation = sgot->output_offset + off; } + if (off >= (bfd_vma) -2) + abort (); + + relocation = htab->sgot->output_offset + off; break; case R_386_GOTOFF: /* Relocation is relative to the start of the global offset table. */ - if (sgot == NULL) - { - sgot = bfd_get_section_by_name (dynobj, ".got"); - BFD_ASSERT (sgot != NULL); - } - /* Note that sgot->output_offset is not involved in this calculation. We always want the start of .got. If we defined _GLOBAL_OFFSET_TABLE in a different way, as is permitted by the ABI, we might have to change this calculation. */ - relocation -= sgot->output_section->vma; - + relocation -= htab->sgot->output_section->vma; break; case R_386_GOTPC: /* Use global offset table as symbol value. */ - - if (sgot == NULL) - { - sgot = bfd_get_section_by_name (dynobj, ".got"); - BFD_ASSERT (sgot != NULL); - } - - relocation = sgot->output_section->vma; - + relocation = htab->sgot->output_section->vma; + unresolved_reloc = false; break; case R_386_PLT32: @@ -1606,35 +1681,44 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, procedure linkage table. */ /* Resolve a PLT32 reloc against a local symbol directly, - without using the procedure linkage table. */ + without using the procedure linkage table. */ if (h == NULL) break; if (h->plt.offset == (bfd_vma) -1 - || splt == NULL) + || htab->splt == NULL) { /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code, or when - using -Bsymbolic. */ + happens when statically linking PIC code, or when + using -Bsymbolic. */ break; } - relocation = (splt->output_section->vma - + splt->output_offset + relocation = (htab->splt->output_section->vma + + htab->splt->output_offset + h->plt.offset); - + unresolved_reloc = false; break; case R_386_32: case R_386_PC32: - if (info->shared - && (input_section->flags & SEC_ALLOC) != 0 - && (r_type != R_386_PC32 - || (h != NULL - && h->dynindx != -1 - && (! info->symbolic - || (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + if ((info->shared + && (input_section->flags & SEC_ALLOC) != 0 + && (r_type != R_386_PC32 + || (h != NULL + && h->dynindx != -1 + && (! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)))) + || (!info->shared + && (input_section->flags & SEC_ALLOC) != 0 + && h != NULL + && h->dynindx != -1 + && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 + && ((h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_DYNAMIC) != 0 + || h->root.type == bfd_link_hash_undefweak + || h->root.type == bfd_link_hash_undefined))) { Elf_Internal_Rel outrel; boolean skip, relocate; @@ -1660,19 +1744,22 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, name + 4) != 0) { if (input_bfd->my_archive) - (*_bfd_error_handler) (_("%s(%s): bad relocation section name `%s\'"), - bfd_get_filename (input_bfd->my_archive), - bfd_get_filename (input_bfd), - name); + (*_bfd_error_handler)\ + (_("%s(%s): bad relocation section name `%s\'"), + bfd_get_filename (input_bfd->my_archive), + bfd_get_filename (input_bfd), + name); else - (*_bfd_error_handler) (_("%s: bad relocation section name `%s\'"), - bfd_get_filename (input_bfd), - name); + (*_bfd_error_handler) + (_("%s: bad relocation section name `%s\'"), + bfd_get_filename (input_bfd), + name); return false; } sreloc = bfd_get_section_by_name (dynobj, name); - BFD_ASSERT (sreloc != NULL); + if (sreloc == NULL) + abort (); } skip = false; @@ -1684,8 +1771,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, bfd_vma off; off = (_bfd_stab_section_offset - (output_bfd, &elf_hash_table (info)->stab_info, - input_section, + (output_bfd, htab->root.stab_info, input_section, &elf_section_data (input_section)->stab_info, rel->r_offset)); if (off == (bfd_vma) -1) @@ -1701,30 +1787,23 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, memset (&outrel, 0, sizeof outrel); relocate = false; } - else if (r_type == R_386_PC32) + else if (h != NULL + && h->dynindx != -1 + && (r_type == R_386_PC32 + || !info->shared + || !info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)) + { - BFD_ASSERT (h != NULL && h->dynindx != -1); relocate = false; - outrel.r_info = ELF32_R_INFO (h->dynindx, R_386_PC32); + outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); } else { - /* h->dynindx may be -1 if this symbol was marked to - become local. */ - if (h == NULL - || ((info->symbolic || h->dynindx == -1) - && (h->elf_link_hash_flags - & ELF_LINK_HASH_DEF_REGULAR) != 0)) - { - relocate = true; - outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); - } - else - { - BFD_ASSERT (h->dynindx != -1); - relocate = false; - outrel.r_info = ELF32_R_INFO (h->dynindx, R_386_32); - } + /* This symbol is local, or marked to become local. */ + relocate = true; + outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); } bfd_elf32_swap_reloc_out (output_bfd, &outrel, @@ -1747,40 +1826,58 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, break; } + /* FIXME: Why do we allow debugging sections to escape this error? + More importantly, why do we not emit dynamic relocs for + R_386_32 above in debugging sections (which are ! SEC_ALLOC)? + If we had emitted the dynamic reloc, we could remove the + fudge here. */ + if (unresolved_reloc + && !(info->shared + && (input_section->flags & SEC_DEBUGGING) != 0 + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_DYNAMIC) != 0)) + (*_bfd_error_handler) + (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"), + bfd_get_filename (input_bfd), + bfd_get_section_name (input_bfd, input_section), + (long) rel->r_offset, + h->root.root.string); + r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, relocation, (bfd_vma) 0); - if (r != bfd_reloc_ok) + switch (r) { - switch (r) - { - default: - case bfd_reloc_outofrange: - abort (); - case bfd_reloc_overflow: + case bfd_reloc_ok: + break; + + case bfd_reloc_overflow: + { + const char *name; + + if (h != NULL) + name = h->root.root.string; + else { - const char *name; - - if (h != NULL) - name = h->root.root.string; - else - { - name = bfd_elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); - if (name == NULL) - return false; - if (*name == '\0') - name = bfd_section_name (input_bfd, sec); - } - if (! ((*info->callbacks->reloc_overflow) - (info, name, howto->name, (bfd_vma) 0, - input_bfd, input_section, rel->r_offset))) + name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + sym->st_name); + if (name == NULL) return false; + if (*name == '\0') + name = bfd_section_name (input_bfd, sec); } - break; - } + if (! ((*info->callbacks->reloc_overflow) + (info, name, howto->name, (bfd_vma) 0, + input_bfd, input_section, rel->r_offset))) + return false; + } + break; + + default: + case bfd_reloc_outofrange: + abort (); + break; } } @@ -1797,15 +1894,14 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; { + struct elf_i386_link_hash_table *htab; bfd *dynobj; - dynobj = elf_hash_table (info)->dynobj; + htab = elf_i386_hash_table (info); + dynobj = htab->root.dynobj; if (h->plt.offset != (bfd_vma) -1) { - asection *splt; - asection *sgot; - asection *srel; bfd_vma plt_index; bfd_vma got_offset; Elf_Internal_Rel rel; @@ -1813,12 +1909,11 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) /* This symbol has an entry in the procedure linkage table. Set it up. */ - BFD_ASSERT (h->dynindx != -1); - - splt = bfd_get_section_by_name (dynobj, ".plt"); - sgot = bfd_get_section_by_name (dynobj, ".got.plt"); - srel = bfd_get_section_by_name (dynobj, ".rel.plt"); - BFD_ASSERT (splt != NULL && sgot != NULL && srel != NULL); + if (h->dynindx == -1 + || htab->splt == NULL + || htab->sgotplt == NULL + || htab->srelplt == NULL) + abort (); /* Get the index in the procedure linkage table which corresponds to this symbol. This is the index of this symbol @@ -1834,42 +1929,42 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) /* Fill in the entry in the procedure linkage table. */ if (! info->shared) { - memcpy (splt->contents + h->plt.offset, elf_i386_plt_entry, + memcpy (htab->splt->contents + h->plt.offset, elf_i386_plt_entry, PLT_ENTRY_SIZE); bfd_put_32 (output_bfd, - (sgot->output_section->vma - + sgot->output_offset + (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + got_offset), - splt->contents + h->plt.offset + 2); + htab->splt->contents + h->plt.offset + 2); } else { - memcpy (splt->contents + h->plt.offset, elf_i386_pic_plt_entry, + memcpy (htab->splt->contents + h->plt.offset, elf_i386_pic_plt_entry, PLT_ENTRY_SIZE); bfd_put_32 (output_bfd, got_offset, - splt->contents + h->plt.offset + 2); + htab->splt->contents + h->plt.offset + 2); } bfd_put_32 (output_bfd, plt_index * sizeof (Elf32_External_Rel), - splt->contents + h->plt.offset + 7); + htab->splt->contents + h->plt.offset + 7); bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE), - splt->contents + h->plt.offset + 12); + htab->splt->contents + h->plt.offset + 12); /* Fill in the entry in the global offset table. */ bfd_put_32 (output_bfd, - (splt->output_section->vma - + splt->output_offset + (htab->splt->output_section->vma + + htab->splt->output_offset + h->plt.offset + 6), - sgot->contents + got_offset); + htab->sgotplt->contents + got_offset); /* Fill in the entry in the .rel.plt section. */ - rel.r_offset = (sgot->output_section->vma - + sgot->output_offset + rel.r_offset = (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + got_offset); rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT); bfd_elf32_swap_reloc_out (output_bfd, &rel, - ((Elf32_External_Rel *) srel->contents + ((Elf32_External_Rel *) htab->srelplt->contents + plt_index)); if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) @@ -1882,19 +1977,16 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) if (h->got.offset != (bfd_vma) -1) { - asection *sgot; - asection *srel; Elf_Internal_Rel rel; /* This symbol has an entry in the global offset table. Set it up. */ - sgot = bfd_get_section_by_name (dynobj, ".got"); - srel = bfd_get_section_by_name (dynobj, ".rel.got"); - BFD_ASSERT (sgot != NULL && srel != NULL); + if (htab->sgot == NULL || htab->srelgot == NULL) + abort (); - rel.r_offset = (sgot->output_section->vma - + sgot->output_offset + rel.r_offset = (htab->sgot->output_section->vma + + htab->sgot->output_offset + (h->got.offset &~ 1)); /* If this is a static link, or it is a -Bsymbolic link and the @@ -1902,49 +1994,49 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) of a version file, we just want to emit a RELATIVE reloc. The entry in the global offset table will already have been initialized in the relocate_section function. */ - if (! elf_hash_table (info)->dynamic_sections_created - || (info->shared - && (info->symbolic || h->dynindx == -1) - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR))) + if (info->shared + && (info->symbolic + || h->dynindx == -1 + || (h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL)) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) { + BFD_ASSERT((h->got.offset & 1) != 0); rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); } else { BFD_ASSERT((h->got.offset & 1) == 0); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got.offset); + bfd_put_32 (output_bfd, (bfd_vma) 0, + htab->sgot->contents + h->got.offset); rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT); } bfd_elf32_swap_reloc_out (output_bfd, &rel, - ((Elf32_External_Rel *) srel->contents - + srel->reloc_count)); - ++srel->reloc_count; + ((Elf32_External_Rel *) htab->srelgot->contents + + htab->srelgot->reloc_count)); + ++htab->srelgot->reloc_count; } if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) { - asection *s; Elf_Internal_Rel rel; /* This symbol needs a copy reloc. Set it up. */ - BFD_ASSERT (h->dynindx != -1 - && (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak)); - - s = bfd_get_section_by_name (h->root.u.def.section->owner, - ".rel.bss"); - BFD_ASSERT (s != NULL); + if (h->dynindx == -1 + || (h->root.type != bfd_link_hash_defined + && h->root.type != bfd_link_hash_defweak) + || htab->srelbss == NULL) + abort (); rel.r_offset = (h->root.u.def.value + h->root.u.def.section->output_section->vma + h->root.u.def.section->output_offset); rel.r_info = ELF32_R_INFO (h->dynindx, R_386_COPY); bfd_elf32_swap_reloc_out (output_bfd, &rel, - ((Elf32_External_Rel *) s->contents - + s->reloc_count)); - ++s->reloc_count; + ((Elf32_External_Rel *) htab->srelbss->contents + + htab->srelbss->reloc_count)); + ++htab->srelbss->reloc_count; } /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ @@ -1962,30 +2054,26 @@ elf_i386_finish_dynamic_sections (output_bfd, info) bfd *output_bfd; struct bfd_link_info *info; { + struct elf_i386_link_hash_table *htab; bfd *dynobj; - asection *sgot; asection *sdyn; - dynobj = elf_hash_table (info)->dynobj; - - sgot = bfd_get_section_by_name (dynobj, ".got.plt"); - BFD_ASSERT (sgot != NULL); + htab = elf_i386_hash_table (info); + dynobj = htab->root.dynobj; sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); - if (elf_hash_table (info)->dynamic_sections_created) + if (htab->root.dynamic_sections_created) { - asection *splt; Elf32_External_Dyn *dyncon, *dynconend; - BFD_ASSERT (sdyn != NULL); + if (sdyn == NULL || htab->sgot == NULL) + abort (); dyncon = (Elf32_External_Dyn *) sdyn->contents; dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->_raw_size); for (; dyncon < dynconend; dyncon++) { Elf_Internal_Dyn dyn; - const char *name; - asection *s; bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); @@ -1995,24 +2083,20 @@ elf_i386_finish_dynamic_sections (output_bfd, info) break; case DT_PLTGOT: - name = ".got"; - goto get_vma; + dyn.d_un.d_ptr = htab->sgot->output_section->vma; + bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); + break; + case DT_JMPREL: - name = ".rel.plt"; - get_vma: - s = bfd_get_section_by_name (output_bfd, name); - BFD_ASSERT (s != NULL); - dyn.d_un.d_ptr = s->vma; + dyn.d_un.d_ptr = htab->srelplt->output_section->vma; bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); break; case DT_PLTRELSZ: - s = bfd_get_section_by_name (output_bfd, ".rel.plt"); - BFD_ASSERT (s != NULL); - if (s->_cooked_size != 0) - dyn.d_un.d_val = s->_cooked_size; + if (htab->srelplt->output_section->_cooked_size != 0) + dyn.d_un.d_val = htab->srelplt->output_section->_cooked_size; else - dyn.d_un.d_val = s->_raw_size; + dyn.d_un.d_val = htab->srelplt->output_section->_raw_size; bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); break; @@ -2026,13 +2110,12 @@ elf_i386_finish_dynamic_sections (output_bfd, info) the linker script arranges for .rel.plt to follow all other relocation sections, we don't have to worry about changing the DT_REL entry. */ - s = bfd_get_section_by_name (output_bfd, ".rel.plt"); - if (s != NULL) + if (htab->srelplt != NULL) { - if (s->_cooked_size != 0) - dyn.d_un.d_val -= s->_cooked_size; + if (htab->srelplt->output_section->_cooked_size != 0) + dyn.d_un.d_val -= htab->srelplt->output_section->_cooked_size; else - dyn.d_un.d_val -= s->_raw_size; + dyn.d_un.d_val -= htab->srelplt->output_section->_raw_size; } bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); break; @@ -2040,43 +2123,49 @@ elf_i386_finish_dynamic_sections (output_bfd, info) } /* Fill in the first entry in the procedure linkage table. */ - splt = bfd_get_section_by_name (dynobj, ".plt"); - if (splt && splt->_raw_size > 0) + if (htab->splt && htab->splt->_raw_size > 0) { if (info->shared) - memcpy (splt->contents, elf_i386_pic_plt0_entry, PLT_ENTRY_SIZE); + memcpy (htab->splt->contents, + elf_i386_pic_plt0_entry, PLT_ENTRY_SIZE); else { - memcpy (splt->contents, elf_i386_plt0_entry, PLT_ENTRY_SIZE); + memcpy (htab->splt->contents, + elf_i386_plt0_entry, PLT_ENTRY_SIZE); bfd_put_32 (output_bfd, - sgot->output_section->vma + sgot->output_offset + 4, - splt->contents + 2); + (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + 4), + htab->splt->contents + 2); bfd_put_32 (output_bfd, - sgot->output_section->vma + sgot->output_offset + 8, - splt->contents + 8); + (htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset + + 8), + htab->splt->contents + 8); } /* UnixWare sets the entsize of .plt to 4, although that doesn't really seem like the right value. */ - elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4; + elf_section_data (htab->splt->output_section) + ->this_hdr.sh_entsize = 4; } } - /* Fill in the first three entries in the global offset table. */ - if (sgot->_raw_size > 0) + if (htab->sgotplt) { - if (sdyn == NULL) - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents); - else - bfd_put_32 (output_bfd, - sdyn->output_section->vma + sdyn->output_offset, - sgot->contents); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8); - } - - elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4; + /* Fill in the first three entries in the global offset table. */ + if (htab->sgotplt->_raw_size > 0) + { + bfd_put_32 (output_bfd, + (sdyn == NULL ? (bfd_vma) 0 + : sdyn->output_section->vma + sdyn->output_offset), + htab->sgotplt->contents); + bfd_put_32 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + 4); + bfd_put_32 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + 8); + } + elf_section_data (htab->sgotplt->output_section)->this_hdr.sh_entsize = 4; + } return true; } @@ -2134,20 +2223,19 @@ elf_i386_fake_sections (abfd, hdr, sec) #define elf_info_to_howto elf_i386_info_to_howto #define elf_info_to_howto_rel elf_i386_info_to_howto_rel -#define bfd_elf32_bfd_final_link _bfd_elf32_gc_common_final_link #define bfd_elf32_bfd_is_local_label_name elf_i386_is_local_label_name #define bfd_elf32_bfd_link_hash_table_create elf_i386_link_hash_table_create #define bfd_elf32_bfd_reloc_type_lookup elf_i386_reloc_type_lookup #define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol #define elf_backend_check_relocs elf_i386_check_relocs -#define elf_backend_create_dynamic_sections _bfd_elf_create_dynamic_sections +#define elf_backend_create_dynamic_sections elf_i386_create_dynamic_sections #define elf_backend_finish_dynamic_sections elf_i386_finish_dynamic_sections #define elf_backend_finish_dynamic_symbol elf_i386_finish_dynamic_symbol #define elf_backend_gc_mark_hook elf_i386_gc_mark_hook #define elf_backend_gc_sweep_hook elf_i386_gc_sweep_hook #define elf_backend_relocate_section elf_i386_relocate_section #define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections -#define elf_backend_fake_sections elf_i386_fake_sections +#define elf_backend_fake_sections elf_i386_fake_sections #include "elf32-target.h"