X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf32-i386.c;h=4d5324a0a8838eb11631de868a2daded4db483f6;hb=4aa65bb8c1e9ce165e775bef10f0ecc88baa650c;hp=81d7540eceb4b920d3b822525a8684ffe3b56c8d;hpb=82b1edf7b9cf3aaa2bf75a55894690fbf2a1c32c;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 81d7540ece..4d5324a0a8 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -1,5 +1,5 @@ /* Intel 80386/80486-specific support for 32-bit ELF - Copyright 1993 Free Software Foundation, Inc. + Copyright 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -15,24 +15,25 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software -Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.h" #include "bfdlink.h" #include "libbfd.h" -#include "libelf.h" +#include "elf-bfd.h" -static CONST struct reloc_howto_struct *elf_i386_reloc_type_lookup +static reloc_howto_type *elf_i386_reloc_type_lookup PARAMS ((bfd *, bfd_reloc_code_real_type)); static void elf_i386_info_to_howto PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *)); static void elf_i386_info_to_howto_rel PARAMS ((bfd *, arelent *, Elf32_Internal_Rel *)); -static boolean elf_i386_create_dynamic_sections - PARAMS ((bfd *, struct bfd_link_info *)); -static boolean elf_i386_create_got_section - PARAMS ((bfd *, struct bfd_link_info *)); +static boolean elf_i386_is_local_label_name PARAMS ((bfd *, const char *)); +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 elf_i386_check_relocs PARAMS ((bfd *, struct bfd_link_info *, asection *, const Elf_Internal_Rela *)); @@ -64,6 +65,13 @@ enum reloc_type R_386_RELATIVE, R_386_GOTOFF, R_386_GOTPC, + FIRST_INVALID_RELOC, + LAST_INVALID_RELOC = 19, + /* The remaining relocs are a GNU extension. */ + R_386_16 = 20, + R_386_PC16, + R_386_8, + R_386_PC8, R_386_max }; @@ -97,6 +105,20 @@ static reloc_howto_type elf_howto_table[]= HOWTO(R_386_RELATIVE, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_RELATIVE", true,0xffffffff,0xffffffff,false), HOWTO(R_386_GOTOFF, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOTOFF", true,0xffffffff,0xffffffff,false), HOWTO(R_386_GOTPC, 0,2,32,true,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOTPC", true,0xffffffff,0xffffffff,true), + { 11 }, + { 12 }, + { 13 }, + { 14 }, + { 15 }, + { 16 }, + { 17 }, + { 18 }, + { 19 }, + /* The remaining relocs are a GNU extension. */ + HOWTO(R_386_16, 0,1,16,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_16", true,0xffff,0xffff,false), + HOWTO(R_386_PC16, 0,1,16,true, 0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_PC16", true,0xffff,0xffff,true), + HOWTO(R_386_8, 0,0,8,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_8", true,0xff,0xff,false), + HOWTO(R_386_PC8, 0,0,8,true, 0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_PC8", true,0xff,0xff,true), }; #ifdef DEBUG_GEN_RELOC @@ -105,7 +127,7 @@ static reloc_howto_type elf_howto_table[]= #define TRACE(str) #endif -static CONST struct reloc_howto_struct * +static reloc_howto_type * elf_i386_reloc_type_lookup (abfd, code) bfd *abfd; bfd_reloc_code_real_type code; @@ -156,6 +178,23 @@ elf_i386_reloc_type_lookup (abfd, code) TRACE ("BFD_RELOC_386_GOTPC"); return &elf_howto_table[ (int)R_386_GOTPC ]; + /* The remaining relocs are a GNU extension. */ + case BFD_RELOC_16: + TRACE ("BFD_RELOC_16"); + return &elf_howto_table[(int) R_386_16]; + + case BFD_RELOC_16_PCREL: + TRACE ("BFD_RELOC_16_PCREL"); + return &elf_howto_table[(int) R_386_PC16]; + + case BFD_RELOC_8: + TRACE ("BFD_RELOC_8"); + return &elf_howto_table[(int) R_386_8]; + + case BFD_RELOC_8_PCREL: + TRACE ("BFD_RELOC_8_PCREL"); + return &elf_howto_table[(int) R_386_PC8]; + default: break; } @@ -170,20 +209,39 @@ elf_i386_info_to_howto (abfd, cache_ptr, dst) arelent *cache_ptr; Elf32_Internal_Rela *dst; { - BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_386_max); - - cache_ptr->howto = &elf_howto_table[ELF32_R_TYPE(dst->r_info)]; + abort (); } static void elf_i386_info_to_howto_rel (abfd, cache_ptr, dst) - bfd *abfd; - arelent *cache_ptr; + bfd *abfd; + arelent *cache_ptr; Elf32_Internal_Rel *dst; { - BFD_ASSERT (ELF32_R_TYPE(dst->r_info) < (unsigned int) R_386_max); + enum reloc_type type; + + type = (enum reloc_type) ELF32_R_TYPE (dst->r_info); + BFD_ASSERT (type < R_386_max); + BFD_ASSERT (type < FIRST_INVALID_RELOC || type > LAST_INVALID_RELOC); + + cache_ptr->howto = &elf_howto_table[(int) type]; +} + +/* Return whether a symbol name implies a local label. The UnixWare + 2.1 cc generates temporary symbols that start with .X, so we + recognize them here. FIXME: do other SVR4 compilers also use .X?. + If so, we should move the .X recognition into + _bfd_elf_is_local_label_name. */ + +static boolean +elf_i386_is_local_label_name (abfd, name) + bfd *abfd; + const char *name; +{ + if (name[0] == '.' && name[1] == 'X') + return true; - cache_ptr->howto = &elf_howto_table[ELF32_R_TYPE(dst->r_info)]; + return _bfd_elf_is_local_label_name (abfd, name); } /* Functions for the i386 ELF linker. */ @@ -200,7 +258,7 @@ elf_i386_info_to_howto_rel (abfd, cache_ptr, dst) /* The first entry in an absolute procedure linkage table looks like this. See the SVR4 ABI i386 supplement to see how this works. */ -static bfd_byte elf_i386_plt0_entry[PLT_ENTRY_SIZE] = +static const bfd_byte elf_i386_plt0_entry[PLT_ENTRY_SIZE] = { 0xff, 0x35, /* pushl contents of address */ 0, 0, 0, 0, /* replaced with address of .got + 4. */ @@ -212,7 +270,7 @@ static bfd_byte elf_i386_plt0_entry[PLT_ENTRY_SIZE] = /* Subsequent entries in an absolute procedure linkage table look like this. */ -static bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] = +static const bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] = { 0xff, 0x25, /* jmp indirect */ 0, 0, 0, 0, /* replaced with address of this symbol in .got. */ @@ -224,16 +282,16 @@ static bfd_byte elf_i386_plt_entry[PLT_ENTRY_SIZE] = /* The first entry in a PIC procedure linkage table look like this. */ -static bfd_byte elf_i386_pic_plt0_entry[PLT_ENTRY_SIZE] = +static const bfd_byte elf_i386_pic_plt0_entry[PLT_ENTRY_SIZE] = { - 0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ - 0xff, 0xa3, 8, 0, 0, 0, /* jmp *8(%ebx) */ + 0xff, 0xb3, 4, 0, 0, 0, /* pushl 4(%ebx) */ + 0xff, 0xa3, 8, 0, 0, 0, /* jmp *8(%ebx) */ 0, 0, 0, 0 /* pad out to 16 bytes. */ }; /* Subsequent entries in a PIC procedure linkage table look like this. */ -static bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = +static const bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = { 0xff, 0xa3, /* jmp *offset(%ebx) */ 0, 0, 0, 0, /* replaced with offset of this symbol in .got. */ @@ -243,123 +301,113 @@ static bfd_byte elf_i386_pic_plt_entry[PLT_ENTRY_SIZE] = 0, 0, 0, 0 /* replaced with offset to start of .plt. */ }; -/* Create dynamic sections when linking against a dynamic object. */ +/* 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. */ -static boolean -elf_i386_create_dynamic_sections (abfd, info) - bfd *abfd; - struct bfd_link_info *info; +/* This structure keeps track of the number of PC relative relocs we + have copied for a given symbol. */ + +struct elf_i386_pcrel_relocs_copied +{ + /* Next section. */ + struct elf_i386_pcrel_relocs_copied *next; + /* A section in dynobj. */ + asection *section; + /* Number of relocs copied in this section. */ + bfd_size_type count; +}; + +/* i386 ELF linker hash entry. */ + +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; +}; + +/* i386 ELF linker hash table. */ + +struct elf_i386_link_hash_table { - flagword flags; - register asection *s; - - /* We need to create .plt, .rel.plt, .got, .got.plt, .dynbss, and - .rel.bss sections. */ - - flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; - - s = bfd_make_section (abfd, ".plt"); - if (s == NULL - || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY | SEC_CODE) - || ! bfd_set_section_alignment (abfd, s, 2)) - return false; - - s = bfd_make_section (abfd, ".rel.plt"); - if (s == NULL - || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) - || ! bfd_set_section_alignment (abfd, s, 2)) - return false; - - if (! elf_i386_create_got_section (abfd, info)) - return false; - - /* The .dynbss section is a place to put symbols which are defined - by dynamic objects, are referenced by regular objects, and are - not functions. We must allocate space for them in the process - image and use a R_386_COPY reloc to tell the dynamic linker to - initialize them at run time. The linker script puts the .dynbss - section into the .bss section of the final image. */ - s = bfd_make_section (abfd, ".dynbss"); - if (s == NULL - || ! bfd_set_section_flags (abfd, s, SEC_ALLOC)) - return false; - - /* The .rel.bss section holds copy relocs. This section is not - normally needed. We need to create it here, though, so that the - linker will map it to an output section. We can't just create it - only if we need it, because we will not know whether we need it - until we have seen all the input files, and the first time the - main linker code calls BFD after examining all the input files - (size_dynamic_sections) the input sections have already been - mapped to the output sections. If the section turns out not to - be needed, we can discard it later. We will never need this - section when generating a shared object, since they do not use - copy relocs. */ - if (! info->shared) + 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))) + +/* Get the i386 ELF linker hash table from a link_info structure. */ + +#define elf_i386_hash_table(p) \ + ((struct elf_i386_link_hash_table *) ((p)->hash)) + +/* Create an entry in an i386 ELF linker hash table. */ + +static struct bfd_hash_entry * +elf_i386_link_hash_newfunc (entry, table, string) + struct bfd_hash_entry *entry; + struct bfd_hash_table *table; + const char *string; +{ + struct elf_i386_link_hash_entry *ret = + (struct elf_i386_link_hash_entry *) entry; + + /* Allocate the structure if it has not already been allocated by a + subclass. */ + if (ret == (struct elf_i386_link_hash_entry *) NULL) + ret = ((struct elf_i386_link_hash_entry *) + bfd_hash_allocate (table, + sizeof (struct elf_i386_link_hash_entry))); + if (ret == (struct elf_i386_link_hash_entry *) NULL) + return (struct bfd_hash_entry *) ret; + + /* Call the allocation method of the superclass. */ + ret = ((struct elf_i386_link_hash_entry *) + _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, + table, string)); + if (ret != (struct elf_i386_link_hash_entry *) NULL) { - s = bfd_make_section (abfd, ".rel.bss"); - if (s == NULL - || ! bfd_set_section_flags (abfd, s, flags | SEC_READONLY) - || ! bfd_set_section_alignment (abfd, s, 2)) - return false; + ret->pcrel_relocs_copied = NULL; } - return true; + return (struct bfd_hash_entry *) ret; } -/* Create the .got section to hold the global offset table, and the - .got.plt section to hold procedure linkage table GOT entries. The - linker script will put .got.plt into the output .got section. */ +/* Create an i386 ELF linker hash table. */ -static boolean -elf_i386_create_got_section (abfd, info) +static struct bfd_link_hash_table * +elf_i386_link_hash_table_create (abfd) bfd *abfd; - struct bfd_link_info *info; { - flagword flags; - register asection *s; - struct elf_link_hash_entry *h; + struct elf_i386_link_hash_table *ret; - /* This function may be called more than once. */ - if (bfd_get_section_by_name (abfd, ".got") != NULL) - return true; + ret = ((struct elf_i386_link_hash_table *) + bfd_alloc (abfd, sizeof (struct elf_i386_link_hash_table))); + if (ret == (struct elf_i386_link_hash_table *) NULL) + return NULL; - flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY; - - s = bfd_make_section (abfd, ".got"); - if (s == NULL - || ! bfd_set_section_flags (abfd, s, flags) - || ! bfd_set_section_alignment (abfd, s, 2)) - return false; - - s = bfd_make_section (abfd, ".got.plt"); - if (s == NULL - || ! bfd_set_section_flags (abfd, s, flags) - || ! bfd_set_section_alignment (abfd, s, 2)) - return false; - - /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the - .got.plt section, which will be placed at the start of the output - .got section. We don't do this in the linker script because we - don't want to define the symbol if we are not creating a global - offset table. */ - h = NULL; - if (! (_bfd_generic_link_add_one_symbol - (info, abfd, "_GLOBAL_OFFSET_TABLE_", BSF_GLOBAL, s, (bfd_vma) 0, - (const char *) NULL, false, get_elf_backend_data (abfd)->collect, - (struct bfd_link_hash_entry **) &h))) - return false; - h->elf_link_hash_flags |= ELF_LINK_HASH_DEF_REGULAR; - h->type = STT_OBJECT; - - if (info->shared - && ! bfd_elf32_link_record_dynamic_symbol (info, h)) - return false; - - /* The first three global offset table entries are reserved. */ - s->_raw_size += 3 * 4; + if (! _bfd_elf_link_hash_table_init (&ret->root, abfd, + elf_i386_link_hash_newfunc)) + { + bfd_release (abfd, ret); + return NULL; + } - return true; + return &ret->root.root; } /* Look through the relocs for a section during the first phase, and @@ -398,7 +446,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs) rel_end = relocs + sec->reloc_count; for (rel = relocs; rel < rel_end; rel++) { - long r_symndx; + unsigned long r_symndx; struct elf_link_hash_entry *h; r_symndx = ELF32_R_SYM (rel->r_info); @@ -417,7 +465,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs) case R_386_GOTOFF: case R_386_GOTPC: elf_hash_table (info)->dynobj = dynobj = abfd; - if (! elf_i386_create_got_section (dynobj, info)) + if (! _bfd_elf_create_got_section (dynobj, info)) return false; break; @@ -430,7 +478,7 @@ 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"); @@ -450,6 +498,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs) | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY + | SEC_LINKER_CREATED | SEC_READONLY)) || ! bfd_set_section_alignment (dynobj, srelgot, 2)) return false; @@ -481,15 +530,12 @@ elf_i386_check_relocs (abfd, info, sec, relocs) if (local_got_offsets == NULL) { size_t size; - register int i; + register unsigned int i; size = symtab_hdr->sh_info * sizeof (bfd_vma); local_got_offsets = (bfd_vma *) bfd_alloc (abfd, size); if (local_got_offsets == NULL) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return false; elf_local_got_offsets (abfd) = local_got_offsets; for (i = 0; i < symtab_hdr->sh_info; i++) local_got_offsets[i] = (bfd_vma) -1; @@ -517,30 +563,40 @@ 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 without - linking in any dynamic objects, in which case we don't - need to generate a procedure linkage table after all. */ - + 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. */ if (h == NULL) continue; - /* 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; - } - h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; break; case R_386_32: case R_386_PC32: + /* If we are creating a shared library, and this is a reloc + against a global symbol, or a non PC relative reloc + against a local symbol, then we need to copy the reloc + into the shared library. However, if we are linking with + -Bsymbolic, we do not need to copy a reloc against a + global symbol which is defined in an object we are + including in the link (i.e., DEF_REGULAR is set). At + this point we have not seen all the input files, so it is + possible that DEF_REGULAR is not set now but will be set + later (it is never cleared). We account for that + possibility below by storing information in the + pcrel_relocs_copied field of the hash table entry. */ if (info->shared - && (sec->flags & SEC_ALLOC) != 0) + && (ELF32_R_TYPE (rel->r_info) != R_386_PC32 + || (h != NULL + && (! info->symbolic + || (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 @@ -549,7 +605,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs) { const char *name; - name = (elf_string_from_elf_section + name = (bfd_elf_string_from_elf_section (abfd, elf_elfheader (abfd)->e_shstrndx, elf_section_data (sec)->rel_hdr.sh_name)); @@ -563,22 +619,58 @@ elf_i386_check_relocs (abfd, info, sec, relocs) sreloc = bfd_get_section_by_name (dynobj, name); if (sreloc == NULL) { + flagword flags; + sreloc = bfd_make_section (dynobj, name); + flags = (SEC_HAS_CONTENTS | SEC_READONLY + | SEC_IN_MEMORY | SEC_LINKER_CREATED); + if ((sec->flags & SEC_ALLOC) != 0) + flags |= SEC_ALLOC | SEC_LOAD; if (sreloc == NULL - || ! bfd_set_section_flags (dynobj, sreloc, - (SEC_ALLOC - | SEC_LOAD - | SEC_HAS_CONTENTS - | SEC_IN_MEMORY - | SEC_READONLY)) + || ! bfd_set_section_flags (dynobj, sreloc, flags) || ! bfd_set_section_alignment (dynobj, sreloc, 2)) return false; } } sreloc->_raw_size += sizeof (Elf32_External_Rel); + + /* If we are linking with -Bsymbolic, and this is a + global symbol, we count the number of PC relative + relocations we have entered for this symbol, so that + we can discard them again if the symbol is later + defined by a regular object. Note 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 && info->symbolic + && ELF32_R_TYPE (rel->r_info) == R_386_PC32) + { + struct elf_i386_link_hash_entry *eh; + struct elf_i386_pcrel_relocs_copied *p; + + eh = (struct elf_i386_link_hash_entry *) h; + + for (p = eh->pcrel_relocs_copied; p != NULL; p = p->next) + if (p->section == sreloc) + break; + + if (p == NULL) + { + p = ((struct elf_i386_pcrel_relocs_copied *) + bfd_alloc (dynobj, sizeof *p)); + if (p == NULL) + return false; + p->next = eh->pcrel_relocs_copied; + eh->pcrel_relocs_copied = p; + p->section = sreloc; + p->count = 0; + } + + ++p->count; + } } - + break; default: @@ -609,18 +701,13 @@ elf_i386_adjust_dynamic_symbol (info, h) /* 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 - && (elf_elfheader (h->root.u.def.section->owner)->e_type - == ET_DYN) - && h->root.type == bfd_link_hash_defined - && (bfd_get_flavour (h->root.u.def.section->owner) - == bfd_target_elf_flavour) - && h->root.u.def.section->output_section == NULL))); + & ELF_LINK_HASH_DEF_REGULAR) == 0))); /* If this is a function, put it in the procedure linkage table. We will fill in the contents of the procedure linkage table later, @@ -628,17 +715,26 @@ elf_i386_adjust_dynamic_symbol (info, h) if (h->type == STT_FUNC || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0) { - if (! elf_hash_table (info)->dynamic_sections_created) + 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) { /* This case can occur if we saw a PLT32 reloc in an input - file, but none of the input files were dynamic objects. - In such a case, we don't actually need to build a - procedure linkage table, and we can just do a PC32 reloc - instead. */ + file, but the symbol was never referred to by a dynamic + object. In such a case, we don't actually need to build + a procedure linkage table, and we can just do a PC32 + reloc instead. */ BFD_ASSERT ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 0); 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); @@ -685,7 +781,8 @@ elf_i386_adjust_dynamic_symbol (info, h) real definition first, and we can just use the same value. */ if (h->weakdef != NULL) { - BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined); + BFD_ASSERT (h->weakdef->root.type == bfd_link_hash_defined + || h->weakdef->root.type == bfd_link_hash_defweak); h->root.u.def.section = h->weakdef->root.u.def.section; h->root.u.def.value = h->weakdef->root.u.def.value; return true; @@ -714,14 +811,11 @@ elf_i386_adjust_dynamic_symbol (info, h) s = bfd_get_section_by_name (dynobj, ".dynbss"); BFD_ASSERT (s != NULL); - /* If the symbol is currently defined in the .bss section of the - dynamic object, then it is OK to simply initialize it to zero. - If the symbol is in some other section, 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 runtime process - image. We need to remember the offset into the .rel.bss section - we are going to use. */ - if ((h->root.u.def.section->flags & SEC_LOAD) != 0) + /* 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 + runtime process image. We need to remember the offset into the + .rel.bss section we are going to use. */ + if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) { asection *srel; @@ -795,6 +889,15 @@ elf_i386_size_dynamic_sections (output_bfd, info) s->_raw_size = 0; } + /* 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 && info->symbolic) + elf_i386_link_hash_traverse (elf_i386_hash_table (info), + elf_i386_discard_copies, + (PTR) NULL); + /* The check_relocs and adjust_dynamic_symbol entry points have determined the sizes of the various dynamic sections. Allocate memory for them. */ @@ -806,7 +909,7 @@ elf_i386_size_dynamic_sections (output_bfd, info) const char *name; boolean strip; - if ((s->flags & SEC_IN_MEMORY) == 0) + if ((s->flags & SEC_LINKER_CREATED) == 0) continue; /* It's OK to base decisions on the section name, because none @@ -851,14 +954,23 @@ elf_i386_size_dynamic_sections (output_bfd, info) /* Remember whether there are any reloc sections other than .rel.plt. */ if (strcmp (name, ".rel.plt") != 0) - relocs = true; - - /* If this relocation section applies to a read only - section, then we probably need a DT_TEXTREL entry. */ - target = bfd_get_section_by_name (output_bfd, name + 4); - if (target != NULL - && (target->flags & SEC_READONLY) != 0) - reltext = true; + { + const char *outname; + + relocs = true; + + /* If this relocation section applies to a read only + section, then we probably need a DT_TEXTREL + entry. The entries in the .rel.plt section + really apply to the .got section, which we + created ourselves and so know is not readonly. */ + outname = bfd_get_section_name (output_bfd, + s->output_section); + target = bfd_get_section_by_name (output_bfd, outname + 4); + if (target != NULL + && (target->flags & SEC_READONLY) != 0) + reltext = true; + } /* We use the reloc_count field as a counter if we need to copy relocs into the output file. */ @@ -888,12 +1000,9 @@ elf_i386_size_dynamic_sections (output_bfd, info) /* Allocate memory for the section contents. */ s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size); if (s->contents == NULL && s->_raw_size != 0) - { - bfd_set_error (bfd_error_no_memory); - return false; - } + return false; } - + if (elf_hash_table (info)->dynamic_sections_created) { /* Add some entries to the .dynamic section. We fill in the @@ -935,6 +1044,31 @@ 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 with -Bsymbolic. It discards the space + allocated to copy PC relative relocs against symbols which are + defined in regular objects. We allocated space for them in the + check_relocs routine, but we won't fill them in in the + relocate_section routine. */ + +/*ARGSUSED*/ +static boolean +elf_i386_discard_copies (h, ignore) + struct elf_i386_link_hash_entry *h; + PTR ignore; +{ + struct elf_i386_pcrel_relocs_copied *s; + + /* We only discard relocs for symbols defined in a regular object. */ + if ((h->root.elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) + return true; + + 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 @@ -974,7 +1108,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, { int r_type; reloc_howto_type *howto; - long r_symndx; + unsigned long r_symndx; struct elf_link_hash_entry *h; Elf_Internal_Sym *sym; asection *sec; @@ -982,7 +1116,10 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, bfd_reloc_status_type r; r_type = ELF32_R_TYPE (rel->r_info); - if (r_type < 0 || r_type >= (int) R_386_max) + if (r_type < 0 + || r_type >= (int) R_386_max + || (r_type >= (int) FIRST_INVALID_RELOC + && r_type <= (int) LAST_INVALID_RELOC)) { bfd_set_error (bfd_error_bad_value); return false; @@ -1029,15 +1166,26 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, else { h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - if (h->root.type == bfd_link_hash_defined) + 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; + 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 && h->plt_offset != (bfd_vma) -1) || (r_type == R_386_GOT32 - && elf_hash_table (info)->dynamic_sections_created) + && 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)) @@ -1047,14 +1195,22 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, 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; + } else relocation = (h->root.u.def.value + sec->output_section->vma + sec->output_offset); } - else if (h->root.type == bfd_link_hash_weak) + else if (h->root.type == bfd_link_hash_undefweak) relocation = 0; - else if (info->shared) + else if (info->shared && !info->symbolic) relocation = 0; else { @@ -1084,13 +1240,19 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, off = h->got_offset; BFD_ASSERT (off != (bfd_vma) -1); - if (! elf_hash_table (info)->dynamic_sections_created) + 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))) { - /* This is actually a static link. We must - initialize this entry in the global offset table. - Since the offset must always be a multiple of 4, - we use the least significant bit to record - whether we have initialized it already. + /* This is actually a static link, or it is a + -Bsymbolic link and the symbol is defined + locally, or the symbol was forced to be local + because of a version file. We must initialize + this entry in the global offset table. Since the + offset must always be a multiple of 4, we use the + least significant bit to record whether we have + initialized it already. When doing a dynamic link, we create a .rel.got relocation entry to initialize the value. This @@ -1196,7 +1358,8 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, if (h->plt_offset == (bfd_vma) -1) { /* We didn't make a PLT entry for this symbol. This - happens when statically linking PIC code. */ + happens when statically linking PIC code, or when + using -Bsymbolic. */ break; } @@ -1215,9 +1378,14 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, case R_386_32: case R_386_PC32: if (info->shared - && (input_section->flags & SEC_ALLOC) != 0) + && (r_type != R_386_PC32 + || (h != NULL + && (! info->symbolic + || (h->elf_link_hash_flags + & ELF_LINK_HASH_DEF_REGULAR) == 0)))) { Elf_Internal_Rel outrel; + boolean skip, relocate; /* When generating a shared object, these relocations are copied into the output file to be resolved at run @@ -1227,7 +1395,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, { const char *name; - name = (elf_string_from_elf_section + name = (bfd_elf_string_from_elf_section (input_bfd, elf_elfheader (input_bfd)->e_shstrndx, elf_section_data (input_section)->rel_hdr.sh_name)); @@ -1243,21 +1411,60 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, BFD_ASSERT (sreloc != NULL); } - outrel.r_offset = (rel->r_offset - + input_section->output_section->vma - + input_section->output_offset); - if (r_type == R_386_PC32) + skip = false; + + if (elf_section_data (input_section)->stab_info == NULL) + outrel.r_offset = rel->r_offset; + else + { + bfd_vma off; + + off = (_bfd_stab_section_offset + (output_bfd, &elf_hash_table (info)->stab_info, + input_section, + &elf_section_data (input_section)->stab_info, + rel->r_offset)); + if (off == (bfd_vma) -1) + skip = true; + outrel.r_offset = off; + } + + outrel.r_offset += (input_section->output_section->vma + + input_section->output_offset); + + if (skip) + { + memset (&outrel, 0, sizeof outrel); + relocate = false; + } + else if (r_type == R_386_PC32) { BFD_ASSERT (h != NULL && h->dynindx != -1); + if ((input_section->flags & SEC_ALLOC) != 0) + relocate = false; + else + relocate = true; outrel.r_info = ELF32_R_INFO (h->dynindx, R_386_PC32); } else { - if (h == NULL) - outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); + /* 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 != (bfd_vma) -1); + BFD_ASSERT (h->dynindx != -1); + if ((input_section->flags & SEC_ALLOC) != 0) + relocate = false; + else + relocate = true; outrel.r_info = ELF32_R_INFO (h->dynindx, R_386_32); } } @@ -1272,7 +1479,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, not want to fiddle with the addend. Otherwise, we need to include the symbol value so that it becomes an addend for the dynamic reloc. */ - if (h != NULL) + if (! relocate) continue; } @@ -1301,9 +1508,9 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, name = h->root.root.string; else { - name = elf_string_from_elf_section (input_bfd, - symtab_hdr->sh_link, - sym->st_name); + name = bfd_elf_string_from_elf_section (input_bfd, + symtab_hdr->sh_link, + sym->st_name); if (name == NULL) return false; if (*name == '\0') @@ -1423,19 +1630,30 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) /* This symbol has an entry in the global offset table. Set it up. */ - - BFD_ASSERT (h->dynindx != -1); sgot = bfd_get_section_by_name (dynobj, ".got"); srel = bfd_get_section_by_name (dynobj, ".rel.got"); BFD_ASSERT (sgot != NULL && srel != NULL); - bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + h->got_offset); - rel.r_offset = (sgot->output_section->vma + sgot->output_offset - + h->got_offset); - rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT); + + (h->got_offset &~ 1)); + + /* If this is a -Bsymbolic link, and the symbol is defined + locally, we just want to emit a RELATIVE reloc. Likewise if + the symbol was forced to be local because of a version file. + The entry in the global offset table will already have been + initialized in the relocate_section function. */ + if (info->shared + && (info->symbolic || h->dynindx == -1) + && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) + rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); + else + { + bfd_put_32 (output_bfd, (bfd_vma) 0, 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)); @@ -1450,7 +1668,8 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) /* 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_defined + || h->root.type == bfd_link_hash_defweak)); s = bfd_get_section_by_name (h->root.u.def.section->owner, ".rel.bss"); @@ -1603,12 +1822,16 @@ elf_i386_finish_dynamic_sections (output_bfd, info) #define TARGET_LITTLE_NAME "elf32-i386" #define ELF_ARCH bfd_arch_i386 #define ELF_MACHINE_CODE EM_386 +#define ELF_MAXPAGESIZE 0x1000 #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_reloc_type_lookup elf_i386_reloc_type_lookup -#define ELF_MAXPAGESIZE 0x1000 +#define bfd_elf32_bfd_is_local_label_name \ + elf_i386_is_local_label_name #define elf_backend_create_dynamic_sections \ - elf_i386_create_dynamic_sections + _bfd_elf_create_dynamic_sections +#define bfd_elf32_bfd_link_hash_table_create \ + elf_i386_link_hash_table_create #define elf_backend_check_relocs elf_i386_check_relocs #define elf_backend_adjust_dynamic_symbol \ elf_i386_adjust_dynamic_symbol @@ -1619,5 +1842,8 @@ elf_i386_finish_dynamic_sections (output_bfd, info) elf_i386_finish_dynamic_symbol #define elf_backend_finish_dynamic_sections \ elf_i386_finish_dynamic_sections +#define elf_backend_want_got_plt 1 +#define elf_backend_plt_readonly 1 +#define elf_backend_want_plt_sym 0 #include "elf32-target.h"