diff options
author | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2002-05-13 17:07:46 +0000 |
---|---|---|
committer | Federico G. Schwindt <fgsch@cvs.openbsd.org> | 2002-05-13 17:07:46 +0000 |
commit | c866442bb5e16be2b5323fee961ceb1315393514 (patch) | |
tree | f12f495081042abe1a40d83bf05d076ff8aa8a17 /gnu/usr.bin/binutils/bfd/elf32-i386.c | |
parent | 99d2ba46f95f9f99286b4c66576c4607669b0e7f (diff) |
resolve conflicts.
Diffstat (limited to 'gnu/usr.bin/binutils/bfd/elf32-i386.c')
-rw-r--r-- | gnu/usr.bin/binutils/bfd/elf32-i386.c | 621 |
1 files changed, 407 insertions, 214 deletions
diff --git a/gnu/usr.bin/binutils/bfd/elf32-i386.c b/gnu/usr.bin/binutils/bfd/elf32-i386.c index fc1b5a8ccb6..b838d3a7539 100644 --- a/gnu/usr.bin/binutils/bfd/elf32-i386.c +++ b/gnu/usr.bin/binutils/bfd/elf32-i386.c @@ -1,5 +1,6 @@ /* Intel 80386/80486-specific support for 32-bit ELF - Copyright 1993, 94-98, 1999 Free Software Foundation, Inc. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001 + Free Software Foundation, Inc. This file is part of BFD, the Binary File Descriptor library. @@ -56,35 +57,66 @@ static boolean elf_i386_finish_dynamic_sections static reloc_howto_type elf_howto_table[]= { - HOWTO(R_386_NONE, 0,0, 0,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_NONE", true,0x00000000,0x00000000,false), - HOWTO(R_386_32, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_32", true,0xffffffff,0xffffffff,false), - HOWTO(R_386_PC32, 0,2,32,true, 0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_PC32", true,0xffffffff,0xffffffff,true), - HOWTO(R_386_GOT32, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GOT32", true,0xffffffff,0xffffffff,false), - HOWTO(R_386_PLT32, 0,2,32,true,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_PLT32", true,0xffffffff,0xffffffff,true), - HOWTO(R_386_COPY, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_COPY", true,0xffffffff,0xffffffff,false), - HOWTO(R_386_GLOB_DAT, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_GLOB_DAT", true,0xffffffff,0xffffffff,false), - HOWTO(R_386_JUMP_SLOT, 0,2,32,false,0,complain_overflow_bitfield, bfd_elf_generic_reloc,"R_386_JUMP_SLOT",true,0xffffffff,0xffffffff,false), - 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), - EMPTY_HOWTO (11), - EMPTY_HOWTO (12), - EMPTY_HOWTO (13), - EMPTY_HOWTO (14), - EMPTY_HOWTO (15), - EMPTY_HOWTO (16), - EMPTY_HOWTO (17), - EMPTY_HOWTO (18), - EMPTY_HOWTO (19), + HOWTO(R_386_NONE, 0, 0, 0, false, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_NONE", + true, 0x00000000, 0x00000000, false), + HOWTO(R_386_32, 0, 2, 32, false, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_32", + true, 0xffffffff, 0xffffffff, false), + HOWTO(R_386_PC32, 0, 2, 32, true, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_PC32", + true, 0xffffffff, 0xffffffff, true), + HOWTO(R_386_GOT32, 0, 2, 32, false, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_GOT32", + true, 0xffffffff, 0xffffffff, false), + HOWTO(R_386_PLT32, 0, 2, 32, true, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_PLT32", + true, 0xffffffff, 0xffffffff, true), + HOWTO(R_386_COPY, 0, 2, 32, false, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_COPY", + true, 0xffffffff, 0xffffffff, false), + HOWTO(R_386_GLOB_DAT, 0, 2, 32, false, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_GLOB_DAT", + true, 0xffffffff, 0xffffffff, false), + HOWTO(R_386_JUMP_SLOT, 0, 2, 32, false, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_JUMP_SLOT", + true, 0xffffffff, 0xffffffff, false), + 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), + + /* We have a gap in the reloc numbers here. + R_386_standard counts the number up to this point, and + R_386_ext_offset is the value to subtract from a reloc type of + R_386_16 thru R_386_PC8 to form an index into this table. */ +#define R_386_standard ((unsigned int) R_386_GOTPC + 1) +#define R_386_ext_offset ((unsigned int) R_386_16 - R_386_standard) + /* 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_signed, bfd_elf_generic_reloc,"R_386_PC8", true,0xff,0xff,true), -}; + 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_signed, + bfd_elf_generic_reloc, "R_386_PC8", + true, 0xff, 0xff, true), + + /* Another gap. */ +#define R_386_ext ((unsigned int) R_386_PC8 + 1 - R_386_ext_offset) +#define R_386_vt_offset ((unsigned int) R_386_GNU_VTINHERIT - R_386_ext) /* GNU extension to record C++ vtable hierarchy. */ -static reloc_howto_type elf32_i386_vtinherit_howto = HOWTO (R_386_GNU_VTINHERIT, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ @@ -97,10 +129,9 @@ static reloc_howto_type elf32_i386_vtinherit_howto = false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ - false); + false), /* GNU extension to record C++ vtable member usage. */ -static reloc_howto_type elf32_i386_vtentry_howto = HOWTO (R_386_GNU_VTENTRY, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ @@ -113,7 +144,11 @@ static reloc_howto_type elf32_i386_vtentry_howto = false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ - false); + false) + +#define R_386_vt ((unsigned int) R_386_GNU_VTENTRY + 1 - R_386_vt_offset) + +}; #ifdef DEBUG_GEN_RELOC #define TRACE(str) fprintf (stderr, "i386 bfd reloc lookup %d (%s)\n", code, str) @@ -130,76 +165,78 @@ elf_i386_reloc_type_lookup (abfd, code) { case BFD_RELOC_NONE: TRACE ("BFD_RELOC_NONE"); - return &elf_howto_table[ (int)R_386_NONE ]; + return &elf_howto_table[(unsigned int) R_386_NONE ]; case BFD_RELOC_32: TRACE ("BFD_RELOC_32"); - return &elf_howto_table[ (int)R_386_32 ]; + return &elf_howto_table[(unsigned int) R_386_32 ]; case BFD_RELOC_CTOR: TRACE ("BFD_RELOC_CTOR"); - return &elf_howto_table[ (int)R_386_32 ]; + return &elf_howto_table[(unsigned int) R_386_32 ]; case BFD_RELOC_32_PCREL: TRACE ("BFD_RELOC_PC32"); - return &elf_howto_table[ (int)R_386_PC32 ]; + return &elf_howto_table[(unsigned int) R_386_PC32 ]; case BFD_RELOC_386_GOT32: TRACE ("BFD_RELOC_386_GOT32"); - return &elf_howto_table[ (int)R_386_GOT32 ]; + return &elf_howto_table[(unsigned int) R_386_GOT32 ]; case BFD_RELOC_386_PLT32: TRACE ("BFD_RELOC_386_PLT32"); - return &elf_howto_table[ (int)R_386_PLT32 ]; + return &elf_howto_table[(unsigned int) R_386_PLT32 ]; case BFD_RELOC_386_COPY: TRACE ("BFD_RELOC_386_COPY"); - return &elf_howto_table[ (int)R_386_COPY ]; + return &elf_howto_table[(unsigned int) R_386_COPY ]; case BFD_RELOC_386_GLOB_DAT: TRACE ("BFD_RELOC_386_GLOB_DAT"); - return &elf_howto_table[ (int)R_386_GLOB_DAT ]; + return &elf_howto_table[(unsigned int) R_386_GLOB_DAT ]; case BFD_RELOC_386_JUMP_SLOT: TRACE ("BFD_RELOC_386_JUMP_SLOT"); - return &elf_howto_table[ (int)R_386_JUMP_SLOT ]; + return &elf_howto_table[(unsigned int) R_386_JUMP_SLOT ]; case BFD_RELOC_386_RELATIVE: TRACE ("BFD_RELOC_386_RELATIVE"); - return &elf_howto_table[ (int)R_386_RELATIVE ]; + return &elf_howto_table[(unsigned int) R_386_RELATIVE ]; case BFD_RELOC_386_GOTOFF: TRACE ("BFD_RELOC_386_GOTOFF"); - return &elf_howto_table[ (int)R_386_GOTOFF ]; + return &elf_howto_table[(unsigned int) R_386_GOTOFF ]; case BFD_RELOC_386_GOTPC: TRACE ("BFD_RELOC_386_GOTPC"); - return &elf_howto_table[ (int)R_386_GOTPC ]; + return &elf_howto_table[(unsigned 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]; + return &elf_howto_table[(unsigned int) R_386_16 - R_386_ext_offset]; case BFD_RELOC_16_PCREL: TRACE ("BFD_RELOC_16_PCREL"); - return &elf_howto_table[(int) R_386_PC16]; + return &elf_howto_table[(unsigned int) R_386_PC16 - R_386_ext_offset]; case BFD_RELOC_8: TRACE ("BFD_RELOC_8"); - return &elf_howto_table[(int) R_386_8]; + return &elf_howto_table[(unsigned int) R_386_8 - R_386_ext_offset]; case BFD_RELOC_8_PCREL: TRACE ("BFD_RELOC_8_PCREL"); - return &elf_howto_table[(int) R_386_PC8]; + return &elf_howto_table[(unsigned int) R_386_PC8 - R_386_ext_offset]; case BFD_RELOC_VTABLE_INHERIT: TRACE ("BFD_RELOC_VTABLE_INHERIT"); - return &elf32_i386_vtinherit_howto; + return &elf_howto_table[(unsigned int) R_386_GNU_VTINHERIT + - R_386_vt_offset]; case BFD_RELOC_VTABLE_ENTRY: TRACE ("BFD_RELOC_VTABLE_ENTRY"); - return &elf32_i386_vtentry_howto; + return &elf_howto_table[(unsigned int) R_386_GNU_VTENTRY + - R_386_vt_offset]; default: break; @@ -224,22 +261,20 @@ elf_i386_info_to_howto_rel (abfd, cache_ptr, dst) arelent *cache_ptr; Elf32_Internal_Rel *dst; { - enum elf_i386_reloc_type type; - - type = (enum elf_i386_reloc_type) ELF32_R_TYPE (dst->r_info); - if (type == R_386_GNU_VTINHERIT) - cache_ptr->howto = &elf32_i386_vtinherit_howto; - else if (type == R_386_GNU_VTENTRY) - cache_ptr->howto = &elf32_i386_vtentry_howto; - else if (type < R_386_max - && (type < FIRST_INVALID_RELOC || type > LAST_INVALID_RELOC)) - cache_ptr->howto = &elf_howto_table[(int) type]; - else + unsigned int r_type = ELF32_R_TYPE (dst->r_info); + unsigned int indx; + + if ((indx = r_type) >= R_386_standard + && ((indx = r_type - R_386_ext_offset) - R_386_standard + >= R_386_ext - R_386_standard) + && ((indx = r_type - R_386_vt_offset) - R_386_ext + >= R_386_vt - R_386_ext)) { (*_bfd_error_handler) (_("%s: invalid relocation type %d"), - bfd_get_filename (abfd), (int) type); - cache_ptr->howto = &elf_howto_table[(int) R_386_NONE]; + bfd_get_filename (abfd), (int) r_type); + indx = (unsigned int) R_386_NONE; } + cache_ptr->howto = &elf_howto_table[indx]; } /* Return whether a symbol name implies a local label. The UnixWare @@ -439,7 +474,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs) bfd *dynobj; Elf_Internal_Shdr *symtab_hdr; struct elf_link_hash_entry **sym_hashes; - bfd_vma *local_got_offsets; + bfd_signed_vma *local_got_refcounts; const Elf_Internal_Rela *rel; const Elf_Internal_Rela *rel_end; asection *sgot; @@ -452,7 +487,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs) dynobj = elf_hash_table (info)->dynobj; symtab_hdr = &elf_tdata (abfd)->symtab_hdr; sym_hashes = elf_sym_hashes (abfd); - local_got_offsets = elf_local_got_offsets (abfd); + local_got_refcounts = elf_local_got_refcounts (abfd); sgot = NULL; srelgot = NULL; @@ -466,6 +501,20 @@ elf_i386_check_relocs (abfd, info, sec, relocs) r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) + { + if (abfd->my_archive) + (*_bfd_error_handler) (_("%s(%s): bad symbol index: %d"), + bfd_get_filename (abfd->my_archive), + bfd_get_filename (abfd), + r_symndx); + else + (*_bfd_error_handler) (_("%s: bad symbol index: %d"), + bfd_get_filename (abfd), + r_symndx); + return false; + } + if (r_symndx < symtab_hdr->sh_info) h = NULL; else @@ -522,57 +571,54 @@ elf_i386_check_relocs (abfd, info, sec, relocs) if (h != NULL) { - if (h->got.offset != (bfd_vma) -1) + if (h->got.refcount == -1) { - /* We have already allocated space in the .got. */ - break; - } - h->got.offset = sgot->_raw_size; + 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; - } + /* 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; + } - srelgot->_raw_size += sizeof (Elf32_External_Rel); + sgot->_raw_size += 4; + srelgot->_raw_size += sizeof (Elf32_External_Rel); + } + else + h->got.refcount += 1; } else { - /* This is a global offset table entry for a local - symbol. */ - if (local_got_offsets == NULL) + /* This is a global offset table entry for a local symbol. */ + if (local_got_refcounts == NULL) { size_t size; - 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) + size = symtab_hdr->sh_info * sizeof (bfd_signed_vma); + local_got_refcounts = ((bfd_signed_vma *) + bfd_alloc (abfd, size)); + if (local_got_refcounts == NULL) 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; + elf_local_got_refcounts (abfd) = local_got_refcounts; + memset (local_got_refcounts, -1, size); } - if (local_got_offsets[r_symndx] != (bfd_vma) -1) + if (local_got_refcounts[r_symndx] == -1) { - /* We have already allocated space in the .got. */ - break; - } - local_got_offsets[r_symndx] = sgot->_raw_size; + local_got_refcounts[r_symndx] = 1; - 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); + 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); + } } + else + local_got_refcounts[r_symndx] += 1; } - - sgot->_raw_size += 4; - break; case R_386_PLT32: @@ -588,8 +634,13 @@ elf_i386_check_relocs (abfd, info, sec, relocs) if (h == NULL) continue; - h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; - + if (h->plt.refcount == -1) + { + h->plt.refcount = 1; + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + } + else + h->plt.refcount += 1; break; case R_386_32: @@ -598,28 +649,33 @@ elf_i386_check_relocs (abfd, info, sec, relocs) h->elf_link_hash_flags |= ELF_LINK_NON_GOT_REF; /* 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. */ + 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). In case of a weak definition, + DEF_REGULAR may be cleared later by a strong definition in + a shared library. We account for that possibility below by + 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)))) { /* 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. */ + reloc types into the output file. We create a reloc + section in dynobj and make room for this reloc. */ if (sreloc == NULL) { const char *name; @@ -631,9 +687,20 @@ elf_i386_check_relocs (abfd, info, sec, relocs) if (name == NULL) return false; - BFD_ASSERT (strncmp (name, ".rel", 4) == 0 - && strcmp (bfd_get_section_name (abfd, sec), - name + 4) == 0); + if (strncmp (name, ".rel", 4) != 0 + || strcmp (bfd_get_section_name (abfd, sec), + name + 4) != 0) + { + if (abfd->my_archive) + (*_bfd_error_handler) (_("%s(%s): bad relocation section name `%s\'"), + bfd_get_filename (abfd->my_archive), + bfd_get_filename (abfd), + name); + else + (*_bfd_error_handler) (_("%s: bad relocation section name `%s\'"), + bfd_get_filename (abfd), + name); + } sreloc = bfd_get_section_by_name (dynobj, name); if (sreloc == NULL) @@ -654,15 +721,13 @@ elf_i386_check_relocs (abfd, info, sec, relocs) 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 + /* If 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 later as necessary. 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 && ELF32_R_TYPE (rel->r_info) == R_386_PC32) { struct elf_i386_link_hash_entry *eh; @@ -766,14 +831,81 @@ elf_i386_gc_mark_hook (abfd, info, rel, h, sym) static boolean elf_i386_gc_sweep_hook (abfd, info, sec, relocs) - bfd *abfd ATTRIBUTE_UNUSED; - struct bfd_link_info *info ATTRIBUTE_UNUSED; - asection *sec ATTRIBUTE_UNUSED; - const Elf_Internal_Rela *relocs ATTRIBUTE_UNUSED; + bfd *abfd; + struct bfd_link_info *info; + asection *sec; + const Elf_Internal_Rela *relocs; { - /* ??? It would seem that the existing i386 code does no sort - of reference counting or whatnot on its GOT and PLT entries, - so it is not possible to garbage collect them at this time. */ + Elf_Internal_Shdr *symtab_hdr; + struct elf_link_hash_entry **sym_hashes; + bfd_signed_vma *local_got_refcounts; + const Elf_Internal_Rela *rel, *relend; + 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"); + + relend = relocs + sec->reloc_count; + for (rel = relocs; rel < relend; rel++) + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_386_GOT32: + case R_386_GOTOFF: + case R_386_GOTPC: + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx >= symtab_hdr->sh_info) + { + 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); + } + } + } + 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); + } + } + } + break; + + case R_386_PLT32: + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx >= symtab_hdr->sh_info) + { + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + if (h->plt.refcount > 0) + h->plt.refcount -= 1; + } + break; + + default: + break; + } return true; } @@ -812,16 +944,18 @@ 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) + 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)) { /* 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. 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); + 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->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; return true; } @@ -859,13 +993,11 @@ elf_i386_adjust_dynamic_symbol (info, h) /* 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); @@ -995,10 +1127,10 @@ elf_i386_size_dynamic_sections (output_bfd, info) 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) + if (info->shared) elf_i386_link_hash_traverse (elf_i386_hash_table (info), elf_i386_discard_copies, - (PTR) NULL); + (PTR) info); /* The check_relocs and adjust_dynamic_symbol entry points have determined the sizes of the various dynamic sections. Allocate @@ -1092,8 +1224,12 @@ elf_i386_size_dynamic_sections (output_bfd, info) continue; } - /* Allocate memory for the section contents. */ - s->contents = (bfd_byte *) bfd_alloc (dynobj, s->_raw_size); + /* Allocate memory for the section contents. We use bfd_zalloc + here in case unused entries are not reclaimed before the + section's contents are written out. This should not happen, + 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) return false; } @@ -1133,6 +1269,7 @@ elf_i386_size_dynamic_sections (output_bfd, info) { if (! bfd_elf32_add_dynamic_entry (info, DT_TEXTREL, 0)) return false; + info->flags |= DF_TEXTREL; } } @@ -1140,26 +1277,32 @@ elf_i386_size_dynamic_sections (output_bfd, info) } /* 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 + 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. */ -/*ARGSUSED*/ static boolean -elf_i386_discard_copies (h, ignore) +elf_i386_discard_copies (h, inf) struct elf_i386_link_hash_entry *h; - PTR ignore ATTRIBUTE_UNUSED; + PTR inf; { 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); + 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; } @@ -1193,9 +1336,14 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, sym_hashes = elf_sym_hashes (input_bfd); local_got_offsets = elf_local_got_offsets (input_bfd); - sgot = NULL; - splt = NULL; 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; @@ -1209,20 +1357,21 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, asection *sec; bfd_vma relocation; bfd_reloc_status_type r; + unsigned int indx; r_type = ELF32_R_TYPE (rel->r_info); - if (r_type == R_386_GNU_VTINHERIT - || r_type == R_386_GNU_VTENTRY) + if (r_type == (int) R_386_GNU_VTINHERIT + || r_type == (int) R_386_GNU_VTENTRY) continue; - if (r_type < 0 - || r_type >= (int) R_386_max - || (r_type >= (int) FIRST_INVALID_RELOC - && r_type <= (int) LAST_INVALID_RELOC)) + + if ((indx = (unsigned) r_type) >= R_386_standard + && ((indx = (unsigned) r_type - R_386_ext_offset) - R_386_standard + >= R_386_ext - R_386_standard)) { bfd_set_error (bfd_error_bad_value); return false; } - howto = elf_howto_table + r_type; + howto = elf_howto_table + indx; r_symndx = ELF32_R_SYM (rel->r_info); @@ -1273,6 +1422,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, 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 @@ -1336,11 +1486,7 @@ 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. */ - if (sgot == NULL) - { - sgot = bfd_get_section_by_name (dynobj, ".got"); - BFD_ASSERT (sgot != NULL); - } + BFD_ASSERT (sgot != NULL); if (h != NULL) { @@ -1459,12 +1605,13 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, /* Relocation is to the entry for this symbol in the procedure linkage table. */ - /* Resolve a PLT32 reloc again a local symbol directly, + /* Resolve a PLT32 reloc against a local symbol directly, without using the procedure linkage table. */ if (h == NULL) break; - if (h->plt.offset == (bfd_vma) -1) + if (h->plt.offset == (bfd_vma) -1 + || splt == NULL) { /* We didn't make a PLT entry for this symbol. This happens when statically linking PIC code, or when @@ -1472,12 +1619,6 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, break; } - if (splt == NULL) - { - splt = bfd_get_section_by_name (dynobj, ".plt"); - BFD_ASSERT (splt != NULL); - } - relocation = (splt->output_section->vma + splt->output_offset + h->plt.offset); @@ -1513,10 +1654,22 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, if (name == NULL) return false; - BFD_ASSERT (strncmp (name, ".rel", 4) == 0 - && strcmp (bfd_get_section_name (input_bfd, - input_section), - name + 4) == 0); + if (strncmp (name, ".rel", 4) != 0 + || strcmp (bfd_get_section_name (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); + else + (*_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); @@ -1744,17 +1897,21 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) + sgot->output_offset + (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. + /* If this is a static link, or it is a -Bsymbolic link and the + symbol is defined locally or was forced to be local because + 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 (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); + 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))) + { + 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); rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT); } @@ -1923,32 +2080,49 @@ elf_i386_finish_dynamic_sections (output_bfd, info) return true; } +/* Set the correct type for an x86 ELF section. We do this by the + section name, which is a hack, but ought to work. */ + +static boolean +elf_i386_fake_sections (abfd, hdr, sec) + bfd *abfd ATTRIBUTE_UNUSED; + Elf32_Internal_Shdr *hdr; + asection *sec; +{ + register const char *name; + + name = bfd_get_section_name (abfd, sec); + + if (strcmp (name, ".reloc") == 0) + /* + * This is an ugly, but unfortunately necessary hack that is + * needed when producing EFI binaries on x86. It tells + * elf.c:elf_fake_sections() not to consider ".reloc" as a section + * containing ELF relocation info. We need this hack in order to + * be able to generate ELF binaries that can be translated into + * EFI applications (which are essentially COFF objects). Those + * files contain a COFF ".reloc" section inside an ELFNN object, + * which would normally cause BFD to segfault because it would + * attempt to interpret this section as containing relocation + * entries for section "oc". With this hack enabled, ".reloc" + * will be treated as a normal data section, which will avoid the + * segfault. However, you won't be able to create an ELFNN binary + * with a section named "oc" that needs relocations, but that's + * the kind of ugly side-effects you get when detecting section + * types based on their names... In practice, this limitation is + * unlikely to bite. + */ + hdr->sh_type = SHT_PROGBITS; + + return true; +} + + #define TARGET_LITTLE_SYM bfd_elf32_i386_vec #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 bfd_elf32_bfd_is_local_label_name \ - elf_i386_is_local_label_name -#define elf_backend_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 -#define elf_backend_size_dynamic_sections \ - elf_i386_size_dynamic_sections -#define elf_backend_relocate_section elf_i386_relocate_section -#define elf_backend_finish_dynamic_symbol \ - elf_i386_finish_dynamic_symbol -#define elf_backend_finish_dynamic_sections \ - elf_i386_finish_dynamic_sections -#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_can_gc_sections 1 #define elf_backend_want_got_plt 1 @@ -1957,4 +2131,23 @@ elf_i386_finish_dynamic_sections (output_bfd, info) #define elf_backend_got_header_size 12 #define elf_backend_plt_header_size PLT_ENTRY_SIZE +#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_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 + #include "elf32-target.h" |