X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=bfd%2Felfxx-ia64.c;h=b6f103a7e7ea50113ce2ab4e012fda6175e5f6c4;hb=6b6b345096317186639f6a8616a5e80482b41878;hp=2af3fb452bd256e500c55a564bec70e0f7bdc898;hpb=55255daec3c2b3f212acfdfe9cefe9fd2899253f;p=deliverable%2Fbinutils-gdb.git diff --git a/bfd/elfxx-ia64.c b/bfd/elfxx-ia64.c index 2af3fb452b..b6f103a7e7 100644 --- a/bfd/elfxx-ia64.c +++ b/bfd/elfxx-ia64.c @@ -1,13 +1,13 @@ /* IA-64 support for 64-bit ELF - Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 - Free Software Foundation, Inc. + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, + 2009 Free Software Foundation, Inc. Contributed by David Mosberger-Tang 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, @@ -17,10 +17,11 @@ 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 "libbfd.h" #include "elf-bfd.h" #include "opcode/ia64.h" @@ -189,172 +190,45 @@ struct elfNN_ia64_allocate_data #define elfNN_ia64_hash_table(p) \ ((struct elfNN_ia64_link_hash_table *) ((p)->hash)) -static bfd_reloc_status_type elfNN_ia64_reloc - PARAMS ((bfd *abfd, arelent *reloc, asymbol *sym, PTR data, - asection *input_section, bfd *output_bfd, char **error_message)); -static reloc_howto_type * lookup_howto - PARAMS ((unsigned int rtype)); -static reloc_howto_type *elfNN_ia64_reloc_type_lookup - PARAMS ((bfd *abfd, bfd_reloc_code_real_type bfd_code)); -static void elfNN_ia64_info_to_howto - PARAMS ((bfd *abfd, arelent *bfd_reloc, Elf_Internal_Rela *elf_reloc)); -static bfd_boolean elfNN_ia64_relax_section - PARAMS((bfd *abfd, asection *sec, struct bfd_link_info *link_info, - bfd_boolean *again)); -static void elfNN_ia64_relax_ldxmov - PARAMS((bfd_byte *contents, bfd_vma off)); -static bfd_boolean is_unwind_section_name - PARAMS ((bfd *abfd, const char *)); -static bfd_boolean elfNN_ia64_section_flags - PARAMS ((flagword *, const Elf_Internal_Shdr *)); -static bfd_boolean elfNN_ia64_fake_sections - PARAMS ((bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)); -static void elfNN_ia64_final_write_processing - PARAMS ((bfd *abfd, bfd_boolean linker)); -static bfd_boolean elfNN_ia64_add_symbol_hook - PARAMS ((bfd *abfd, struct bfd_link_info *info, Elf_Internal_Sym *sym, - const char **namep, flagword *flagsp, asection **secp, - bfd_vma *valp)); -static bfd_boolean elfNN_ia64_is_local_label_name - PARAMS ((bfd *abfd, const char *name)); +static struct elfNN_ia64_dyn_sym_info * get_dyn_sym_info + (struct elfNN_ia64_link_hash_table *ia64_info, + struct elf_link_hash_entry *h, + bfd *abfd, const Elf_Internal_Rela *rel, bfd_boolean create); static bfd_boolean elfNN_ia64_dynamic_symbol_p - PARAMS ((struct elf_link_hash_entry *h, struct bfd_link_info *info, int)); -static struct bfd_hash_entry *elfNN_ia64_new_elf_hash_entry - PARAMS ((struct bfd_hash_entry *entry, struct bfd_hash_table *table, - const char *string)); -static void elfNN_ia64_hash_copy_indirect - PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, - struct elf_link_hash_entry *)); -static void elfNN_ia64_hash_hide_symbol - PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean)); -static hashval_t elfNN_ia64_local_htab_hash PARAMS ((const void *)); -static int elfNN_ia64_local_htab_eq PARAMS ((const void *ptr1, - const void *ptr2)); -static struct bfd_link_hash_table *elfNN_ia64_hash_table_create - PARAMS ((bfd *abfd)); -static void elfNN_ia64_hash_table_free - PARAMS ((struct bfd_link_hash_table *hash)); -static bfd_boolean elfNN_ia64_global_dyn_sym_thunk - PARAMS ((struct bfd_hash_entry *, PTR)); -static int elfNN_ia64_local_dyn_sym_thunk - PARAMS ((void **, PTR)); + (struct elf_link_hash_entry *h, struct bfd_link_info *info, int); +static bfd_reloc_status_type elfNN_ia64_install_value + (bfd_byte *hit_addr, bfd_vma val, unsigned int r_type); +static bfd_boolean elfNN_ia64_choose_gp + (bfd *abfd, struct bfd_link_info *info); +static void elfNN_ia64_relax_ldxmov + (bfd_byte *contents, bfd_vma off); static void elfNN_ia64_dyn_sym_traverse - PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info, - bfd_boolean (*func) (struct elfNN_ia64_dyn_sym_info *, PTR), - PTR info)); -static bfd_boolean elfNN_ia64_create_dynamic_sections - PARAMS ((bfd *abfd, struct bfd_link_info *info)); -static struct elfNN_ia64_local_hash_entry * get_local_sym_hash - PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info, - bfd *abfd, const Elf_Internal_Rela *rel, bfd_boolean create)); -static struct elfNN_ia64_dyn_sym_info * get_dyn_sym_info - PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info, - struct elf_link_hash_entry *h, - bfd *abfd, const Elf_Internal_Rela *rel, bfd_boolean create)); -static asection *get_got - PARAMS ((bfd *abfd, struct bfd_link_info *info, - struct elfNN_ia64_link_hash_table *ia64_info)); -static asection *get_fptr - PARAMS ((bfd *abfd, struct bfd_link_info *info, - struct elfNN_ia64_link_hash_table *ia64_info)); -static asection *get_pltoff - PARAMS ((bfd *abfd, struct bfd_link_info *info, - struct elfNN_ia64_link_hash_table *ia64_info)); -static asection *get_reloc_section - PARAMS ((bfd *abfd, struct elfNN_ia64_link_hash_table *ia64_info, - asection *sec, bfd_boolean create)); -static bfd_boolean elfNN_ia64_check_relocs - PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *sec, - const Elf_Internal_Rela *relocs)); -static bfd_boolean elfNN_ia64_adjust_dynamic_symbol - PARAMS ((struct bfd_link_info *info, struct elf_link_hash_entry *h)); -static long global_sym_index - PARAMS ((struct elf_link_hash_entry *h)); -static bfd_boolean allocate_fptr - PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); + (struct elfNN_ia64_link_hash_table *ia64_info, + bfd_boolean (*func) (struct elfNN_ia64_dyn_sym_info *, PTR), + PTR info); static bfd_boolean allocate_global_data_got - PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); + (struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data); static bfd_boolean allocate_global_fptr_got - PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); + (struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data); static bfd_boolean allocate_local_got - PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); -static bfd_boolean allocate_pltoff_entries - PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); -static bfd_boolean allocate_plt_entries - PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); -static bfd_boolean allocate_plt2_entries - PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); -static bfd_boolean allocate_dynrel_entries - PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); -static bfd_boolean elfNN_ia64_size_dynamic_sections - PARAMS ((bfd *output_bfd, struct bfd_link_info *info)); -static bfd_reloc_status_type elfNN_ia64_install_value - PARAMS ((bfd_byte *hit_addr, bfd_vma val, unsigned int r_type)); -static void elfNN_ia64_install_dyn_reloc - PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *sec, - asection *srel, bfd_vma offset, unsigned int type, - long dynindx, bfd_vma addend)); -static bfd_vma set_got_entry - PARAMS ((bfd *abfd, struct bfd_link_info *info, - struct elfNN_ia64_dyn_sym_info *dyn_i, long dynindx, - bfd_vma addend, bfd_vma value, unsigned int dyn_r_type)); -static bfd_vma set_fptr_entry - PARAMS ((bfd *abfd, struct bfd_link_info *info, - struct elfNN_ia64_dyn_sym_info *dyn_i, - bfd_vma value)); -static bfd_vma set_pltoff_entry - PARAMS ((bfd *abfd, struct bfd_link_info *info, - struct elfNN_ia64_dyn_sym_info *dyn_i, - bfd_vma value, bfd_boolean)); -static bfd_vma elfNN_ia64_tprel_base - PARAMS ((struct bfd_link_info *info)); -static bfd_vma elfNN_ia64_dtprel_base - PARAMS ((struct bfd_link_info *info)); -static int elfNN_ia64_unwind_entry_compare - PARAMS ((const PTR, const PTR)); -static bfd_boolean elfNN_ia64_choose_gp - PARAMS ((bfd *abfd, struct bfd_link_info *info)); -static bfd_boolean elfNN_ia64_final_link - PARAMS ((bfd *abfd, struct bfd_link_info *info)); -static bfd_boolean elfNN_ia64_relocate_section - PARAMS ((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 elfNN_ia64_finish_dynamic_symbol - PARAMS ((bfd *output_bfd, struct bfd_link_info *info, - struct elf_link_hash_entry *h, Elf_Internal_Sym *sym)); -static bfd_boolean elfNN_ia64_finish_dynamic_sections - PARAMS ((bfd *abfd, struct bfd_link_info *info)); -static bfd_boolean elfNN_ia64_set_private_flags - PARAMS ((bfd *abfd, flagword flags)); -static bfd_boolean elfNN_ia64_merge_private_bfd_data - PARAMS ((bfd *ibfd, bfd *obfd)); -static bfd_boolean elfNN_ia64_print_private_bfd_data - PARAMS ((bfd *abfd, PTR ptr)); -static enum elf_reloc_type_class elfNN_ia64_reloc_type_class - PARAMS ((const Elf_Internal_Rela *)); + (struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data); static bfd_boolean elfNN_ia64_hpux_vec - PARAMS ((const bfd_target *vec)); -static void elfNN_hpux_post_process_headers - PARAMS ((bfd *abfd, struct bfd_link_info *info)); -bfd_boolean elfNN_hpux_backend_section_from_bfd_section - PARAMS ((bfd *abfd, asection *sec, int *retval)); + (const bfd_target *vec); +static bfd_boolean allocate_dynrel_entries + (struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data); +static asection *get_pltoff + (bfd *abfd, struct bfd_link_info *info, + struct elfNN_ia64_link_hash_table *ia64_info); /* ia64-specific relocation. */ /* Perform a relocation. Not much to do here as all the hard work is done in elfNN_ia64_final_link_relocate. */ static bfd_reloc_status_type -elfNN_ia64_reloc (abfd, reloc, sym, data, input_section, - output_bfd, error_message) - bfd *abfd ATTRIBUTE_UNUSED; - arelent *reloc; - asymbol *sym ATTRIBUTE_UNUSED; - PTR data ATTRIBUTE_UNUSED; - asection *input_section; - bfd *output_bfd; - char **error_message; +elfNN_ia64_reloc (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc, + asymbol *sym ATTRIBUTE_UNUSED, + PTR data ATTRIBUTE_UNUSED, asection *input_section, + bfd *output_bfd, char **error_message) { if (output_bfd) { @@ -480,8 +354,7 @@ static unsigned char elf_code_to_howto_index[R_IA64_MAX_RELOC_CODE + 1]; /* Given a BFD reloc type, return the matching HOWTO structure. */ static reloc_howto_type * -lookup_howto (rtype) - unsigned int rtype; +lookup_howto (unsigned int rtype) { static int inited = 0; int i; @@ -504,9 +377,8 @@ lookup_howto (rtype) } static reloc_howto_type* -elfNN_ia64_reloc_type_lookup (abfd, bfd_code) - bfd *abfd ATTRIBUTE_UNUSED; - bfd_reloc_code_real_type bfd_code; +elfNN_ia64_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, + bfd_reloc_code_real_type bfd_code) { unsigned int rtype; @@ -613,13 +485,28 @@ elfNN_ia64_reloc_type_lookup (abfd, bfd_code) return lookup_howto (rtype); } +static reloc_howto_type * +elfNN_ia64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, + const char *r_name) +{ + unsigned int i; + + for (i = 0; + i < sizeof (ia64_howto_table) / sizeof (ia64_howto_table[0]); + i++) + if (ia64_howto_table[i].name != NULL + && strcasecmp (ia64_howto_table[i].name, r_name) == 0) + return &ia64_howto_table[i]; + + return NULL; +} + /* Given a ELF reloc, return the matching HOWTO structure. */ static void -elfNN_ia64_info_to_howto (abfd, bfd_reloc, elf_reloc) - bfd *abfd ATTRIBUTE_UNUSED; - arelent *bfd_reloc; - Elf_Internal_Rela *elf_reloc; +elfNN_ia64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, + arelent *bfd_reloc, + Elf_Internal_Rela *elf_reloc) { bfd_reloc->howto = lookup_howto ((unsigned int) ELFNN_R_TYPE (elf_reloc->r_info)); @@ -787,7 +674,7 @@ elfNN_ia64_relax_br (bfd_byte *contents, bfd_vma off) /* It should never happen. */ abort (); } - + /* We can turn br.cond/br.call into brl.cond/brl.call. */ if (!(IS_BR_COND (br_code) || IS_BR_CALL (br_code))) return FALSE; @@ -869,11 +756,9 @@ elfNN_ia64_relax_brl (bfd_byte *contents, bfd_vma off) /* These functions do relaxation for IA-64 ELF. */ static bfd_boolean -elfNN_ia64_relax_section (abfd, sec, link_info, again) - bfd *abfd; - asection *sec; - struct bfd_link_info *link_info; - bfd_boolean *again; +elfNN_ia64_relax_section (bfd *abfd, asection *sec, + struct bfd_link_info *link_info, + bfd_boolean *again) { struct one_fixup { @@ -1109,8 +994,20 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) + sec->output_offset + roff) & (bfd_vma) -4; + /* The .plt section is aligned at 32byte and the .text section + is aligned at 64byte. The .text section is right after the + .plt section. After the first relaxation pass, linker may + increase the gap between the .plt and .text sections up + to 32byte. We assume linker will always insert 32byte + between the .plt and .text sections after the the first + relaxation pass. */ + if (tsec == ia64_info->plt_sec) + offset = -0x1000000 + 32; + else + offset = -0x1000000; + /* If the branch is in range, no need to do anything. */ - if ((bfd_signed_vma) (symaddr - reladdr) >= -0x1000000 + if ((bfd_signed_vma) (symaddr - reladdr) >= offset && (bfd_signed_vma) (symaddr - reladdr) <= 0x0FFFFF0) { /* If the 60-bit branch is in 21-bit range, optimize it. */ @@ -1390,9 +1287,7 @@ elfNN_ia64_relax_section (abfd, sec, link_info, again) #undef skip_relax_pass_1 static void -elfNN_ia64_relax_ldxmov (contents, off) - bfd_byte *contents; - bfd_vma off; +elfNN_ia64_relax_ldxmov (bfd_byte *contents, bfd_vma off) { int shift, r1, r3; bfd_vma dword, insn; @@ -1424,22 +1319,15 @@ elfNN_ia64_relax_ldxmov (contents, off) /* Return TRUE if NAME is an unwind table section name. */ static inline bfd_boolean -is_unwind_section_name (abfd, name) - bfd *abfd; - const char *name; +is_unwind_section_name (bfd *abfd, const char *name) { - size_t len1, len2, len3; - if (elfNN_ia64_hpux_vec (abfd->xvec) && !strcmp (name, ELF_STRING_ia64_unwind_hdr)) return FALSE; - len1 = sizeof (ELF_STRING_ia64_unwind) - 1; - len2 = sizeof (ELF_STRING_ia64_unwind_info) - 1; - len3 = sizeof (ELF_STRING_ia64_unwind_once) - 1; - return ((strncmp (name, ELF_STRING_ia64_unwind, len1) == 0 - && strncmp (name, ELF_STRING_ia64_unwind_info, len2) != 0) - || strncmp (name, ELF_STRING_ia64_unwind_once, len3) == 0); + return ((CONST_STRNEQ (name, ELF_STRING_ia64_unwind) + && ! CONST_STRNEQ (name, ELF_STRING_ia64_unwind_info)) + || CONST_STRNEQ (name, ELF_STRING_ia64_unwind_once)); } /* Handle an IA-64 specific section when reading an object file. This @@ -1487,9 +1375,8 @@ elfNN_ia64_section_from_shdr (bfd *abfd, flag. */ static bfd_boolean -elfNN_ia64_section_flags (flags, hdr) - flagword *flags; - const Elf_Internal_Shdr *hdr; +elfNN_ia64_section_flags (flagword *flags, + const Elf_Internal_Shdr *hdr) { if (hdr->sh_flags & SHF_IA_64_SHORT) *flags |= SEC_SMALL_DATA; @@ -1501,10 +1388,8 @@ elfNN_ia64_section_flags (flags, hdr) section name, which is a hack, but ought to work. */ static bfd_boolean -elfNN_ia64_fake_sections (abfd, hdr, sec) - bfd *abfd ATTRIBUTE_UNUSED; - Elf_Internal_Shdr *hdr; - asection *sec; +elfNN_ia64_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, + asection *sec) { register const char *name; @@ -1555,9 +1440,8 @@ elfNN_ia64_fake_sections (abfd, hdr, sec) object file. */ static void -elfNN_ia64_final_write_processing (abfd, linker) - bfd *abfd; - bfd_boolean linker ATTRIBUTE_UNUSED; +elfNN_ia64_final_write_processing (bfd *abfd, + bfd_boolean linker ATTRIBUTE_UNUSED) { Elf_Internal_Shdr *hdr; asection *s; @@ -1595,14 +1479,13 @@ elfNN_ia64_final_write_processing (abfd, linker) file. We use it to put .comm items in .sbss, and not .bss. */ static bfd_boolean -elfNN_ia64_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) - bfd *abfd; - struct bfd_link_info *info; - Elf_Internal_Sym *sym; - const char **namep ATTRIBUTE_UNUSED; - flagword *flagsp ATTRIBUTE_UNUSED; - asection **secp; - bfd_vma *valp; +elfNN_ia64_add_symbol_hook (bfd *abfd, + struct bfd_link_info *info, + Elf_Internal_Sym *sym, + const char **namep ATTRIBUTE_UNUSED, + flagword *flagsp ATTRIBUTE_UNUSED, + asection **secp, + bfd_vma *valp) { if (sym->st_shndx == SHN_COMMON && !info->relocatable @@ -1785,9 +1668,8 @@ elfNN_ia64_modify_program_headers (bfd *abfd, '.' are local. */ static bfd_boolean -elfNN_ia64_is_local_label_name (abfd, name) - bfd *abfd ATTRIBUTE_UNUSED; - const char *name; +elfNN_ia64_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, + const char *name) { return name[0] == '.'; } @@ -1795,10 +1677,8 @@ elfNN_ia64_is_local_label_name (abfd, name) /* Should we do dynamic things to this symbol? */ static bfd_boolean -elfNN_ia64_dynamic_symbol_p (h, info, r_type) - struct elf_link_hash_entry *h; - struct bfd_link_info *info; - int r_type; +elfNN_ia64_dynamic_symbol_p (struct elf_link_hash_entry *h, + struct bfd_link_info *info, int r_type) { bfd_boolean ignore_protected = ((r_type & 0xf8) == 0x40 /* FPTR relocs */ @@ -1808,10 +1688,9 @@ elfNN_ia64_dynamic_symbol_p (h, info, r_type) } static struct bfd_hash_entry* -elfNN_ia64_new_elf_hash_entry (entry, table, string) - struct bfd_hash_entry *entry; - struct bfd_hash_table *table; - const char *string; +elfNN_ia64_new_elf_hash_entry (struct bfd_hash_entry *entry, + struct bfd_hash_table *table, + const char *string) { struct elfNN_ia64_link_hash_entry *ret; ret = (struct elfNN_ia64_link_hash_entry *) entry; @@ -1837,9 +1716,9 @@ elfNN_ia64_new_elf_hash_entry (entry, table, string) } static void -elfNN_ia64_hash_copy_indirect (info, xdir, xind) - struct bfd_link_info *info; - struct elf_link_hash_entry *xdir, *xind; +elfNN_ia64_hash_copy_indirect (struct bfd_link_info *info, + struct elf_link_hash_entry *xdir, + struct elf_link_hash_entry *xind) { struct elfNN_ia64_link_hash_entry *dir, *ind; @@ -1900,10 +1779,9 @@ elfNN_ia64_hash_copy_indirect (info, xdir, xind) } static void -elfNN_ia64_hash_hide_symbol (info, xh, force_local) - struct bfd_link_info *info; - struct elf_link_hash_entry *xh; - bfd_boolean force_local; +elfNN_ia64_hash_hide_symbol (struct bfd_link_info *info, + struct elf_link_hash_entry *xh, + bfd_boolean force_local) { struct elfNN_ia64_link_hash_entry *h; struct elfNN_ia64_dyn_sym_info *dyn_i; @@ -1925,8 +1803,7 @@ elfNN_ia64_hash_hide_symbol (info, xh, force_local) /* Compute a hash of a local hash entry. */ static hashval_t -elfNN_ia64_local_htab_hash (ptr) - const void *ptr; +elfNN_ia64_local_htab_hash (const void *ptr) { struct elfNN_ia64_local_hash_entry *entry = (struct elfNN_ia64_local_hash_entry *) ptr; @@ -1938,8 +1815,7 @@ elfNN_ia64_local_htab_hash (ptr) /* Compare local hash entries. */ static int -elfNN_ia64_local_htab_eq (ptr1, ptr2) - const void *ptr1, *ptr2; +elfNN_ia64_local_htab_eq (const void *ptr1, const void *ptr2) { struct elfNN_ia64_local_hash_entry *entry1 = (struct elfNN_ia64_local_hash_entry *) ptr1; @@ -1954,8 +1830,7 @@ elfNN_ia64_local_htab_eq (ptr1, ptr2) linker (without using static variables). */ static struct bfd_link_hash_table* -elfNN_ia64_hash_table_create (abfd) - bfd *abfd; +elfNN_ia64_hash_table_create (bfd *abfd) { struct elfNN_ia64_link_hash_table *ret; @@ -2031,8 +1906,7 @@ elfNN_ia64_local_dyn_info_free (void **slot, /* Destroy IA-64 linker hash table. */ static void -elfNN_ia64_hash_table_free (hash) - struct bfd_link_hash_table *hash; +elfNN_ia64_hash_table_free (struct bfd_link_hash_table *hash) { struct elfNN_ia64_link_hash_table *ia64_info = (struct elfNN_ia64_link_hash_table *) hash; @@ -2053,14 +1927,13 @@ elfNN_ia64_hash_table_free (hash) struct elfNN_ia64_dyn_sym_traverse_data { - bfd_boolean (*func) PARAMS ((struct elfNN_ia64_dyn_sym_info *, PTR)); + bfd_boolean (*func) (struct elfNN_ia64_dyn_sym_info *, PTR); PTR data; }; static bfd_boolean -elfNN_ia64_global_dyn_sym_thunk (xentry, xdata) - struct bfd_hash_entry *xentry; - PTR xdata; +elfNN_ia64_global_dyn_sym_thunk (struct bfd_hash_entry *xentry, + PTR xdata) { struct elfNN_ia64_link_hash_entry *entry = (struct elfNN_ia64_link_hash_entry *) xentry; @@ -2081,9 +1954,7 @@ elfNN_ia64_global_dyn_sym_thunk (xentry, xdata) } static bfd_boolean -elfNN_ia64_local_dyn_sym_thunk (slot, xdata) - void **slot; - PTR xdata; +elfNN_ia64_local_dyn_sym_thunk (void **slot, PTR xdata) { struct elfNN_ia64_local_hash_entry *entry = (struct elfNN_ia64_local_hash_entry *) *slot; @@ -2101,10 +1972,9 @@ elfNN_ia64_local_dyn_sym_thunk (slot, xdata) } static void -elfNN_ia64_dyn_sym_traverse (ia64_info, func, data) - struct elfNN_ia64_link_hash_table *ia64_info; - bfd_boolean (*func) PARAMS ((struct elfNN_ia64_dyn_sym_info *, PTR)); - PTR data; +elfNN_ia64_dyn_sym_traverse (struct elfNN_ia64_link_hash_table *ia64_info, + bfd_boolean (*func) (struct elfNN_ia64_dyn_sym_info *, PTR), + PTR data) { struct elfNN_ia64_dyn_sym_traverse_data xdata; @@ -2118,9 +1988,8 @@ elfNN_ia64_dyn_sym_traverse (ia64_info, func, data) } static bfd_boolean -elfNN_ia64_create_dynamic_sections (abfd, info) - bfd *abfd; - struct bfd_link_info *info; +elfNN_ia64_create_dynamic_sections (bfd *abfd, + struct bfd_link_info *info) { struct elfNN_ia64_link_hash_table *ia64_info; asection *s; @@ -2170,11 +2039,9 @@ elfNN_ia64_create_dynamic_sections (abfd, info) /* Find and/or create a hash entry for local symbol. */ static struct elfNN_ia64_local_hash_entry * -get_local_sym_hash (ia64_info, abfd, rel, create) - struct elfNN_ia64_link_hash_table *ia64_info; - bfd *abfd; - const Elf_Internal_Rela *rel; - bfd_boolean create; +get_local_sym_hash (struct elfNN_ia64_link_hash_table *ia64_info, + bfd *abfd, const Elf_Internal_Rela *rel, + bfd_boolean create) { struct elfNN_ia64_local_hash_entry e, *ret; asection *sec = abfd->sections; @@ -2216,7 +2083,7 @@ addend_compare (const void *xp, const void *yp) const struct elfNN_ia64_dyn_sym_info *y = (const struct elfNN_ia64_dyn_sym_info *) yp; - return x->addend - y->addend; + return x->addend < y->addend ? -1 : x->addend > y->addend ? 1 : 0; } /* Sort elfNN_ia64_dyn_sym_info array and remove duplicates. */ @@ -2225,37 +2092,62 @@ static unsigned int sort_dyn_sym_info (struct elfNN_ia64_dyn_sym_info *info, unsigned int count) { - bfd_vma curr, prev; - unsigned int i, dup, diff, dest, src, len; + bfd_vma curr, prev, got_offset; + unsigned int i, kept, dup, diff, dest, src, len; qsort (info, count, sizeof (*info), addend_compare); /* Find the first duplicate. */ prev = info [0].addend; + got_offset = info [0].got_offset; for (i = 1; i < count; i++) { curr = info [i].addend; if (curr == prev) - break; + { + /* For duplicates, make sure that GOT_OFFSET is valid. */ + if (got_offset == (bfd_vma) -1) + got_offset = info [i].got_offset; + break; + } + got_offset = info [i].got_offset; prev = curr; } + /* We may move a block of elements to here. */ + dest = i++; + /* Remove duplicates. */ if (i < count) { - /* We need to move a block of elements to here. */ - dest = i++; while (i < count) { + /* For duplicates, make sure that the kept one has a valid + got_offset. */ + kept = dest - 1; + if (got_offset != (bfd_vma) -1) + info [kept].got_offset = got_offset; + curr = info [i].addend; + got_offset = info [i].got_offset; /* Move a block of elements whose first one is different from the previous. */ if (curr == prev) { for (src = i + 1; src < count; src++) - if (info [src].addend != curr) - break; + { + if (info [src].addend != curr) + break; + /* For duplicates, make sure that GOT_OFFSET is + valid. */ + if (got_offset == (bfd_vma) -1) + got_offset = info [src].got_offset; + } + + /* Make sure that the kept one has a valid got_offset. */ + if (got_offset != (bfd_vma) -1) + info [kept].got_offset = got_offset; } else src = i; @@ -2263,13 +2155,25 @@ sort_dyn_sym_info (struct elfNN_ia64_dyn_sym_info *info, if (src >= count) break; - /* Find the next duplicate. */ + /* Find the next duplicate. SRC will be kept. */ prev = info [src].addend; + got_offset = info [src].got_offset; for (dup = src + 1; dup < count; dup++) { curr = info [dup].addend; if (curr == prev) - break; + { + /* Make sure that got_offset is valid. */ + if (got_offset == (bfd_vma) -1) + got_offset = info [dup].got_offset; + + /* For duplicates, make sure that the kept one has + a valid got_offset. */ + if (got_offset != (bfd_vma) -1) + info [dup - 1].got_offset = got_offset; + break; + } + got_offset = info [dup].got_offset; prev = curr; } @@ -2280,20 +2184,41 @@ sort_dyn_sym_info (struct elfNN_ia64_dyn_sym_info *info, if (len == 1 && dup < count) { /* If we only move 1 element, we combine it with the next - one. Find the next different one. */ + one. There must be at least a duplicate. Find the + next different one. */ for (diff = dup + 1, src++; diff < count; diff++, src++) - if (info [diff].addend != curr) - break; + { + if (info [diff].addend != curr) + break; + /* Make sure that got_offset is valid. */ + if (got_offset == (bfd_vma) -1) + got_offset = info [diff].got_offset; + } + + /* Makre sure that the last duplicated one has an valid + offset. */ + BFD_ASSERT (curr == prev); + if (got_offset != (bfd_vma) -1) + info [diff - 1].got_offset = got_offset; if (diff < count) { - /* Find the next duplicate. */ + /* Find the next duplicate. Track the current valid + offset. */ prev = info [diff].addend; + got_offset = info [diff].got_offset; for (dup = diff + 1; dup < count; dup++) { curr = info [dup].addend; if (curr == prev) - break; + { + /* For duplicates, make sure that GOT_OFFSET + is valid. */ + if (got_offset == (bfd_vma) -1) + got_offset = info [dup].got_offset; + break; + } + got_offset = info [dup].got_offset; prev = curr; diff++; } @@ -2310,6 +2235,19 @@ sort_dyn_sym_info (struct elfNN_ia64_dyn_sym_info *info, count = dest; } + else + { + /* When we get here, either there is no duplicate at all or + the only duplicate is the last element. */ + if (dest < count) + { + /* If the last element is a duplicate, make sure that the + kept one has a valid got_offset. We also update count. */ + if (got_offset != (bfd_vma) -1) + info [dest - 1].got_offset = got_offset; + count = dest; + } + } return count; } @@ -2331,12 +2269,9 @@ sort_dyn_sym_info (struct elfNN_ia64_dyn_sym_info *info, requires a copy which is O(N), but this only happens once. */ static struct elfNN_ia64_dyn_sym_info * -get_dyn_sym_info (ia64_info, h, abfd, rel, create) - struct elfNN_ia64_link_hash_table *ia64_info; - struct elf_link_hash_entry *h; - bfd *abfd; - const Elf_Internal_Rela *rel; - bfd_boolean create; +get_dyn_sym_info (struct elfNN_ia64_link_hash_table *ia64_info, + struct elf_link_hash_entry *h, bfd *abfd, + const Elf_Internal_Rela *rel, bfd_boolean create) { struct elfNN_ia64_dyn_sym_info **info_p, *info, *dyn_i, key; unsigned int *count_p, *sorted_count_p, *size_p; @@ -2432,8 +2367,9 @@ has_space: /* Append the new one to the array. */ dyn_i = info + count; memset (dyn_i, 0, sizeof (*dyn_i)); + dyn_i->got_offset = (bfd_vma) -1; dyn_i->addend = addend; - + /* We increment count only since the new ones are unsorted and may have duplicate. */ (*count_p)++; @@ -2472,10 +2408,8 @@ has_space: } static asection * -get_got (abfd, info, ia64_info) - bfd *abfd; - struct bfd_link_info *info; - struct elfNN_ia64_link_hash_table *ia64_info; +get_got (bfd *abfd, struct bfd_link_info *info, + struct elfNN_ia64_link_hash_table *ia64_info) { asection *got; bfd *dynobj; @@ -2512,10 +2446,8 @@ get_got (abfd, info, ia64_info) of a procedure, thus ensuring a unique address for each procedure. */ static asection * -get_fptr (abfd, info, ia64_info) - bfd *abfd; - struct bfd_link_info *info; - struct elfNN_ia64_link_hash_table *ia64_info; +get_fptr (bfd *abfd, struct bfd_link_info *info, + struct elfNN_ia64_link_hash_table *ia64_info) { asection *fptr; bfd *dynobj; @@ -2568,10 +2500,8 @@ get_fptr (abfd, info, ia64_info) } static asection * -get_pltoff (abfd, info, ia64_info) - bfd *abfd; - struct bfd_link_info *info ATTRIBUTE_UNUSED; - struct elfNN_ia64_link_hash_table *ia64_info; +get_pltoff (bfd *abfd, struct bfd_link_info *info ATTRIBUTE_UNUSED, + struct elfNN_ia64_link_hash_table *ia64_info) { asection *pltoff; bfd *dynobj; @@ -2605,11 +2535,9 @@ get_pltoff (abfd, info, ia64_info) } static asection * -get_reloc_section (abfd, ia64_info, sec, create) - bfd *abfd; - struct elfNN_ia64_link_hash_table *ia64_info; - asection *sec; - bfd_boolean create; +get_reloc_section (bfd *abfd, + struct elfNN_ia64_link_hash_table *ia64_info, + asection *sec, bfd_boolean create) { const char *srel_name; asection *srel; @@ -2621,10 +2549,10 @@ get_reloc_section (abfd, ia64_info, sec, create) if (srel_name == NULL) return NULL; - BFD_ASSERT ((strncmp (srel_name, ".rela", 5) == 0 + BFD_ASSERT ((CONST_STRNEQ (srel_name, ".rela") && strcmp (bfd_get_section_name (abfd, sec), srel_name+5) == 0) - || (strncmp (srel_name, ".rel", 4) == 0 + || (CONST_STRNEQ (srel_name, ".rel") && strcmp (bfd_get_section_name (abfd, sec), srel_name+4) == 0)); @@ -2680,11 +2608,9 @@ count_dyn_reloc (bfd *abfd, struct elfNN_ia64_dyn_sym_info *dyn_i, } static bfd_boolean -elfNN_ia64_check_relocs (abfd, info, sec, relocs) - bfd *abfd; - struct bfd_link_info *info; - asection *sec; - const Elf_Internal_Rela *relocs; +elfNN_ia64_check_relocs (bfd *abfd, struct bfd_link_info *info, + asection *sec, + const Elf_Internal_Rela *relocs) { struct elfNN_ia64_link_hash_table *ia64_info; const Elf_Internal_Rela *relend; @@ -2886,7 +2812,7 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) } /* Now, we only do lookup without insertion, which is very fast - with the modified get_dyn_sym_info. */ + with the modified get_dyn_sym_info. */ for (rel = relocs; rel < relend; ++rel) { struct elfNN_ia64_dyn_sym_info *dyn_i; @@ -3140,9 +3066,8 @@ elfNN_ia64_check_relocs (abfd, info, sec, relocs) external GOT entries first. */ static bfd_boolean -allocate_global_data_got (dyn_i, data) - struct elfNN_ia64_dyn_sym_info *dyn_i; - PTR data; +allocate_global_data_got (struct elfNN_ia64_dyn_sym_info *dyn_i, + PTR data) { struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; @@ -3189,9 +3114,8 @@ allocate_global_data_got (dyn_i, data) /* Next, allocate all the GOT entries used by LTOFF_FPTR relocs. */ static bfd_boolean -allocate_global_fptr_got (dyn_i, data) - struct elfNN_ia64_dyn_sym_info *dyn_i; - PTR data; +allocate_global_fptr_got (struct elfNN_ia64_dyn_sym_info *dyn_i, + PTR data) { struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; @@ -3208,9 +3132,8 @@ allocate_global_fptr_got (dyn_i, data) /* Lastly, allocate all the GOT entries for local data. */ static bfd_boolean -allocate_local_got (dyn_i, data) - struct elfNN_ia64_dyn_sym_info *dyn_i; - PTR data; +allocate_local_got (struct elfNN_ia64_dyn_sym_info *dyn_i, + PTR data) { struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; @@ -3226,8 +3149,7 @@ allocate_local_got (dyn_i, data) /* Search for the index of a global symbol in it's defining object file. */ static long -global_sym_index (h) - struct elf_link_hash_entry *h; +global_sym_index (struct elf_link_hash_entry *h) { struct elf_link_hash_entry **p; bfd *obj; @@ -3246,9 +3168,7 @@ global_sym_index (h) in a main executable that is not exported. */ static bfd_boolean -allocate_fptr (dyn_i, data) - struct elfNN_ia64_dyn_sym_info *dyn_i; - PTR data; +allocate_fptr (struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data) { struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; @@ -3294,9 +3214,8 @@ allocate_fptr (dyn_i, data) /* Allocate all the minimal PLT entries. */ static bfd_boolean -allocate_plt_entries (dyn_i, data) - struct elfNN_ia64_dyn_sym_info *dyn_i; - PTR data; +allocate_plt_entries (struct elfNN_ia64_dyn_sym_info *dyn_i, + PTR data) { struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; @@ -3332,9 +3251,8 @@ allocate_plt_entries (dyn_i, data) /* Allocate all the full PLT entries. */ static bfd_boolean -allocate_plt2_entries (dyn_i, data) - struct elfNN_ia64_dyn_sym_info *dyn_i; - PTR data; +allocate_plt2_entries (struct elfNN_ia64_dyn_sym_info *dyn_i, + PTR data) { struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; @@ -3360,9 +3278,8 @@ allocate_plt2_entries (dyn_i, data) ??? Relaxation might be able to determine that they are. */ static bfd_boolean -allocate_pltoff_entries (dyn_i, data) - struct elfNN_ia64_dyn_sym_info *dyn_i; - PTR data; +allocate_pltoff_entries (struct elfNN_ia64_dyn_sym_info *dyn_i, + PTR data) { struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; @@ -3378,9 +3295,8 @@ allocate_pltoff_entries (dyn_i, data) to be dynamic. */ static bfd_boolean -allocate_dynrel_entries (dyn_i, data) - struct elfNN_ia64_dyn_sym_info *dyn_i; - PTR data; +allocate_dynrel_entries (struct elfNN_ia64_dyn_sym_info *dyn_i, + PTR data) { struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; struct elfNN_ia64_link_hash_table *ia64_info; @@ -3495,9 +3411,8 @@ allocate_dynrel_entries (dyn_i, data) } static bfd_boolean -elfNN_ia64_adjust_dynamic_symbol (info, h) - struct bfd_link_info *info ATTRIBUTE_UNUSED; - struct elf_link_hash_entry *h; +elfNN_ia64_adjust_dynamic_symbol (struct bfd_link_info *info ATTRIBUTE_UNUSED, + struct elf_link_hash_entry *h) { /* ??? Undefined symbols with PLT entries should be re-defined to be the PLT entry. */ @@ -3525,9 +3440,8 @@ elfNN_ia64_adjust_dynamic_symbol (info, h) } static bfd_boolean -elfNN_ia64_size_dynamic_sections (output_bfd, info) - bfd *output_bfd ATTRIBUTE_UNUSED; - struct bfd_link_info *info; +elfNN_ia64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, + struct bfd_link_info *info) { struct elfNN_ia64_allocate_data data; struct elfNN_ia64_link_hash_table *ia64_info; @@ -3702,7 +3616,7 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) if (strcmp (name, ".got.plt") == 0) strip = FALSE; - else if (strncmp (name, ".rel", 4) == 0) + else if (CONST_STRNEQ (name, ".rel")) { if (!strip) { @@ -3775,10 +3689,8 @@ elfNN_ia64_size_dynamic_sections (output_bfd, info) } static bfd_reloc_status_type -elfNN_ia64_install_value (hit_addr, v, r_type) - bfd_byte *hit_addr; - bfd_vma v; - unsigned int r_type; +elfNN_ia64_install_value (bfd_byte *hit_addr, bfd_vma v, + unsigned int r_type) { const struct ia64_operand *op; int bigendian = 0, shift = 0; @@ -4000,16 +3912,10 @@ elfNN_ia64_install_value (hit_addr, v, r_type) } static void -elfNN_ia64_install_dyn_reloc (abfd, info, sec, srel, offset, type, - dynindx, addend) - bfd *abfd; - struct bfd_link_info *info; - asection *sec; - asection *srel; - bfd_vma offset; - unsigned int type; - long dynindx; - bfd_vma addend; +elfNN_ia64_install_dyn_reloc (bfd *abfd, struct bfd_link_info *info, + asection *sec, asection *srel, + bfd_vma offset, unsigned int type, + long dynindx, bfd_vma addend) { Elf_Internal_Rela outrel; bfd_byte *loc; @@ -4039,14 +3945,10 @@ elfNN_ia64_install_dyn_reloc (abfd, info, sec, srel, offset, type, and return the gp-relative address of the linkage table entry. */ static bfd_vma -set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type) - bfd *abfd; - struct bfd_link_info *info; - struct elfNN_ia64_dyn_sym_info *dyn_i; - long dynindx; - bfd_vma addend; - bfd_vma value; - unsigned int dyn_r_type; +set_got_entry (bfd *abfd, struct bfd_link_info *info, + struct elfNN_ia64_dyn_sym_info *dyn_i, + long dynindx, bfd_vma addend, bfd_vma value, + unsigned int dyn_r_type) { struct elfNN_ia64_link_hash_table *ia64_info; asection *got_sec; @@ -4183,11 +4085,9 @@ set_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type) address and its global pointer. Return the descriptor's address. */ static bfd_vma -set_fptr_entry (abfd, info, dyn_i, value) - bfd *abfd; - struct bfd_link_info *info; - struct elfNN_ia64_dyn_sym_info *dyn_i; - bfd_vma value; +set_fptr_entry (bfd *abfd, struct bfd_link_info *info, + struct elfNN_ia64_dyn_sym_info *dyn_i, + bfd_vma value) { struct elfNN_ia64_link_hash_table *ia64_info; asection *fptr_sec; @@ -4235,12 +4135,9 @@ set_fptr_entry (abfd, info, dyn_i, value) and its global pointer. Return the descriptor's address. */ static bfd_vma -set_pltoff_entry (abfd, info, dyn_i, value, is_plt) - bfd *abfd; - struct bfd_link_info *info; - struct elfNN_ia64_dyn_sym_info *dyn_i; - bfd_vma value; - bfd_boolean is_plt; +set_pltoff_entry (bfd *abfd, struct bfd_link_info *info, + struct elfNN_ia64_dyn_sym_info *dyn_i, + bfd_vma value, bfd_boolean is_plt) { struct elfNN_ia64_link_hash_table *ia64_info; asection *pltoff_sec; @@ -4300,12 +4197,9 @@ set_pltoff_entry (abfd, info, dyn_i, value, is_plt) is assigned offset round(2 * size of pointer, PT_TLS p_align). */ static bfd_vma -elfNN_ia64_tprel_base (info) - struct bfd_link_info *info; +elfNN_ia64_tprel_base (struct bfd_link_info *info) { asection *tls_sec = elf_hash_table (info)->tls_sec; - - BFD_ASSERT (tls_sec != NULL); return tls_sec->vma - align_power ((bfd_vma) ARCH_SIZE / 4, tls_sec->alignment_power); } @@ -4315,10 +4209,8 @@ elfNN_ia64_tprel_base (info) This is PT_TLS segment p_vaddr. */ static bfd_vma -elfNN_ia64_dtprel_base (info) - struct bfd_link_info *info; +elfNN_ia64_dtprel_base (struct bfd_link_info *info) { - BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); return elf_hash_table (info)->tls_sec->vma; } @@ -4329,9 +4221,7 @@ elfNN_ia64_dtprel_base (info) static bfd *elfNN_ia64_unwind_entry_compare_bfd; static int -elfNN_ia64_unwind_entry_compare (a, b) - const PTR a; - const PTR b; +elfNN_ia64_unwind_entry_compare (const PTR a, const PTR b) { bfd_vma av, bv; @@ -4343,9 +4233,7 @@ elfNN_ia64_unwind_entry_compare (a, b) /* Make sure we've got ourselves a nice fat __gp value. */ static bfd_boolean -elfNN_ia64_choose_gp (abfd, info) - bfd *abfd; - struct bfd_link_info *info; +elfNN_ia64_choose_gp (bfd *abfd, struct bfd_link_info *info) { bfd_vma min_vma = (bfd_vma) -1, max_vma = 0; bfd_vma min_short_vma = min_vma, max_short_vma = 0; @@ -4461,9 +4349,7 @@ elfNN_ia64_choose_gp (abfd, info) } static bfd_boolean -elfNN_ia64_final_link (abfd, info) - bfd *abfd; - struct bfd_link_info *info; +elfNN_ia64_final_link (bfd *abfd, struct bfd_link_info *info) { struct elfNN_ia64_link_hash_table *ia64_info; asection *unwind_output_sec; @@ -4532,16 +4418,14 @@ elfNN_ia64_final_link (abfd, info) } static bfd_boolean -elfNN_ia64_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; +elfNN_ia64_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 elfNN_ia64_link_hash_table *ia64_info; Elf_Internal_Shdr *symtab_hdr; @@ -4564,7 +4448,6 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, elf_section_data(input_section->output_section) ->this_hdr.sh_flags |= flags; - return TRUE; } gp_val = _bfd_get_gp_value (output_bfd); @@ -4613,7 +4496,8 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, sym_sec = local_sections[r_symndx]; msec = sym_sec; value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel); - if ((sym_sec->flags & SEC_MERGE) + if (!info->relocatable + && (sym_sec->flags & SEC_MERGE) != 0 && ELF_ST_TYPE (sym->st_info) == STT_SECTION && sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE) { @@ -4642,9 +4526,15 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, - sym_sec->output_section->vma - sym_sec->output_offset; } - - qsort (loc_h->info, loc_h->count, - sizeof (*loc_h->info), addend_compare); + + /* We may have introduced duplicated entries. We need + to remove them properly. */ + count = sort_dyn_sym_info (loc_h->info, loc_h->count); + if (count != loc_h->count) + { + loc_h->count = count; + loc_h->sorted_count = count; + } loc_h->sec_merge_done = 1; } @@ -4667,6 +4557,20 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, continue; } + /* 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. */ + if (sym_sec != NULL && elf_discarded_section (sym_sec)) + { + _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); + rel->r_info = 0; + rel->r_addend = 0; + continue; + } + + if (info->relocatable) + continue; + hit_addr = contents + rel->r_offset; value += rel->r_addend; dynamic_symbol_p = elfNN_ia64_dynamic_symbol_p (h, info, r_type); @@ -4998,32 +4902,12 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, case R_IA64_SEGREL32LSB: case R_IA64_SEGREL64MSB: case R_IA64_SEGREL64LSB: - if (r_symndx == 0) - { - /* If the input section was discarded from the output, then - do nothing. */ - r = bfd_reloc_ok; - } - else { - struct elf_segment_map *m; - Elf_Internal_Phdr *p; - /* Find the segment that contains the output_section. */ - for (m = elf_tdata (output_bfd)->segment_map, - p = elf_tdata (output_bfd)->phdr; - m != NULL; - m = m->next, p++) - { - int i; - for (i = m->count - 1; i >= 0; i--) - if (m->sections[i] == input_section->output_section) - break; - if (i >= 0) - break; - } + Elf_Internal_Phdr *p = _bfd_elf_find_segment_containing_section + (output_bfd, input_section->output_section); - if (m == NULL) + if (p == NULL) { r = bfd_reloc_notsupported; } @@ -5096,6 +4980,8 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, case R_IA64_TPREL14: case R_IA64_TPREL22: case R_IA64_TPREL64I: + if (elf_hash_table (info)->tls_sec == NULL) + goto missing_tls_sec; value -= elfNN_ia64_tprel_base (info); r = elfNN_ia64_install_value (hit_addr, value, r_type); break; @@ -5107,6 +4993,8 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, case R_IA64_DTPREL32MSB: case R_IA64_DTPREL64LSB: case R_IA64_DTPREL64MSB: + if (elf_hash_table (info)->tls_sec == NULL) + goto missing_tls_sec; value -= elfNN_ia64_dtprel_base (info); r = elfNN_ia64_install_value (hit_addr, value, r_type); break; @@ -5125,6 +5013,8 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, case R_IA64_LTOFF_TPREL22: if (!dynamic_symbol_p) { + if (elf_hash_table (info)->tls_sec == NULL) + goto missing_tls_sec; if (!info->shared) value -= elfNN_ia64_tprel_base (info); else @@ -5142,7 +5032,11 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, break; case R_IA64_LTOFF_DTPREL22: if (!dynamic_symbol_p) - value -= elfNN_ia64_dtprel_base (info); + { + if (elf_hash_table (info)->tls_sec == NULL) + goto missing_tls_sec; + value -= elfNN_ia64_dtprel_base (info); + } got_r_type = R_IA64_DTPRELNNLSB; break; } @@ -5193,6 +5087,7 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, case bfd_reloc_outofrange: case bfd_reloc_overflow: default: +missing_tls_sec: { const char *name; @@ -5204,6 +5099,25 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, switch (r_type) { + case R_IA64_TPREL14: + case R_IA64_TPREL22: + case R_IA64_TPREL64I: + case R_IA64_DTPREL14: + case R_IA64_DTPREL22: + case R_IA64_DTPREL64I: + case R_IA64_DTPREL32LSB: + case R_IA64_DTPREL32MSB: + case R_IA64_DTPREL64LSB: + case R_IA64_DTPREL64MSB: + case R_IA64_LTOFF_TPREL22: + case R_IA64_LTOFF_DTPMOD22: + case R_IA64_LTOFF_DTPREL22: + (*_bfd_error_handler) + (_("%B: missing TLS section for relocation %s against `%s' at 0x%lx in section `%A'."), + input_bfd, input_section, howto->name, name, + rel->r_offset); + break; + case R_IA64_PCREL21B: case R_IA64_PCREL21BI: case R_IA64_PCREL21M: @@ -5242,11 +5156,10 @@ elfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, } static bfd_boolean -elfNN_ia64_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; +elfNN_ia64_finish_dynamic_symbol (bfd *output_bfd, + struct bfd_link_info *info, + struct elf_link_hash_entry *h, + Elf_Internal_Sym *sym) { struct elfNN_ia64_link_hash_table *ia64_info; struct elfNN_ia64_dyn_sym_info *dyn_i; @@ -5331,9 +5244,8 @@ elfNN_ia64_finish_dynamic_symbol (output_bfd, info, h, sym) } static bfd_boolean -elfNN_ia64_finish_dynamic_sections (abfd, info) - bfd *abfd; - struct bfd_link_info *info; +elfNN_ia64_finish_dynamic_sections (bfd *abfd, + struct bfd_link_info *info) { struct elfNN_ia64_link_hash_table *ia64_info; bfd *dynobj; @@ -5419,9 +5331,7 @@ elfNN_ia64_finish_dynamic_sections (abfd, info) /* Function to keep IA-64 specific file flags. */ static bfd_boolean -elfNN_ia64_set_private_flags (abfd, flags) - bfd *abfd; - flagword flags; +elfNN_ia64_set_private_flags (bfd *abfd, flagword flags) { BFD_ASSERT (!elf_flags_init (abfd) || elf_elfheader (abfd)->e_flags == flags); @@ -5434,8 +5344,7 @@ elfNN_ia64_set_private_flags (abfd, flags) /* Merge backend specific data from an object file to the output object file when linking. */ static bfd_boolean -elfNN_ia64_merge_private_bfd_data (ibfd, obfd) - bfd *ibfd, *obfd; +elfNN_ia64_merge_private_bfd_data (bfd *ibfd, bfd *obfd) { flagword out_flags; flagword in_flags; @@ -5523,9 +5432,7 @@ elfNN_ia64_merge_private_bfd_data (ibfd, obfd) } static bfd_boolean -elfNN_ia64_print_private_bfd_data (abfd, ptr) - bfd *abfd; - PTR ptr; +elfNN_ia64_print_private_bfd_data (bfd *abfd, PTR ptr) { FILE *file = (FILE *) ptr; flagword flags = elf_elfheader (abfd)->e_flags; @@ -5547,8 +5454,7 @@ elfNN_ia64_print_private_bfd_data (abfd, ptr) } static enum elf_reloc_type_class -elfNN_ia64_reloc_type_class (rela) - const Elf_Internal_Rela *rela; +elfNN_ia64_reloc_type_class (const Elf_Internal_Rela *rela) { switch ((int) ELFNN_R_TYPE (rela->r_info)) { @@ -5569,9 +5475,9 @@ elfNN_ia64_reloc_type_class (rela) static const struct bfd_elf_special_section elfNN_ia64_special_sections[] = { - { ".sbss", 5, -1, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT }, - { ".sdata", 6, -1, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT }, - { NULL, 0, 0, 0, 0 } + { STRING_COMMA_LEN (".sbss"), -1, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT }, + { STRING_COMMA_LEN (".sdata"), -1, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT }, + { NULL, 0, 0, 0, 0 } }; static bfd_boolean @@ -5598,7 +5504,7 @@ elfNN_ia64_object_p (bfd *abfd) if (elf_sec_group (sec) == NULL && ((sec->flags & (SEC_LINK_ONCE | SEC_CODE | SEC_GROUP)) == (SEC_LINK_ONCE | SEC_CODE)) - && strncmp (sec->name, ".gnu.linkonce.t.", 16) == 0) + && CONST_STRNEQ (sec->name, ".gnu.linkonce.t.")) { name = sec->name + 16; @@ -5675,21 +5581,18 @@ elfNN_ia64_hpux_vec (const bfd_target *vec) } static void -elfNN_hpux_post_process_headers (abfd, info) - bfd *abfd; - struct bfd_link_info *info ATTRIBUTE_UNUSED; +elfNN_hpux_post_process_headers (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) { Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); - i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_HPUX; + i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi; i_ehdrp->e_ident[EI_ABIVERSION] = 1; } -bfd_boolean -elfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval) - bfd *abfd ATTRIBUTE_UNUSED; - asection *sec; - int *retval; +static bfd_boolean +elfNN_hpux_backend_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, int *retval) { if (bfd_is_com_section (sec)) { @@ -5715,6 +5618,267 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, } } +static bfd_boolean +elfNN_vms_section_from_shdr (bfd *abfd, + Elf_Internal_Shdr *hdr, + const char *name, + int shindex) +{ + asection *newsect; + + switch (hdr->sh_type) + { + case SHT_IA_64_VMS_TRACE: + case SHT_IA_64_VMS_DEBUG: + case SHT_IA_64_VMS_DEBUG_STR: + break; + + default: + return elfNN_ia64_section_from_shdr (abfd, hdr, name, shindex); + } + + if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) + return FALSE; + newsect = hdr->bfd_section; + + return TRUE; +} + +static bfd_boolean +elfNN_vms_object_p (bfd *abfd) +{ + Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); + Elf_Internal_Phdr *i_phdr = elf_tdata (abfd)->phdr; + unsigned int i; + unsigned int num_text = 0; + unsigned int num_data = 0; + unsigned int num_rodata = 0; + char name[16]; + + if (!elfNN_ia64_object_p (abfd)) + return FALSE; + + for (i = 0; i < i_ehdrp->e_phnum; i++, i_phdr++) + { + /* Is there a section for this segment? */ + bfd_vma base_vma = i_phdr->p_vaddr; + bfd_vma limit_vma = base_vma + i_phdr->p_filesz; + + if (i_phdr->p_type != PT_LOAD) + continue; + + again: + while (base_vma < limit_vma) + { + bfd_vma next_vma = limit_vma; + asection *nsec; + asection *sec; + flagword flags; + char *nname = NULL; + + /* Find a section covering base_vma. */ + for (sec = abfd->sections; sec != NULL; sec = sec->next) + { + if ((sec->flags & (SEC_ALLOC | SEC_LOAD)) == 0) + continue; + if (sec->vma <= base_vma && sec->vma + sec->size > base_vma) + { + base_vma = sec->vma + sec->size; + goto again; + } + if (sec->vma < next_vma && sec->vma + sec->size >= base_vma) + next_vma = sec->vma; + } + + /* No section covering [base_vma; next_vma). Create a fake one. */ + flags = SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS; + if (i_phdr->p_flags & PF_X) + { + flags |= SEC_CODE; + if (num_text++ == 0) + nname = ".text"; + else + sprintf (name, ".text$%u", num_text); + } + else if ((i_phdr->p_flags & (PF_R | PF_W)) == PF_R) + { + flags |= SEC_READONLY; + sprintf (name, ".rodata$%u", num_rodata++); + } + else + { + flags |= SEC_DATA; + sprintf (name, ".data$%u", num_data++); + } + + /* Allocate name. */ + if (nname == NULL) + { + size_t name_len = strlen (name) + 1; + nname = bfd_alloc (abfd, name_len); + if (nname == NULL) + return FALSE; + memcpy (nname, name, name_len); + } + + /* Create and fill new section. */ + nsec = bfd_make_section_anyway_with_flags (abfd, nname, flags); + if (nsec == NULL) + return FALSE; + nsec->vma = base_vma; + nsec->size = next_vma - base_vma; + nsec->filepos = i_phdr->p_offset + (base_vma - i_phdr->p_vaddr); + + base_vma = next_vma; + } + } + return TRUE; +} + +static void +elfNN_vms_post_process_headers (bfd *abfd, + struct bfd_link_info *info ATTRIBUTE_UNUSED) +{ + Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); + + i_ehdrp->e_ident[EI_OSABI] = ELFOSABI_OPENVMS; + i_ehdrp->e_ident[EI_ABIVERSION] = 2; +} + +static bfd_boolean +elfNN_vms_section_processing (bfd *abfd ATTRIBUTE_UNUSED, + Elf_Internal_Shdr *hdr) +{ + if (hdr->bfd_section != NULL) + { + const char *name = bfd_get_section_name (abfd, hdr->bfd_section); + + if (strcmp (name, ".text") == 0) + hdr->sh_flags |= SHF_IA_64_VMS_SHARED; + else if ((strcmp (name, ".debug") == 0) + || (strcmp (name, ".debug_abbrev") == 0) + || (strcmp (name, ".debug_aranges") == 0) + || (strcmp (name, ".debug_frame") == 0) + || (strcmp (name, ".debug_info") == 0) + || (strcmp (name, ".debug_loc") == 0) + || (strcmp (name, ".debug_macinfo") == 0) + || (strcmp (name, ".debug_pubnames") == 0) + || (strcmp (name, ".debug_pubtypes") == 0)) + hdr->sh_type = SHT_IA_64_VMS_DEBUG; + else if ((strcmp (name, ".debug_line") == 0) + || (strcmp (name, ".debug_ranges") == 0)) + hdr->sh_type = SHT_IA_64_VMS_TRACE; + else if (strcmp (name, ".debug_str") == 0) + hdr->sh_type = SHT_IA_64_VMS_DEBUG_STR; + else if (strcmp (name, ".vms_display_name_info") == 0) + { + int idx, symcount; + asymbol **syms; + struct elf_obj_tdata *t = elf_tdata (abfd); + int buf[2]; + int demangler_sym_idx = -1; + + symcount = bfd_get_symcount (abfd); + syms = bfd_get_outsymbols (abfd); + for (idx = 0; idx < symcount; idx++) + { + asymbol *sym; + sym = syms[idx]; + if ((sym->flags & (BSF_DEBUGGING | BSF_DYNAMIC)) + && strchr (sym->name, '@') + && (strcmp (sym->section->name, BFD_ABS_SECTION_NAME) == 0)) + { + demangler_sym_idx = sym->udata.i; + break; + } + } + + hdr->sh_type = SHT_IA_64_VMS_DISPLAY_NAME_INFO; + hdr->sh_entsize = 4; + hdr->sh_addralign = 0; + hdr->sh_link = t->symtab_section; + + /* Find symtab index of demangler routine and stuff it in + the second long word of section data. */ + + if (demangler_sym_idx > -1) + { + bfd_seek (abfd, hdr->sh_offset, SEEK_SET); + bfd_bread (buf, hdr->sh_size, abfd); + buf [1] = demangler_sym_idx; + bfd_seek (abfd, hdr->sh_offset, SEEK_SET); + bfd_bwrite (buf, hdr->sh_size, abfd); + } + } + } + + return TRUE; +} + +/* The final processing done just before writing out a VMS IA-64 ELF + object file. */ + +static void +elfNN_vms_final_write_processing (bfd *abfd, + bfd_boolean linker ATTRIBUTE_UNUSED) +{ + Elf_Internal_Shdr *hdr; + asection *s; + int unwind_info_sect_idx = 0; + + for (s = abfd->sections; s; s = s->next) + { + hdr = &elf_section_data (s)->this_hdr; + + if (strcmp (bfd_get_section_name (abfd, hdr->bfd_section), + ".IA_64.unwind_info") == 0) + unwind_info_sect_idx = elf_section_data (s)->this_idx; + + switch (hdr->sh_type) + { + case SHT_IA_64_UNWIND: + /* VMS requires sh_info to point to the unwind info section. */ + hdr->sh_info = unwind_info_sect_idx; + break; + } + } + + if (! elf_flags_init (abfd)) + { + unsigned long flags = 0; + + if (abfd->xvec->byteorder == BFD_ENDIAN_BIG) + flags |= EF_IA_64_BE; + if (bfd_get_mach (abfd) == bfd_mach_ia64_elf64) + flags |= EF_IA_64_ABI64; + + elf_elfheader(abfd)->e_flags = flags; + elf_flags_init (abfd) = TRUE; + } +} + +static bfd_boolean +elfNN_vms_close_and_cleanup (bfd *abfd) +{ + if (bfd_get_format (abfd) == bfd_object) + { + long isize, irsize; + + if (elf_shstrtab (abfd) != NULL) + _bfd_elf_strtab_free (elf_shstrtab (abfd)); + + /* Pad to 8 byte boundary for IPF/VMS. */ + isize = bfd_get_size (abfd); + if ((irsize = isize/8*8) < isize) + { + int ishort = (irsize + 8) - isize; + bfd_seek (abfd, isize, SEEK_SET); + bfd_bwrite (bfd_zmalloc (ishort), ishort, abfd); + } + } + + return _bfd_generic_close_and_cleanup (abfd); +} #define TARGET_LITTLE_SYM bfd_elfNN_ia64_little_vec #define TARGET_LITTLE_NAME "elfNN-ia64-little" @@ -5748,6 +5912,8 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, #define bfd_elfNN_bfd_reloc_type_lookup \ elfNN_ia64_reloc_type_lookup +#define bfd_elfNN_bfd_reloc_name_lookup \ + elfNN_ia64_reloc_name_lookup #define bfd_elfNN_bfd_is_local_label_name \ elfNN_ia64_is_local_label_name #define bfd_elfNN_bfd_relax_section \ @@ -5769,6 +5935,8 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, elfNN_ia64_adjust_dynamic_symbol #define elf_backend_size_dynamic_sections \ elfNN_ia64_size_dynamic_sections +#define elf_backend_omit_section_dynsym \ + ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) #define elf_backend_relocate_section \ elfNN_ia64_relocate_section #define elf_backend_finish_dynamic_symbol \ @@ -5800,6 +5968,7 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, #define elf_backend_reloc_type_class elfNN_ia64_reloc_type_class #define elf_backend_rela_normal 1 #define elf_backend_special_sections elfNN_ia64_special_sections +#define elf_backend_default_execstack 0 /* FIXME: PR 290: The Intel C compiler generates SHT_IA_64_UNWIND with SHF_LINK_ORDER. But it doesn't set the sh_link or sh_info fields. @@ -5833,13 +6002,54 @@ elfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, #undef elf_backend_want_p_paddr_set_to_zero #define elf_backend_want_p_paddr_set_to_zero 1 -#undef ELF_MAXPAGESIZE -#define ELF_MAXPAGESIZE 0x1000 /* 4K */ #undef ELF_COMMONPAGESIZE +#undef ELF_OSABI +#define ELF_OSABI ELFOSABI_HPUX #undef elfNN_bed #define elfNN_bed elfNN_ia64_hpux_bed #include "elfNN-target.h" +/* VMS-specific vectors. */ + +#undef TARGET_LITTLE_SYM +#define TARGET_LITTLE_SYM bfd_elfNN_ia64_vms_vec +#undef TARGET_LITTLE_NAME +#define TARGET_LITTLE_NAME "elfNN-ia64-vms" +#undef TARGET_BIG_SYM +#undef TARGET_BIG_NAME + +/* These are VMS specific functions. */ + +#undef elf_backend_object_p +#define elf_backend_object_p elfNN_vms_object_p + +#undef elf_backend_section_from_shdr +#define elf_backend_section_from_shdr elfNN_vms_section_from_shdr + +#undef elf_backend_post_process_headers +#define elf_backend_post_process_headers elfNN_vms_post_process_headers + +#undef elf_backend_section_processing +#define elf_backend_section_processing elfNN_vms_section_processing + +#undef elf_backend_final_write_processing +#define elf_backend_final_write_processing elfNN_vms_final_write_processing + +#undef bfd_elfNN_close_and_cleanup +#define bfd_elfNN_close_and_cleanup elfNN_vms_close_and_cleanup + +#undef elf_backend_section_from_bfd_section + +#undef elf_backend_symbol_processing + #undef elf_backend_want_p_paddr_set_to_zero + +#undef ELF_MAXPAGESIZE +#define ELF_MAXPAGESIZE 0x10000 /* 64KB */ + +#undef elfNN_bed +#define elfNN_bed elfNN_ia64_vms_bed + +#include "elfNN-target.h"