X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felf32-i386.c;h=dda6e1fa22537f774d57a8141d1a9bb887102d09;hb=7df3ce47694f5c804a9468d4c098825b5901216e;hp=754aa52254d5509d8b13a296884c54fc7f860ced;hpb=cb878726df95ae9effe3b5b06a519bf2f2786226;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elf32-i386.c b/bfd/elf32-i386.c index 754aa52254..dda6e1fa22 100644 --- a/bfd/elf32-i386.c +++ b/bfd/elf32-i386.c @@ -1,12 +1,12 @@ /* Intel 80386/80486-specific support for 32-bit ELF Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, - 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. 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 + the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, @@ -16,14 +16,16 @@ 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., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, + MA 02110-1301, USA. */ -#include "bfd.h" #include "sysdep.h" +#include "bfd.h" #include "bfdlink.h" #include "libbfd.h" #include "elf-bfd.h" #include "elf-vxworks.h" +#include "bfd_stdint.h" /* 386 uses REL relocations instead of RELA. */ #define USE_REL 1 @@ -330,12 +332,23 @@ elf_i386_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, return 0; } -static void -elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, - arelent *cache_ptr, - Elf_Internal_Rela *dst) +static reloc_howto_type * +elf_i386_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 0; i < sizeof (elf_howto_table) / sizeof (elf_howto_table[0]); i++) + if (elf_howto_table[i].name != NULL + && strcasecmp (elf_howto_table[i].name, r_name) == 0) + return &elf_howto_table[i]; + + return NULL; +} + +static reloc_howto_type * +elf_i386_rtype_to_howto (bfd *abfd, unsigned r_type) { - unsigned int r_type = ELF32_R_TYPE (dst->r_info); unsigned int indx; if ((indx = r_type) >= R_386_standard @@ -350,7 +363,17 @@ elf_i386_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED, abfd, (int) r_type); indx = R_386_NONE; } - cache_ptr->howto = &elf_howto_table[indx]; + BFD_ASSERT (elf_howto_table [indx].type == r_type); + return &elf_howto_table[indx]; +} + +static void +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); + cache_ptr->howto = elf_i386_rtype_to_howto (abfd, r_type); } /* Return whether a symbol name implies a local label. The UnixWare @@ -582,10 +605,6 @@ struct elf_i386_link_hash_entry #define GOT_TLS_IE_NEG 6 #define GOT_TLS_IE_BOTH 7 #define GOT_TLS_GDESC 8 -#define GOT_TLS_MASK 0x0f -#define GOT_TLS_IE_IE 0x10 -#define GOT_TLS_IE_GD 0x20 -#define GOT_TLS_IE_MASK 0x30 #define GOT_TLS_GD_BOTH_P(type) \ ((type) == (GOT_TLS_GD | GOT_TLS_GDESC)) #define GOT_TLS_GD_P(type) \ @@ -623,14 +642,16 @@ struct elf_i386_obj_tdata #define elf_i386_local_tlsdesc_gotent(abfd) \ (elf_i386_tdata (abfd)->local_tlsdesc_gotent) +#define is_i386_elf(bfd) \ + (bfd_get_flavour (bfd) == bfd_target_elf_flavour \ + && elf_tdata (bfd) != NULL \ + && elf_object_id (bfd) == I386_ELF_TDATA) + 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; + return bfd_elf_allocate_object (abfd, sizeof (struct elf_i386_obj_tdata), + I386_ELF_TDATA); } /* i386 ELF linker hash table. */ @@ -671,6 +692,9 @@ struct elf_i386_link_hash_table /* Small local sym to section mapping cache. */ struct sym_sec_cache sym_sec; + + /* _TLS_MODULE_BASE_ symbol. */ + struct bfd_link_hash_entry *tls_module_base; }; /* Get the i386 ELF linker hash table from a link_info structure. */ @@ -746,6 +770,7 @@ elf_i386_link_hash_table_create (bfd *abfd) ret->is_vxworks = 0; ret->srelplt2 = NULL; ret->plt0_pad_byte = 0; + ret->tls_module_base = NULL; return &ret->elf.root; } @@ -879,31 +904,293 @@ elf_i386_copy_indirect_symbol (struct bfd_link_info *info, _bfd_elf_link_hash_copy_indirect (info, dir, ind); } -static int -elf_i386_tls_transition (struct bfd_link_info *info, int r_type, int is_local) +typedef union + { + unsigned char c[2]; + uint16_t i; + } +i386_opcode16; + +/* Return TRUE if the TLS access code sequence support transition + from R_TYPE. */ + +static bfd_boolean +elf_i386_check_tls_transition (bfd *abfd, asection *sec, + bfd_byte *contents, + Elf_Internal_Shdr *symtab_hdr, + struct elf_link_hash_entry **sym_hashes, + unsigned int r_type, + const Elf_Internal_Rela *rel, + const Elf_Internal_Rela *relend) { - if (info->shared) - return r_type; + unsigned int val, type; + unsigned long r_symndx; + struct elf_link_hash_entry *h; + bfd_vma offset; + + /* Get the section contents. */ + if (contents == NULL) + { + if (elf_section_data (sec)->this_hdr.contents != NULL) + contents = elf_section_data (sec)->this_hdr.contents; + else + { + /* FIXME: How to better handle error condition? */ + if (!bfd_malloc_and_get_section (abfd, sec, &contents)) + return FALSE; + /* Cache the section contents for elf_link_input_bfd. */ + elf_section_data (sec)->this_hdr.contents = contents; + } + } + + offset = rel->r_offset; switch (r_type) + { + case R_386_TLS_GD: + case R_386_TLS_LDM: + if (offset < 2 || (rel + 1) >= relend) + return FALSE; + + type = bfd_get_8 (abfd, contents + offset - 2); + if (r_type == R_386_TLS_GD) + { + /* Check transition from LD access model. Only + leal foo@tlsgd(,%reg,1), %eax; call ___tls_get_addr + leal foo@tlsgd(%reg), %eax; call ___tls_get_addr; nop + can transit to different access model. */ + if ((offset + 10) > sec->size || + (type != 0x8d && type != 0x04)) + return FALSE; + + val = bfd_get_8 (abfd, contents + offset - 1); + if (type == 0x04) + { + /* leal foo@tlsgd(,%reg,1), %eax; call ___tls_get_addr */ + if (offset < 3) + return FALSE; + + if (bfd_get_8 (abfd, contents + offset - 3) != 0x8d) + return FALSE; + + if ((val & 0xc7) != 0x05 || val == (4 << 3)) + return FALSE; + } + else + { + /* leal foo@tlsgd(%reg), %eax; call ___tls_get_addr; nop */ + if ((val & 0xf8) != 0x80 || (val & 7) == 4) + return FALSE; + + if (bfd_get_8 (abfd, contents + offset + 9) != 0x90) + return FALSE; + } + } + else + { + /* Check transition from LD access model. Only + leal foo@tlsgd(%reg), %eax; call ___tls_get_addr + can transit to different access model. */ + if (type != 0x8d || (offset + 9) > sec->size) + return FALSE; + + val = bfd_get_8 (abfd, contents + offset - 1); + if ((val & 0xf8) != 0x80 || (val & 7) == 4) + return FALSE; + } + + if (bfd_get_8 (abfd, contents + offset + 4) != 0xe8) + return FALSE; + + r_symndx = ELF32_R_SYM (rel[1].r_info); + if (r_symndx < symtab_hdr->sh_info) + return FALSE; + + h = sym_hashes[r_symndx - symtab_hdr->sh_info]; + return (h != NULL + && h->root.root.string != NULL + && (ELF32_R_TYPE (rel[1].r_info) == R_386_PC32 + || ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32) + && (strcmp (h->root.root.string, "___tls_get_addr") == 0)); + + case R_386_TLS_IE: + /* Check transition from IE access model: + movl foo@indntpoff(%rip), %eax + movl foo@indntpoff(%rip), %reg + addl foo@indntpoff(%rip), %reg + */ + + if (offset < 1 || (offset + 4) > sec->size) + return FALSE; + + /* Check "movl foo@tpoff(%rip), %eax" first. */ + val = bfd_get_8 (abfd, contents + offset - 1); + if (val == 0xa1) + return TRUE; + + if (offset < 2) + return FALSE; + + /* Check movl|addl foo@tpoff(%rip), %reg. */ + type = bfd_get_8 (abfd, contents + offset - 2); + return ((type == 0x8b || type == 0x03) + && (val & 0xc7) == 0x05); + + case R_386_TLS_GOTIE: + case R_386_TLS_IE_32: + /* Check transition from {IE_32,GOTIE} access model: + subl foo@{tpoff,gontoff}(%reg1), %reg2 + movl foo@{tpoff,gontoff}(%reg1), %reg2 + addl foo@{tpoff,gontoff}(%reg1), %reg2 + */ + + if (offset < 2 || (offset + 4) > sec->size) + return FALSE; + + val = bfd_get_8 (abfd, contents + offset - 1); + if ((val & 0xc0) != 0x80 || (val & 7) == 4) + return FALSE; + + type = bfd_get_8 (abfd, contents + offset - 2); + return type == 0x8b || type == 0x2b || type == 0x03; + + case R_386_TLS_GOTDESC: + /* Check transition from GDesc access model: + leal x@tlsdesc(%ebx), %eax + + Make sure it's a leal adding ebx to a 32-bit offset + into any register, although it's probably almost always + going to be eax. */ + + if (offset < 2 || (offset + 4) > sec->size) + return FALSE; + + if (bfd_get_8 (abfd, contents + offset - 2) != 0x8d) + return FALSE; + + val = bfd_get_8 (abfd, contents + offset - 1); + return (val & 0xc7) == 0x83; + + case R_386_TLS_DESC_CALL: + /* Check transition from GDesc access model: + call *x@tlsdesc(%rax) + */ + if (offset + 2 <= sec->size) + { + /* Make sure that it's a call *x@tlsdesc(%rax). */ + static i386_opcode16 call = { { 0xff, 0x10 } }; + return bfd_get_16 (abfd, contents + offset) == call.i; + } + + return FALSE; + + default: + abort (); + } +} + +/* Return TRUE if the TLS access transition is OK or no transition + will be performed. Update R_TYPE if there is a transition. */ + +static bfd_boolean +elf_i386_tls_transition (struct bfd_link_info *info, bfd *abfd, + asection *sec, bfd_byte *contents, + Elf_Internal_Shdr *symtab_hdr, + struct elf_link_hash_entry **sym_hashes, + unsigned int *r_type, int tls_type, + const Elf_Internal_Rela *rel, + const Elf_Internal_Rela *relend, + struct elf_link_hash_entry *h) +{ + unsigned int from_type = *r_type; + unsigned int to_type = from_type; + bfd_boolean check = TRUE; + + switch (from_type) { case R_386_TLS_GD: case R_386_TLS_GOTDESC: case R_386_TLS_DESC_CALL: case R_386_TLS_IE_32: - 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; + if (!info->shared) + { + if (h == NULL) + to_type = R_386_TLS_LE_32; + else if (from_type != R_386_TLS_IE + && from_type != R_386_TLS_GOTIE) + to_type = R_386_TLS_IE_32; + } + + /* When we are called from elf_i386_relocate_section, CONTENTS + isn't NULL and there may be additional transitions based on + TLS_TYPE. */ + if (contents != NULL) + { + unsigned int new_to_type = to_type; + + if (!info->shared + && h != NULL + && h->dynindx == -1 + && (tls_type & GOT_TLS_IE)) + new_to_type = R_386_TLS_LE_32; + + if (to_type == R_386_TLS_GD + || to_type == R_386_TLS_GOTDESC + || to_type == R_386_TLS_DESC_CALL) + { + if (tls_type == GOT_TLS_IE_POS) + new_to_type = R_386_TLS_GOTIE; + else if (tls_type & GOT_TLS_IE) + new_to_type = R_386_TLS_IE_32; + } + + /* We checked the transition before when we were called from + elf_i386_check_relocs. We only want to check the new + transition which hasn't been checked before. */ + check = new_to_type != to_type && from_type == to_type; + to_type = new_to_type; + } + + break; + case R_386_TLS_LDM: - return R_386_TLS_LE_32; + if (!info->shared) + to_type = R_386_TLS_LE_32; + break; + + default: + return TRUE; } - return r_type; + /* Return TRUE if there is no transition. */ + if (from_type == to_type) + return TRUE; + + /* Check if the transition can be performed. */ + if (check + && ! elf_i386_check_tls_transition (abfd, sec, contents, + symtab_hdr, sym_hashes, + from_type, rel, relend)) + { + reloc_howto_type *from, *to; + + from = elf_i386_rtype_to_howto (abfd, from_type); + to = elf_i386_rtype_to_howto (abfd, to_type); + + (*_bfd_error_handler) + (_("%B: TLS transition from %s to %s against `%s' at 0x%lx " + "in section `%A' failed"), + abfd, sec, from->name, to->name, + h ? h->root.root.string : "a local symbol", + (unsigned long) rel->r_offset); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + + *r_type = to_type; + return TRUE; } /* Look through the relocs for a section during the first phase, and @@ -926,8 +1213,10 @@ elf_i386_check_relocs (bfd *abfd, if (info->relocatable) return TRUE; + BFD_ASSERT (is_i386_elf (abfd)); + htab = elf_i386_hash_table (info); - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + symtab_hdr = &elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); sreloc = NULL; @@ -960,7 +1249,11 @@ elf_i386_check_relocs (bfd *abfd, h = (struct elf_link_hash_entry *) h->root.u.i.link; } - r_type = elf_i386_tls_transition (info, r_type, h == NULL); + if (! elf_i386_tls_transition (info, abfd, sec, NULL, + symtab_hdr, sym_hashes, + &r_type, GOT_UNKNOWN, + rel, rel_end, h)) + return FALSE; switch (r_type) { @@ -1011,25 +1304,12 @@ elf_i386_check_relocs (bfd *abfd, case R_386_TLS_IE_32: if (ELF32_R_TYPE (rel->r_info) == r_type) tls_type = GOT_TLS_IE_NEG; - else if (h - && ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD) - /* If this is a GD->IE transition, we may use either - of R_386_TLS_TPOFF and R_386_TLS_TPOFF32. But if - we may have both R_386_TLS_IE and R_386_TLS_GD, - we can't share the same R_386_TLS_TPOFF since - they require different offsets. So we remember - it comes from R_386_TLS_GD. */ - tls_type = GOT_TLS_IE | GOT_TLS_IE_GD; 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: - if (h) - { - /* We remember it comes from R_386_TLS_IE. */ - tls_type = GOT_TLS_IE_POS | GOT_TLS_IE_IE; - break; - } case R_386_TLS_GOTIE: tls_type = GOT_TLS_IE_POS; break; } @@ -1069,8 +1349,7 @@ elf_i386_check_relocs (bfd *abfd, 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. */ - else if (old_tls_type != tls_type - && old_tls_type != GOT_UNKNOWN + else if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN && (! GOT_TLS_GD_ANY_P (old_tls_type) || (tls_type & GOT_TLS_IE) == 0)) { @@ -1165,7 +1444,7 @@ elf_i386_check_relocs (bfd *abfd, && (sec->flags & SEC_ALLOC) != 0 && (r_type != R_386_PC32 || (h != NULL - && (! info->symbolic + && (! SYMBOLIC_BIND (info, h) || h->root.type == bfd_link_hash_defweak || !h->def_regular)))) || (ELIMINATE_COPY_RELOCS @@ -1183,45 +1462,14 @@ elf_i386_check_relocs (bfd *abfd, this reloc. */ if (sreloc == NULL) { - const char *name; - bfd *dynobj; - unsigned int strndx = elf_elfheader (abfd)->e_shstrndx; - unsigned int shnam = elf_section_data (sec)->rel_hdr.sh_name; - - name = bfd_elf_string_from_elf_section (abfd, strndx, shnam); - if (name == NULL) - return FALSE; - - if (strncmp (name, ".rel", 4) != 0 - || strcmp (bfd_get_section_name (abfd, sec), - name + 4) != 0) - { - (*_bfd_error_handler) - (_("%B: bad relocation section name `%s\'"), - abfd, name); - } - if (htab->elf.dynobj == NULL) htab->elf.dynobj = abfd; - dynobj = htab->elf.dynobj; - sreloc = bfd_get_section_by_name (dynobj, name); + sreloc = _bfd_elf_make_dynamic_reloc_section + (sec, htab->elf.dynobj, 2, abfd, /*rela?*/ FALSE); + if (sreloc == NULL) - { - flagword flags; - - flags = (SEC_HAS_CONTENTS | SEC_READONLY - | SEC_IN_MEMORY | SEC_LINKER_CREATED); - if ((sec->flags & SEC_ALLOC) != 0) - flags |= SEC_ALLOC | SEC_LOAD; - sreloc = bfd_make_section_with_flags (dynobj, - name, - flags); - if (sreloc == NULL - || ! bfd_set_section_alignment (dynobj, sreloc, 2)) - return FALSE; - } - elf_section_data (sec)->sreloc = sreloc; + return FALSE; } /* If this is a global symbol, we count the number of @@ -1277,7 +1525,9 @@ elf_i386_check_relocs (bfd *abfd, /* This relocation describes which C++ vtable entries are actually used. Record for later use during GC. */ case R_386_GNU_VTENTRY: - if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) + BFD_ASSERT (h != NULL); + if (h != NULL + && !bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset)) return FALSE; break; @@ -1294,38 +1544,20 @@ elf_i386_check_relocs (bfd *abfd, static asection * elf_i386_gc_mark_hook (asection *sec, - struct bfd_link_info *info ATTRIBUTE_UNUSED, + struct bfd_link_info *info, Elf_Internal_Rela *rel, struct elf_link_hash_entry *h, Elf_Internal_Sym *sym) { if (h != NULL) - { - switch (ELF32_R_TYPE (rel->r_info)) - { - case R_386_GNU_VTINHERIT: - case R_386_GNU_VTENTRY: - break; - - default: - switch (h->root.type) - { - case bfd_link_hash_defined: - case bfd_link_hash_defweak: - return h->root.u.def.section; - - case bfd_link_hash_common: - return h->root.u.c.p->section; - - default: - break; - } - } - } - else - return bfd_section_from_elf_index (sec->owner, sym->st_shndx); - - return NULL; + switch (ELF32_R_TYPE (rel->r_info)) + { + case R_386_GNU_VTINHERIT: + case R_386_GNU_VTENTRY: + return NULL; + } + + return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); } /* Update the got entry reference counts for the section being removed. */ @@ -1341,9 +1573,12 @@ elf_i386_gc_sweep_hook (bfd *abfd, bfd_signed_vma *local_got_refcounts; const Elf_Internal_Rela *rel, *relend; + if (info->relocatable) + return TRUE; + elf_section_data (sec)->local_dynrel = NULL; - symtab_hdr = &elf_tdata (abfd)->symtab_hdr; + symtab_hdr = &elf_symtab_hdr (abfd); sym_hashes = elf_sym_hashes (abfd); local_got_refcounts = elf_local_got_refcounts (abfd); @@ -1377,7 +1612,12 @@ elf_i386_gc_sweep_hook (bfd *abfd, } r_type = ELF32_R_TYPE (rel->r_info); - r_type = elf_i386_tls_transition (info, r_type, h != NULL); + if (! elf_i386_tls_transition (info, abfd, sec, NULL, + symtab_hdr, sym_hashes, + &r_type, GOT_UNKNOWN, + rel, relend, h)) + return FALSE; + switch (r_type) { case R_386_TLS_LDM: @@ -1438,7 +1678,6 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, { struct elf_i386_link_hash_table *htab; asection *s; - unsigned int power_of_two; /* If this is a function, put it in the procedure linkage table. We will fill in the contents of the procedure linkage table later, @@ -1558,29 +1797,9 @@ elf_i386_adjust_dynamic_symbol (struct bfd_link_info *info, h->needs_copy = 1; } - /* We need to figure out the alignment required for this symbol. I - have no idea how ELF linkers handle this. */ - power_of_two = bfd_log2 (h->size); - if (power_of_two > 3) - power_of_two = 3; - - /* Apply the required alignment. */ s = htab->sdynbss; - s->size = BFD_ALIGN (s->size, (bfd_size_type) (1 << power_of_two)); - 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; - } - - /* Define the symbol as being at this point in the section. */ - h->root.u.def.section = s; - h->root.u.def.value = s->size; - - /* Increment the section size to make room for the symbol. */ - s->size += h->size; - return TRUE; + return _bfd_elf_adjust_dynamic_copy (h, s); } /* Allocate space in .plt, .got and associated reloc sections for @@ -1700,14 +1919,6 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) asection *s; bfd_boolean dyn; int tls_type = elf_i386_hash_entry(h)->tls_type; - - /* If we have both R_386_TLS_IE and R_386_TLS_GD, GOT_TLS_IE_BOTH - should be used. */ - if ((tls_type & GOT_TLS_IE_MASK) - == (GOT_TLS_IE_IE | GOT_TLS_IE_GD)) - tls_type = GOT_TLS_IE_BOTH; - else - tls_type &= GOT_TLS_MASK; /* Make sure this symbol is output as a dynamic symbol. Undefined weak syms won't yet be marked as dynamic. */ @@ -1792,8 +2003,20 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) } } + if (htab->is_vxworks) + { + struct elf_i386_dyn_relocs **pp; + for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) + { + if (strcmp (p->sec->output_section->name, ".tls_vars") == 0) + *pp = p->next; + else + pp = &p->next; + } + } + /* Also discard relocs on undefined weak syms with non-default - visibility. */ + visibility. */ if (eh->dyn_relocs != NULL && h->root.type == bfd_link_hash_undefweak) { @@ -1846,7 +2069,11 @@ allocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) /* Finally, allocate space. */ for (p = eh->dyn_relocs; p != NULL; p = p->next) { - asection *sreloc = elf_section_data (p->sec)->sreloc; + asection *sreloc; + + sreloc = elf_section_data (p->sec)->sreloc; + + BFD_ASSERT (sreloc != NULL); sreloc->size += p->count * sizeof (Elf32_External_Rel); } @@ -1924,7 +2151,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, Elf_Internal_Shdr *symtab_hdr; asection *srel; - if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) + if (! is_i386_elf (ibfd)) continue; for (s = ibfd->sections; s != NULL; s = s->next) @@ -1944,6 +2171,13 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, linker script /DISCARD/, so we'll be discarding the relocs too. */ } + else if (htab->is_vxworks + && strcmp (p->sec->output_section->name, + ".tls_vars") == 0) + { + /* Relocations in vxworks .tls_vars sections are + handled specially by the loader. */ + } else if (p->count != 0) { srel = elf_section_data (p->sec)->sreloc; @@ -1958,7 +2192,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (!local_got) continue; - symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; + symtab_hdr = &elf_symtab_hdr (ibfd); locsymcount = symtab_hdr->sh_info; end_local_got = local_got + locsymcount; local_tls_type = elf_i386_local_got_tls_type (ibfd); @@ -2018,7 +2252,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* Allocate global sym .plt and .got entries, and space for global sym dynamic relocs. */ - elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info); + elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info); /* For every jump slot reserved in the sgotplt, reloc_count is incremented. However, when we reserve space for TLS descriptors, @@ -2052,7 +2286,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, if (htab->elf.hplt != NULL) strip_section = FALSE; } - else if (strncmp (bfd_get_section_name (dynobj, s), ".rel", 4) == 0) + else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rel")) { if (s->size != 0 && s != htab->srelplt && s != htab->srelplt2) relocs = TRUE; @@ -2131,8 +2365,7 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, /* If any dynamic relocs apply to a read-only section, then we need a DT_TEXTREL entry. */ if ((info->flags & DF_TEXTREL) == 0) - elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, - (PTR) info); + elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, info); if ((info->flags & DF_TEXTREL) != 0) { @@ -2140,6 +2373,9 @@ elf_i386_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, return FALSE; } } + if (htab->is_vxworks + && !elf_vxworks_add_dynamic_entries (output_bfd, info)) + return FALSE; } #undef add_dynamic_entry @@ -2171,6 +2407,9 @@ elf_i386_always_size_sections (bfd *output_bfd, tls_sec, 0, NULL, FALSE, bed->collect, &bh))) return FALSE; + + elf_i386_hash_table (info)->tls_module_base = bh; + tlsbase = (struct elf_link_hash_entry *)bh; tlsbase->def_regular = 1; tlsbase->other = STV_HIDDEN; @@ -2215,6 +2454,27 @@ elf_i386_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, return TRUE; } +/* _TLS_MODULE_BASE_ needs to be treated especially when linking + executables. Rather than setting it to the beginning of the TLS + section, we have to set it to the end. This function may be called + multiple times, it is idempotent. */ + +static void +set_tls_module_base (struct bfd_link_info *info) +{ + struct bfd_link_hash_entry *base; + + if (!info->executable) + return; + + base = elf_i386_hash_table (info)->tls_module_base; + + if (!base) + return; + + base->u.def.value = elf_hash_table (info)->tls_size; +} + /* Return the base VMA address which should be subtracted from real addresses when resolving @dtpoff relocation. This is PT_TLS segment p_vaddr. */ @@ -2261,12 +2521,22 @@ elf_i386_relocate_section (bfd *output_bfd, bfd_vma *local_tlsdesc_gotents; Elf_Internal_Rela *rel; Elf_Internal_Rela *relend; + bfd_boolean is_vxworks_tls; + BFD_ASSERT (is_i386_elf (input_bfd)); + htab = elf_i386_hash_table (info); - symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; + symtab_hdr = &elf_symtab_hdr (input_bfd); sym_hashes = elf_sym_hashes (input_bfd); local_got_offsets = elf_local_got_offsets (input_bfd); local_tlsdesc_gotents = elf_i386_local_tlsdesc_gotent (input_bfd); + /* We have to handle relocations in vxworks .tls_vars sections + specially, because the dynamic loader is 'weird'. */ + is_vxworks_tls = (htab->is_vxworks && info->shared + && !strcmp (input_section->output_section->name, + ".tls_vars")); + + set_tls_module_base (info); rel = relocs; relend = relocs + input_section->reloc_count; @@ -2305,51 +2575,6 @@ elf_i386_relocate_section (bfd *output_bfd, howto = elf_howto_table + indx; r_symndx = ELF32_R_SYM (rel->r_info); - - if (info->relocatable) - { - bfd_vma val; - bfd_byte *where; - - /* This is a relocatable link. We don't have to change - anything, unless the reloc is against a section symbol, - in which case we have to adjust according to where the - section symbol winds up in the output section. */ - if (r_symndx >= symtab_hdr->sh_info) - continue; - - sym = local_syms + r_symndx; - if (ELF_ST_TYPE (sym->st_info) != STT_SECTION) - continue; - - sec = local_sections[r_symndx]; - val = sec->output_offset; - if (val == 0) - continue; - - where = contents + rel->r_offset; - switch (howto->size) - { - /* FIXME: overflow checks. */ - case 0: - val += bfd_get_8 (input_bfd, where); - bfd_put_8 (input_bfd, val, where); - break; - case 1: - val += bfd_get_16 (input_bfd, where); - bfd_put_16 (input_bfd, val, where); - break; - case 2: - val += bfd_get_32 (input_bfd, where); - bfd_put_32 (input_bfd, val, where); - break; - default: - abort (); - } - continue; - } - - /* This is a final link. */ h = NULL; sym = NULL; sec = NULL; @@ -2361,10 +2586,12 @@ elf_i386_relocate_section (bfd *output_bfd, relocation = (sec->output_section->vma + sec->output_offset + sym->st_value); - if ((sec->flags & SEC_MERGE) - && ELF_ST_TYPE (sym->st_info) == STT_SECTION) + + if (ELF_ST_TYPE (sym->st_info) == STT_SECTION + && ((sec->flags & SEC_MERGE) != 0 + || (info->relocatable + && sec->output_offset != 0))) { - asection *msec; bfd_vma addend; bfd_byte *where = contents + rel->r_offset; @@ -2398,10 +2625,16 @@ elf_i386_relocate_section (bfd *output_bfd, abort (); } - msec = sec; - addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend); - addend -= relocation; - addend += msec->output_section->vma + msec->output_offset; + if (info->relocatable) + addend += sec->output_offset; + else + { + asection *msec = sec; + addend = _bfd_elf_rel_local_sym (output_bfd, sym, &msec, + addend); + addend -= relocation; + addend += msec->output_section->vma + msec->output_offset; + } switch (howto->size) { @@ -2434,21 +2667,20 @@ elf_i386_relocate_section (bfd *output_bfd, unresolved_reloc, warned); } - if (r_symndx == 0) + if (sec != NULL && elf_discarded_section (sec)) { - /* r_symndx will be zero only for relocs against symbols from - removed linkonce sections, or sections discarded by a linker - script. For these relocs, we just want the section contents - zeroed. Avoid any special processing in the switch below. */ - r_type = R_386_NONE; - - relocation = 0; - if (howto->pc_relative) - relocation = (input_section->output_section->vma - + input_section->output_offset - + rel->r_offset); + /* For relocs against symbols from removed linkonce sections, + or sections discarded by a linker script, we just want the + section contents zeroed. Avoid any special processing. */ + _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); + rel->r_info = 0; + rel->r_addend = 0; + continue; } + if (info->relocatable) + continue; + switch (r_type) { case R_386_GOT32: @@ -2548,19 +2780,46 @@ elf_i386_relocate_section (bfd *output_bfd, /* Check to make sure it isn't a protected function symbol for shared library since it may not be local when used - as function address. */ - if (info->shared - && !info->executable - && h - && h->def_regular - && h->type == STT_FUNC - && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) + as function address. We also need to make sure that a + symbol is defined locally. */ + if (info->shared && h) { - (*_bfd_error_handler) - (_("%B: relocation R_386_GOTOFF against protected function `%s' can not be used when making a shared object"), - input_bfd, h->root.root.string); - bfd_set_error (bfd_error_bad_value); - return FALSE; + if (!h->def_regular) + { + const char *v; + + switch (ELF_ST_VISIBILITY (h->other)) + { + case STV_HIDDEN: + v = _("hidden symbol"); + break; + case STV_INTERNAL: + v = _("internal symbol"); + break; + case STV_PROTECTED: + v = _("protected symbol"); + break; + default: + v = _("symbol"); + break; + } + + (*_bfd_error_handler) + (_("%B: relocation R_386_GOTOFF against undefined %s `%s' can not be used when making a shared object"), + input_bfd, v, h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } + else if (!info->executable + && h->type == STT_FUNC + && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) + { + (*_bfd_error_handler) + (_("%B: relocation R_386_GOTOFF against protected function `%s' can not be used when making a shared object"), + input_bfd, h->root.root.string); + bfd_set_error (bfd_error_bad_value); + return FALSE; + } } /* Note that sgot is not involved in this @@ -2605,7 +2864,8 @@ elf_i386_relocate_section (bfd *output_bfd, case R_386_32: case R_386_PC32: - if ((input_section->flags & SEC_ALLOC) == 0) + if ((input_section->flags & SEC_ALLOC) == 0 + || is_vxworks_tls) break; if ((info->shared @@ -2652,7 +2912,7 @@ elf_i386_relocate_section (bfd *output_bfd, && h->dynindx != -1 && (r_type == R_386_PC32 || !info->shared - || !info->symbolic + || !SYMBOLIC_BIND (info, h) || !h->def_regular)) outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); else @@ -2663,11 +2923,12 @@ elf_i386_relocate_section (bfd *output_bfd, } sreloc = elf_section_data (input_section)->sreloc; - if (sreloc == NULL) - abort (); + + BFD_ASSERT (sreloc != NULL && sreloc->contents != NULL); 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 @@ -2704,98 +2965,54 @@ elf_i386_relocate_section (bfd *output_bfd, case R_386_TLS_DESC_CALL: 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) tls_type = elf_i386_local_got_tls_type (input_bfd) [r_symndx]; else if (h != NULL) - { - tls_type = elf_i386_hash_entry(h)->tls_type; - /* If we have both R_386_TLS_IE and R_386_TLS_GD, - GOT_TLS_IE_BOTH should be used. */ - if ((tls_type & GOT_TLS_IE_MASK) - == (GOT_TLS_IE_IE | GOT_TLS_IE_GD)) - tls_type = GOT_TLS_IE_BOTH; - else - tls_type &= GOT_TLS_MASK; - if (!info->shared && h->dynindx == -1 && (tls_type & GOT_TLS_IE)) - r_type = R_386_TLS_LE_32; - } + tls_type = elf_i386_hash_entry(h)->tls_type; if (tls_type == GOT_TLS_IE) tls_type = GOT_TLS_IE_NEG; - if (r_type == R_386_TLS_GD - || r_type == R_386_TLS_GOTDESC - || r_type == R_386_TLS_DESC_CALL) - { - 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 (! elf_i386_tls_transition (info, input_bfd, + input_section, contents, + symtab_hdr, sym_hashes, + &r_type, tls_type, rel, + relend, h)) + return FALSE; if (r_type == R_386_TLS_LE_32) { BFD_ASSERT (! unresolved_reloc); if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_GD) { - unsigned int val, type; + unsigned int type; bfd_vma roff; /* GD->LE transition. */ - BFD_ASSERT (rel->r_offset >= 2); type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); - BFD_ASSERT (type == 0x8d || type == 0x04); - BFD_ASSERT (rel->r_offset + 9 <= input_section->size); - BFD_ASSERT (bfd_get_8 (input_bfd, - contents + rel->r_offset + 4) - == 0xe8); - BFD_ASSERT (rel + 1 < relend); - BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32); - roff = rel->r_offset + 5; - val = bfd_get_8 (input_bfd, - contents + rel->r_offset - 1); if (type == 0x04) { /* leal foo(,%reg,1), %eax; call ___tls_get_addr Change it into: movl %gs:0, %eax; subl $foo@tpoff, %eax (6 byte form of subl). */ - BFD_ASSERT (rel->r_offset >= 3); - BFD_ASSERT (bfd_get_8 (input_bfd, - contents + rel->r_offset - 3) - == 0x8d); - BFD_ASSERT ((val & 0xc7) == 0x05 && val != (4 << 3)); memcpy (contents + rel->r_offset - 3, "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12); + roff = rel->r_offset + 5; } else { - BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4); - if (rel->r_offset + 10 <= input_section->size - && bfd_get_8 (input_bfd, - contents + rel->r_offset + 9) == 0x90) - { - /* leal foo(%reg), %eax; call ___tls_get_addr; nop - Change it into: - movl %gs:0, %eax; subl $foo@tpoff, %eax - (6 byte form of subl). */ - memcpy (contents + rel->r_offset - 2, - "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12); - roff = rel->r_offset + 6; - } - else - { - /* leal foo(%reg), %eax; call ___tls_get_addr - Change it into: - movl %gs:0, %eax; subl $foo@tpoff, %eax - (5 byte form of subl). */ - memcpy (contents + rel->r_offset - 2, - "\x65\xa1\0\0\0\0\x2d\0\0\0", 11); - } + /* leal foo(%reg), %eax; call ___tls_get_addr; nop + Change it into: + movl %gs:0, %eax; subl $foo@tpoff, %eax + (6 byte form of subl). */ + memcpy (contents + rel->r_offset - 2, + "\x65\xa1\0\0\0\0\x81\xe8\0\0\0", 12); + roff = rel->r_offset + 6; } bfd_put_32 (output_bfd, tpoff (info, relocation), contents + roff); - /* Skip R_386_PLT32. */ + /* Skip R_386_PC32/R_386_PLT32. */ rel++; continue; } @@ -2809,19 +3026,11 @@ elf_i386_relocate_section (bfd *output_bfd, Registers other than %eax may be set up here. */ - unsigned int val, type; + unsigned int val; bfd_vma roff; - /* First, make sure it's a leal adding ebx to a - 32-bit offset into any register, although it's - probably almost always going to be eax. */ roff = rel->r_offset; - BFD_ASSERT (roff >= 2); - type = bfd_get_8 (input_bfd, contents + roff - 2); - BFD_ASSERT (type == 0x8d); val = bfd_get_8 (input_bfd, contents + roff - 1); - BFD_ASSERT ((val & 0xc7) == 0x83); - BFD_ASSERT (roff + 4 <= input_section->size); /* Now modify the instruction as appropriate. */ /* aoliva FIXME: remove the above and xor the byte @@ -2838,27 +3047,18 @@ elf_i386_relocate_section (bfd *output_bfd, It's originally: call *(%eax) Turn it into: - nop; nop */ + xchg %ax,%ax */ - unsigned int val, type; bfd_vma roff; - - /* First, make sure it's a call *(%eax). */ + roff = rel->r_offset; - BFD_ASSERT (roff + 2 <= input_section->size); - type = bfd_get_8 (input_bfd, contents + roff); - BFD_ASSERT (type == 0xff); - val = bfd_get_8 (input_bfd, contents + roff + 1); - BFD_ASSERT (val == 0x10); - - /* Now modify the instruction as appropriate. */ - bfd_put_8 (output_bfd, 0x90, contents + roff); + bfd_put_8 (output_bfd, 0x66, contents + roff); bfd_put_8 (output_bfd, 0x90, contents + roff + 1); continue; } else if (ELF32_R_TYPE (rel->r_info) == R_386_TLS_IE) { - unsigned int val, type; + unsigned int val; /* IE->LE transition: Originally it can be one of: @@ -2869,9 +3069,7 @@ elf_i386_relocate_section (bfd *output_bfd, 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->size); if (val == 0xa1) { /* movl foo, %eax. */ @@ -2880,14 +3078,14 @@ elf_i386_relocate_section (bfd *output_bfd, } else { - BFD_ASSERT (rel->r_offset >= 2); + unsigned int type; + 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, @@ -2896,7 +3094,6 @@ elf_i386_relocate_section (bfd *output_bfd, 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, @@ -2925,11 +3122,8 @@ elf_i386_relocate_section (bfd *output_bfd, subl $foo, %reg2 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->size); - BFD_ASSERT ((val & 0xc0) == 0x80 && (val & 7) != 4); if (type == 0x8b) { /* movl */ @@ -3130,38 +3324,21 @@ elf_i386_relocate_section (bfd *output_bfd, bfd_vma roff; /* GD->IE transition. */ - BFD_ASSERT (rel->r_offset >= 2); type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); - BFD_ASSERT (type == 0x8d || type == 0x04); - BFD_ASSERT (rel->r_offset + 9 <= input_section->size); - BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4) - == 0xe8); - BFD_ASSERT (rel + 1 < relend); - BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32); - roff = rel->r_offset - 3; val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); if (type == 0x04) { /* leal foo(,%reg,1), %eax; call ___tls_get_addr Change it into: movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */ - BFD_ASSERT (rel->r_offset >= 3); - BFD_ASSERT (bfd_get_8 (input_bfd, - contents + rel->r_offset - 3) - == 0x8d); - BFD_ASSERT ((val & 0xc7) == 0x05 && val != (4 << 3)); val >>= 3; + roff = rel->r_offset - 3; } else { /* leal foo(%reg), %eax; call ___tls_get_addr; nop Change it into: movl %gs:0, %eax; subl $foo@gottpoff(%reg), %eax. */ - BFD_ASSERT (rel->r_offset + 10 <= input_section->size); - BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4); - BFD_ASSERT (bfd_get_8 (input_bfd, - contents + rel->r_offset + 9) - == 0x90); roff = rel->r_offset - 2; } memcpy (contents + roff, @@ -3172,12 +3349,8 @@ elf_i386_relocate_section (bfd *output_bfd, 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; - } + if (tls_type == GOT_TLS_IE_POS) + contents[roff + 6] = 0x03; bfd_put_32 (output_bfd, htab->sgot->output_section->vma + htab->sgot->output_offset + off @@ -3195,25 +3368,18 @@ elf_i386_relocate_section (bfd *output_bfd, leal x@tlsdesc(%ebx), %eax Change it to: - movl x@gotntpoff(%ebx), %eax # before nop; nop + movl x@gotntpoff(%ebx), %eax # before xchg %ax,%ax or: movl x@gottpoff(%ebx), %eax # before negl %eax Registers other than %eax may be set up here. */ - unsigned int val, type; bfd_vma roff; /* First, make sure it's a leal adding ebx to a 32-bit offset into any register, although it's probably almost always going to be eax. */ roff = rel->r_offset; - BFD_ASSERT (roff >= 2); - type = bfd_get_8 (input_bfd, contents + roff - 2); - BFD_ASSERT (type == 0x8d); - val = bfd_get_8 (input_bfd, contents + roff - 1); - BFD_ASSERT ((val & 0xc7) == 0x83); - BFD_ASSERT (roff + 4 <= input_section->size); /* Now modify the instruction as appropriate. */ /* To turn a leal into a movl in the form we use it, it @@ -3241,28 +3407,21 @@ elf_i386_relocate_section (bfd *output_bfd, call *(%eax) Change it to: - nop; nop + xchg %ax,%ax or negl %eax depending on how we transformed the TLS_GOTDESC above. */ - unsigned int val, type; bfd_vma roff; - /* First, make sure it's a call *(%eax). */ roff = rel->r_offset; - BFD_ASSERT (roff + 2 <= input_section->size); - type = bfd_get_8 (input_bfd, contents + roff); - BFD_ASSERT (type == 0xff); - val = bfd_get_8 (input_bfd, contents + roff + 1); - BFD_ASSERT (val == 0x10); /* Now modify the instruction as appropriate. */ if (tls_type != GOT_TLS_IE_NEG) { - /* nop; nop */ - bfd_put_8 (output_bfd, 0x90, contents + roff); + /* xchg %ax,%ax */ + bfd_put_8 (output_bfd, 0x66, contents + roff); bfd_put_8 (output_bfd, 0x90, contents + roff + 1); } else @@ -3279,28 +3438,23 @@ elf_i386_relocate_section (bfd *output_bfd, break; case R_386_TLS_LDM: - if (! info->shared) - { - unsigned int val; + if (! elf_i386_tls_transition (info, input_bfd, + input_section, contents, + symtab_hdr, sym_hashes, + &r_type, GOT_UNKNOWN, rel, + relend, h)) + return FALSE; + if (r_type != R_386_TLS_LDM) + { /* LD->LE transition: - Ensure it is: leal foo(%reg), %eax; call ___tls_get_addr. We change it into: movl %gs:0, %eax; nop; leal 0(%esi,1), %esi. */ - BFD_ASSERT (rel->r_offset >= 2); - BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 2) - == 0x8d); - val = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); - BFD_ASSERT ((val & 0xf8) == 0x80 && (val & 7) != 4); - BFD_ASSERT (rel->r_offset + 9 <= input_section->size); - BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4) - == 0xe8); - BFD_ASSERT (rel + 1 < relend); - BFD_ASSERT (ELF32_R_TYPE (rel[1].r_info) == R_386_PLT32); + BFD_ASSERT (r_type == R_386_TLS_LE_32); memcpy (contents + rel->r_offset - 2, "\x65\xa1\0\0\0\0\x90\x8d\x74\x26", 11); - /* Skip R_386_PLT32. */ + /* Skip R_386_PC32/R_386_PLT32. */ rel++; continue; } @@ -3707,6 +3861,9 @@ elf_i386_finish_dynamic_sections (bfd *output_bfd, switch (dyn.d_tag) { default: + if (htab->is_vxworks + && elf_vxworks_finish_dynamic_entry (output_bfd, &dyn)) + break; continue; case DT_PLTGOT: @@ -3872,6 +4029,18 @@ elf_i386_plt_sym_val (bfd_vma i, const asection *plt, return plt->vma + (i + 1) * PLT_ENTRY_SIZE; } +/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ + +static bfd_boolean +elf_i386_hash_symbol (struct elf_link_hash_entry *h) +{ + if (h->plt.offset != (bfd_vma) -1 + && !h->def_regular + && !h->pointer_equality_needed) + return FALSE; + + return _bfd_elf_hash_symbol (h); +} #define TARGET_LITTLE_SYM bfd_elf32_i386_vec #define TARGET_LITTLE_NAME "elf32-i386" @@ -3895,8 +4064,10 @@ elf_i386_plt_sym_val (bfd_vma i, const asection *plt, #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 bfd_elf32_bfd_reloc_name_lookup elf_i386_reloc_name_lookup #define elf_backend_adjust_dynamic_symbol elf_i386_adjust_dynamic_symbol +#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible #define elf_backend_check_relocs elf_i386_check_relocs #define elf_backend_copy_indirect_symbol elf_i386_copy_indirect_symbol #define elf_backend_create_dynamic_sections elf_i386_create_dynamic_sections @@ -3911,7 +4082,10 @@ elf_i386_plt_sym_val (bfd_vma i, const asection *plt, #define elf_backend_relocate_section elf_i386_relocate_section #define elf_backend_size_dynamic_sections elf_i386_size_dynamic_sections #define elf_backend_always_size_sections elf_i386_always_size_sections +#define elf_backend_omit_section_dynsym \ + ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) #define elf_backend_plt_sym_val elf_i386_plt_sym_val +#define elf_backend_hash_symbol elf_i386_hash_symbol #include "elf32-target.h" @@ -3921,6 +4095,8 @@ elf_i386_plt_sym_val (bfd_vma i, const asection *plt, #define TARGET_LITTLE_SYM bfd_elf32_i386_freebsd_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-i386-freebsd" +#undef ELF_OSABI +#define ELF_OSABI ELFOSABI_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 @@ -3935,7 +4111,7 @@ elf_i386_post_process_headers (bfd *abfd, i_ehdrp = elf_elfheader (abfd); /* Put an ABI label supported by FreeBSD >= 4.1. */ - i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_FREEBSD; + i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi; #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); @@ -3955,7 +4131,7 @@ elf_i386_post_process_headers (bfd *abfd, #define TARGET_LITTLE_SYM bfd_elf32_i386_vxworks_vec #undef TARGET_LITTLE_NAME #define TARGET_LITTLE_NAME "elf32-i386-vxworks" - +#undef ELF_OSABI /* Like elf_i386_link_hash_table_create but with tweaks for VxWorks. */ @@ -3977,7 +4153,8 @@ elf_i386_vxworks_link_hash_table_create (bfd *abfd) } -#undef elf_backend_post_process_headers +#undef elf_backend_relocs_compatible +#undef elf_backend_post_process_headers #undef bfd_elf32_bfd_link_hash_table_create #define bfd_elf32_bfd_link_hash_table_create \ elf_i386_vxworks_link_hash_table_create