X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf32-i386.c;h=dee26a025cd37cca0735a32c5781971f1fc0b52e;hb=f2c503287936db895a7ab693f3ddf618a46a89a3;hp=f8b64d577ab9599434235be8d671862036bb34ac;hpb=239e1f3afa2f6bc24acde3b81481f933b40a3531;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index f8b64d577a..dee26a025c 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -1,22 +1,22 @@ /* Intel 80386/80486-specific support for 32-bit ELF - Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002 - Free Software Foundation, Inc. + Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004 Free Software Foundation, Inc. -This file is part of BFD, the Binary File Descriptor library. + This file is part of BFD, the Binary File Descriptor library. -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "bfd.h" #include "sysdep.h" @@ -24,323 +24,280 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "libbfd.h" #include "elf-bfd.h" -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_is_local_label_name - PARAMS ((bfd *, const char *)); -static boolean elf_i386_grok_prstatus - PARAMS ((bfd *abfd, Elf_Internal_Note *note)); -static boolean elf_i386_grok_psinfo - PARAMS ((bfd *abfd, Elf_Internal_Note *note)); -static struct bfd_hash_entry *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 void elf_i386_copy_indirect_symbol - PARAMS ((struct elf_link_hash_entry *, struct elf_link_hash_entry *)); -static int elf_i386_tls_transition - PARAMS ((struct bfd_link_info *, int, int)); - -static boolean elf_i386_mkobject - PARAMS((bfd *)); -static boolean elf_i386_object_p - PARAMS((bfd *)); -static boolean elf_i386_check_relocs - PARAMS ((bfd *, struct bfd_link_info *, asection *, - const Elf_Internal_Rela *)); -static asection *elf_i386_gc_mark_hook - PARAMS ((asection *, struct bfd_link_info *, Elf_Internal_Rela *, - struct elf_link_hash_entry *, Elf_Internal_Sym *)); -static boolean elf_i386_gc_sweep_hook - 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_dynrelocs - PARAMS ((struct elf_link_hash_entry *, PTR)); -static boolean readonly_dynrelocs - PARAMS ((struct elf_link_hash_entry *, PTR)); -static boolean elf_i386_fake_sections - PARAMS ((bfd *, Elf32_Internal_Shdr *, asection *)); -static boolean elf_i386_size_dynamic_sections - PARAMS ((bfd *, struct bfd_link_info *)); -static bfd_vma dtpoff_base - PARAMS ((struct bfd_link_info *)); -static bfd_vma tpoff - PARAMS ((struct bfd_link_info *, bfd_vma)); -static boolean elf_i386_relocate_section - PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *, - Elf_Internal_Rela *, Elf_Internal_Sym *, asection **)); -static boolean elf_i386_finish_dynamic_symbol - PARAMS ((bfd *, struct bfd_link_info *, struct elf_link_hash_entry *, - Elf_Internal_Sym *)); -static enum elf_reloc_type_class elf_i386_reloc_type_class - PARAMS ((const Elf_Internal_Rela *)); -static boolean elf_i386_finish_dynamic_sections - PARAMS ((bfd *, struct bfd_link_info *)); - -#define USE_REL 1 /* 386 uses REL relocations instead of RELA */ +/* 386 uses REL relocations instead of RELA. */ +#define USE_REL 1 #include "elf/i386.h" static reloc_howto_type elf_howto_table[]= { - HOWTO(R_386_NONE, 0, 0, 0, false, 0, complain_overflow_bitfield, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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, + 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), + 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_TLS_LE - R_386_standard) - - /* The remaining relocs are a GNU extension. */ - HOWTO(R_386_TLS_LE, 0, 2, 32, false, 0, complain_overflow_bitfield, +#define R_386_standard (R_386_GOTPC + 1) +#define R_386_ext_offset (R_386_TLS_TPOFF - R_386_standard) + + /* These relocs are a GNU extension. */ + HOWTO(R_386_TLS_TPOFF, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_TPOFF", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_IE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_IE", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_GOTIE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, + bfd_elf_generic_reloc, "R_386_TLS_GOTIE", + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_LE, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_LE", - true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_GD, 0, 2, 32, false, 0, complain_overflow_bitfield, + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_GD, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_GD", - true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_LDM, 0, 2, 32, false, 0, complain_overflow_bitfield, + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_LDM, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_LDM", - true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_16, 0, 1, 16, false, 0, complain_overflow_bitfield, + TRUE, 0xffffffff, 0xffffffff, FALSE), + 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, + 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, + 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, + 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), + TRUE, 0xff, 0xff, TRUE), -#define R_386_ext ((unsigned int) R_386_PC8 + 1 - R_386_ext_offset) -#define R_386_tls_offset ((unsigned int) R_386_TLS_LDO_32 - R_386_ext) +#define R_386_ext (R_386_PC8 + 1 - R_386_ext_offset) +#define R_386_tls_offset (R_386_TLS_LDO_32 - R_386_ext) /* These are common with Solaris TLS implementation. */ - HOWTO(R_386_TLS_LDO_32, 0, 2, 32, false, 0, complain_overflow_bitfield, + HOWTO(R_386_TLS_LDO_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_LDO_32", - true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_IE_32, 0, 2, 32, false, 0, complain_overflow_bitfield, + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_IE_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_IE_32", - true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_LE_32, 0, 2, 32, false, 0, complain_overflow_bitfield, + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_LE_32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_LE_32", - true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_DTPMOD32, 0, 2, 32, false, 0, complain_overflow_bitfield, + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_DTPMOD32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_DTPMOD32", - true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_DTPOFF32, 0, 2, 32, false, 0, complain_overflow_bitfield, + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_DTPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_DTPOFF32", - true, 0xffffffff, 0xffffffff, false), - HOWTO(R_386_TLS_TPOFF32, 0, 2, 32, false, 0, complain_overflow_bitfield, + TRUE, 0xffffffff, 0xffffffff, FALSE), + HOWTO(R_386_TLS_TPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, bfd_elf_generic_reloc, "R_386_TLS_TPOFF32", - true, 0xffffffff, 0xffffffff, false), + TRUE, 0xffffffff, 0xffffffff, FALSE), /* Another gap. */ -#define R_386_tls ((unsigned int) R_386_TLS_TPOFF32 + 1 - R_386_tls_offset) -#define R_386_vt_offset ((unsigned int) R_386_GNU_VTINHERIT - R_386_tls) +#define R_386_tls (R_386_TLS_TPOFF32 + 1 - R_386_tls_offset) +#define R_386_vt_offset (R_386_GNU_VTINHERIT - R_386_tls) /* GNU extension to record C++ vtable hierarchy. */ HOWTO (R_386_GNU_VTINHERIT, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ - false, /* pc_relative */ + FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ NULL, /* special_function */ "R_386_GNU_VTINHERIT", /* name */ - false, /* partial_inplace */ + FALSE, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ - false), /* pcrel_offset */ + FALSE), /* pcrel_offset */ /* GNU extension to record C++ vtable member usage. */ HOWTO (R_386_GNU_VTENTRY, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ - false, /* pc_relative */ + FALSE, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ _bfd_elf_rel_vtable_reloc_fn, /* special_function */ "R_386_GNU_VTENTRY", /* name */ - false, /* partial_inplace */ + FALSE, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ - false) /* pcrel_offset */ + FALSE) /* pcrel_offset */ -#define R_386_vt ((unsigned int) R_386_GNU_VTENTRY + 1 - R_386_vt_offset) +#define R_386_vt (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) +#define TRACE(str) \ + fprintf (stderr, "i386 bfd reloc lookup %d (%s)\n", code, str) #else #define TRACE(str) #endif static reloc_howto_type * -elf_i386_reloc_type_lookup (abfd, code) - bfd *abfd ATTRIBUTE_UNUSED; - bfd_reloc_code_real_type code; +elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type code) { switch (code) { case BFD_RELOC_NONE: TRACE ("BFD_RELOC_NONE"); - return &elf_howto_table[(unsigned int) R_386_NONE ]; + return &elf_howto_table[R_386_NONE]; case BFD_RELOC_32: TRACE ("BFD_RELOC_32"); - return &elf_howto_table[(unsigned int) R_386_32 ]; + return &elf_howto_table[R_386_32]; case BFD_RELOC_CTOR: TRACE ("BFD_RELOC_CTOR"); - return &elf_howto_table[(unsigned int) R_386_32 ]; + return &elf_howto_table[R_386_32]; case BFD_RELOC_32_PCREL: TRACE ("BFD_RELOC_PC32"); - return &elf_howto_table[(unsigned int) R_386_PC32 ]; + return &elf_howto_table[R_386_PC32]; case BFD_RELOC_386_GOT32: TRACE ("BFD_RELOC_386_GOT32"); - return &elf_howto_table[(unsigned int) R_386_GOT32 ]; + return &elf_howto_table[R_386_GOT32]; case BFD_RELOC_386_PLT32: TRACE ("BFD_RELOC_386_PLT32"); - return &elf_howto_table[(unsigned int) R_386_PLT32 ]; + return &elf_howto_table[R_386_PLT32]; case BFD_RELOC_386_COPY: TRACE ("BFD_RELOC_386_COPY"); - return &elf_howto_table[(unsigned int) R_386_COPY ]; + return &elf_howto_table[R_386_COPY]; case BFD_RELOC_386_GLOB_DAT: TRACE ("BFD_RELOC_386_GLOB_DAT"); - return &elf_howto_table[(unsigned int) R_386_GLOB_DAT ]; + return &elf_howto_table[R_386_GLOB_DAT]; case BFD_RELOC_386_JUMP_SLOT: TRACE ("BFD_RELOC_386_JUMP_SLOT"); - return &elf_howto_table[(unsigned int) R_386_JUMP_SLOT ]; + return &elf_howto_table[R_386_JUMP_SLOT]; case BFD_RELOC_386_RELATIVE: TRACE ("BFD_RELOC_386_RELATIVE"); - return &elf_howto_table[(unsigned int) R_386_RELATIVE ]; + return &elf_howto_table[R_386_RELATIVE]; case BFD_RELOC_386_GOTOFF: TRACE ("BFD_RELOC_386_GOTOFF"); - return &elf_howto_table[(unsigned int) R_386_GOTOFF ]; + return &elf_howto_table[R_386_GOTOFF]; case BFD_RELOC_386_GOTPC: TRACE ("BFD_RELOC_386_GOTPC"); - return &elf_howto_table[(unsigned int) R_386_GOTPC ]; + return &elf_howto_table[R_386_GOTPC]; + + /* These relocs are a GNU extension. */ + case BFD_RELOC_386_TLS_TPOFF: + TRACE ("BFD_RELOC_386_TLS_TPOFF"); + return &elf_howto_table[R_386_TLS_TPOFF - R_386_ext_offset]; + + case BFD_RELOC_386_TLS_IE: + TRACE ("BFD_RELOC_386_TLS_IE"); + return &elf_howto_table[R_386_TLS_IE - R_386_ext_offset]; + + case BFD_RELOC_386_TLS_GOTIE: + TRACE ("BFD_RELOC_386_TLS_GOTIE"); + return &elf_howto_table[R_386_TLS_GOTIE - R_386_ext_offset]; - /* The remaining relocs are a GNU extension. */ case BFD_RELOC_386_TLS_LE: TRACE ("BFD_RELOC_386_TLS_LE"); - return &elf_howto_table[(unsigned int) R_386_TLS_LE - R_386_ext_offset]; + return &elf_howto_table[R_386_TLS_LE - R_386_ext_offset]; case BFD_RELOC_386_TLS_GD: TRACE ("BFD_RELOC_386_TLS_GD"); - return &elf_howto_table[(unsigned int) R_386_TLS_GD - R_386_ext_offset]; + return &elf_howto_table[R_386_TLS_GD - R_386_ext_offset]; case BFD_RELOC_386_TLS_LDM: TRACE ("BFD_RELOC_386_TLS_LDM"); - return &elf_howto_table[(unsigned int) R_386_TLS_LDM - R_386_ext_offset]; + return &elf_howto_table[R_386_TLS_LDM - R_386_ext_offset]; case BFD_RELOC_16: TRACE ("BFD_RELOC_16"); - return &elf_howto_table[(unsigned int) R_386_16 - R_386_ext_offset]; + return &elf_howto_table[R_386_16 - R_386_ext_offset]; case BFD_RELOC_16_PCREL: TRACE ("BFD_RELOC_16_PCREL"); - return &elf_howto_table[(unsigned int) R_386_PC16 - R_386_ext_offset]; + return &elf_howto_table[R_386_PC16 - R_386_ext_offset]; case BFD_RELOC_8: TRACE ("BFD_RELOC_8"); - return &elf_howto_table[(unsigned int) R_386_8 - R_386_ext_offset]; + return &elf_howto_table[R_386_8 - R_386_ext_offset]; case BFD_RELOC_8_PCREL: TRACE ("BFD_RELOC_8_PCREL"); - return &elf_howto_table[(unsigned int) R_386_PC8 - R_386_ext_offset]; + return &elf_howto_table[R_386_PC8 - R_386_ext_offset]; /* Common with Sun TLS implementation. */ case BFD_RELOC_386_TLS_LDO_32: TRACE ("BFD_RELOC_386_TLS_LDO_32"); - return &elf_howto_table[(unsigned int) R_386_TLS_LDO_32 - R_386_tls_offset]; + return &elf_howto_table[R_386_TLS_LDO_32 - R_386_tls_offset]; case BFD_RELOC_386_TLS_IE_32: TRACE ("BFD_RELOC_386_TLS_IE_32"); - return &elf_howto_table[(unsigned int) R_386_TLS_IE_32 - R_386_tls_offset]; + return &elf_howto_table[R_386_TLS_IE_32 - R_386_tls_offset]; case BFD_RELOC_386_TLS_LE_32: TRACE ("BFD_RELOC_386_TLS_LE_32"); - return &elf_howto_table[(unsigned int) R_386_TLS_LE_32 - R_386_tls_offset]; + return &elf_howto_table[R_386_TLS_LE_32 - R_386_tls_offset]; case BFD_RELOC_386_TLS_DTPMOD32: TRACE ("BFD_RELOC_386_TLS_DTPMOD32"); - return &elf_howto_table[(unsigned int) R_386_TLS_DTPMOD32 - R_386_tls_offset]; + return &elf_howto_table[R_386_TLS_DTPMOD32 - R_386_tls_offset]; case BFD_RELOC_386_TLS_DTPOFF32: TRACE ("BFD_RELOC_386_TLS_DTPOFF32"); - return &elf_howto_table[(unsigned int) R_386_TLS_DTPOFF32 - R_386_tls_offset]; + return &elf_howto_table[R_386_TLS_DTPOFF32 - R_386_tls_offset]; case BFD_RELOC_386_TLS_TPOFF32: TRACE ("BFD_RELOC_386_TLS_TPOFF32"); - return &elf_howto_table[(unsigned int) R_386_TLS_TPOFF32 - R_386_tls_offset]; + return &elf_howto_table[R_386_TLS_TPOFF32 - R_386_tls_offset]; case BFD_RELOC_VTABLE_INHERIT: TRACE ("BFD_RELOC_VTABLE_INHERIT"); - return &elf_howto_table[(unsigned int) R_386_GNU_VTINHERIT - - R_386_vt_offset]; + return &elf_howto_table[R_386_GNU_VTINHERIT - R_386_vt_offset]; case BFD_RELOC_VTABLE_ENTRY: TRACE ("BFD_RELOC_VTABLE_ENTRY"); - return &elf_howto_table[(unsigned int) R_386_GNU_VTENTRY - - R_386_vt_offset]; + return &elf_howto_table[R_386_GNU_VTENTRY - R_386_vt_offset]; default: break; @@ -351,19 +308,9 @@ elf_i386_reloc_type_lookup (abfd, code) } static void -elf_i386_info_to_howto (abfd, cache_ptr, dst) - bfd *abfd ATTRIBUTE_UNUSED; - arelent *cache_ptr ATTRIBUTE_UNUSED; - Elf32_Internal_Rela *dst ATTRIBUTE_UNUSED; -{ - abort (); -} - -static void -elf_i386_info_to_howto_rel (abfd, cache_ptr, dst) - bfd *abfd ATTRIBUTE_UNUSED; - arelent *cache_ptr; - Elf32_Internal_Rel *dst; +elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, + arelent *cache_ptr, + Elf_Internal_Rela *dst) { unsigned int r_type = ELF32_R_TYPE (dst->r_info); unsigned int indx; @@ -378,7 +325,7 @@ elf_i386_info_to_howto_rel (abfd, cache_ptr, dst) { (*_bfd_error_handler) (_("%s: invalid relocation type %d"), bfd_archive_filename (abfd), (int) r_type); - indx = (unsigned int) R_386_NONE; + indx = R_386_NONE; } cache_ptr->howto = &elf_howto_table[indx]; } @@ -389,43 +336,60 @@ elf_i386_info_to_howto_rel (abfd, cache_ptr, dst) 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; +static bfd_boolean +elf_i386_is_local_label_name (bfd *abfd, const char *name) { if (name[0] == '.' && name[1] == 'X') - return true; + return TRUE; return _bfd_elf_is_local_label_name (abfd, name); } /* Support for core dump NOTE sections. */ -static boolean -elf_i386_grok_prstatus (abfd, note) - bfd *abfd; - Elf_Internal_Note *note; + +static bfd_boolean +elf_i386_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) { int offset; size_t raw_size; - switch (note->descsz) + if (note->namesz == 8 && strcmp (note->namedata, "FreeBSD") == 0) { - default: - return false; + int pr_version = bfd_get_32 (abfd, note->descdata); + + if (pr_version != 1) + return FALSE; + + /* pr_cursig */ + elf_tdata (abfd)->core_signal = bfd_get_32 (abfd, note->descdata + 20); + + /* pr_pid */ + elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); + + /* pr_reg */ + offset = 28; + raw_size = bfd_get_32 (abfd, note->descdata + 8); + } + else + { + switch (note->descsz) + { + default: + return FALSE; - case 144: /* Linux/i386 */ - /* pr_cursig */ - elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); + case 144: /* Linux/i386 */ + /* pr_cursig */ + elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); - /* pr_pid */ - elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); + /* pr_pid */ + elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); - /* pr_reg */ - offset = 72; - raw_size = 68; + /* pr_reg */ + offset = 72; + raw_size = 68; - break; + break; + } } /* Make a ".reg/999" section. */ @@ -433,27 +397,39 @@ elf_i386_grok_prstatus (abfd, note) raw_size, note->descpos + offset); } -static boolean -elf_i386_grok_psinfo (abfd, note) - bfd *abfd; - Elf_Internal_Note *note; +static bfd_boolean +elf_i386_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) { - switch (note->descsz) + if (note->namesz == 8 && strcmp (note->namedata, "FreeBSD") == 0) { - default: - return false; - - case 124: /* Linux/i386 elf_prpsinfo */ - elf_tdata (abfd)->core_program - = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); - elf_tdata (abfd)->core_command - = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80); + int pr_version = bfd_get_32 (abfd, note->descdata); + + if (pr_version != 1) + return FALSE; + + elf_tdata (abfd)->core_program + = _bfd_elfcore_strndup (abfd, note->descdata + 8, 17); + elf_tdata (abfd)->core_command + = _bfd_elfcore_strndup (abfd, note->descdata + 25, 81); + } + else + { + switch (note->descsz) + { + default: + return FALSE; + + case 124: /* Linux/i386 elf_prpsinfo. */ + elf_tdata (abfd)->core_program + = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16); + elf_tdata (abfd)->core_command + = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80); + } } /* Note that for some reason, a spurious space is tacked onto the end of the args in some (at least one anyway) implementations, so strip it off if it exists. */ - { char *command = elf_tdata (abfd)->core_command; int n = strlen (command); @@ -462,7 +438,7 @@ elf_i386_grok_psinfo (abfd, note) command[n - 1] = '\0'; } - return true; + return TRUE; } /* Functions for the i386 ELF linker. @@ -484,6 +460,12 @@ elf_i386_grok_psinfo (abfd, note) #define ELF_DYNAMIC_INTERPRETER "/usr/lib/libc.so.1" +/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid + copying dynamic variables from a shared lib into an app's dynbss + section, and instead use a dynamic relocation to point into the + shared lib. */ +#define ELIMINATE_COPY_RELOCS 1 + /* The size in bytes of an entry in the procedure linkage table. */ #define PLT_ENTRY_SIZE 16 @@ -563,9 +545,14 @@ struct elf_i386_link_hash_entry /* Track dynamic relocs copied for this symbol. */ struct elf_i386_dyn_relocs *dyn_relocs; - enum { - GOT_UNKNOWN = 0, GOT_NORMAL, GOT_TLS_GD, GOT_TLS_IE - } tls_type; +#define GOT_UNKNOWN 0 +#define GOT_NORMAL 1 +#define GOT_TLS_GD 2 +#define GOT_TLS_IE 4 +#define GOT_TLS_IE_POS 5 +#define GOT_TLS_IE_NEG 6 +#define GOT_TLS_IE_BOTH 7 + unsigned char tls_type; }; #define elf_i386_hash_entry(ent) ((struct elf_i386_link_hash_entry *)(ent)) @@ -584,30 +571,14 @@ struct elf_i386_obj_tdata #define elf_i386_local_got_tls_type(abfd) \ (elf_i386_tdata (abfd)->local_got_tls_type) -static boolean -elf_i386_mkobject (abfd) - bfd *abfd; +static bfd_boolean +elf_i386_mkobject (bfd *abfd) { bfd_size_type amt = sizeof (struct elf_i386_obj_tdata); abfd->tdata.any = bfd_zalloc (abfd, amt); if (abfd->tdata.any == NULL) - return false; - return true; -} - -static boolean -elf_i386_object_p (abfd) - bfd *abfd; -{ - /* Allocate our special target data. */ - struct elf_i386_obj_tdata *new_tdata; - bfd_size_type amt = sizeof (struct elf_i386_obj_tdata); - new_tdata = bfd_zalloc (abfd, amt); - if (new_tdata == NULL) - return false; - new_tdata->root = *abfd->tdata.elf_obj_data; - abfd->tdata.any = new_tdata; - return true; + return FALSE; + return TRUE; } /* i386 ELF linker hash table. */ @@ -642,10 +613,9 @@ struct elf_i386_link_hash_table /* Create an entry in an i386 ELF linker hash table. */ static struct bfd_hash_entry * -link_hash_newfunc (entry, table, string) - struct bfd_hash_entry *entry; - struct bfd_hash_table *table; - const char *string; +link_hash_newfunc (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string) { /* Allocate the structure if it has not already been allocated by a subclass. */ @@ -674,13 +644,12 @@ link_hash_newfunc (entry, table, string) /* Create an i386 ELF linker hash table. */ static struct bfd_link_hash_table * -elf_i386_link_hash_table_create (abfd) - bfd *abfd; +elf_i386_link_hash_table_create (bfd *abfd) { struct elf_i386_link_hash_table *ret; bfd_size_type amt = sizeof (struct elf_i386_link_hash_table); - ret = (struct elf_i386_link_hash_table *) bfd_malloc (amt); + ret = bfd_malloc (amt); if (ret == NULL) return NULL; @@ -697,6 +666,7 @@ elf_i386_link_hash_table_create (abfd) ret->srelplt = NULL; ret->sdynbss = NULL; ret->srelbss = NULL; + ret->tls_ldm_got.refcount = 0; ret->sym_sec.abfd = NULL; return &ret->elf.root; @@ -705,15 +675,13 @@ elf_i386_link_hash_table_create (abfd) /* 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; +static bfd_boolean +create_got_section (bfd *dynobj, struct bfd_link_info *info) { struct elf_i386_link_hash_table *htab; if (! _bfd_elf_create_got_section (dynobj, info)) - return false; + return FALSE; htab = elf_i386_hash_table (info); htab->sgot = bfd_get_section_by_name (dynobj, ".got"); @@ -728,27 +696,25 @@ create_got_section (dynobj, info) | SEC_IN_MEMORY | SEC_LINKER_CREATED | SEC_READONLY)) || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2)) - return false; - return true; + 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; +static bfd_boolean +elf_i386_create_dynamic_sections (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; + return FALSE; if (!_bfd_elf_create_dynamic_sections (dynobj, info)) - return false; + return FALSE; htab->splt = bfd_get_section_by_name (dynobj, ".plt"); htab->srelplt = bfd_get_section_by_name (dynobj, ".rel.plt"); @@ -760,14 +726,15 @@ elf_i386_create_dynamic_sections (dynobj, info) || (!info->shared && !htab->srelbss)) abort (); - return true; + return TRUE; } /* Copy the extra info we tack onto an elf_link_hash_entry. */ static void -elf_i386_copy_indirect_symbol (dir, ind) - struct elf_link_hash_entry *dir, *ind; +elf_i386_copy_indirect_symbol (const struct elf_backend_data *bed, + struct elf_link_hash_entry *dir, + struct elf_link_hash_entry *ind) { struct elf_i386_link_hash_entry *edir, *eind; @@ -808,14 +775,31 @@ elf_i386_copy_indirect_symbol (dir, ind) eind->dyn_relocs = NULL; } - _bfd_elf_link_hash_copy_indirect (dir, ind); + if (ind->root.type == bfd_link_hash_indirect + && dir->got.refcount <= 0) + { + edir->tls_type = eind->tls_type; + eind->tls_type = GOT_UNKNOWN; + } + + if (ELIMINATE_COPY_RELOCS + && ind->root.type != bfd_link_hash_indirect + && (dir->elf_link_hash_flags & ELF_LINK_HASH_DYNAMIC_ADJUSTED) != 0) + /* If called to transfer flags for a weakdef during processing + of elf_adjust_dynamic_symbol, don't copy ELF_LINK_NON_GOT_REF. + We clear it ourselves for ELIMINATE_COPY_RELOCS. */ + dir->elf_link_hash_flags |= + (ind->elf_link_hash_flags & (ELF_LINK_HASH_REF_DYNAMIC + | ELF_LINK_HASH_REF_REGULAR + | ELF_LINK_HASH_REF_REGULAR_NONWEAK + | ELF_LINK_HASH_NEEDS_PLT + | ELF_LINK_POINTER_EQUALITY_NEEDED)); + else + _bfd_elf_link_hash_copy_indirect (bed, dir, ind); } static int -elf_i386_tls_transition (info, r_type, is_local) - struct bfd_link_info *info; - int r_type; - int is_local; +elf_i386_tls_transition (struct bfd_link_info *info, int r_type, int is_local) { if (info->shared) return r_type; @@ -827,6 +811,11 @@ elf_i386_tls_transition (info, r_type, is_local) if (is_local) return R_386_TLS_LE_32; return R_386_TLS_IE_32; + case R_386_TLS_IE: + case R_386_TLS_GOTIE: + if (is_local) + return R_386_TLS_LE_32; + return r_type; case R_386_TLS_LDM: return R_386_TLS_LE_32; } @@ -838,12 +827,11 @@ elf_i386_tls_transition (info, r_type, is_local) calculate needed space in the global offset table, procedure linkage table, and dynamic reloc sections. */ -static boolean -elf_i386_check_relocs (abfd, info, sec, relocs) - bfd *abfd; - struct bfd_link_info *info; - asection *sec; - const Elf_Internal_Rela *relocs; +static bfd_boolean +elf_i386_check_relocs (bfd *abfd, + struct bfd_link_info *info, + asection *sec, + const Elf_Internal_Rela *relocs) { struct elf_i386_link_hash_table *htab; Elf_Internal_Shdr *symtab_hdr; @@ -852,8 +840,8 @@ elf_i386_check_relocs (abfd, info, sec, relocs) const Elf_Internal_Rela *rel_end; asection *sreloc; - if (info->relocateable) - return true; + if (info->relocatable) + return TRUE; htab = elf_i386_hash_table (info); symtab_hdr = &elf_tdata (abfd)->symtab_hdr; @@ -876,7 +864,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs) (*_bfd_error_handler) (_("%s: bad symbol index: %d"), bfd_archive_filename (abfd), r_symndx); - return false; + return FALSE; } if (r_symndx < symtab_hdr->sh_info) @@ -888,10 +876,34 @@ elf_i386_check_relocs (abfd, info, sec, relocs) switch (r_type) { + case R_386_TLS_LDM: + htab->tls_ldm_got.refcount += 1; + goto create_got; + + 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. */ + + /* If this is a local symbol, we resolve it directly without + creating a procedure linkage table entry. */ + if (h == NULL) + continue; + + h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; + h->plt.refcount += 1; + break; + case R_386_TLS_IE_32: + case R_386_TLS_IE: + case R_386_TLS_GOTIE: if (info->shared) info->flags |= DF_STATIC_TLS; - /* FALLTHROUGH */ + /* Fall through */ + case R_386_GOT32: case R_386_TLS_GD: /* This symbol requires a global offset table entry. */ @@ -903,7 +915,17 @@ elf_i386_check_relocs (abfd, info, sec, relocs) default: case R_386_GOT32: tls_type = GOT_NORMAL; break; case R_386_TLS_GD: tls_type = GOT_TLS_GD; break; - case R_386_TLS_IE_32: tls_type = GOT_TLS_IE; break; + case R_386_TLS_IE_32: + if (ELF32_R_TYPE (rel->r_info) == r_type) + tls_type = GOT_TLS_IE_NEG; + else + /* If this is a GD->IE transition, we may use either of + R_386_TLS_TPOFF and R_386_TLS_TPOFF32. */ + tls_type = GOT_TLS_IE; + break; + case R_386_TLS_IE: + case R_386_TLS_GOTIE: + tls_type = GOT_TLS_IE_POS; break; } if (h != NULL) @@ -923,10 +945,9 @@ elf_i386_check_relocs (abfd, info, sec, relocs) size = symtab_hdr->sh_info; size *= (sizeof (bfd_signed_vma) + sizeof(char)); - local_got_refcounts = ((bfd_signed_vma *) - bfd_zalloc (abfd, size)); + local_got_refcounts = bfd_zalloc (abfd, size); if (local_got_refcounts == NULL) - return false; + return FALSE; elf_local_got_refcounts (abfd) = local_got_refcounts; elf_i386_local_got_tls_type (abfd) = (char *) (local_got_refcounts + symtab_hdr->sh_info); @@ -935,19 +956,24 @@ elf_i386_check_relocs (abfd, info, sec, relocs) old_tls_type = elf_i386_local_got_tls_type (abfd) [r_symndx]; } + if ((old_tls_type & GOT_TLS_IE) && (tls_type & GOT_TLS_IE)) + tls_type |= old_tls_type; /* If a TLS symbol is accessed using IE at least once, there is no point to use dynamic model for it. */ - if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN - && (old_tls_type != GOT_TLS_GD || tls_type != GOT_TLS_IE)) + else if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN + && (old_tls_type != GOT_TLS_GD + || (tls_type & GOT_TLS_IE) == 0)) { - if (old_tls_type == GOT_TLS_IE && tls_type == GOT_TLS_GD) - tls_type = GOT_TLS_IE; + if ((old_tls_type & GOT_TLS_IE) && tls_type == GOT_TLS_GD) + tls_type = old_tls_type; else { (*_bfd_error_handler) - (_("%s: `%s' accessed both as normal and thread local symbol"), - bfd_archive_filename (abfd), h->root.root.string); - return false; + (_("%s: `%s' accessed both as normal and " + "thread local symbol"), + bfd_archive_filename (abfd), + h ? h->root.root.string : ""); + return FALSE; } } @@ -969,30 +995,18 @@ elf_i386_check_relocs (abfd, info, sec, relocs) if (htab->elf.dynobj == NULL) htab->elf.dynobj = abfd; if (!create_got_section (htab->elf.dynobj, info)) - return false; + return FALSE; } - break; - - case R_386_TLS_LDM: - htab->tls_ldm_got.refcount += 1; - goto create_got; - - 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. */ - - /* If this is a local symbol, we resolve it directly without - creating a procedure linkage table entry. */ - if (h == NULL) - continue; + if (r_type != R_386_TLS_IE) + break; + /* Fall through */ - h->elf_link_hash_flags |= ELF_LINK_HASH_NEEDS_PLT; - h->plt.refcount += 1; - break; + case R_386_TLS_LE_32: + case R_386_TLS_LE: + if (!info->shared) + break; + info->flags |= DF_STATIC_TLS; + /* Fall through */ case R_386_32: case R_386_PC32: @@ -1009,6 +1023,8 @@ elf_i386_check_relocs (abfd, info, sec, relocs) /* We may need a .plt entry if the function this reloc refers to is in a shared lib. */ h->plt.refcount += 1; + if (r_type != R_386_PC32) + h->elf_link_hash_flags |= ELF_LINK_POINTER_EQUALITY_NEEDED; } /* If we are creating a shared library, and this is a reloc @@ -1040,7 +1056,8 @@ elf_i386_check_relocs (abfd, info, sec, relocs) || h->root.type == bfd_link_hash_defweak || (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0)))) - || (!info->shared + || (ELIMINATE_COPY_RELOCS + && !info->shared && (sec->flags & SEC_ALLOC) != 0 && h != NULL && (h->root.type == bfd_link_hash_defweak @@ -1062,7 +1079,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs) name = bfd_elf_string_from_elf_section (abfd, strndx, shnam); if (name == NULL) - return false; + return FALSE; if (strncmp (name, ".rel", 4) != 0 || strcmp (bfd_get_section_name (abfd, sec), @@ -1090,7 +1107,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs) if (sreloc == NULL || ! bfd_set_section_flags (dynobj, sreloc, flags) || ! bfd_set_section_alignment (dynobj, sreloc, 2)) - return false; + return FALSE; } elf_section_data (sec)->sreloc = sreloc; } @@ -1111,7 +1128,7 @@ elf_i386_check_relocs (abfd, info, sec, relocs) s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec, r_symndx); if (s == NULL) - return false; + return FALSE; head = ((struct elf_i386_dyn_relocs **) &elf_section_data (s)->local_dynrel); @@ -1121,10 +1138,9 @@ elf_i386_check_relocs (abfd, info, sec, relocs) if (p == NULL || p->sec != sec) { bfd_size_type amt = sizeof *p; - p = ((struct elf_i386_dyn_relocs *) - bfd_alloc (htab->elf.dynobj, amt)); + p = bfd_alloc (htab->elf.dynobj, amt); if (p == NULL) - return false; + return FALSE; p->next = *head; *head = p; p->sec = sec; @@ -1141,25 +1157,15 @@ elf_i386_check_relocs (abfd, info, sec, relocs) /* This relocation describes the C++ object vtable hierarchy. Reconstruct it for later use during GC. */ case R_386_GNU_VTINHERIT: - if (!_bfd_elf32_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) - return false; + if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) + return FALSE; break; /* This relocation describes which C++ vtable entries are actually used. Record for later use during GC. */ case R_386_GNU_VTENTRY: - if (!_bfd_elf32_gc_record_vtentry (abfd, sec, h, rel->r_offset)) - return false; - break; - - case R_386_TLS_LE_32: - case R_386_TLS_LE: - if (info->shared) - { - (*_bfd_error_handler) (_("%s: TLS local exec code cannot be linked into shared objects"), - bfd_archive_filename (abfd)); - return false; - } + if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) + return FALSE; break; default: @@ -1167,19 +1173,18 @@ elf_i386_check_relocs (abfd, info, sec, relocs) } } - return true; + return TRUE; } /* Return the section that should be marked against GC for a given relocation. */ static asection * -elf_i386_gc_mark_hook (sec, info, rel, h, sym) - asection *sec; - struct bfd_link_info *info ATTRIBUTE_UNUSED; - Elf_Internal_Rela *rel; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; +elf_i386_gc_mark_hook (asection *sec, + struct bfd_link_info *info ATTRIBUTE_UNUSED, + Elf_Internal_Rela *rel, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) { if (h != NULL) { @@ -1212,19 +1217,16 @@ elf_i386_gc_mark_hook (sec, info, rel, h, sym) /* Update the got entry reference counts for the section being removed. */ -static boolean -elf_i386_gc_sweep_hook (abfd, info, sec, relocs) - bfd *abfd; - struct bfd_link_info *info; - asection *sec; - const Elf_Internal_Rela *relocs; +static bfd_boolean +elf_i386_gc_sweep_hook (bfd *abfd, + struct bfd_link_info *info, + asection *sec, + const Elf_Internal_Rela *relocs) { 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; elf_section_data (sec)->local_dynrel = NULL; @@ -1234,76 +1236,76 @@ elf_i386_gc_sweep_hook (abfd, info, sec, relocs) relend = relocs + sec->reloc_count; for (rel = relocs; rel < relend; rel++) - switch (elf_i386_tls_transition (info, ELF32_R_TYPE (rel->r_info), - ELF32_R_SYM (rel->r_info) - >= symtab_hdr->sh_info)) - { - case R_386_TLS_LDM: - if (elf_i386_hash_table (info)->tls_ldm_got.refcount > 0) - elf_i386_hash_table (info)->tls_ldm_got.refcount -= 1; - break; - - case R_386_TLS_GD: - case R_386_TLS_IE_32: - case R_386_GOT32: - 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; - } - else if (local_got_refcounts != NULL) - { - if (local_got_refcounts[r_symndx] > 0) - local_got_refcounts[r_symndx] -= 1; - } - break; + { + unsigned long r_symndx; + unsigned int r_type; + struct elf_link_hash_entry *h = NULL; - case R_386_32: - case R_386_PC32: - r_symndx = ELF32_R_SYM (rel->r_info); - if (r_symndx >= symtab_hdr->sh_info) - { - struct elf_i386_link_hash_entry *eh; - struct elf_i386_dyn_relocs **pp; - struct elf_i386_dyn_relocs *p; + r_symndx = ELF32_R_SYM (rel->r_info); + if (r_symndx >= symtab_hdr->sh_info) + { + struct elf_i386_link_hash_entry *eh; + struct elf_i386_dyn_relocs **pp; + struct elf_i386_dyn_relocs *p; - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + eh = (struct elf_i386_link_hash_entry *) h; - if (!info->shared && h->plt.refcount > 0) - h->plt.refcount -= 1; + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) + if (p->sec == sec) + { + /* Everything must go for SEC. */ + *pp = p->next; + break; + } + } - eh = (struct elf_i386_link_hash_entry *) h; + r_type = ELF32_R_TYPE (rel->r_info); + r_type = elf_i386_tls_transition (info, r_type, h != NULL); + switch (r_type) + { + case R_386_TLS_LDM: + if (elf_i386_hash_table (info)->tls_ldm_got.refcount > 0) + elf_i386_hash_table (info)->tls_ldm_got.refcount -= 1; + break; - for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) - if (p->sec == sec) - { - if (ELF32_R_TYPE (rel->r_info) == R_386_PC32) - p->pc_count -= 1; - p->count -= 1; - if (p->count == 0) - *pp = p->next; - break; - } - } - break; + case R_386_TLS_GD: + case R_386_TLS_IE_32: + case R_386_TLS_IE: + case R_386_TLS_GOTIE: + case R_386_GOT32: + if (h != NULL) + { + if (h->got.refcount > 0) + h->got.refcount -= 1; + } + else if (local_got_refcounts != NULL) + { + if (local_got_refcounts[r_symndx] > 0) + local_got_refcounts[r_symndx] -= 1; + } + 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; + case R_386_32: + case R_386_PC32: + if (info->shared) + break; + /* Fall through */ - default: - break; - } + case R_386_PLT32: + if (h != NULL) + { + if (h->plt.refcount > 0) + h->plt.refcount -= 1; + } + break; + + default: + break; + } + } - return true; + return TRUE; } /* Adjust a symbol defined by a dynamic object and referenced by a @@ -1312,14 +1314,11 @@ elf_i386_gc_sweep_hook (abfd, info, sec, relocs) change the definition to something the rest of the link can understand. */ -static boolean -elf_i386_adjust_dynamic_symbol (info, h) - struct bfd_link_info *info; - struct elf_link_hash_entry *h; +static bfd_boolean +elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *h) { struct elf_i386_link_hash_table *htab; - struct elf_i386_link_hash_entry * eh; - struct elf_i386_dyn_relocs *p; asection *s; unsigned int power_of_two; @@ -1330,11 +1329,9 @@ elf_i386_adjust_dynamic_symbol (info, h) || (h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_PLT) != 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 - && h->root.type != bfd_link_hash_undefweak - && h->root.type != bfd_link_hash_undefined)) + || SYMBOL_CALLS_LOCAL (info, h) + || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + && h->root.type == bfd_link_hash_undefweak)) { /* This case can occur if we saw a PLT32 reloc in an input file, but the symbol was never referred to by a dynamic @@ -1345,7 +1342,7 @@ elf_i386_adjust_dynamic_symbol (info, h) h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; } - return true; + return TRUE; } else /* It's possible that we incorrectly decided a .plt reloc was @@ -1364,7 +1361,11 @@ elf_i386_adjust_dynamic_symbol (info, h) || 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; + if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) + h->elf_link_hash_flags + = ((h->elf_link_hash_flags & ~ELF_LINK_NON_GOT_REF) + | (h->weakdef->elf_link_hash_flags & ELF_LINK_NON_GOT_REF)); + return TRUE; } /* This is a reference to a symbol defined by a dynamic object which @@ -1375,34 +1376,40 @@ elf_i386_adjust_dynamic_symbol (info, h) For such cases we need not do anything here; the relocations will be handled correctly by relocate_section. */ if (info->shared) - return true; + return TRUE; /* If there are no references to this symbol that do not use the GOT, we don't need to generate a copy reloc. */ if ((h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0) - return true; + return TRUE; /* If -z nocopyreloc was given, we won't generate them either. */ if (info->nocopyreloc) { h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; - return true; + return TRUE; } - eh = (struct elf_i386_link_hash_entry *) h; - for (p = eh->dyn_relocs; p != NULL; p = p->next) + if (ELIMINATE_COPY_RELOCS) { - s = p->sec->output_section; - if (s != NULL && (s->flags & SEC_READONLY) != 0) - break; - } + struct elf_i386_link_hash_entry * eh; + struct elf_i386_dyn_relocs *p; - /* If we didn't find any dynamic relocs in read-only sections, then - we'll be keeping the dynamic relocs and avoiding the copy reloc. */ - if (p == NULL) - { - h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; - return true; + eh = (struct elf_i386_link_hash_entry *) h; + for (p = eh->dyn_relocs; p != NULL; p = p->next) + { + s = p->sec->output_section; + if (s != NULL && (s->flags & SEC_READONLY) != 0) + break; + } + + /* If we didn't find any dynamic relocs in read-only sections, then + we'll be keeping the dynamic relocs and avoiding the copy reloc. */ + if (p == NULL) + { + h->elf_link_hash_flags &= ~ELF_LINK_NON_GOT_REF; + return TRUE; + } } /* We must allocate the symbol in our .dynbss section, which will @@ -1438,7 +1445,7 @@ elf_i386_adjust_dynamic_symbol (info, h) if (power_of_two > bfd_get_section_alignment (htab->elf.dynobj, s)) { if (! bfd_set_section_alignment (htab->elf.dynobj, s, power_of_two)) - return false; + return FALSE; } /* Define the symbol as being at this point in the section. */ @@ -1448,27 +1455,14 @@ elf_i386_adjust_dynamic_symbol (info, h) /* Increment the section size to make room for the symbol. */ s->_raw_size += h->size; - return true; + 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 dynamic relocs. */ -static boolean -allocate_dynrelocs (h, inf) - struct elf_link_hash_entry *h; - PTR inf; +static bfd_boolean +allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) { struct bfd_link_info *info; struct elf_i386_link_hash_table *htab; @@ -1476,7 +1470,7 @@ allocate_dynrelocs (h, inf) struct elf_i386_dyn_relocs *p; if (h->root.type == bfd_link_hash_indirect) - return true; + return TRUE; if (h->root.type == bfd_link_hash_warning) /* When warning symbols are created, they **replace** the "real" @@ -1495,11 +1489,12 @@ allocate_dynrelocs (h, inf) 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 (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; } - if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info, h)) + if (info->shared + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) { asection *s = htab->splt; @@ -1544,17 +1539,17 @@ allocate_dynrelocs (h, inf) h->elf_link_hash_flags &= ~ELF_LINK_HASH_NEEDS_PLT; } - /* If R_386_TLS_IE_32 symbol is now local to the binary, + /* If R_386_TLS_{IE_32,IE,GOTIE} symbol is now local to the binary, make it a R_386_TLS_LE_32 requiring no TLS entry. */ if (h->got.refcount > 0 && !info->shared && h->dynindx == -1 - && elf_i386_hash_entry(h)->tls_type == GOT_TLS_IE) + && (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE)) h->got.offset = (bfd_vma) -1; else if (h->got.refcount > 0) { asection *s; - boolean dyn; + bfd_boolean dyn; int tls_type = elf_i386_hash_entry(h)->tls_type; /* Make sure this symbol is output as a dynamic symbol. @@ -1562,25 +1557,33 @@ allocate_dynrelocs (h, inf) 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 (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; } s = htab->sgot; h->got.offset = s->_raw_size; s->_raw_size += 4; /* R_386_TLS_GD needs 2 consecutive GOT slots. */ - if (tls_type == GOT_TLS_GD) + if (tls_type == GOT_TLS_GD || tls_type == GOT_TLS_IE_BOTH) s->_raw_size += 4; dyn = htab->elf.dynamic_sections_created; /* R_386_TLS_IE_32 needs one dynamic relocation, - R_386_TLS_GD needs one if local symbol and two if global. */ - if ((tls_type == GOT_TLS_GD && h->dynindx == -1) - || tls_type == GOT_TLS_IE) + R_386_TLS_IE resp. R_386_TLS_GOTIE needs one dynamic relocation, + (but if both R_386_TLS_IE_32 and R_386_TLS_IE is present, we + need two), R_386_TLS_GD needs one if local symbol and two if + global. */ + if (tls_type == GOT_TLS_IE_BOTH) + htab->srelgot->_raw_size += 2 * sizeof (Elf32_External_Rel); + else if ((tls_type == GOT_TLS_GD && h->dynindx == -1) + || (tls_type & GOT_TLS_IE)) htab->srelgot->_raw_size += sizeof (Elf32_External_Rel); else if (tls_type == GOT_TLS_GD) htab->srelgot->_raw_size += 2 * sizeof (Elf32_External_Rel); - else if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h)) + else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak) + && (info->shared + || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) htab->srelgot->_raw_size += sizeof (Elf32_External_Rel); } else @@ -1588,7 +1591,7 @@ allocate_dynrelocs (h, inf) eh = (struct elf_i386_link_hash_entry *) h; if (eh->dyn_relocs == NULL) - return true; + return TRUE; /* In the shared -Bsymbolic case, discard space allocated for dynamic pc-relative relocs against symbols which turn out to be @@ -1598,9 +1601,13 @@ allocate_dynrelocs (h, inf) if (info->shared) { - if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) != 0 - && ((h->elf_link_hash_flags & ELF_LINK_FORCED_LOCAL) != 0 - || info->symbolic)) + /* The only reloc that uses pc_count is R_386_PC32, which will + appear on a call or on something like ".long foo - .". We + want calls to protected symbols to resolve directly to the + function rather than going via the plt. If people want + function pointer comparisons to work as expected then they + should avoid writing assembly like ".long foo - .". */ + if (SYMBOL_CALLS_LOCAL (info, h)) { struct elf_i386_dyn_relocs **pp; @@ -1614,8 +1621,14 @@ allocate_dynrelocs (h, inf) pp = &p->next; } } + + /* Also discard relocs on undefined weak syms with non-default + visibility. */ + if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT + && h->root.type == bfd_link_hash_undefweak) + eh->dyn_relocs = NULL; } - else + else if (ELIMINATE_COPY_RELOCS) { /* For the non-shared case, discard space for relocs against symbols which turn out to need copy relocs or are not @@ -1633,8 +1646,8 @@ allocate_dynrelocs (h, inf) 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 (! bfd_elf_link_record_dynamic_symbol (info, h)) + return FALSE; } /* If that succeeded, we know we'll be keeping all the @@ -1655,15 +1668,13 @@ allocate_dynrelocs (h, inf) sreloc->_raw_size += p->count * sizeof (Elf32_External_Rel); } - return true; + return TRUE; } /* Find any dynamic relocs that apply to read-only sections. */ -static boolean -readonly_dynrelocs (h, inf) - struct elf_link_hash_entry *h; - PTR inf; +static bfd_boolean +readonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) { struct elf_i386_link_hash_entry *eh; struct elf_i386_dyn_relocs *p; @@ -1683,23 +1694,22 @@ readonly_dynrelocs (h, inf) info->flags |= DF_TEXTREL; /* Not an error, just cut short the traversal. */ - return false; + return FALSE; } } - return true; + return TRUE; } /* Set the sizes of the dynamic sections. */ -static boolean -elf_i386_size_dynamic_sections (output_bfd, info) - bfd *output_bfd ATTRIBUTE_UNUSED; - struct bfd_link_info *info; +static bfd_boolean +elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) { struct elf_i386_link_hash_table *htab; bfd *dynobj; asection *s; - boolean relocs; + bfd_boolean relocs; bfd *ibfd; htab = elf_i386_hash_table (info); @@ -1710,7 +1720,7 @@ elf_i386_size_dynamic_sections (output_bfd, info) if (htab->elf.dynamic_sections_created) { /* Set the contents of the .interp section to the interpreter. */ - if (! info->shared) + if (info->executable) { s = bfd_get_section_by_name (dynobj, ".interp"); if (s == NULL) @@ -1777,12 +1787,18 @@ elf_i386_size_dynamic_sections (output_bfd, info) { *local_got = s->_raw_size; s->_raw_size += 4; - if (*local_tls_type == GOT_TLS_GD) + if (*local_tls_type == GOT_TLS_GD + || *local_tls_type == GOT_TLS_IE_BOTH) s->_raw_size += 4; if (info->shared || *local_tls_type == GOT_TLS_GD - || *local_tls_type == GOT_TLS_IE) - srel->_raw_size += sizeof (Elf32_External_Rel); + || (*local_tls_type & GOT_TLS_IE)) + { + if (*local_tls_type == GOT_TLS_IE_BOTH) + srel->_raw_size += 2 * sizeof (Elf32_External_Rel); + else + srel->_raw_size += sizeof (Elf32_External_Rel); + } } else *local_got = (bfd_vma) -1; @@ -1806,7 +1822,7 @@ elf_i386_size_dynamic_sections (output_bfd, info) /* We now have determined the sizes of the various dynamic sections. Allocate memory for them. */ - relocs = false; + relocs = FALSE; for (s = dynobj->sections; s != NULL; s = s->next) { if ((s->flags & SEC_LINKER_CREATED) == 0) @@ -1822,7 +1838,7 @@ elf_i386_size_dynamic_sections (output_bfd, info) else if (strncmp (bfd_get_section_name (dynobj, s), ".rel", 4) == 0) { if (s->_raw_size != 0 && s != htab->srelplt) - relocs = true; + relocs = TRUE; /* We use the reloc_count field as a counter if we need to copy relocs into the output file. */ @@ -1855,9 +1871,9 @@ elf_i386_size_dynamic_sections (output_bfd, info) 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); + s->contents = bfd_zalloc (dynobj, s->_raw_size); if (s->contents == NULL) - return false; + return FALSE; } if (htab->elf.dynamic_sections_created) @@ -1868,12 +1884,12 @@ elf_i386_size_dynamic_sections (output_bfd, info) the .dynamic section. The DT_DEBUG entry is filled in by the dynamic linker and used by the debugger. */ #define add_dynamic_entry(TAG, VAL) \ - bfd_elf32_add_dynamic_entry (info, (bfd_vma) (TAG), (bfd_vma) (VAL)) + _bfd_elf_add_dynamic_entry (info, TAG, VAL) - if (! info->shared) + if (info->executable) { if (!add_dynamic_entry (DT_DEBUG, 0)) - return false; + return FALSE; } if (htab->splt->_raw_size != 0) @@ -1882,7 +1898,7 @@ elf_i386_size_dynamic_sections (output_bfd, info) || !add_dynamic_entry (DT_PLTRELSZ, 0) || !add_dynamic_entry (DT_PLTREL, DT_REL) || !add_dynamic_entry (DT_JMPREL, 0)) - return false; + return FALSE; } if (relocs) @@ -1890,7 +1906,7 @@ elf_i386_size_dynamic_sections (output_bfd, info) if (!add_dynamic_entry (DT_REL, 0) || !add_dynamic_entry (DT_RELSZ, 0) || !add_dynamic_entry (DT_RELENT, sizeof (Elf32_External_Rel))) - return false; + return FALSE; /* If any dynamic relocs apply to a read-only section, then we need a DT_TEXTREL entry. */ @@ -1901,23 +1917,22 @@ elf_i386_size_dynamic_sections (output_bfd, info) if ((info->flags & DF_TEXTREL) != 0) { if (!add_dynamic_entry (DT_TEXTREL, 0)) - return false; + return FALSE; } } } #undef add_dynamic_entry - return true; + 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; +static bfd_boolean +elf_i386_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, + Elf_Internal_Shdr *hdr, + asection *sec) { register const char *name; @@ -1942,7 +1957,7 @@ elf_i386_fake_sections (abfd, hdr, sec) if (strcmp (name, ".reloc") == 0) hdr->sh_type = SHT_PROGBITS; - return true; + return TRUE; } /* Return the base VMA address which should be subtracted from real addresses @@ -1950,42 +1965,39 @@ elf_i386_fake_sections (abfd, hdr, sec) This is PT_TLS segment p_vaddr. */ static bfd_vma -dtpoff_base (info) - struct bfd_link_info *info; +dtpoff_base (struct bfd_link_info *info) { - BFD_ASSERT (elf_hash_table (info)->tls_segment != NULL); - return elf_hash_table (info)->tls_segment->start; + /* If tls_sec is NULL, we should have signalled an error already. */ + if (elf_hash_table (info)->tls_sec == NULL) + return 0; + return elf_hash_table (info)->tls_sec->vma; } /* Return the relocation value for @tpoff relocation if STT_TLS virtual address is ADDRESS. */ static bfd_vma -tpoff (info, address) - struct bfd_link_info *info; - bfd_vma address; +tpoff (struct bfd_link_info *info, bfd_vma address) { - struct elf_link_tls_segment *tls_segment - = elf_hash_table (info)->tls_segment; + struct elf_link_hash_table *htab = elf_hash_table (info); - BFD_ASSERT (tls_segment != NULL); - return (align_power (tls_segment->size, tls_segment->align) - + tls_segment->start - address); + /* If tls_sec is NULL, we should have signalled an error already. */ + if (htab->tls_sec == NULL) + return 0; + return htab->tls_size + htab->tls_sec->vma - address; } /* Relocate an i386 ELF section. */ -static boolean -elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, - contents, relocs, local_syms, local_sections) - bfd *output_bfd; - struct bfd_link_info *info; - bfd *input_bfd; - asection *input_section; - bfd_byte *contents; - Elf_Internal_Rela *relocs; - Elf_Internal_Sym *local_syms; - asection **local_sections; +static bfd_boolean +elf_i386_relocate_section (bfd *output_bfd, + struct bfd_link_info *info, + bfd *input_bfd, + asection *input_section, + bfd_byte *contents, + Elf_Internal_Rela *relocs, + Elf_Internal_Sym *local_syms, + asection **local_sections) { struct elf_i386_link_hash_table *htab; Elf_Internal_Shdr *symtab_hdr; @@ -2011,30 +2023,30 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, asection *sec; bfd_vma off; bfd_vma relocation; - boolean unresolved_reloc; + bfd_boolean unresolved_reloc; bfd_reloc_status_type r; unsigned int indx; int tls_type; r_type = ELF32_R_TYPE (rel->r_info); - if (r_type == (int) R_386_GNU_VTINHERIT - || r_type == (int) R_386_GNU_VTENTRY) + if (r_type == R_386_GNU_VTINHERIT + || r_type == R_386_GNU_VTENTRY) continue; - if ((indx = (unsigned) r_type) >= R_386_standard + 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_tls_offset) - R_386_ext >= R_386_tls - R_386_ext)) { bfd_set_error (bfd_error_bad_value); - return false; + return FALSE; } howto = elf_howto_table + indx; r_symndx = ELF32_R_SYM (rel->r_info); - if (info->relocateable) + if (info->relocatable) { bfd_vma val; bfd_byte *where; @@ -2081,7 +2093,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, h = NULL; sym = NULL; sec = NULL; - unresolved_reloc = false; + unresolved_reloc = FALSE; if (r_symndx < symtab_hdr->sh_info) { sym = local_syms + r_symndx; @@ -2154,43 +2166,12 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, } else { - h = sym_hashes[r_symndx - symtab_hdr->sh_info]; - 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; + bfd_boolean warned; - relocation = 0; - if (h->root.type == bfd_link_hash_defined - || h->root.type == bfd_link_hash_defweak) - { - sec = h->root.u.def.section; - 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) - ; - else if (info->shared - && (!info->symbolic || info->allow_shlib_undefined) - && !info->no_undefined - && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT) - ; - else - { - if (! ((*info->callbacks->undefined_symbol) - (info, h->root.root.string, input_bfd, - input_section, rel->r_offset, - (!info->shared || info->no_undefined - || ELF_ST_VISIBILITY (h->other))))) - return false; - } + RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, + r_symndx, symtab_hdr, sym_hashes, + h, sec, relocation, + unresolved_reloc, warned); } switch (r_type) @@ -2203,16 +2184,15 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, if (h != NULL) { - boolean dyn; + bfd_boolean dyn; off = h->got.offset; dyn = htab->elf.dynamic_sections_created; - if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info, h) + if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) || (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))) + && SYMBOL_REFERENCES_LOCAL (info, h)) + || (ELF_ST_VISIBILITY (h->other) + && h->root.type == bfd_link_hash_undefweak)) { /* This is actually a static link, or it is a -Bsymbolic link and the symbol is defined @@ -2236,7 +2216,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, } } else - unresolved_reloc = false; + unresolved_reloc = FALSE; } else { @@ -2257,20 +2237,20 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, if (info->shared) { - asection *srelgot; - Elf_Internal_Rel outrel; - Elf32_External_Rel *loc; + asection *s; + Elf_Internal_Rela outrel; + bfd_byte *loc; - srelgot = htab->srelgot; - if (srelgot == NULL) + s = htab->srelgot; + if (s == NULL) abort (); outrel.r_offset = (htab->sgot->output_section->vma + htab->sgot->output_offset + off); outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); - loc = (Elf32_External_Rel *) srelgot->contents; - loc += srelgot->reloc_count++; + loc = s->contents; + loc += s->reloc_count++ * sizeof (Elf32_External_Rel); bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); } @@ -2281,25 +2261,30 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, if (off >= (bfd_vma) -2) abort (); - relocation = htab->sgot->output_offset + off; + relocation = htab->sgot->output_section->vma + + htab->sgot->output_offset + off + - htab->sgotplt->output_section->vma + - htab->sgotplt->output_offset; break; case R_386_GOTOFF: /* Relocation is relative to the start of the global offset table. */ - /* 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 + /* Note that sgot is not involved in this + calculation. We always want the start of .got.plt. If we + defined _GLOBAL_OFFSET_TABLE_ in a different way, as is permitted by the ABI, we might have to change this calculation. */ - relocation -= htab->sgot->output_section->vma; + relocation -= htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset; break; case R_386_GOTPC: /* Use global offset table as symbol value. */ - relocation = htab->sgot->output_section->vma; - unresolved_reloc = false; + relocation = htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset; + unresolved_reloc = FALSE; break; case R_386_PLT32: @@ -2323,7 +2308,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, relocation = (htab->splt->output_section->vma + htab->splt->output_offset + h->plt.offset); - unresolved_reloc = false; + unresolved_reloc = FALSE; break; case R_386_32: @@ -2336,13 +2321,13 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, break; if ((info->shared + && (h == NULL + || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT + || h->root.type != bfd_link_hash_undefweak) && (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 + || !SYMBOL_CALLS_LOCAL (info, h))) + || (ELIMINATE_COPY_RELOCS + && !info->shared && h != NULL && h->dynindx != -1 && (h->elf_link_hash_flags & ELF_LINK_NON_GOT_REF) == 0 @@ -2353,25 +2338,25 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, || h->root.type == bfd_link_hash_undefweak || h->root.type == bfd_link_hash_undefined))) { - Elf_Internal_Rel outrel; - boolean skip, relocate; + Elf_Internal_Rela outrel; + bfd_byte *loc; + bfd_boolean skip, relocate; asection *sreloc; - Elf32_External_Rel *loc; /* When generating a shared object, these relocations are copied into the output file to be resolved at run time. */ - skip = false; - relocate = false; + skip = FALSE; + relocate = FALSE; outrel.r_offset = _bfd_elf_section_offset (output_bfd, info, input_section, rel->r_offset); if (outrel.r_offset == (bfd_vma) -1) - skip = true; + skip = TRUE; else if (outrel.r_offset == (bfd_vma) -2) - skip = true, relocate = true; + skip = TRUE, relocate = TRUE; outrel.r_offset += (input_section->output_section->vma + input_section->output_offset); @@ -2388,7 +2373,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, else { /* This symbol is local, or marked to become local. */ - relocate = true; + relocate = TRUE; outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); } @@ -2396,8 +2381,8 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, if (sreloc == NULL) abort (); - loc = (Elf32_External_Rel *) sreloc->contents; - loc += sreloc->reloc_count++; + loc = sreloc->contents; + loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel); bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); /* If this reloc is against an external symbol, we do @@ -2409,8 +2394,29 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, } break; + case R_386_TLS_IE: + if (info->shared) + { + Elf_Internal_Rela outrel; + bfd_byte *loc; + asection *sreloc; + + outrel.r_offset = rel->r_offset + + input_section->output_section->vma + + input_section->output_offset; + outrel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); + sreloc = elf_section_data (input_section)->sreloc; + if (sreloc == NULL) + abort (); + loc = sreloc->contents; + loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + } + /* Fall through */ + case R_386_TLS_GD: case R_386_TLS_IE_32: + case R_386_TLS_GOTIE: r_type = elf_i386_tls_transition (info, r_type, h == NULL); tls_type = GOT_UNKNOWN; if (h == NULL && local_got_offsets) @@ -2418,11 +2424,18 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, else if (h != NULL) { tls_type = elf_i386_hash_entry(h)->tls_type; - if (!info->shared && h->dynindx == -1 && tls_type == GOT_TLS_IE) + if (!info->shared && h->dynindx == -1 && (tls_type & GOT_TLS_IE)) r_type = R_386_TLS_LE_32; } - if (r_type == R_386_TLS_GD && tls_type == GOT_TLS_IE) - r_type = R_386_TLS_IE_32; + if (tls_type == GOT_TLS_IE) + tls_type = GOT_TLS_IE_NEG; + if (r_type == R_386_TLS_GD) + { + if (tls_type == GOT_TLS_IE_POS) + r_type = R_386_TLS_GOTIE; + else if (tls_type & GOT_TLS_IE) + r_type = R_386_TLS_IE_32; + } if (r_type == R_386_TLS_LE_32) { @@ -2490,27 +2503,83 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, rel++; continue; } - else + else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_IE) { unsigned int val, type; /* IE->LE transition: - Originally it can be either: + Originally it can be one of: + movl foo, %eax + movl foo, %reg + addl foo, %reg + We change it into: + movl $foo, %eax + movl $foo, %reg + addl $foo, %reg. */ + BFD_ASSERT (rel->r_offset >= 1); + val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); + BFD_ASSERT (rel->r_offset + 4 <= input_section->_raw_size); + if (val == 0xa1) + { + /* movl foo, %eax. */ + bfd_put_8 (output_bfd, 0xb8, + contents + rel->r_offset - 1); + } + else + { + BFD_ASSERT (rel->r_offset >= 2); + type = bfd_get_8 (input_bfd, + contents + rel->r_offset - 2); + switch (type) + { + case 0x8b: + /* movl */ + BFD_ASSERT ((val & 0xc7) == 0x05); + bfd_put_8 (output_bfd, 0xc7, + contents + rel->r_offset - 2); + bfd_put_8 (output_bfd, + 0xc0 | ((val >> 3) & 7), + contents + rel->r_offset - 1); + break; + case 0x03: + /* addl */ + BFD_ASSERT ((val & 0xc7) == 0x05); + bfd_put_8 (output_bfd, 0x81, + contents + rel->r_offset - 2); + bfd_put_8 (output_bfd, + 0xc0 | ((val >> 3) & 7), + contents + rel->r_offset - 1); + break; + default: + BFD_FAIL (); + break; + } + } + bfd_put_32 (output_bfd, -tpoff (info, relocation), + contents + rel->r_offset); + continue; + } + else + { + unsigned int val, type; + + /* {IE_32,GOTIE}->LE transition: + Originally it can be one of: subl foo(%reg1), %reg2 - or movl foo(%reg1), %reg2 + addl foo(%reg1), %reg2 We change it into: subl $foo, %reg2 - or - movl $foo, %reg2 (6 byte form) */ + movl $foo, %reg2 (6 byte form) + addl $foo, %reg2. */ BFD_ASSERT (rel->r_offset >= 2); type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); BFD_ASSERT (rel->r_offset + 4 <= input_section->_raw_size); + BFD_ASSERT ((val & 0xc0) == 0x80 && (val & 7) != 4); if (type == 0x8b) { /* movl */ - BFD_ASSERT ((val & 0xc0) == 0x80 && (val & 7) != 4); bfd_put_8 (output_bfd, 0xc7, contents + rel->r_offset - 2); bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7), @@ -2519,16 +2588,27 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, else if (type == 0x2b) { /* subl */ - BFD_ASSERT ((val & 0xc0) == 0x80 && (val & 7) != 4); bfd_put_8 (output_bfd, 0x81, contents + rel->r_offset - 2); bfd_put_8 (output_bfd, 0xe8 | ((val >> 3) & 7), contents + rel->r_offset - 1); } + else if (type == 0x03) + { + /* addl */ + bfd_put_8 (output_bfd, 0x81, + contents + rel->r_offset - 2); + bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7), + contents + rel->r_offset - 1); + } else BFD_FAIL (); - bfd_put_32 (output_bfd, tpoff (info, relocation), - contents + rel->r_offset); + if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GOTIE) + bfd_put_32 (output_bfd, -tpoff (info, relocation), + contents + rel->r_offset); + else + bfd_put_32 (output_bfd, tpoff (info, relocation), + contents + rel->r_offset); continue; } } @@ -2548,10 +2628,10 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, if ((off & 1) != 0) off &= ~1; - else + else { - Elf_Internal_Rel outrel; - Elf32_External_Rel *loc; + Elf_Internal_Rela outrel; + bfd_byte *loc; int dr_type, indx; if (htab->srelgot == NULL) @@ -2560,16 +2640,25 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, outrel.r_offset = (htab->sgot->output_section->vma + htab->sgot->output_offset + off); - bfd_put_32 (output_bfd, 0, - htab->sgot->contents + off); indx = h && h->dynindx != -1 ? h->dynindx : 0; if (r_type == R_386_TLS_GD) dr_type = R_386_TLS_DTPMOD32; + else if (tls_type == GOT_TLS_IE_POS) + dr_type = R_386_TLS_TPOFF; else dr_type = R_386_TLS_TPOFF32; + if (dr_type == R_386_TLS_TPOFF && indx == 0) + bfd_put_32 (output_bfd, relocation - dtpoff_base (info), + htab->sgot->contents + off); + else if (dr_type == R_386_TLS_TPOFF32 && indx == 0) + bfd_put_32 (output_bfd, dtpoff_base (info) - relocation, + htab->sgot->contents + off); + else + bfd_put_32 (output_bfd, 0, + htab->sgot->contents + off); outrel.r_info = ELF32_R_INFO (indx, dr_type); - loc = (Elf32_External_Rel *) htab->srelgot->contents; - loc += htab->srelgot->reloc_count++; + loc = htab->srelgot->contents; + loc += htab->srelgot->reloc_count++ * sizeof (Elf32_External_Rel); bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); if (r_type == R_386_TLS_GD) @@ -2589,11 +2678,21 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, R_386_TLS_DTPOFF32); outrel.r_offset += 4; htab->srelgot->reloc_count++; - loc++; - bfd_elf32_swap_reloc_out (output_bfd, &outrel, - loc); + loc += sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); } } + else if (tls_type == GOT_TLS_IE_BOTH) + { + bfd_put_32 (output_bfd, + indx == 0 ? relocation - dtpoff_base (info) : 0, + htab->sgot->contents + off + 4); + outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF); + outrel.r_offset += 4; + htab->srelgot->reloc_count++; + loc += sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + } if (h != NULL) h->got.offset |= 1; @@ -2605,8 +2704,16 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, abort (); if (r_type == ELF32_R_TYPE (rel->r_info)) { - relocation = htab->sgot->output_offset + off; - unresolved_reloc = false; + bfd_vma g_o_t = htab->sgotplt->output_section->vma + + htab->sgotplt->output_offset; + relocation = htab->sgot->output_section->vma + + htab->sgot->output_offset + off - g_o_t; + if ((r_type == R_386_TLS_IE || r_type == R_386_TLS_GOTIE) + && tls_type == GOT_TLS_IE_BOTH) + relocation += 4; + if (r_type == R_386_TLS_IE) + relocation += g_o_t; + unresolved_reloc = FALSE; } else { @@ -2651,7 +2758,22 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, memcpy (contents + roff, "\x65\xa1\0\0\0\0\x2b\x80\0\0\0", 12); contents[roff + 7] = 0x80 | (val & 7); - bfd_put_32 (output_bfd, htab->sgot->output_offset + off, + /* If foo is used only with foo@gotntpoff(%reg) and + foo@indntpoff, but not with foo@gottpoff(%reg), change + subl $foo@gottpoff(%reg), %eax + into: + addl $foo@gotntpoff(%reg), %eax. */ + if (r_type == R_386_TLS_GOTIE) + { + contents[roff + 6] = 0x03; + if (tls_type == GOT_TLS_IE_BOTH) + off += 4; + } + bfd_put_32 (output_bfd, + htab->sgot->output_section->vma + + htab->sgot->output_offset + off + - htab->sgotplt->output_section->vma + - htab->sgotplt->output_offset, contents + roff + 8); /* Skip R_386_PLT32. */ rel++; @@ -2694,8 +2816,8 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, off &= ~1; else { - Elf_Internal_Rel outrel; - Elf32_External_Rel *loc; + Elf_Internal_Rela outrel; + bfd_byte *loc; if (htab->srelgot == NULL) abort (); @@ -2708,17 +2830,20 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, bfd_put_32 (output_bfd, 0, htab->sgot->contents + off + 4); outrel.r_info = ELF32_R_INFO (0, R_386_TLS_DTPMOD32); - loc = (Elf32_External_Rel *) htab->srelgot->contents; - loc += htab->srelgot->reloc_count++; + loc = htab->srelgot->contents; + loc += htab->srelgot->reloc_count++ * sizeof (Elf32_External_Rel); bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); htab->tls_ldm_got.offset |= 1; } - relocation = htab->sgot->output_offset + off; - unresolved_reloc = false; + relocation = htab->sgot->output_section->vma + + htab->sgot->output_offset + off + - htab->sgotplt->output_section->vma + - htab->sgotplt->output_offset; + unresolved_reloc = FALSE; break; case R_386_TLS_LDO_32: - if (info->shared) + if (info->shared || (input_section->flags & SEC_CODE) == 0) relocation -= dtpoff_base (info); else /* When converting LDO to LE, we must negate. */ @@ -2726,11 +2851,42 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, break; case R_386_TLS_LE_32: - relocation = tpoff (info, relocation); - break; - case R_386_TLS_LE: - relocation = -tpoff (info, relocation); + if (info->shared) + { + Elf_Internal_Rela outrel; + asection *sreloc; + bfd_byte *loc; + int indx; + + outrel.r_offset = rel->r_offset + + input_section->output_section->vma + + input_section->output_offset; + if (h != NULL && h->dynindx != -1) + indx = h->dynindx; + else + indx = 0; + if (r_type == R_386_TLS_LE_32) + outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF32); + else + outrel.r_info = ELF32_R_INFO (indx, R_386_TLS_TPOFF); + sreloc = elf_section_data (input_section)->sreloc; + if (sreloc == NULL) + abort (); + loc = sreloc->contents; + loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rel); + bfd_elf32_swap_reloc_out (output_bfd, &outrel, loc); + if (indx) + continue; + else if (r_type == R_386_TLS_LE_32) + relocation = dtpoff_base (info) - relocation; + else + relocation -= dtpoff_base (info); + } + else if (r_type == R_386_TLS_LE_32) + relocation = tpoff (info, relocation); + else + relocation = -tpoff (info, relocation); break; default: @@ -2743,16 +2899,19 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, if (unresolved_reloc && !((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_archive_filename (input_bfd), - bfd_get_section_name (input_bfd, input_section), - (long) rel->r_offset, - h->root.root.string); + { + (*_bfd_error_handler) + (_("%s(%s+0x%lx): unresolvable relocation against symbol `%s'"), + bfd_archive_filename (input_bfd), + bfd_get_section_name (input_bfd, input_section), + (long) rel->r_offset, + h->root.root.string); + return FALSE; + } r = _bfd_final_link_relocate (howto, input_bfd, input_section, contents, rel->r_offset, - relocation, (bfd_vma) 0); + relocation, 0); if (r != bfd_reloc_ok) { @@ -2766,7 +2925,7 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, symtab_hdr->sh_link, sym->st_name); if (name == NULL) - return false; + return FALSE; if (*name == '\0') name = bfd_section_name (input_bfd, sec); } @@ -2774,9 +2933,9 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, if (r == bfd_reloc_overflow) { if (! ((*info->callbacks->reloc_overflow) - (info, name, howto->name, (bfd_vma) 0, + (info, name, howto->name, 0, input_bfd, input_section, rel->r_offset))) - return false; + return FALSE; } else { @@ -2785,23 +2944,22 @@ elf_i386_relocate_section (output_bfd, info, input_bfd, input_section, bfd_archive_filename (input_bfd), bfd_get_section_name (input_bfd, input_section), (long) rel->r_offset, name, (int) r); - return false; + return FALSE; } } } - return true; + return TRUE; } /* Finish up dynamic symbol handling. We set the contents of various dynamic sections here. */ -static boolean -elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) - bfd *output_bfd; - struct bfd_link_info *info; - struct elf_link_hash_entry *h; - Elf_Internal_Sym *sym; +static bfd_boolean +elf_i386_finish_dynamic_symbol (bfd *output_bfd, + struct bfd_link_info *info, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) { struct elf_i386_link_hash_table *htab; @@ -2811,8 +2969,8 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) { bfd_vma plt_index; bfd_vma got_offset; - Elf_Internal_Rel rel; - Elf32_External_Rel *loc; + Elf_Internal_Rela rel; + bfd_byte *loc; /* This symbol has an entry in the procedure linkage table. Set it up. */ @@ -2871,26 +3029,31 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) + htab->sgotplt->output_offset + got_offset); rel.r_info = ELF32_R_INFO (h->dynindx, R_386_JUMP_SLOT); - loc = (Elf32_External_Rel *) htab->srelplt->contents + plt_index; + loc = htab->srelplt->contents + plt_index * sizeof (Elf32_External_Rel); bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); if ((h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR) == 0) { /* Mark the symbol as undefined, rather than as defined in - the .plt section. Leave the value alone. This is a clue + the .plt section. Leave the value if there were any + relocations where pointer equality matters (this is a clue for the dynamic linker, to make function pointer comparisons work between an application and shared - library. */ + library), otherwise set it to zero. If a function is only + called from a binary, there is no need to slow down + shared libraries because of that. */ sym->st_shndx = SHN_UNDEF; + if ((h->elf_link_hash_flags & ELF_LINK_POINTER_EQUALITY_NEEDED) == 0) + sym->st_value = 0; } } if (h->got.offset != (bfd_vma) -1 && elf_i386_hash_entry(h)->tls_type != GOT_TLS_GD - && elf_i386_hash_entry(h)->tls_type != GOT_TLS_IE) + && (elf_i386_hash_entry(h)->tls_type & GOT_TLS_IE) == 0) { - Elf_Internal_Rel rel; - Elf32_External_Rel *loc; + Elf_Internal_Rela rel; + bfd_byte *loc; /* This symbol has an entry in the global offset table. Set it up. */ @@ -2908,10 +3071,7 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) 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_FORCED_LOCAL)) - && (h->elf_link_hash_flags & ELF_LINK_HASH_DEF_REGULAR)) + && SYMBOL_REFERENCES_LOCAL (info, h)) { BFD_ASSERT((h->got.offset & 1) != 0); rel.r_info = ELF32_R_INFO (0, R_386_RELATIVE); @@ -2924,15 +3084,15 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) rel.r_info = ELF32_R_INFO (h->dynindx, R_386_GLOB_DAT); } - loc = (Elf32_External_Rel *) htab->srelgot->contents; - loc += htab->srelgot->reloc_count++; + loc = htab->srelgot->contents; + loc += htab->srelgot->reloc_count++ * sizeof (Elf32_External_Rel); bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); } if ((h->elf_link_hash_flags & ELF_LINK_HASH_NEEDS_COPY) != 0) { - Elf_Internal_Rel rel; - Elf32_External_Rel *loc; + Elf_Internal_Rela rel; + bfd_byte *loc; /* This symbol needs a copy reloc. Set it up. */ @@ -2946,8 +3106,8 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) + 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); - loc = (Elf32_External_Rel *) htab->srelbss->contents; - loc += htab->srelbss->reloc_count++; + loc = htab->srelbss->contents; + loc += htab->srelbss->reloc_count++ * sizeof (Elf32_External_Rel); bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); } @@ -2956,17 +3116,16 @@ elf_i386_finish_dynamic_symbol (output_bfd, info, h, sym) || strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) sym->st_shndx = SHN_ABS; - return true; + return TRUE; } /* Used to decide how to sort relocs in an optimal manner for the dynamic linker, before writing them out. */ static enum elf_reloc_type_class -elf_i386_reloc_type_class (rela) - const Elf_Internal_Rela *rela; +elf_i386_reloc_type_class (const Elf_Internal_Rela *rela) { - switch ((int) ELF32_R_TYPE (rela->r_info)) + switch (ELF32_R_TYPE (rela->r_info)) { case R_386_RELATIVE: return reloc_class_relative; @@ -2981,10 +3140,9 @@ elf_i386_reloc_type_class (rela) /* Finish up the dynamic sections. */ -static boolean -elf_i386_finish_dynamic_sections (output_bfd, info) - bfd *output_bfd; - struct bfd_link_info *info; +static bfd_boolean +elf_i386_finish_dynamic_sections (bfd *output_bfd, + struct bfd_link_info *info) { struct elf_i386_link_hash_table *htab; bfd *dynobj; @@ -3016,19 +3174,18 @@ elf_i386_finish_dynamic_sections (output_bfd, info) continue; case DT_PLTGOT: - dyn.d_un.d_ptr = htab->sgot->output_section->vma; + s = htab->sgotplt; + dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; break; case DT_JMPREL: - dyn.d_un.d_ptr = htab->srelplt->output_section->vma; + s = htab->srelplt; + dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; break; case DT_PLTRELSZ: - s = htab->srelplt->output_section; - if (s->_cooked_size != 0) - dyn.d_un.d_val = s->_cooked_size; - else - dyn.d_un.d_val = s->_raw_size; + s = htab->srelplt; + dyn.d_un.d_val = s->_raw_size; break; case DT_RELSZ: @@ -3037,18 +3194,23 @@ elf_i386_finish_dynamic_sections (output_bfd, info) included in the overall relocs (DT_REL). This is what Solaris does. However, UnixWare can not handle that case. Therefore, we override the DT_RELSZ entry - here to make it not include the JMPREL relocs. Since - 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. */ - if (htab->srelplt != NULL) - { - s = htab->srelplt->output_section; - if (s->_cooked_size != 0) - dyn.d_un.d_val -= s->_cooked_size; - else - dyn.d_un.d_val -= s->_raw_size; - } + here to make it not include the JMPREL relocs. */ + s = htab->srelplt; + if (s == NULL) + continue; + dyn.d_un.d_val -= s->_raw_size; + break; + + case DT_REL: + /* We may not be using the standard ELF linker script. + If .rel.plt is the first .rel section, we adjust + DT_REL to not include it. */ + s = htab->srelplt; + if (s == NULL) + continue; + if (dyn.d_un.d_ptr != s->output_section->vma + s->output_offset) + continue; + dyn.d_un.d_ptr += s->_raw_size; break; } @@ -3090,18 +3252,33 @@ elf_i386_finish_dynamic_sections (output_bfd, info) if (htab->sgotplt->_raw_size > 0) { bfd_put_32 (output_bfd, - (sdyn == NULL ? (bfd_vma) 0 + (sdyn == NULL ? 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); + bfd_put_32 (output_bfd, 0, htab->sgotplt->contents + 4); + bfd_put_32 (output_bfd, 0, htab->sgotplt->contents + 8); } elf_section_data (htab->sgotplt->output_section)->this_hdr.sh_entsize = 4; } - return true; + + if (htab->sgot && htab->sgot->_raw_size > 0) + elf_section_data (htab->sgot->output_section)->this_hdr.sh_entsize = 4; + + return TRUE; } +/* Return address for Ith PLT stub in section PLT, for relocation REL + or (bfd_vma) -1 if it should not be included. */ + +static bfd_vma +elf_i386_plt_sym_val (bfd_vma i, const asection *plt, + const arelent *rel ATTRIBUTE_UNUSED) +{ + return plt->vma + (i + 1) * PLT_ENTRY_SIZE; +} + + #define TARGET_LITTLE_SYM bfd_elf32_i386_vec #define TARGET_LITTLE_NAME "elf32-i386" #define ELF_ARCH bfd_arch_i386 @@ -3114,13 +3291,12 @@ elf_i386_finish_dynamic_sections (output_bfd, info) #define elf_backend_plt_readonly 1 #define elf_backend_want_plt_sym 0 #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 +/* Support RELA for objdump of prelink objects. */ +#define elf_info_to_howto elf_i386_info_to_howto_rel #define elf_info_to_howto_rel elf_i386_info_to_howto_rel #define bfd_elf32_mkobject elf_i386_mkobject -#define elf_backend_object_p elf_i386_object_p #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 @@ -3140,7 +3316,40 @@ elf_i386_finish_dynamic_sections (output_bfd, info) #define elf_backend_reloc_type_class elf_i386_reloc_type_class #define elf_backend_relocate_section elf_i386_relocate_section #define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections +#define elf_backend_plt_sym_val elf_i386_plt_sym_val -#ifndef ELF32_I386_C_INCLUDED #include "elf32-target.h" + +/* FreeBSD support. */ + +#undef TARGET_LITTLE_SYM +#define TARGET_LITTLE_SYM bfd_elf32_i386_freebsd_vec +#undef TARGET_LITTLE_NAME +#define TARGET_LITTLE_NAME "elf32-i386-freebsd" + +/* The kernel recognizes executables as valid only if they carry a + "FreeBSD" label in the ELF header. So we put this label on all + executables and (for simplicity) also all other object files. */ + +static void +elf_i386_post_process_headers (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + Elf_Internal_Ehdr *i_ehdrp; + + i_ehdrp = elf_elfheader (abfd); + + /* Put an ABI label supported by FreeBSD >= 4.1. */ + i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; +#ifdef OLD_FREEBSD_ABI_LABEL + /* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard. */ + memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8); #endif +} + +#undef elf_backend_post_process_headers +#define elf_backend_post_process_headers elf_i386_post_process_headers +#undef elf32_bed +#define elf32_bed elf32_i386_fbsd_bed + +#include "elf32-target.h"