184865Sobrien/* IA-64 support for 64-bit ELF 2218822Sdim Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 3130561Sobrien Free Software Foundation, Inc. 484865Sobrien Contributed by David Mosberger-Tang <davidm@hpl.hp.com> 584865Sobrien 6130561Sobrien This file is part of BFD, the Binary File Descriptor library. 784865Sobrien 8130561Sobrien This program is free software; you can redistribute it and/or modify 9130561Sobrien it under the terms of the GNU General Public License as published by 10130561Sobrien the Free Software Foundation; either version 2 of the License, or 11130561Sobrien (at your option) any later version. 1284865Sobrien 13130561Sobrien This program is distributed in the hope that it will be useful, 14130561Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 15130561Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16130561Sobrien GNU General Public License for more details. 1784865Sobrien 18130561Sobrien You should have received a copy of the GNU General Public License 19130561Sobrien along with this program; if not, write to the Free Software 20218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2184865Sobrien 22218822Sdim#include "sysdep.h" 2384865Sobrien#include "bfd.h" 2484865Sobrien#include "libbfd.h" 2584865Sobrien#include "elf-bfd.h" 2684865Sobrien#include "opcode/ia64.h" 2784865Sobrien#include "elf/ia64.h" 28130561Sobrien#include "objalloc.h" 29130561Sobrien#include "hashtab.h" 3084865Sobrien 31218822Sdim#define ARCH_SIZE NN 32218822Sdim 33218822Sdim#if ARCH_SIZE == 64 34218822Sdim#define LOG_SECTION_ALIGN 3 35218822Sdim#endif 36218822Sdim 37218822Sdim#if ARCH_SIZE == 32 38218822Sdim#define LOG_SECTION_ALIGN 2 39218822Sdim#endif 40218822Sdim 41130561Sobrien/* THE RULES for all the stuff the linker creates -- 4284865Sobrien 43130561Sobrien GOT Entries created in response to LTOFF or LTOFF_FPTR 44130561Sobrien relocations. Dynamic relocs created for dynamic 45130561Sobrien symbols in an application; REL relocs for locals 46130561Sobrien in a shared library. 4784865Sobrien 48130561Sobrien FPTR The canonical function descriptor. Created for local 49130561Sobrien symbols in applications. Descriptors for dynamic symbols 50130561Sobrien and local symbols in shared libraries are created by 51130561Sobrien ld.so. Thus there are no dynamic relocs against these 52130561Sobrien objects. The FPTR relocs for such _are_ passed through 53130561Sobrien to the dynamic relocation tables. 54130561Sobrien 55130561Sobrien FULL_PLT Created for a PCREL21B relocation against a dynamic symbol. 56130561Sobrien Requires the creation of a PLTOFF entry. This does not 57130561Sobrien require any dynamic relocations. 58130561Sobrien 59130561Sobrien PLTOFF Created by PLTOFF relocations. For local symbols, this 60130561Sobrien is an alternate function descriptor, and in shared libraries 61130561Sobrien requires two REL relocations. Note that this cannot be 62130561Sobrien transformed into an FPTR relocation, since it must be in 63130561Sobrien range of the GP. For dynamic symbols, this is a function 64130561Sobrien descriptor for a MIN_PLT entry, and requires one IPLT reloc. 65130561Sobrien 66130561Sobrien MIN_PLT Created by PLTOFF entries against dynamic symbols. This 67130561Sobrien does not require dynamic relocations. */ 68130561Sobrien 6984865Sobrien#define NELEMS(a) ((int) (sizeof (a) / sizeof ((a)[0]))) 7084865Sobrien 7184865Sobrientypedef struct bfd_hash_entry *(*new_hash_entry_func) 7284865Sobrien PARAMS ((struct bfd_hash_entry *, struct bfd_hash_table *, const char *)); 7384865Sobrien 7484865Sobrien/* In dynamically (linker-) created sections, we generally need to keep track 7584865Sobrien of the place a symbol or expression got allocated to. This is done via hash 7684865Sobrien tables that store entries of the following type. */ 7784865Sobrien 7884865Sobrienstruct elfNN_ia64_dyn_sym_info 7984865Sobrien{ 8084865Sobrien /* The addend for which this entry is relevant. */ 8184865Sobrien bfd_vma addend; 8284865Sobrien 8384865Sobrien bfd_vma got_offset; 8484865Sobrien bfd_vma fptr_offset; 8584865Sobrien bfd_vma pltoff_offset; 8684865Sobrien bfd_vma plt_offset; 8784865Sobrien bfd_vma plt2_offset; 88104834Sobrien bfd_vma tprel_offset; 89104834Sobrien bfd_vma dtpmod_offset; 90104834Sobrien bfd_vma dtprel_offset; 9184865Sobrien 92130561Sobrien /* The symbol table entry, if any, that this was derived from. */ 9384865Sobrien struct elf_link_hash_entry *h; 9484865Sobrien 9584865Sobrien /* Used to count non-got, non-plt relocations for delayed sizing 9684865Sobrien of relocation sections. */ 9784865Sobrien struct elfNN_ia64_dyn_reloc_entry 9884865Sobrien { 9984865Sobrien struct elfNN_ia64_dyn_reloc_entry *next; 10084865Sobrien asection *srel; 10184865Sobrien int type; 10284865Sobrien int count; 103130561Sobrien 104130561Sobrien /* Is this reloc against readonly section? */ 105130561Sobrien bfd_boolean reltext; 10684865Sobrien } *reloc_entries; 10784865Sobrien 108130561Sobrien /* TRUE when the section contents have been updated. */ 10984865Sobrien unsigned got_done : 1; 11084865Sobrien unsigned fptr_done : 1; 11184865Sobrien unsigned pltoff_done : 1; 112104834Sobrien unsigned tprel_done : 1; 113104834Sobrien unsigned dtpmod_done : 1; 114104834Sobrien unsigned dtprel_done : 1; 11584865Sobrien 116130561Sobrien /* TRUE for the different kinds of linker data we want created. */ 11784865Sobrien unsigned want_got : 1; 118130561Sobrien unsigned want_gotx : 1; 11984865Sobrien unsigned want_fptr : 1; 12084865Sobrien unsigned want_ltoff_fptr : 1; 12184865Sobrien unsigned want_plt : 1; 12284865Sobrien unsigned want_plt2 : 1; 12384865Sobrien unsigned want_pltoff : 1; 124104834Sobrien unsigned want_tprel : 1; 125104834Sobrien unsigned want_dtpmod : 1; 126104834Sobrien unsigned want_dtprel : 1; 12784865Sobrien}; 12884865Sobrien 12984865Sobrienstruct elfNN_ia64_local_hash_entry 13084865Sobrien{ 131130561Sobrien int id; 132130561Sobrien unsigned int r_sym; 133218822Sdim /* The number of elements in elfNN_ia64_dyn_sym_info array. */ 134218822Sdim unsigned int count; 135218822Sdim /* The number of sorted elements in elfNN_ia64_dyn_sym_info array. */ 136218822Sdim unsigned int sorted_count; 137218822Sdim /* The size of elfNN_ia64_dyn_sym_info array. */ 138218822Sdim unsigned int size; 139218822Sdim /* The array of elfNN_ia64_dyn_sym_info. */ 14084865Sobrien struct elfNN_ia64_dyn_sym_info *info; 14189857Sobrien 142130561Sobrien /* TRUE if this hash entry's addends was translated for 14389857Sobrien SHF_MERGE optimization. */ 14489857Sobrien unsigned sec_merge_done : 1; 14584865Sobrien}; 14684865Sobrien 14784865Sobrienstruct elfNN_ia64_link_hash_entry 14884865Sobrien{ 14984865Sobrien struct elf_link_hash_entry root; 150218822Sdim /* The number of elements in elfNN_ia64_dyn_sym_info array. */ 151218822Sdim unsigned int count; 152218822Sdim /* The number of sorted elements in elfNN_ia64_dyn_sym_info array. */ 153218822Sdim unsigned int sorted_count; 154218822Sdim /* The size of elfNN_ia64_dyn_sym_info array. */ 155218822Sdim unsigned int size; 156218822Sdim /* The array of elfNN_ia64_dyn_sym_info. */ 15784865Sobrien struct elfNN_ia64_dyn_sym_info *info; 15884865Sobrien}; 15984865Sobrien 16084865Sobrienstruct elfNN_ia64_link_hash_table 16184865Sobrien{ 162130561Sobrien /* The main hash table. */ 16384865Sobrien struct elf_link_hash_table root; 16484865Sobrien 16584865Sobrien asection *got_sec; /* the linkage table section (or NULL) */ 16684865Sobrien asection *rel_got_sec; /* dynamic relocation section for same */ 16784865Sobrien asection *fptr_sec; /* function descriptor table (or NULL) */ 168130561Sobrien asection *rel_fptr_sec; /* dynamic relocation section for same */ 16984865Sobrien asection *plt_sec; /* the primary plt section (or NULL) */ 17084865Sobrien asection *pltoff_sec; /* private descriptors for plt (or NULL) */ 17184865Sobrien asection *rel_pltoff_sec; /* dynamic relocation section for same */ 17284865Sobrien 17384865Sobrien bfd_size_type minplt_entries; /* number of minplt entries */ 17489857Sobrien unsigned reltext : 1; /* are there relocs against readonly sections? */ 175130561Sobrien unsigned self_dtpmod_done : 1;/* has self DTPMOD entry been finished? */ 176130561Sobrien bfd_vma self_dtpmod_offset; /* .got offset to self DTPMOD entry */ 17784865Sobrien 178130561Sobrien htab_t loc_hash_table; 179130561Sobrien void *loc_hash_memory; 18084865Sobrien}; 18184865Sobrien 182130561Sobrienstruct elfNN_ia64_allocate_data 183130561Sobrien{ 184130561Sobrien struct bfd_link_info *info; 185130561Sobrien bfd_size_type ofs; 186218822Sdim bfd_boolean only_got; 187130561Sobrien}; 188130561Sobrien 18984865Sobrien#define elfNN_ia64_hash_table(p) \ 19084865Sobrien ((struct elfNN_ia64_link_hash_table *) ((p)->hash)) 19184865Sobrien 19284865Sobrienstatic bfd_reloc_status_type elfNN_ia64_reloc 19384865Sobrien PARAMS ((bfd *abfd, arelent *reloc, asymbol *sym, PTR data, 19484865Sobrien asection *input_section, bfd *output_bfd, char **error_message)); 19584865Sobrienstatic reloc_howto_type * lookup_howto 19684865Sobrien PARAMS ((unsigned int rtype)); 19784865Sobrienstatic reloc_howto_type *elfNN_ia64_reloc_type_lookup 19884865Sobrien PARAMS ((bfd *abfd, bfd_reloc_code_real_type bfd_code)); 19984865Sobrienstatic void elfNN_ia64_info_to_howto 200130561Sobrien PARAMS ((bfd *abfd, arelent *bfd_reloc, Elf_Internal_Rela *elf_reloc)); 201130561Sobrienstatic bfd_boolean elfNN_ia64_relax_section 20284865Sobrien PARAMS((bfd *abfd, asection *sec, struct bfd_link_info *link_info, 203130561Sobrien bfd_boolean *again)); 204130561Sobrienstatic void elfNN_ia64_relax_ldxmov 205218822Sdim PARAMS((bfd_byte *contents, bfd_vma off)); 206130561Sobrienstatic bfd_boolean is_unwind_section_name 20789857Sobrien PARAMS ((bfd *abfd, const char *)); 208130561Sobrienstatic bfd_boolean elfNN_ia64_section_flags 209218822Sdim PARAMS ((flagword *, const Elf_Internal_Shdr *)); 210130561Sobrienstatic bfd_boolean elfNN_ia64_fake_sections 211130561Sobrien PARAMS ((bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)); 21284865Sobrienstatic void elfNN_ia64_final_write_processing 213130561Sobrien PARAMS ((bfd *abfd, bfd_boolean linker)); 214130561Sobrienstatic bfd_boolean elfNN_ia64_add_symbol_hook 215130561Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info, Elf_Internal_Sym *sym, 21684865Sobrien const char **namep, flagword *flagsp, asection **secp, 21784865Sobrien bfd_vma *valp)); 218130561Sobrienstatic bfd_boolean elfNN_ia64_is_local_label_name 21984865Sobrien PARAMS ((bfd *abfd, const char *name)); 220130561Sobrienstatic bfd_boolean elfNN_ia64_dynamic_symbol_p 221130561Sobrien PARAMS ((struct elf_link_hash_entry *h, struct bfd_link_info *info, int)); 22284865Sobrienstatic struct bfd_hash_entry *elfNN_ia64_new_elf_hash_entry 22384865Sobrien PARAMS ((struct bfd_hash_entry *entry, struct bfd_hash_table *table, 22484865Sobrien const char *string)); 22589857Sobrienstatic void elfNN_ia64_hash_copy_indirect 226218822Sdim PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, 227104834Sobrien struct elf_link_hash_entry *)); 22889857Sobrienstatic void elfNN_ia64_hash_hide_symbol 229130561Sobrien PARAMS ((struct bfd_link_info *, struct elf_link_hash_entry *, bfd_boolean)); 230130561Sobrienstatic hashval_t elfNN_ia64_local_htab_hash PARAMS ((const void *)); 231130561Sobrienstatic int elfNN_ia64_local_htab_eq PARAMS ((const void *ptr1, 232130561Sobrien const void *ptr2)); 23384865Sobrienstatic struct bfd_link_hash_table *elfNN_ia64_hash_table_create 23484865Sobrien PARAMS ((bfd *abfd)); 235130561Sobrienstatic void elfNN_ia64_hash_table_free 236130561Sobrien PARAMS ((struct bfd_link_hash_table *hash)); 237130561Sobrienstatic bfd_boolean elfNN_ia64_global_dyn_sym_thunk 23889857Sobrien PARAMS ((struct bfd_hash_entry *, PTR)); 239130561Sobrienstatic int elfNN_ia64_local_dyn_sym_thunk 240130561Sobrien PARAMS ((void **, PTR)); 24184865Sobrienstatic void elfNN_ia64_dyn_sym_traverse 24284865Sobrien PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info, 243130561Sobrien bfd_boolean (*func) (struct elfNN_ia64_dyn_sym_info *, PTR), 24484865Sobrien PTR info)); 245130561Sobrienstatic bfd_boolean elfNN_ia64_create_dynamic_sections 24684865Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info)); 24789857Sobrienstatic struct elfNN_ia64_local_hash_entry * get_local_sym_hash 24889857Sobrien PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info, 249130561Sobrien bfd *abfd, const Elf_Internal_Rela *rel, bfd_boolean create)); 25084865Sobrienstatic struct elfNN_ia64_dyn_sym_info * get_dyn_sym_info 25184865Sobrien PARAMS ((struct elfNN_ia64_link_hash_table *ia64_info, 25284865Sobrien struct elf_link_hash_entry *h, 253130561Sobrien bfd *abfd, const Elf_Internal_Rela *rel, bfd_boolean create)); 25484865Sobrienstatic asection *get_got 25584865Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info, 25684865Sobrien struct elfNN_ia64_link_hash_table *ia64_info)); 25784865Sobrienstatic asection *get_fptr 25884865Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info, 25984865Sobrien struct elfNN_ia64_link_hash_table *ia64_info)); 26084865Sobrienstatic asection *get_pltoff 26184865Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info, 26284865Sobrien struct elfNN_ia64_link_hash_table *ia64_info)); 26384865Sobrienstatic asection *get_reloc_section 26484865Sobrien PARAMS ((bfd *abfd, struct elfNN_ia64_link_hash_table *ia64_info, 265130561Sobrien asection *sec, bfd_boolean create)); 266130561Sobrienstatic bfd_boolean elfNN_ia64_check_relocs 26784865Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *sec, 26884865Sobrien const Elf_Internal_Rela *relocs)); 269130561Sobrienstatic bfd_boolean elfNN_ia64_adjust_dynamic_symbol 27084865Sobrien PARAMS ((struct bfd_link_info *info, struct elf_link_hash_entry *h)); 27189857Sobrienstatic long global_sym_index 27284865Sobrien PARAMS ((struct elf_link_hash_entry *h)); 273130561Sobrienstatic bfd_boolean allocate_fptr 27484865Sobrien PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); 275130561Sobrienstatic bfd_boolean allocate_global_data_got 27684865Sobrien PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); 277130561Sobrienstatic bfd_boolean allocate_global_fptr_got 27884865Sobrien PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); 279130561Sobrienstatic bfd_boolean allocate_local_got 28084865Sobrien PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); 281130561Sobrienstatic bfd_boolean allocate_pltoff_entries 28284865Sobrien PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); 283130561Sobrienstatic bfd_boolean allocate_plt_entries 28484865Sobrien PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); 285130561Sobrienstatic bfd_boolean allocate_plt2_entries 28684865Sobrien PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); 287130561Sobrienstatic bfd_boolean allocate_dynrel_entries 28884865Sobrien PARAMS ((struct elfNN_ia64_dyn_sym_info *dyn_i, PTR data)); 289130561Sobrienstatic bfd_boolean elfNN_ia64_size_dynamic_sections 29084865Sobrien PARAMS ((bfd *output_bfd, struct bfd_link_info *info)); 29184865Sobrienstatic bfd_reloc_status_type elfNN_ia64_install_value 292218822Sdim PARAMS ((bfd_byte *hit_addr, bfd_vma val, unsigned int r_type)); 29384865Sobrienstatic void elfNN_ia64_install_dyn_reloc 29484865Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info, asection *sec, 29584865Sobrien asection *srel, bfd_vma offset, unsigned int type, 29684865Sobrien long dynindx, bfd_vma addend)); 29784865Sobrienstatic bfd_vma set_got_entry 29884865Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info, 29984865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i, long dynindx, 30084865Sobrien bfd_vma addend, bfd_vma value, unsigned int dyn_r_type)); 30184865Sobrienstatic bfd_vma set_fptr_entry 30284865Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info, 30384865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i, 30484865Sobrien bfd_vma value)); 30584865Sobrienstatic bfd_vma set_pltoff_entry 30684865Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info, 30784865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i, 308130561Sobrien bfd_vma value, bfd_boolean)); 309104834Sobrienstatic bfd_vma elfNN_ia64_tprel_base 310104834Sobrien PARAMS ((struct bfd_link_info *info)); 311104834Sobrienstatic bfd_vma elfNN_ia64_dtprel_base 312104834Sobrien PARAMS ((struct bfd_link_info *info)); 31389857Sobrienstatic int elfNN_ia64_unwind_entry_compare 31489857Sobrien PARAMS ((const PTR, const PTR)); 315130561Sobrienstatic bfd_boolean elfNN_ia64_choose_gp 31684865Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info)); 317130561Sobrienstatic bfd_boolean elfNN_ia64_final_link 318130561Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info)); 319130561Sobrienstatic bfd_boolean elfNN_ia64_relocate_section 32084865Sobrien PARAMS ((bfd *output_bfd, struct bfd_link_info *info, bfd *input_bfd, 32184865Sobrien asection *input_section, bfd_byte *contents, 32284865Sobrien Elf_Internal_Rela *relocs, Elf_Internal_Sym *local_syms, 32384865Sobrien asection **local_sections)); 324130561Sobrienstatic bfd_boolean elfNN_ia64_finish_dynamic_symbol 32584865Sobrien PARAMS ((bfd *output_bfd, struct bfd_link_info *info, 32684865Sobrien struct elf_link_hash_entry *h, Elf_Internal_Sym *sym)); 327130561Sobrienstatic bfd_boolean elfNN_ia64_finish_dynamic_sections 32884865Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info)); 329130561Sobrienstatic bfd_boolean elfNN_ia64_set_private_flags 33084865Sobrien PARAMS ((bfd *abfd, flagword flags)); 331130561Sobrienstatic bfd_boolean elfNN_ia64_merge_private_bfd_data 33284865Sobrien PARAMS ((bfd *ibfd, bfd *obfd)); 333130561Sobrienstatic bfd_boolean elfNN_ia64_print_private_bfd_data 33484865Sobrien PARAMS ((bfd *abfd, PTR ptr)); 33589857Sobrienstatic enum elf_reloc_type_class elfNN_ia64_reloc_type_class 33689857Sobrien PARAMS ((const Elf_Internal_Rela *)); 337130561Sobrienstatic bfd_boolean elfNN_ia64_hpux_vec 33889857Sobrien PARAMS ((const bfd_target *vec)); 33989857Sobrienstatic void elfNN_hpux_post_process_headers 34089857Sobrien PARAMS ((bfd *abfd, struct bfd_link_info *info)); 341130561Sobrienbfd_boolean elfNN_hpux_backend_section_from_bfd_section 34289857Sobrien PARAMS ((bfd *abfd, asection *sec, int *retval)); 34384865Sobrien 344130561Sobrien/* ia64-specific relocation. */ 34584865Sobrien 34684865Sobrien/* Perform a relocation. Not much to do here as all the hard work is 34784865Sobrien done in elfNN_ia64_final_link_relocate. */ 34884865Sobrienstatic bfd_reloc_status_type 34984865SobrienelfNN_ia64_reloc (abfd, reloc, sym, data, input_section, 35084865Sobrien output_bfd, error_message) 35184865Sobrien bfd *abfd ATTRIBUTE_UNUSED; 35284865Sobrien arelent *reloc; 35384865Sobrien asymbol *sym ATTRIBUTE_UNUSED; 35484865Sobrien PTR data ATTRIBUTE_UNUSED; 35584865Sobrien asection *input_section; 35684865Sobrien bfd *output_bfd; 35784865Sobrien char **error_message; 35884865Sobrien{ 35984865Sobrien if (output_bfd) 36084865Sobrien { 36184865Sobrien reloc->address += input_section->output_offset; 36284865Sobrien return bfd_reloc_ok; 36384865Sobrien } 364130561Sobrien 365130561Sobrien if (input_section->flags & SEC_DEBUGGING) 366130561Sobrien return bfd_reloc_continue; 367130561Sobrien 36884865Sobrien *error_message = "Unsupported call to elfNN_ia64_reloc"; 36984865Sobrien return bfd_reloc_notsupported; 37084865Sobrien} 37184865Sobrien 37284865Sobrien#define IA64_HOWTO(TYPE, NAME, SIZE, PCREL, IN) \ 37384865Sobrien HOWTO (TYPE, 0, SIZE, 0, PCREL, 0, complain_overflow_signed, \ 374130561Sobrien elfNN_ia64_reloc, NAME, FALSE, 0, -1, IN) 37584865Sobrien 37684865Sobrien/* This table has to be sorted according to increasing number of the 37784865Sobrien TYPE field. */ 37884865Sobrienstatic reloc_howto_type ia64_howto_table[] = 37984865Sobrien { 380130561Sobrien IA64_HOWTO (R_IA64_NONE, "NONE", 0, FALSE, TRUE), 38184865Sobrien 382130561Sobrien IA64_HOWTO (R_IA64_IMM14, "IMM14", 0, FALSE, TRUE), 383130561Sobrien IA64_HOWTO (R_IA64_IMM22, "IMM22", 0, FALSE, TRUE), 384130561Sobrien IA64_HOWTO (R_IA64_IMM64, "IMM64", 0, FALSE, TRUE), 385130561Sobrien IA64_HOWTO (R_IA64_DIR32MSB, "DIR32MSB", 2, FALSE, TRUE), 386130561Sobrien IA64_HOWTO (R_IA64_DIR32LSB, "DIR32LSB", 2, FALSE, TRUE), 387130561Sobrien IA64_HOWTO (R_IA64_DIR64MSB, "DIR64MSB", 4, FALSE, TRUE), 388130561Sobrien IA64_HOWTO (R_IA64_DIR64LSB, "DIR64LSB", 4, FALSE, TRUE), 38984865Sobrien 390130561Sobrien IA64_HOWTO (R_IA64_GPREL22, "GPREL22", 0, FALSE, TRUE), 391130561Sobrien IA64_HOWTO (R_IA64_GPREL64I, "GPREL64I", 0, FALSE, TRUE), 392130561Sobrien IA64_HOWTO (R_IA64_GPREL32MSB, "GPREL32MSB", 2, FALSE, TRUE), 393130561Sobrien IA64_HOWTO (R_IA64_GPREL32LSB, "GPREL32LSB", 2, FALSE, TRUE), 394130561Sobrien IA64_HOWTO (R_IA64_GPREL64MSB, "GPREL64MSB", 4, FALSE, TRUE), 395130561Sobrien IA64_HOWTO (R_IA64_GPREL64LSB, "GPREL64LSB", 4, FALSE, TRUE), 39684865Sobrien 397130561Sobrien IA64_HOWTO (R_IA64_LTOFF22, "LTOFF22", 0, FALSE, TRUE), 398130561Sobrien IA64_HOWTO (R_IA64_LTOFF64I, "LTOFF64I", 0, FALSE, TRUE), 39984865Sobrien 400130561Sobrien IA64_HOWTO (R_IA64_PLTOFF22, "PLTOFF22", 0, FALSE, TRUE), 401130561Sobrien IA64_HOWTO (R_IA64_PLTOFF64I, "PLTOFF64I", 0, FALSE, TRUE), 402130561Sobrien IA64_HOWTO (R_IA64_PLTOFF64MSB, "PLTOFF64MSB", 4, FALSE, TRUE), 403130561Sobrien IA64_HOWTO (R_IA64_PLTOFF64LSB, "PLTOFF64LSB", 4, FALSE, TRUE), 40484865Sobrien 405130561Sobrien IA64_HOWTO (R_IA64_FPTR64I, "FPTR64I", 0, FALSE, TRUE), 406130561Sobrien IA64_HOWTO (R_IA64_FPTR32MSB, "FPTR32MSB", 2, FALSE, TRUE), 407130561Sobrien IA64_HOWTO (R_IA64_FPTR32LSB, "FPTR32LSB", 2, FALSE, TRUE), 408130561Sobrien IA64_HOWTO (R_IA64_FPTR64MSB, "FPTR64MSB", 4, FALSE, TRUE), 409130561Sobrien IA64_HOWTO (R_IA64_FPTR64LSB, "FPTR64LSB", 4, FALSE, TRUE), 41084865Sobrien 411130561Sobrien IA64_HOWTO (R_IA64_PCREL60B, "PCREL60B", 0, TRUE, TRUE), 412130561Sobrien IA64_HOWTO (R_IA64_PCREL21B, "PCREL21B", 0, TRUE, TRUE), 413130561Sobrien IA64_HOWTO (R_IA64_PCREL21M, "PCREL21M", 0, TRUE, TRUE), 414130561Sobrien IA64_HOWTO (R_IA64_PCREL21F, "PCREL21F", 0, TRUE, TRUE), 415130561Sobrien IA64_HOWTO (R_IA64_PCREL32MSB, "PCREL32MSB", 2, TRUE, TRUE), 416130561Sobrien IA64_HOWTO (R_IA64_PCREL32LSB, "PCREL32LSB", 2, TRUE, TRUE), 417130561Sobrien IA64_HOWTO (R_IA64_PCREL64MSB, "PCREL64MSB", 4, TRUE, TRUE), 418130561Sobrien IA64_HOWTO (R_IA64_PCREL64LSB, "PCREL64LSB", 4, TRUE, TRUE), 41984865Sobrien 420130561Sobrien IA64_HOWTO (R_IA64_LTOFF_FPTR22, "LTOFF_FPTR22", 0, FALSE, TRUE), 421130561Sobrien IA64_HOWTO (R_IA64_LTOFF_FPTR64I, "LTOFF_FPTR64I", 0, FALSE, TRUE), 422130561Sobrien IA64_HOWTO (R_IA64_LTOFF_FPTR32MSB, "LTOFF_FPTR32MSB", 2, FALSE, TRUE), 423130561Sobrien IA64_HOWTO (R_IA64_LTOFF_FPTR32LSB, "LTOFF_FPTR32LSB", 2, FALSE, TRUE), 424130561Sobrien IA64_HOWTO (R_IA64_LTOFF_FPTR64MSB, "LTOFF_FPTR64MSB", 4, FALSE, TRUE), 425130561Sobrien IA64_HOWTO (R_IA64_LTOFF_FPTR64LSB, "LTOFF_FPTR64LSB", 4, FALSE, TRUE), 42684865Sobrien 427130561Sobrien IA64_HOWTO (R_IA64_SEGREL32MSB, "SEGREL32MSB", 2, FALSE, TRUE), 428130561Sobrien IA64_HOWTO (R_IA64_SEGREL32LSB, "SEGREL32LSB", 2, FALSE, TRUE), 429130561Sobrien IA64_HOWTO (R_IA64_SEGREL64MSB, "SEGREL64MSB", 4, FALSE, TRUE), 430130561Sobrien IA64_HOWTO (R_IA64_SEGREL64LSB, "SEGREL64LSB", 4, FALSE, TRUE), 43184865Sobrien 432130561Sobrien IA64_HOWTO (R_IA64_SECREL32MSB, "SECREL32MSB", 2, FALSE, TRUE), 433130561Sobrien IA64_HOWTO (R_IA64_SECREL32LSB, "SECREL32LSB", 2, FALSE, TRUE), 434130561Sobrien IA64_HOWTO (R_IA64_SECREL64MSB, "SECREL64MSB", 4, FALSE, TRUE), 435130561Sobrien IA64_HOWTO (R_IA64_SECREL64LSB, "SECREL64LSB", 4, FALSE, TRUE), 43684865Sobrien 437130561Sobrien IA64_HOWTO (R_IA64_REL32MSB, "REL32MSB", 2, FALSE, TRUE), 438130561Sobrien IA64_HOWTO (R_IA64_REL32LSB, "REL32LSB", 2, FALSE, TRUE), 439130561Sobrien IA64_HOWTO (R_IA64_REL64MSB, "REL64MSB", 4, FALSE, TRUE), 440130561Sobrien IA64_HOWTO (R_IA64_REL64LSB, "REL64LSB", 4, FALSE, TRUE), 44184865Sobrien 442130561Sobrien IA64_HOWTO (R_IA64_LTV32MSB, "LTV32MSB", 2, FALSE, TRUE), 443130561Sobrien IA64_HOWTO (R_IA64_LTV32LSB, "LTV32LSB", 2, FALSE, TRUE), 444130561Sobrien IA64_HOWTO (R_IA64_LTV64MSB, "LTV64MSB", 4, FALSE, TRUE), 445130561Sobrien IA64_HOWTO (R_IA64_LTV64LSB, "LTV64LSB", 4, FALSE, TRUE), 44684865Sobrien 447130561Sobrien IA64_HOWTO (R_IA64_PCREL21BI, "PCREL21BI", 0, TRUE, TRUE), 448130561Sobrien IA64_HOWTO (R_IA64_PCREL22, "PCREL22", 0, TRUE, TRUE), 449130561Sobrien IA64_HOWTO (R_IA64_PCREL64I, "PCREL64I", 0, TRUE, TRUE), 45084865Sobrien 451130561Sobrien IA64_HOWTO (R_IA64_IPLTMSB, "IPLTMSB", 4, FALSE, TRUE), 452130561Sobrien IA64_HOWTO (R_IA64_IPLTLSB, "IPLTLSB", 4, FALSE, TRUE), 453130561Sobrien IA64_HOWTO (R_IA64_COPY, "COPY", 4, FALSE, TRUE), 454130561Sobrien IA64_HOWTO (R_IA64_LTOFF22X, "LTOFF22X", 0, FALSE, TRUE), 455130561Sobrien IA64_HOWTO (R_IA64_LDXMOV, "LDXMOV", 0, FALSE, TRUE), 45684865Sobrien 457130561Sobrien IA64_HOWTO (R_IA64_TPREL14, "TPREL14", 0, FALSE, FALSE), 458130561Sobrien IA64_HOWTO (R_IA64_TPREL22, "TPREL22", 0, FALSE, FALSE), 459130561Sobrien IA64_HOWTO (R_IA64_TPREL64I, "TPREL64I", 0, FALSE, FALSE), 460130561Sobrien IA64_HOWTO (R_IA64_TPREL64MSB, "TPREL64MSB", 4, FALSE, FALSE), 461130561Sobrien IA64_HOWTO (R_IA64_TPREL64LSB, "TPREL64LSB", 4, FALSE, FALSE), 462130561Sobrien IA64_HOWTO (R_IA64_LTOFF_TPREL22, "LTOFF_TPREL22", 0, FALSE, FALSE), 463104834Sobrien 464218822Sdim IA64_HOWTO (R_IA64_DTPMOD64MSB, "DTPMOD64MSB", 4, FALSE, FALSE), 465218822Sdim IA64_HOWTO (R_IA64_DTPMOD64LSB, "DTPMOD64LSB", 4, FALSE, FALSE), 466130561Sobrien IA64_HOWTO (R_IA64_LTOFF_DTPMOD22, "LTOFF_DTPMOD22", 0, FALSE, FALSE), 467104834Sobrien 468130561Sobrien IA64_HOWTO (R_IA64_DTPREL14, "DTPREL14", 0, FALSE, FALSE), 469130561Sobrien IA64_HOWTO (R_IA64_DTPREL22, "DTPREL22", 0, FALSE, FALSE), 470130561Sobrien IA64_HOWTO (R_IA64_DTPREL64I, "DTPREL64I", 0, FALSE, FALSE), 471130561Sobrien IA64_HOWTO (R_IA64_DTPREL32MSB, "DTPREL32MSB", 2, FALSE, FALSE), 472130561Sobrien IA64_HOWTO (R_IA64_DTPREL32LSB, "DTPREL32LSB", 2, FALSE, FALSE), 473130561Sobrien IA64_HOWTO (R_IA64_DTPREL64MSB, "DTPREL64MSB", 4, FALSE, FALSE), 474130561Sobrien IA64_HOWTO (R_IA64_DTPREL64LSB, "DTPREL64LSB", 4, FALSE, FALSE), 475130561Sobrien IA64_HOWTO (R_IA64_LTOFF_DTPREL22, "LTOFF_DTPREL22", 0, FALSE, FALSE), 47684865Sobrien }; 47784865Sobrien 47884865Sobrienstatic unsigned char elf_code_to_howto_index[R_IA64_MAX_RELOC_CODE + 1]; 47984865Sobrien 48084865Sobrien/* Given a BFD reloc type, return the matching HOWTO structure. */ 48184865Sobrien 482130561Sobrienstatic reloc_howto_type * 48384865Sobrienlookup_howto (rtype) 48484865Sobrien unsigned int rtype; 48584865Sobrien{ 48684865Sobrien static int inited = 0; 48784865Sobrien int i; 48884865Sobrien 48984865Sobrien if (!inited) 49084865Sobrien { 49184865Sobrien inited = 1; 49284865Sobrien 49384865Sobrien memset (elf_code_to_howto_index, 0xff, sizeof (elf_code_to_howto_index)); 49484865Sobrien for (i = 0; i < NELEMS (ia64_howto_table); ++i) 49584865Sobrien elf_code_to_howto_index[ia64_howto_table[i].type] = i; 49684865Sobrien } 49784865Sobrien 498218822Sdim if (rtype > R_IA64_MAX_RELOC_CODE) 499218822Sdim return 0; 50084865Sobrien i = elf_code_to_howto_index[rtype]; 50184865Sobrien if (i >= NELEMS (ia64_howto_table)) 50284865Sobrien return 0; 50384865Sobrien return ia64_howto_table + i; 50484865Sobrien} 50584865Sobrien 50684865Sobrienstatic reloc_howto_type* 50784865SobrienelfNN_ia64_reloc_type_lookup (abfd, bfd_code) 50884865Sobrien bfd *abfd ATTRIBUTE_UNUSED; 50984865Sobrien bfd_reloc_code_real_type bfd_code; 51084865Sobrien{ 51184865Sobrien unsigned int rtype; 51284865Sobrien 51384865Sobrien switch (bfd_code) 51484865Sobrien { 51584865Sobrien case BFD_RELOC_NONE: rtype = R_IA64_NONE; break; 51684865Sobrien 51784865Sobrien case BFD_RELOC_IA64_IMM14: rtype = R_IA64_IMM14; break; 51884865Sobrien case BFD_RELOC_IA64_IMM22: rtype = R_IA64_IMM22; break; 51984865Sobrien case BFD_RELOC_IA64_IMM64: rtype = R_IA64_IMM64; break; 52084865Sobrien 52184865Sobrien case BFD_RELOC_IA64_DIR32MSB: rtype = R_IA64_DIR32MSB; break; 52284865Sobrien case BFD_RELOC_IA64_DIR32LSB: rtype = R_IA64_DIR32LSB; break; 52384865Sobrien case BFD_RELOC_IA64_DIR64MSB: rtype = R_IA64_DIR64MSB; break; 52484865Sobrien case BFD_RELOC_IA64_DIR64LSB: rtype = R_IA64_DIR64LSB; break; 52584865Sobrien 52684865Sobrien case BFD_RELOC_IA64_GPREL22: rtype = R_IA64_GPREL22; break; 52784865Sobrien case BFD_RELOC_IA64_GPREL64I: rtype = R_IA64_GPREL64I; break; 52884865Sobrien case BFD_RELOC_IA64_GPREL32MSB: rtype = R_IA64_GPREL32MSB; break; 52984865Sobrien case BFD_RELOC_IA64_GPREL32LSB: rtype = R_IA64_GPREL32LSB; break; 53084865Sobrien case BFD_RELOC_IA64_GPREL64MSB: rtype = R_IA64_GPREL64MSB; break; 53184865Sobrien case BFD_RELOC_IA64_GPREL64LSB: rtype = R_IA64_GPREL64LSB; break; 53284865Sobrien 53384865Sobrien case BFD_RELOC_IA64_LTOFF22: rtype = R_IA64_LTOFF22; break; 53484865Sobrien case BFD_RELOC_IA64_LTOFF64I: rtype = R_IA64_LTOFF64I; break; 53584865Sobrien 53684865Sobrien case BFD_RELOC_IA64_PLTOFF22: rtype = R_IA64_PLTOFF22; break; 53784865Sobrien case BFD_RELOC_IA64_PLTOFF64I: rtype = R_IA64_PLTOFF64I; break; 53884865Sobrien case BFD_RELOC_IA64_PLTOFF64MSB: rtype = R_IA64_PLTOFF64MSB; break; 53984865Sobrien case BFD_RELOC_IA64_PLTOFF64LSB: rtype = R_IA64_PLTOFF64LSB; break; 54084865Sobrien case BFD_RELOC_IA64_FPTR64I: rtype = R_IA64_FPTR64I; break; 54184865Sobrien case BFD_RELOC_IA64_FPTR32MSB: rtype = R_IA64_FPTR32MSB; break; 54284865Sobrien case BFD_RELOC_IA64_FPTR32LSB: rtype = R_IA64_FPTR32LSB; break; 54384865Sobrien case BFD_RELOC_IA64_FPTR64MSB: rtype = R_IA64_FPTR64MSB; break; 54484865Sobrien case BFD_RELOC_IA64_FPTR64LSB: rtype = R_IA64_FPTR64LSB; break; 54584865Sobrien 54684865Sobrien case BFD_RELOC_IA64_PCREL21B: rtype = R_IA64_PCREL21B; break; 54784865Sobrien case BFD_RELOC_IA64_PCREL21BI: rtype = R_IA64_PCREL21BI; break; 54884865Sobrien case BFD_RELOC_IA64_PCREL21M: rtype = R_IA64_PCREL21M; break; 54984865Sobrien case BFD_RELOC_IA64_PCREL21F: rtype = R_IA64_PCREL21F; break; 55084865Sobrien case BFD_RELOC_IA64_PCREL22: rtype = R_IA64_PCREL22; break; 55184865Sobrien case BFD_RELOC_IA64_PCREL60B: rtype = R_IA64_PCREL60B; break; 55284865Sobrien case BFD_RELOC_IA64_PCREL64I: rtype = R_IA64_PCREL64I; break; 55384865Sobrien case BFD_RELOC_IA64_PCREL32MSB: rtype = R_IA64_PCREL32MSB; break; 55484865Sobrien case BFD_RELOC_IA64_PCREL32LSB: rtype = R_IA64_PCREL32LSB; break; 55584865Sobrien case BFD_RELOC_IA64_PCREL64MSB: rtype = R_IA64_PCREL64MSB; break; 55684865Sobrien case BFD_RELOC_IA64_PCREL64LSB: rtype = R_IA64_PCREL64LSB; break; 55784865Sobrien 55884865Sobrien case BFD_RELOC_IA64_LTOFF_FPTR22: rtype = R_IA64_LTOFF_FPTR22; break; 55984865Sobrien case BFD_RELOC_IA64_LTOFF_FPTR64I: rtype = R_IA64_LTOFF_FPTR64I; break; 56089857Sobrien case BFD_RELOC_IA64_LTOFF_FPTR32MSB: rtype = R_IA64_LTOFF_FPTR32MSB; break; 56189857Sobrien case BFD_RELOC_IA64_LTOFF_FPTR32LSB: rtype = R_IA64_LTOFF_FPTR32LSB; break; 56284865Sobrien case BFD_RELOC_IA64_LTOFF_FPTR64MSB: rtype = R_IA64_LTOFF_FPTR64MSB; break; 56384865Sobrien case BFD_RELOC_IA64_LTOFF_FPTR64LSB: rtype = R_IA64_LTOFF_FPTR64LSB; break; 56484865Sobrien 56584865Sobrien case BFD_RELOC_IA64_SEGREL32MSB: rtype = R_IA64_SEGREL32MSB; break; 56684865Sobrien case BFD_RELOC_IA64_SEGREL32LSB: rtype = R_IA64_SEGREL32LSB; break; 56784865Sobrien case BFD_RELOC_IA64_SEGREL64MSB: rtype = R_IA64_SEGREL64MSB; break; 56884865Sobrien case BFD_RELOC_IA64_SEGREL64LSB: rtype = R_IA64_SEGREL64LSB; break; 56984865Sobrien 57084865Sobrien case BFD_RELOC_IA64_SECREL32MSB: rtype = R_IA64_SECREL32MSB; break; 57184865Sobrien case BFD_RELOC_IA64_SECREL32LSB: rtype = R_IA64_SECREL32LSB; break; 57284865Sobrien case BFD_RELOC_IA64_SECREL64MSB: rtype = R_IA64_SECREL64MSB; break; 57384865Sobrien case BFD_RELOC_IA64_SECREL64LSB: rtype = R_IA64_SECREL64LSB; break; 57484865Sobrien 57584865Sobrien case BFD_RELOC_IA64_REL32MSB: rtype = R_IA64_REL32MSB; break; 57684865Sobrien case BFD_RELOC_IA64_REL32LSB: rtype = R_IA64_REL32LSB; break; 57784865Sobrien case BFD_RELOC_IA64_REL64MSB: rtype = R_IA64_REL64MSB; break; 57884865Sobrien case BFD_RELOC_IA64_REL64LSB: rtype = R_IA64_REL64LSB; break; 57984865Sobrien 58084865Sobrien case BFD_RELOC_IA64_LTV32MSB: rtype = R_IA64_LTV32MSB; break; 58184865Sobrien case BFD_RELOC_IA64_LTV32LSB: rtype = R_IA64_LTV32LSB; break; 58284865Sobrien case BFD_RELOC_IA64_LTV64MSB: rtype = R_IA64_LTV64MSB; break; 58384865Sobrien case BFD_RELOC_IA64_LTV64LSB: rtype = R_IA64_LTV64LSB; break; 58484865Sobrien 58584865Sobrien case BFD_RELOC_IA64_IPLTMSB: rtype = R_IA64_IPLTMSB; break; 58684865Sobrien case BFD_RELOC_IA64_IPLTLSB: rtype = R_IA64_IPLTLSB; break; 58784865Sobrien case BFD_RELOC_IA64_COPY: rtype = R_IA64_COPY; break; 58884865Sobrien case BFD_RELOC_IA64_LTOFF22X: rtype = R_IA64_LTOFF22X; break; 58984865Sobrien case BFD_RELOC_IA64_LDXMOV: rtype = R_IA64_LDXMOV; break; 59084865Sobrien 591104834Sobrien case BFD_RELOC_IA64_TPREL14: rtype = R_IA64_TPREL14; break; 59284865Sobrien case BFD_RELOC_IA64_TPREL22: rtype = R_IA64_TPREL22; break; 593104834Sobrien case BFD_RELOC_IA64_TPREL64I: rtype = R_IA64_TPREL64I; break; 59484865Sobrien case BFD_RELOC_IA64_TPREL64MSB: rtype = R_IA64_TPREL64MSB; break; 59584865Sobrien case BFD_RELOC_IA64_TPREL64LSB: rtype = R_IA64_TPREL64LSB; break; 596104834Sobrien case BFD_RELOC_IA64_LTOFF_TPREL22: rtype = R_IA64_LTOFF_TPREL22; break; 59784865Sobrien 598104834Sobrien case BFD_RELOC_IA64_DTPMOD64MSB: rtype = R_IA64_DTPMOD64MSB; break; 599104834Sobrien case BFD_RELOC_IA64_DTPMOD64LSB: rtype = R_IA64_DTPMOD64LSB; break; 600104834Sobrien case BFD_RELOC_IA64_LTOFF_DTPMOD22: rtype = R_IA64_LTOFF_DTPMOD22; break; 601104834Sobrien 602104834Sobrien case BFD_RELOC_IA64_DTPREL14: rtype = R_IA64_DTPREL14; break; 603104834Sobrien case BFD_RELOC_IA64_DTPREL22: rtype = R_IA64_DTPREL22; break; 604104834Sobrien case BFD_RELOC_IA64_DTPREL64I: rtype = R_IA64_DTPREL64I; break; 605104834Sobrien case BFD_RELOC_IA64_DTPREL32MSB: rtype = R_IA64_DTPREL32MSB; break; 606104834Sobrien case BFD_RELOC_IA64_DTPREL32LSB: rtype = R_IA64_DTPREL32LSB; break; 607104834Sobrien case BFD_RELOC_IA64_DTPREL64MSB: rtype = R_IA64_DTPREL64MSB; break; 608104834Sobrien case BFD_RELOC_IA64_DTPREL64LSB: rtype = R_IA64_DTPREL64LSB; break; 609104834Sobrien case BFD_RELOC_IA64_LTOFF_DTPREL22: rtype = R_IA64_LTOFF_DTPREL22; break; 610104834Sobrien 61184865Sobrien default: return 0; 61284865Sobrien } 61384865Sobrien return lookup_howto (rtype); 61484865Sobrien} 61584865Sobrien 616218822Sdimstatic reloc_howto_type * 617218822SdimelfNN_ia64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 618218822Sdim const char *r_name) 619218822Sdim{ 620218822Sdim unsigned int i; 621218822Sdim 622218822Sdim for (i = 0; 623218822Sdim i < sizeof (ia64_howto_table) / sizeof (ia64_howto_table[0]); 624218822Sdim i++) 625218822Sdim if (ia64_howto_table[i].name != NULL 626218822Sdim && strcasecmp (ia64_howto_table[i].name, r_name) == 0) 627218822Sdim return &ia64_howto_table[i]; 628218822Sdim 629218822Sdim return NULL; 630218822Sdim} 631218822Sdim 63284865Sobrien/* Given a ELF reloc, return the matching HOWTO structure. */ 63384865Sobrien 63484865Sobrienstatic void 63584865SobrienelfNN_ia64_info_to_howto (abfd, bfd_reloc, elf_reloc) 63684865Sobrien bfd *abfd ATTRIBUTE_UNUSED; 63784865Sobrien arelent *bfd_reloc; 638130561Sobrien Elf_Internal_Rela *elf_reloc; 63984865Sobrien{ 64089857Sobrien bfd_reloc->howto 64189857Sobrien = lookup_howto ((unsigned int) ELFNN_R_TYPE (elf_reloc->r_info)); 64284865Sobrien} 64384865Sobrien 64484865Sobrien#define PLT_HEADER_SIZE (3 * 16) 64584865Sobrien#define PLT_MIN_ENTRY_SIZE (1 * 16) 64684865Sobrien#define PLT_FULL_ENTRY_SIZE (2 * 16) 64784865Sobrien#define PLT_RESERVED_WORDS 3 64884865Sobrien 64984865Sobrienstatic const bfd_byte plt_header[PLT_HEADER_SIZE] = 65084865Sobrien{ 65184865Sobrien 0x0b, 0x10, 0x00, 0x1c, 0x00, 0x21, /* [MMI] mov r2=r14;; */ 65284865Sobrien 0xe0, 0x00, 0x08, 0x00, 0x48, 0x00, /* addl r14=0,r2 */ 65384865Sobrien 0x00, 0x00, 0x04, 0x00, /* nop.i 0x0;; */ 65484865Sobrien 0x0b, 0x80, 0x20, 0x1c, 0x18, 0x14, /* [MMI] ld8 r16=[r14],8;; */ 65584865Sobrien 0x10, 0x41, 0x38, 0x30, 0x28, 0x00, /* ld8 r17=[r14],8 */ 65684865Sobrien 0x00, 0x00, 0x04, 0x00, /* nop.i 0x0;; */ 65784865Sobrien 0x11, 0x08, 0x00, 0x1c, 0x18, 0x10, /* [MIB] ld8 r1=[r14] */ 65884865Sobrien 0x60, 0x88, 0x04, 0x80, 0x03, 0x00, /* mov b6=r17 */ 65984865Sobrien 0x60, 0x00, 0x80, 0x00 /* br.few b6;; */ 66084865Sobrien}; 66184865Sobrien 66284865Sobrienstatic const bfd_byte plt_min_entry[PLT_MIN_ENTRY_SIZE] = 66384865Sobrien{ 66484865Sobrien 0x11, 0x78, 0x00, 0x00, 0x00, 0x24, /* [MIB] mov r15=0 */ 66584865Sobrien 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, /* nop.i 0x0 */ 66684865Sobrien 0x00, 0x00, 0x00, 0x40 /* br.few 0 <PLT0>;; */ 66784865Sobrien}; 66884865Sobrien 66984865Sobrienstatic const bfd_byte plt_full_entry[PLT_FULL_ENTRY_SIZE] = 67084865Sobrien{ 67184865Sobrien 0x0b, 0x78, 0x00, 0x02, 0x00, 0x24, /* [MMI] addl r15=0,r1;; */ 672130561Sobrien 0x00, 0x41, 0x3c, 0x70, 0x29, 0xc0, /* ld8.acq r16=[r15],8*/ 67384865Sobrien 0x01, 0x08, 0x00, 0x84, /* mov r14=r1;; */ 67484865Sobrien 0x11, 0x08, 0x00, 0x1e, 0x18, 0x10, /* [MIB] ld8 r1=[r15] */ 67584865Sobrien 0x60, 0x80, 0x04, 0x80, 0x03, 0x00, /* mov b6=r16 */ 67684865Sobrien 0x60, 0x00, 0x80, 0x00 /* br.few b6;; */ 67784865Sobrien}; 67884865Sobrien 67984865Sobrien#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" 68084865Sobrien 68184865Sobrienstatic const bfd_byte oor_brl[16] = 68284865Sobrien{ 68384865Sobrien 0x05, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */ 68484865Sobrien 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* brl.sptk.few tgt;; */ 68584865Sobrien 0x00, 0x00, 0x00, 0xc0 68684865Sobrien}; 687130561Sobrien 68884865Sobrienstatic const bfd_byte oor_ip[48] = 68984865Sobrien{ 69084865Sobrien 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MLX] nop.m 0 */ 69184865Sobrien 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, /* movl r15=0 */ 69284865Sobrien 0x01, 0x00, 0x00, 0x60, 69384865Sobrien 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MII] nop.m 0 */ 69484865Sobrien 0x00, 0x01, 0x00, 0x60, 0x00, 0x00, /* mov r16=ip;; */ 69584865Sobrien 0xf2, 0x80, 0x00, 0x80, /* add r16=r15,r16;; */ 69684865Sobrien 0x11, 0x00, 0x00, 0x00, 0x01, 0x00, /* [MIB] nop.m 0 */ 69784865Sobrien 0x60, 0x80, 0x04, 0x80, 0x03, 0x00, /* mov b6=r16 */ 69884865Sobrien 0x60, 0x00, 0x80, 0x00 /* br b6;; */ 69984865Sobrien}; 700130561Sobrien 701130561Sobrienstatic size_t oor_branch_size = sizeof (oor_brl); 702130561Sobrien 703130561Sobrienvoid 704130561Sobrienbfd_elfNN_ia64_after_parse (int itanium) 705130561Sobrien{ 706130561Sobrien oor_branch_size = itanium ? sizeof (oor_ip) : sizeof (oor_brl); 707130561Sobrien} 708130561Sobrien 709218822Sdim#define BTYPE_SHIFT 6 710218822Sdim#define Y_SHIFT 26 711218822Sdim#define X6_SHIFT 27 712218822Sdim#define X4_SHIFT 27 713218822Sdim#define X3_SHIFT 33 714218822Sdim#define X2_SHIFT 31 715218822Sdim#define X_SHIFT 33 716218822Sdim#define OPCODE_SHIFT 37 717218822Sdim 718218822Sdim#define OPCODE_BITS (0xfLL << OPCODE_SHIFT) 719218822Sdim#define X6_BITS (0x3fLL << X6_SHIFT) 720218822Sdim#define X4_BITS (0xfLL << X4_SHIFT) 721218822Sdim#define X3_BITS (0x7LL << X3_SHIFT) 722218822Sdim#define X2_BITS (0x3LL << X2_SHIFT) 723218822Sdim#define X_BITS (0x1LL << X_SHIFT) 724218822Sdim#define Y_BITS (0x1LL << Y_SHIFT) 725218822Sdim#define BTYPE_BITS (0x7LL << BTYPE_SHIFT) 726218822Sdim#define PREDICATE_BITS (0x3fLL) 727218822Sdim 728218822Sdim#define IS_NOP_B(i) \ 729218822Sdim (((i) & (OPCODE_BITS | X6_BITS)) == (2LL << OPCODE_SHIFT)) 730218822Sdim#define IS_NOP_F(i) \ 731218822Sdim (((i) & (OPCODE_BITS | X_BITS | X6_BITS | Y_BITS)) \ 732218822Sdim == (0x1LL << X6_SHIFT)) 733218822Sdim#define IS_NOP_I(i) \ 734218822Sdim (((i) & (OPCODE_BITS | X3_BITS | X6_BITS | Y_BITS)) \ 735218822Sdim == (0x1LL << X6_SHIFT)) 736218822Sdim#define IS_NOP_M(i) \ 737218822Sdim (((i) & (OPCODE_BITS | X3_BITS | X2_BITS | X4_BITS | Y_BITS)) \ 738218822Sdim == (0x1LL << X4_SHIFT)) 739218822Sdim#define IS_BR_COND(i) \ 740218822Sdim (((i) & (OPCODE_BITS | BTYPE_BITS)) == (0x4LL << OPCODE_SHIFT)) 741218822Sdim#define IS_BR_CALL(i) \ 742218822Sdim (((i) & OPCODE_BITS) == (0x5LL << OPCODE_SHIFT)) 743218822Sdim 744218822Sdimstatic bfd_boolean 745218822SdimelfNN_ia64_relax_br (bfd_byte *contents, bfd_vma off) 746218822Sdim{ 747218822Sdim unsigned int template, mlx; 748218822Sdim bfd_vma t0, t1, s0, s1, s2, br_code; 749218822Sdim long br_slot; 750218822Sdim bfd_byte *hit_addr; 751218822Sdim 752218822Sdim hit_addr = (bfd_byte *) (contents + off); 753218822Sdim br_slot = (long) hit_addr & 0x3; 754218822Sdim hit_addr -= br_slot; 755218822Sdim t0 = bfd_getl64 (hit_addr + 0); 756218822Sdim t1 = bfd_getl64 (hit_addr + 8); 757218822Sdim 758218822Sdim /* Check if we can turn br into brl. A label is always at the start 759218822Sdim of the bundle. Even if there are predicates on NOPs, we still 760218822Sdim perform this optimization. */ 761218822Sdim template = t0 & 0x1e; 762218822Sdim s0 = (t0 >> 5) & 0x1ffffffffffLL; 763218822Sdim s1 = ((t0 >> 46) | (t1 << 18)) & 0x1ffffffffffLL; 764218822Sdim s2 = (t1 >> 23) & 0x1ffffffffffLL; 765218822Sdim switch (br_slot) 766218822Sdim { 767218822Sdim case 0: 768218822Sdim /* Check if slot 1 and slot 2 are NOPs. Possible template is 769218822Sdim BBB. We only need to check nop.b. */ 770218822Sdim if (!(IS_NOP_B (s1) && IS_NOP_B (s2))) 771218822Sdim return FALSE; 772218822Sdim br_code = s0; 773218822Sdim break; 774218822Sdim case 1: 775218822Sdim /* Check if slot 2 is NOP. Possible templates are MBB and BBB. 776218822Sdim For BBB, slot 0 also has to be nop.b. */ 777218822Sdim if (!((template == 0x12 /* MBB */ 778218822Sdim && IS_NOP_B (s2)) 779218822Sdim || (template == 0x16 /* BBB */ 780218822Sdim && IS_NOP_B (s0) 781218822Sdim && IS_NOP_B (s2)))) 782218822Sdim return FALSE; 783218822Sdim br_code = s1; 784218822Sdim break; 785218822Sdim case 2: 786218822Sdim /* Check if slot 1 is NOP. Possible templates are MIB, MBB, BBB, 787218822Sdim MMB and MFB. For BBB, slot 0 also has to be nop.b. */ 788218822Sdim if (!((template == 0x10 /* MIB */ 789218822Sdim && IS_NOP_I (s1)) 790218822Sdim || (template == 0x12 /* MBB */ 791218822Sdim && IS_NOP_B (s1)) 792218822Sdim || (template == 0x16 /* BBB */ 793218822Sdim && IS_NOP_B (s0) 794218822Sdim && IS_NOP_B (s1)) 795218822Sdim || (template == 0x18 /* MMB */ 796218822Sdim && IS_NOP_M (s1)) 797218822Sdim || (template == 0x1c /* MFB */ 798218822Sdim && IS_NOP_F (s1)))) 799218822Sdim return FALSE; 800218822Sdim br_code = s2; 801218822Sdim break; 802218822Sdim default: 803218822Sdim /* It should never happen. */ 804218822Sdim abort (); 805218822Sdim } 806218822Sdim 807218822Sdim /* We can turn br.cond/br.call into brl.cond/brl.call. */ 808218822Sdim if (!(IS_BR_COND (br_code) || IS_BR_CALL (br_code))) 809218822Sdim return FALSE; 810218822Sdim 811218822Sdim /* Turn br into brl by setting bit 40. */ 812218822Sdim br_code |= 0x1LL << 40; 813218822Sdim 814218822Sdim /* Turn the old bundle into a MLX bundle with the same stop-bit 815218822Sdim variety. */ 816218822Sdim if (t0 & 0x1) 817218822Sdim mlx = 0x5; 818218822Sdim else 819218822Sdim mlx = 0x4; 820218822Sdim 821218822Sdim if (template == 0x16) 822218822Sdim { 823218822Sdim /* For BBB, we need to put nop.m in slot 0. We keep the original 824218822Sdim predicate only if slot 0 isn't br. */ 825218822Sdim if (br_slot == 0) 826218822Sdim t0 = 0LL; 827218822Sdim else 828218822Sdim t0 &= PREDICATE_BITS << 5; 829218822Sdim t0 |= 0x1LL << (X4_SHIFT + 5); 830218822Sdim } 831218822Sdim else 832218822Sdim { 833218822Sdim /* Keep the original instruction in slot 0. */ 834218822Sdim t0 &= 0x1ffffffffffLL << 5; 835218822Sdim } 836218822Sdim 837218822Sdim t0 |= mlx; 838218822Sdim 839218822Sdim /* Put brl in slot 1. */ 840218822Sdim t1 = br_code << 23; 841218822Sdim 842218822Sdim bfd_putl64 (t0, hit_addr); 843218822Sdim bfd_putl64 (t1, hit_addr + 8); 844218822Sdim return TRUE; 845218822Sdim} 846218822Sdim 847130561Sobrienstatic void 848218822SdimelfNN_ia64_relax_brl (bfd_byte *contents, bfd_vma off) 849130561Sobrien{ 850130561Sobrien int template; 851130561Sobrien bfd_byte *hit_addr; 852130561Sobrien bfd_vma t0, t1, i0, i1, i2; 853130561Sobrien 854130561Sobrien hit_addr = (bfd_byte *) (contents + off); 855130561Sobrien hit_addr -= (long) hit_addr & 0x3; 856218822Sdim t0 = bfd_getl64 (hit_addr); 857218822Sdim t1 = bfd_getl64 (hit_addr + 8); 858130561Sobrien 859130561Sobrien /* Keep the instruction in slot 0. */ 860130561Sobrien i0 = (t0 >> 5) & 0x1ffffffffffLL; 861130561Sobrien /* Use nop.b for slot 1. */ 862130561Sobrien i1 = 0x4000000000LL; 863130561Sobrien /* For slot 2, turn brl into br by masking out bit 40. */ 864130561Sobrien i2 = (t1 >> 23) & 0x0ffffffffffLL; 865130561Sobrien 866130561Sobrien /* Turn a MLX bundle into a MBB bundle with the same stop-bit 867130561Sobrien variety. */ 868218822Sdim if (t0 & 0x1) 869218822Sdim template = 0x13; 870218822Sdim else 871218822Sdim template = 0x12; 872130561Sobrien t0 = (i1 << 46) | (i0 << 5) | template; 873130561Sobrien t1 = (i2 << 23) | (i1 >> 18); 874130561Sobrien 875218822Sdim bfd_putl64 (t0, hit_addr); 876218822Sdim bfd_putl64 (t1, hit_addr + 8); 877130561Sobrien} 878218822Sdim 879218822Sdim/* Rename some of the generic section flags to better document how they 880218822Sdim are used here. */ 881218822Sdim#define skip_relax_pass_0 need_finalize_relax 882218822Sdim#define skip_relax_pass_1 has_gp_reloc 883218822Sdim 88484865Sobrien 885130561Sobrien/* These functions do relaxation for IA-64 ELF. */ 88684865Sobrien 887130561Sobrienstatic bfd_boolean 88884865SobrienelfNN_ia64_relax_section (abfd, sec, link_info, again) 88984865Sobrien bfd *abfd; 89084865Sobrien asection *sec; 89184865Sobrien struct bfd_link_info *link_info; 892130561Sobrien bfd_boolean *again; 89384865Sobrien{ 89484865Sobrien struct one_fixup 89584865Sobrien { 89684865Sobrien struct one_fixup *next; 89784865Sobrien asection *tsec; 89884865Sobrien bfd_vma toff; 89984865Sobrien bfd_vma trampoff; 90084865Sobrien }; 90184865Sobrien 90284865Sobrien Elf_Internal_Shdr *symtab_hdr; 90384865Sobrien Elf_Internal_Rela *internal_relocs; 90484865Sobrien Elf_Internal_Rela *irel, *irelend; 90584865Sobrien bfd_byte *contents; 906104834Sobrien Elf_Internal_Sym *isymbuf = NULL; 90784865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 90884865Sobrien struct one_fixup *fixups = NULL; 909130561Sobrien bfd_boolean changed_contents = FALSE; 910130561Sobrien bfd_boolean changed_relocs = FALSE; 911130561Sobrien bfd_boolean changed_got = FALSE; 912218822Sdim bfd_boolean skip_relax_pass_0 = TRUE; 913218822Sdim bfd_boolean skip_relax_pass_1 = TRUE; 914130561Sobrien bfd_vma gp = 0; 91584865Sobrien 91684865Sobrien /* Assume we're not going to change any sizes, and we'll only need 91784865Sobrien one pass. */ 918130561Sobrien *again = FALSE; 91984865Sobrien 920130561Sobrien /* Don't even try to relax for non-ELF outputs. */ 921130561Sobrien if (!is_elf_hash_table (link_info->hash)) 922130561Sobrien return FALSE; 923130561Sobrien 924130561Sobrien /* Nothing to do if there are no relocations or there is no need for 925218822Sdim the current pass. */ 92684865Sobrien if ((sec->flags & SEC_RELOC) == 0 927130561Sobrien || sec->reloc_count == 0 928218822Sdim || (link_info->relax_pass == 0 && sec->skip_relax_pass_0) 929218822Sdim || (link_info->relax_pass == 1 && sec->skip_relax_pass_1)) 930130561Sobrien return TRUE; 93184865Sobrien 93284865Sobrien symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 93384865Sobrien 93484865Sobrien /* Load the relocations for this section. */ 935130561Sobrien internal_relocs = (_bfd_elf_link_read_relocs 93684865Sobrien (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL, 93784865Sobrien link_info->keep_memory)); 93884865Sobrien if (internal_relocs == NULL) 939130561Sobrien return FALSE; 94084865Sobrien 94184865Sobrien ia64_info = elfNN_ia64_hash_table (link_info); 94284865Sobrien irelend = internal_relocs + sec->reloc_count; 94384865Sobrien 94484865Sobrien /* Get the section contents. */ 94584865Sobrien if (elf_section_data (sec)->this_hdr.contents != NULL) 94684865Sobrien contents = elf_section_data (sec)->this_hdr.contents; 94784865Sobrien else 94884865Sobrien { 949218822Sdim if (!bfd_malloc_and_get_section (abfd, sec, &contents)) 95084865Sobrien goto error_return; 95184865Sobrien } 95284865Sobrien 953130561Sobrien for (irel = internal_relocs; irel < irelend; irel++) 95484865Sobrien { 955130561Sobrien unsigned long r_type = ELFNN_R_TYPE (irel->r_info); 95684865Sobrien bfd_vma symaddr, reladdr, trampoff, toff, roff; 95784865Sobrien asection *tsec; 95884865Sobrien struct one_fixup *f; 95989857Sobrien bfd_size_type amt; 960130561Sobrien bfd_boolean is_branch; 961130561Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 962218822Sdim char symtype; 96384865Sobrien 964130561Sobrien switch (r_type) 965130561Sobrien { 966130561Sobrien case R_IA64_PCREL21B: 967130561Sobrien case R_IA64_PCREL21BI: 968130561Sobrien case R_IA64_PCREL21M: 969130561Sobrien case R_IA64_PCREL21F: 970218822Sdim /* In pass 1, all br relaxations are done. We can skip it. */ 971218822Sdim if (link_info->relax_pass == 1) 972130561Sobrien continue; 973218822Sdim skip_relax_pass_0 = FALSE; 974130561Sobrien is_branch = TRUE; 975130561Sobrien break; 97684865Sobrien 977130561Sobrien case R_IA64_PCREL60B: 978218822Sdim /* We can't optimize brl to br in pass 0 since br relaxations 979218822Sdim will increase the code size. Defer it to pass 1. */ 980218822Sdim if (link_info->relax_pass == 0) 981130561Sobrien { 982218822Sdim skip_relax_pass_1 = FALSE; 983130561Sobrien continue; 984130561Sobrien } 985130561Sobrien is_branch = TRUE; 986130561Sobrien break; 987130561Sobrien 988130561Sobrien case R_IA64_LTOFF22X: 989130561Sobrien case R_IA64_LDXMOV: 990218822Sdim /* We can't relax ldx/mov in pass 0 since br relaxations will 991218822Sdim increase the code size. Defer it to pass 1. */ 992218822Sdim if (link_info->relax_pass == 0) 993130561Sobrien { 994218822Sdim skip_relax_pass_1 = FALSE; 995130561Sobrien continue; 996130561Sobrien } 997130561Sobrien is_branch = FALSE; 998130561Sobrien break; 999130561Sobrien 1000130561Sobrien default: 1001130561Sobrien continue; 1002130561Sobrien } 1003130561Sobrien 100484865Sobrien /* Get the value of the symbol referred to by the reloc. */ 100584865Sobrien if (ELFNN_R_SYM (irel->r_info) < symtab_hdr->sh_info) 100684865Sobrien { 1007104834Sobrien /* A local symbol. */ 1008104834Sobrien Elf_Internal_Sym *isym; 100989857Sobrien 1010104834Sobrien /* Read this BFD's local symbols. */ 1011104834Sobrien if (isymbuf == NULL) 1012104834Sobrien { 1013104834Sobrien isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; 1014104834Sobrien if (isymbuf == NULL) 1015104834Sobrien isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, 1016104834Sobrien symtab_hdr->sh_info, 0, 1017104834Sobrien NULL, NULL, NULL); 1018104834Sobrien if (isymbuf == 0) 1019104834Sobrien goto error_return; 1020104834Sobrien } 1021104834Sobrien 1022130561Sobrien isym = isymbuf + ELFNN_R_SYM (irel->r_info); 1023104834Sobrien if (isym->st_shndx == SHN_UNDEF) 1024130561Sobrien continue; /* We can't do anything with undefined symbols. */ 1025104834Sobrien else if (isym->st_shndx == SHN_ABS) 102684865Sobrien tsec = bfd_abs_section_ptr; 1027104834Sobrien else if (isym->st_shndx == SHN_COMMON) 102884865Sobrien tsec = bfd_com_section_ptr; 1029104834Sobrien else if (isym->st_shndx == SHN_IA_64_ANSI_COMMON) 103089857Sobrien tsec = bfd_com_section_ptr; 103189857Sobrien else 1032104834Sobrien tsec = bfd_section_from_elf_index (abfd, isym->st_shndx); 103384865Sobrien 1034104834Sobrien toff = isym->st_value; 1035130561Sobrien dyn_i = get_dyn_sym_info (ia64_info, NULL, abfd, irel, FALSE); 1036218822Sdim symtype = ELF_ST_TYPE (isym->st_info); 103784865Sobrien } 103884865Sobrien else 103984865Sobrien { 104084865Sobrien unsigned long indx; 104184865Sobrien struct elf_link_hash_entry *h; 104284865Sobrien 104384865Sobrien indx = ELFNN_R_SYM (irel->r_info) - symtab_hdr->sh_info; 104484865Sobrien h = elf_sym_hashes (abfd)[indx]; 104584865Sobrien BFD_ASSERT (h != NULL); 104684865Sobrien 104784865Sobrien while (h->root.type == bfd_link_hash_indirect 104884865Sobrien || h->root.type == bfd_link_hash_warning) 104984865Sobrien h = (struct elf_link_hash_entry *) h->root.u.i.link; 105084865Sobrien 1051130561Sobrien dyn_i = get_dyn_sym_info (ia64_info, h, abfd, irel, FALSE); 105284865Sobrien 105384865Sobrien /* For branches to dynamic symbols, we're interested instead 105484865Sobrien in a branch to the PLT entry. */ 1055130561Sobrien if (is_branch && dyn_i && dyn_i->want_plt2) 105684865Sobrien { 1057130561Sobrien /* Internal branches shouldn't be sent to the PLT. 1058130561Sobrien Leave this for now and we'll give an error later. */ 1059130561Sobrien if (r_type != R_IA64_PCREL21B) 1060130561Sobrien continue; 1061130561Sobrien 106284865Sobrien tsec = ia64_info->plt_sec; 106384865Sobrien toff = dyn_i->plt2_offset; 1064130561Sobrien BFD_ASSERT (irel->r_addend == 0); 106584865Sobrien } 1066130561Sobrien 1067130561Sobrien /* Can't do anything else with dynamic symbols. */ 1068130561Sobrien else if (elfNN_ia64_dynamic_symbol_p (h, link_info, r_type)) 1069130561Sobrien continue; 1070130561Sobrien 107184865Sobrien else 107284865Sobrien { 1073130561Sobrien /* We can't do anything with undefined symbols. */ 107484865Sobrien if (h->root.type == bfd_link_hash_undefined 107584865Sobrien || h->root.type == bfd_link_hash_undefweak) 107684865Sobrien continue; 107784865Sobrien 107884865Sobrien tsec = h->root.u.def.section; 107984865Sobrien toff = h->root.u.def.value; 108084865Sobrien } 1081218822Sdim 1082218822Sdim symtype = h->type; 108384865Sobrien } 108484865Sobrien 1085130561Sobrien if (tsec->sec_info_type == ELF_INFO_TYPE_MERGE) 1086218822Sdim { 1087218822Sdim /* At this stage in linking, no SEC_MERGE symbol has been 1088218822Sdim adjusted, so all references to such symbols need to be 1089218822Sdim passed through _bfd_merged_section_offset. (Later, in 1090218822Sdim relocate_section, all SEC_MERGE symbols *except* for 1091218822Sdim section symbols have been adjusted.) 1092218822Sdim 1093218822Sdim gas may reduce relocations against symbols in SEC_MERGE 1094218822Sdim sections to a relocation against the section symbol when 1095218822Sdim the original addend was zero. When the reloc is against 1096218822Sdim a section symbol we should include the addend in the 1097218822Sdim offset passed to _bfd_merged_section_offset, since the 1098218822Sdim location of interest is the original symbol. On the 1099218822Sdim other hand, an access to "sym+addend" where "sym" is not 1100218822Sdim a section symbol should not include the addend; Such an 1101218822Sdim access is presumed to be an offset from "sym"; The 1102218822Sdim location of interest is just "sym". */ 1103218822Sdim if (symtype == STT_SECTION) 1104218822Sdim toff += irel->r_addend; 1105218822Sdim 1106218822Sdim toff = _bfd_merged_section_offset (abfd, &tsec, 1107218822Sdim elf_section_data (tsec)->sec_info, 1108218822Sdim toff); 1109218822Sdim 1110218822Sdim if (symtype != STT_SECTION) 1111218822Sdim toff += irel->r_addend; 1112218822Sdim } 1113130561Sobrien else 1114130561Sobrien toff += irel->r_addend; 111584865Sobrien 1116130561Sobrien symaddr = tsec->output_section->vma + tsec->output_offset + toff; 1117130561Sobrien 111884865Sobrien roff = irel->r_offset; 111984865Sobrien 1120130561Sobrien if (is_branch) 1121130561Sobrien { 1122130561Sobrien bfd_signed_vma offset; 112384865Sobrien 1124130561Sobrien reladdr = (sec->output_section->vma 1125130561Sobrien + sec->output_offset 1126130561Sobrien + roff) & (bfd_vma) -4; 112784865Sobrien 1128130561Sobrien /* If the branch is in range, no need to do anything. */ 1129130561Sobrien if ((bfd_signed_vma) (symaddr - reladdr) >= -0x1000000 1130130561Sobrien && (bfd_signed_vma) (symaddr - reladdr) <= 0x0FFFFF0) 1131130561Sobrien { 1132130561Sobrien /* If the 60-bit branch is in 21-bit range, optimize it. */ 1133130561Sobrien if (r_type == R_IA64_PCREL60B) 1134130561Sobrien { 1135218822Sdim elfNN_ia64_relax_brl (contents, roff); 113684865Sobrien 1137130561Sobrien irel->r_info 1138218822Sdim = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), 1139130561Sobrien R_IA64_PCREL21B); 114084865Sobrien 1141130561Sobrien /* If the original relocation offset points to slot 1142130561Sobrien 1, change it to slot 2. */ 1143130561Sobrien if ((irel->r_offset & 3) == 1) 1144130561Sobrien irel->r_offset += 1; 1145130561Sobrien } 114684865Sobrien 1147130561Sobrien continue; 114884865Sobrien } 1149130561Sobrien else if (r_type == R_IA64_PCREL60B) 1150130561Sobrien continue; 1151218822Sdim else if (elfNN_ia64_relax_br (contents, roff)) 1152218822Sdim { 1153218822Sdim irel->r_info 1154218822Sdim = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), 1155218822Sdim R_IA64_PCREL60B); 115684865Sobrien 1157218822Sdim /* Make the relocation offset point to slot 1. */ 1158218822Sdim irel->r_offset = (irel->r_offset & ~((bfd_vma) 0x3)) + 1; 1159218822Sdim continue; 1160218822Sdim } 1161218822Sdim 1162218822Sdim /* We can't put a trampoline in a .init/.fini section. Issue 1163218822Sdim an error. */ 1164218822Sdim if (strcmp (sec->output_section->name, ".init") == 0 1165218822Sdim || strcmp (sec->output_section->name, ".fini") == 0) 1166218822Sdim { 1167218822Sdim (*_bfd_error_handler) 1168218822Sdim (_("%B: Can't relax br at 0x%lx in section `%A'. Please use brl or indirect branch."), 1169218822Sdim sec->owner, sec, (unsigned long) roff); 1170218822Sdim bfd_set_error (bfd_error_bad_value); 1171218822Sdim goto error_return; 1172218822Sdim } 1173218822Sdim 1174130561Sobrien /* If the branch and target are in the same section, you've 1175218822Sdim got one honking big section and we can't help you unless 1176218822Sdim you are branching backwards. You'll get an error message 1177218822Sdim later. */ 1178218822Sdim if (tsec == sec && toff > roff) 1179130561Sobrien continue; 118084865Sobrien 1181130561Sobrien /* Look for an existing fixup to this address. */ 1182130561Sobrien for (f = fixups; f ; f = f->next) 1183130561Sobrien if (f->tsec == tsec && f->toff == toff) 1184130561Sobrien break; 1185130561Sobrien 1186130561Sobrien if (f == NULL) 118784865Sobrien { 1188130561Sobrien /* Two alternatives: If it's a branch to a PLT entry, we can 1189130561Sobrien make a copy of the FULL_PLT entry. Otherwise, we'll have 1190130561Sobrien to use a `brl' insn to get where we're going. */ 119184865Sobrien 1192130561Sobrien size_t size; 1193130561Sobrien 1194130561Sobrien if (tsec == ia64_info->plt_sec) 1195130561Sobrien size = sizeof (plt_full_entry); 1196130561Sobrien else 1197130561Sobrien size = oor_branch_size; 1198130561Sobrien 1199130561Sobrien /* Resize the current section to make room for the new branch. */ 1200218822Sdim trampoff = (sec->size + 15) & (bfd_vma) -16; 1201130561Sobrien 1202130561Sobrien /* If trampoline is out of range, there is nothing we 1203130561Sobrien can do. */ 1204130561Sobrien offset = trampoff - (roff & (bfd_vma) -4); 1205130561Sobrien if (offset < -0x1000000 || offset > 0x0FFFFF0) 1206130561Sobrien continue; 1207130561Sobrien 1208130561Sobrien amt = trampoff + size; 1209130561Sobrien contents = (bfd_byte *) bfd_realloc (contents, amt); 1210130561Sobrien if (contents == NULL) 1211130561Sobrien goto error_return; 1212218822Sdim sec->size = amt; 1213130561Sobrien 1214130561Sobrien if (tsec == ia64_info->plt_sec) 1215130561Sobrien { 1216130561Sobrien memcpy (contents + trampoff, plt_full_entry, size); 1217130561Sobrien 1218130561Sobrien /* Hijack the old relocation for use as the PLTOFF reloc. */ 1219130561Sobrien irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), 1220130561Sobrien R_IA64_PLTOFF22); 1221130561Sobrien irel->r_offset = trampoff; 1222130561Sobrien } 1223130561Sobrien else 1224130561Sobrien { 1225130561Sobrien if (size == sizeof (oor_ip)) 1226130561Sobrien { 1227130561Sobrien memcpy (contents + trampoff, oor_ip, size); 1228130561Sobrien irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), 1229130561Sobrien R_IA64_PCREL64I); 1230130561Sobrien irel->r_addend -= 16; 1231130561Sobrien irel->r_offset = trampoff + 2; 1232130561Sobrien } 1233130561Sobrien else 1234130561Sobrien { 1235130561Sobrien memcpy (contents + trampoff, oor_brl, size); 1236130561Sobrien irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), 1237130561Sobrien R_IA64_PCREL60B); 1238130561Sobrien irel->r_offset = trampoff + 2; 1239130561Sobrien } 1240130561Sobrien 1241130561Sobrien } 1242130561Sobrien 1243130561Sobrien /* Record the fixup so we don't do it again this section. */ 1244130561Sobrien f = (struct one_fixup *) 1245130561Sobrien bfd_malloc ((bfd_size_type) sizeof (*f)); 1246130561Sobrien f->next = fixups; 1247130561Sobrien f->tsec = tsec; 1248130561Sobrien f->toff = toff; 1249130561Sobrien f->trampoff = trampoff; 1250130561Sobrien fixups = f; 125184865Sobrien } 125284865Sobrien else 125384865Sobrien { 1254130561Sobrien /* If trampoline is out of range, there is nothing we 1255130561Sobrien can do. */ 1256130561Sobrien offset = f->trampoff - (roff & (bfd_vma) -4); 1257130561Sobrien if (offset < -0x1000000 || offset > 0x0FFFFF0) 1258130561Sobrien continue; 1259130561Sobrien 1260130561Sobrien /* Nop out the reloc, since we're finalizing things here. */ 1261130561Sobrien irel->r_info = ELFNN_R_INFO (0, R_IA64_NONE); 126284865Sobrien } 126384865Sobrien 1264130561Sobrien /* Fix up the existing branch to hit the trampoline. */ 1265218822Sdim if (elfNN_ia64_install_value (contents + roff, offset, r_type) 1266218822Sdim != bfd_reloc_ok) 1267130561Sobrien goto error_return; 1268130561Sobrien 1269130561Sobrien changed_contents = TRUE; 1270130561Sobrien changed_relocs = TRUE; 127184865Sobrien } 127284865Sobrien else 127384865Sobrien { 1274130561Sobrien /* Fetch the gp. */ 1275130561Sobrien if (gp == 0) 1276130561Sobrien { 1277130561Sobrien bfd *obfd = sec->output_section->owner; 1278130561Sobrien gp = _bfd_get_gp_value (obfd); 1279130561Sobrien if (gp == 0) 1280130561Sobrien { 1281130561Sobrien if (!elfNN_ia64_choose_gp (obfd, link_info)) 1282130561Sobrien goto error_return; 1283130561Sobrien gp = _bfd_get_gp_value (obfd); 1284130561Sobrien } 1285130561Sobrien } 128684865Sobrien 1287130561Sobrien /* If the data is out of range, do nothing. */ 1288130561Sobrien if ((bfd_signed_vma) (symaddr - gp) >= 0x200000 1289130561Sobrien ||(bfd_signed_vma) (symaddr - gp) < -0x200000) 1290130561Sobrien continue; 129184865Sobrien 1292130561Sobrien if (r_type == R_IA64_LTOFF22X) 1293130561Sobrien { 1294130561Sobrien irel->r_info = ELFNN_R_INFO (ELFNN_R_SYM (irel->r_info), 1295130561Sobrien R_IA64_GPREL22); 1296130561Sobrien changed_relocs = TRUE; 1297130561Sobrien if (dyn_i->want_gotx) 1298130561Sobrien { 1299130561Sobrien dyn_i->want_gotx = 0; 1300130561Sobrien changed_got |= !dyn_i->want_got; 1301130561Sobrien } 1302130561Sobrien } 1303130561Sobrien else 1304130561Sobrien { 1305218822Sdim elfNN_ia64_relax_ldxmov (contents, roff); 1306130561Sobrien irel->r_info = ELFNN_R_INFO (0, R_IA64_NONE); 1307130561Sobrien changed_contents = TRUE; 1308130561Sobrien changed_relocs = TRUE; 1309130561Sobrien } 1310130561Sobrien } 131184865Sobrien } 131284865Sobrien 1313130561Sobrien /* ??? If we created fixups, this may push the code segment large 1314130561Sobrien enough that the data segment moves, which will change the GP. 1315130561Sobrien Reset the GP so that we re-calculate next round. We need to 1316130561Sobrien do this at the _beginning_ of the next round; now will not do. */ 1317218822Sdim 131884865Sobrien /* Clean up and go home. */ 131984865Sobrien while (fixups) 132084865Sobrien { 132184865Sobrien struct one_fixup *f = fixups; 132284865Sobrien fixups = fixups->next; 132384865Sobrien free (f); 132484865Sobrien } 132584865Sobrien 1326104834Sobrien if (isymbuf != NULL 1327104834Sobrien && symtab_hdr->contents != (unsigned char *) isymbuf) 132884865Sobrien { 132984865Sobrien if (! link_info->keep_memory) 1330104834Sobrien free (isymbuf); 133184865Sobrien else 133284865Sobrien { 1333104834Sobrien /* Cache the symbols for elf_link_input_bfd. */ 1334104834Sobrien symtab_hdr->contents = (unsigned char *) isymbuf; 133584865Sobrien } 133684865Sobrien } 133784865Sobrien 1338104834Sobrien if (contents != NULL 1339104834Sobrien && elf_section_data (sec)->this_hdr.contents != contents) 134084865Sobrien { 1341104834Sobrien if (!changed_contents && !link_info->keep_memory) 1342104834Sobrien free (contents); 134384865Sobrien else 134484865Sobrien { 1345104834Sobrien /* Cache the section contents for elf_link_input_bfd. */ 1346104834Sobrien elf_section_data (sec)->this_hdr.contents = contents; 134784865Sobrien } 134884865Sobrien } 134984865Sobrien 1350104834Sobrien if (elf_section_data (sec)->relocs != internal_relocs) 1351104834Sobrien { 1352104834Sobrien if (!changed_relocs) 1353104834Sobrien free (internal_relocs); 1354104834Sobrien else 1355104834Sobrien elf_section_data (sec)->relocs = internal_relocs; 1356104834Sobrien } 1357104834Sobrien 1358130561Sobrien if (changed_got) 1359130561Sobrien { 1360130561Sobrien struct elfNN_ia64_allocate_data data; 1361130561Sobrien data.info = link_info; 1362130561Sobrien data.ofs = 0; 1363130561Sobrien ia64_info->self_dtpmod_offset = (bfd_vma) -1; 1364130561Sobrien 1365130561Sobrien elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_data_got, &data); 1366130561Sobrien elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_fptr_got, &data); 1367130561Sobrien elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_local_got, &data); 1368218822Sdim ia64_info->got_sec->size = data.ofs; 1369130561Sobrien 1370218822Sdim if (ia64_info->root.dynamic_sections_created 1371218822Sdim && ia64_info->rel_got_sec != NULL) 1372218822Sdim { 1373218822Sdim /* Resize .rela.got. */ 1374218822Sdim ia64_info->rel_got_sec->size = 0; 1375218822Sdim if (link_info->shared 1376218822Sdim && ia64_info->self_dtpmod_offset != (bfd_vma) -1) 1377218822Sdim ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela); 1378218822Sdim data.only_got = TRUE; 1379218822Sdim elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_dynrel_entries, 1380218822Sdim &data); 1381218822Sdim } 1382130561Sobrien } 1383130561Sobrien 1384218822Sdim if (link_info->relax_pass == 0) 1385218822Sdim { 1386218822Sdim /* Pass 0 is only needed to relax br. */ 1387218822Sdim sec->skip_relax_pass_0 = skip_relax_pass_0; 1388218822Sdim sec->skip_relax_pass_1 = skip_relax_pass_1; 1389218822Sdim } 1390130561Sobrien 139184865Sobrien *again = changed_contents || changed_relocs; 1392130561Sobrien return TRUE; 139384865Sobrien 139484865Sobrien error_return: 1395104834Sobrien if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents) 1396104834Sobrien free (isymbuf); 1397104834Sobrien if (contents != NULL 1398104834Sobrien && elf_section_data (sec)->this_hdr.contents != contents) 1399104834Sobrien free (contents); 1400104834Sobrien if (internal_relocs != NULL 1401104834Sobrien && elf_section_data (sec)->relocs != internal_relocs) 1402104834Sobrien free (internal_relocs); 1403130561Sobrien return FALSE; 140484865Sobrien} 1405218822Sdim#undef skip_relax_pass_0 1406218822Sdim#undef skip_relax_pass_1 1407130561Sobrien 1408130561Sobrienstatic void 1409218822SdimelfNN_ia64_relax_ldxmov (contents, off) 1410130561Sobrien bfd_byte *contents; 1411130561Sobrien bfd_vma off; 1412130561Sobrien{ 1413130561Sobrien int shift, r1, r3; 1414130561Sobrien bfd_vma dword, insn; 1415130561Sobrien 1416130561Sobrien switch ((int)off & 0x3) 1417130561Sobrien { 1418130561Sobrien case 0: shift = 5; break; 1419130561Sobrien case 1: shift = 14; off += 3; break; 1420130561Sobrien case 2: shift = 23; off += 6; break; 1421130561Sobrien default: 1422130561Sobrien abort (); 1423130561Sobrien } 1424130561Sobrien 1425218822Sdim dword = bfd_getl64 (contents + off); 1426130561Sobrien insn = (dword >> shift) & 0x1ffffffffffLL; 1427130561Sobrien 1428130561Sobrien r1 = (insn >> 6) & 127; 1429130561Sobrien r3 = (insn >> 20) & 127; 1430130561Sobrien if (r1 == r3) 1431130561Sobrien insn = 0x8000000; /* nop */ 1432130561Sobrien else 1433130561Sobrien insn = (insn & 0x7f01fff) | 0x10800000000LL; /* (qp) mov r1 = r3 */ 1434130561Sobrien 1435130561Sobrien dword &= ~(0x1ffffffffffLL << shift); 1436130561Sobrien dword |= (insn << shift); 1437218822Sdim bfd_putl64 (dword, contents + off); 1438130561Sobrien} 143984865Sobrien 1440130561Sobrien/* Return TRUE if NAME is an unwind table section name. */ 144184865Sobrien 1442130561Sobrienstatic inline bfd_boolean 1443218822Sdimis_unwind_section_name (bfd *abfd, const char *name) 144484865Sobrien{ 144589857Sobrien if (elfNN_ia64_hpux_vec (abfd->xvec) 144689857Sobrien && !strcmp (name, ELF_STRING_ia64_unwind_hdr)) 1447130561Sobrien return FALSE; 144889857Sobrien 1449218822Sdim return ((CONST_STRNEQ (name, ELF_STRING_ia64_unwind) 1450218822Sdim && ! CONST_STRNEQ (name, ELF_STRING_ia64_unwind_info)) 1451218822Sdim || CONST_STRNEQ (name, ELF_STRING_ia64_unwind_once)); 145284865Sobrien} 145384865Sobrien 145484865Sobrien/* Handle an IA-64 specific section when reading an object file. This 1455218822Sdim is called when bfd_section_from_shdr finds a section with an unknown 1456218822Sdim type. */ 145784865Sobrien 1458130561Sobrienstatic bfd_boolean 1459218822SdimelfNN_ia64_section_from_shdr (bfd *abfd, 1460218822Sdim Elf_Internal_Shdr *hdr, 1461218822Sdim const char *name, 1462218822Sdim int shindex) 146384865Sobrien{ 146484865Sobrien asection *newsect; 146584865Sobrien 146684865Sobrien /* There ought to be a place to keep ELF backend specific flags, but 146784865Sobrien at the moment there isn't one. We just keep track of the 146884865Sobrien sections by their name, instead. Fortunately, the ABI gives 146984865Sobrien suggested names for all the MIPS specific sections, so we will 147084865Sobrien probably get away with this. */ 147184865Sobrien switch (hdr->sh_type) 147284865Sobrien { 147384865Sobrien case SHT_IA_64_UNWIND: 147489857Sobrien case SHT_IA_64_HP_OPT_ANOT: 147584865Sobrien break; 147684865Sobrien 147784865Sobrien case SHT_IA_64_EXT: 147884865Sobrien if (strcmp (name, ELF_STRING_ia64_archext) != 0) 1479130561Sobrien return FALSE; 148084865Sobrien break; 148184865Sobrien 148284865Sobrien default: 1483130561Sobrien return FALSE; 148484865Sobrien } 148584865Sobrien 1486218822Sdim if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) 1487130561Sobrien return FALSE; 148884865Sobrien newsect = hdr->bfd_section; 148984865Sobrien 1490130561Sobrien return TRUE; 149184865Sobrien} 149284865Sobrien 149384865Sobrien/* Convert IA-64 specific section flags to bfd internal section flags. */ 149484865Sobrien 149584865Sobrien/* ??? There is no bfd internal flag equivalent to the SHF_IA_64_NORECOV 149684865Sobrien flag. */ 149784865Sobrien 1498130561Sobrienstatic bfd_boolean 149984865SobrienelfNN_ia64_section_flags (flags, hdr) 150084865Sobrien flagword *flags; 1501218822Sdim const Elf_Internal_Shdr *hdr; 150284865Sobrien{ 150384865Sobrien if (hdr->sh_flags & SHF_IA_64_SHORT) 150484865Sobrien *flags |= SEC_SMALL_DATA; 150584865Sobrien 1506130561Sobrien return TRUE; 150784865Sobrien} 150884865Sobrien 150984865Sobrien/* Set the correct type for an IA-64 ELF section. We do this by the 151084865Sobrien section name, which is a hack, but ought to work. */ 151184865Sobrien 1512130561Sobrienstatic bfd_boolean 151384865SobrienelfNN_ia64_fake_sections (abfd, hdr, sec) 151484865Sobrien bfd *abfd ATTRIBUTE_UNUSED; 1515130561Sobrien Elf_Internal_Shdr *hdr; 151684865Sobrien asection *sec; 151784865Sobrien{ 151884865Sobrien register const char *name; 151984865Sobrien 152084865Sobrien name = bfd_get_section_name (abfd, sec); 152184865Sobrien 152289857Sobrien if (is_unwind_section_name (abfd, name)) 152384865Sobrien { 152484865Sobrien /* We don't have the sections numbered at this point, so sh_info 152584865Sobrien is set later, in elfNN_ia64_final_write_processing. */ 152684865Sobrien hdr->sh_type = SHT_IA_64_UNWIND; 152784865Sobrien hdr->sh_flags |= SHF_LINK_ORDER; 152884865Sobrien } 152984865Sobrien else if (strcmp (name, ELF_STRING_ia64_archext) == 0) 153084865Sobrien hdr->sh_type = SHT_IA_64_EXT; 153189857Sobrien else if (strcmp (name, ".HP.opt_annot") == 0) 153289857Sobrien hdr->sh_type = SHT_IA_64_HP_OPT_ANOT; 153384865Sobrien else if (strcmp (name, ".reloc") == 0) 1534130561Sobrien /* This is an ugly, but unfortunately necessary hack that is 1535130561Sobrien needed when producing EFI binaries on IA-64. It tells 1536130561Sobrien elf.c:elf_fake_sections() not to consider ".reloc" as a section 1537130561Sobrien containing ELF relocation info. We need this hack in order to 1538130561Sobrien be able to generate ELF binaries that can be translated into 1539130561Sobrien EFI applications (which are essentially COFF objects). Those 1540130561Sobrien files contain a COFF ".reloc" section inside an ELFNN object, 1541130561Sobrien which would normally cause BFD to segfault because it would 1542130561Sobrien attempt to interpret this section as containing relocation 1543130561Sobrien entries for section "oc". With this hack enabled, ".reloc" 1544130561Sobrien will be treated as a normal data section, which will avoid the 1545130561Sobrien segfault. However, you won't be able to create an ELFNN binary 1546130561Sobrien with a section named "oc" that needs relocations, but that's 1547130561Sobrien the kind of ugly side-effects you get when detecting section 1548130561Sobrien types based on their names... In practice, this limitation is 1549130561Sobrien unlikely to bite. */ 155084865Sobrien hdr->sh_type = SHT_PROGBITS; 155184865Sobrien 155284865Sobrien if (sec->flags & SEC_SMALL_DATA) 155384865Sobrien hdr->sh_flags |= SHF_IA_64_SHORT; 155484865Sobrien 1555218822Sdim /* Some HP linkers look for the SHF_IA_64_HP_TLS flag instead of SHF_TLS. */ 1556218822Sdim 1557218822Sdim if (elfNN_ia64_hpux_vec (abfd->xvec) && (sec->flags & SHF_TLS)) 1558218822Sdim hdr->sh_flags |= SHF_IA_64_HP_TLS; 1559218822Sdim 1560130561Sobrien return TRUE; 156184865Sobrien} 156284865Sobrien 156384865Sobrien/* The final processing done just before writing out an IA-64 ELF 156484865Sobrien object file. */ 156584865Sobrien 156684865Sobrienstatic void 156784865SobrienelfNN_ia64_final_write_processing (abfd, linker) 156884865Sobrien bfd *abfd; 1569130561Sobrien bfd_boolean linker ATTRIBUTE_UNUSED; 157084865Sobrien{ 157184865Sobrien Elf_Internal_Shdr *hdr; 1572218822Sdim asection *s; 157384865Sobrien 157484865Sobrien for (s = abfd->sections; s; s = s->next) 157584865Sobrien { 157684865Sobrien hdr = &elf_section_data (s)->this_hdr; 157784865Sobrien switch (hdr->sh_type) 157884865Sobrien { 157984865Sobrien case SHT_IA_64_UNWIND: 1580218822Sdim /* The IA-64 processor-specific ABI requires setting sh_link 1581218822Sdim to the unwind section, whereas HP-UX requires sh_info to 1582218822Sdim do so. For maximum compatibility, we'll set both for 1583218822Sdim now... */ 1584218822Sdim hdr->sh_info = hdr->sh_link; 158584865Sobrien break; 158684865Sobrien } 158784865Sobrien } 1588130561Sobrien 1589130561Sobrien if (! elf_flags_init (abfd)) 1590130561Sobrien { 1591130561Sobrien unsigned long flags = 0; 1592130561Sobrien 1593130561Sobrien if (abfd->xvec->byteorder == BFD_ENDIAN_BIG) 1594130561Sobrien flags |= EF_IA_64_BE; 1595130561Sobrien if (bfd_get_mach (abfd) == bfd_mach_ia64_elf64) 1596130561Sobrien flags |= EF_IA_64_ABI64; 1597130561Sobrien 1598130561Sobrien elf_elfheader(abfd)->e_flags = flags; 1599130561Sobrien elf_flags_init (abfd) = TRUE; 1600130561Sobrien } 160184865Sobrien} 160284865Sobrien 160384865Sobrien/* Hook called by the linker routine which adds symbols from an object 160484865Sobrien file. We use it to put .comm items in .sbss, and not .bss. */ 160584865Sobrien 1606130561Sobrienstatic bfd_boolean 160784865SobrienelfNN_ia64_add_symbol_hook (abfd, info, sym, namep, flagsp, secp, valp) 160884865Sobrien bfd *abfd; 160984865Sobrien struct bfd_link_info *info; 1610130561Sobrien Elf_Internal_Sym *sym; 161184865Sobrien const char **namep ATTRIBUTE_UNUSED; 161284865Sobrien flagword *flagsp ATTRIBUTE_UNUSED; 161384865Sobrien asection **secp; 161484865Sobrien bfd_vma *valp; 161584865Sobrien{ 161684865Sobrien if (sym->st_shndx == SHN_COMMON 1617130561Sobrien && !info->relocatable 161889857Sobrien && sym->st_size <= elf_gp_size (abfd)) 161984865Sobrien { 162084865Sobrien /* Common symbols less than or equal to -G nn bytes are 162184865Sobrien automatically put into .sbss. */ 162284865Sobrien 162384865Sobrien asection *scomm = bfd_get_section_by_name (abfd, ".scommon"); 162484865Sobrien 162584865Sobrien if (scomm == NULL) 162684865Sobrien { 1627218822Sdim scomm = bfd_make_section_with_flags (abfd, ".scommon", 1628218822Sdim (SEC_ALLOC 1629218822Sdim | SEC_IS_COMMON 1630218822Sdim | SEC_LINKER_CREATED)); 1631218822Sdim if (scomm == NULL) 1632130561Sobrien return FALSE; 163384865Sobrien } 163484865Sobrien 163584865Sobrien *secp = scomm; 163684865Sobrien *valp = sym->st_size; 163784865Sobrien } 163884865Sobrien 1639130561Sobrien return TRUE; 164084865Sobrien} 164184865Sobrien 164284865Sobrien/* Return the number of additional phdrs we will need. */ 164384865Sobrien 164484865Sobrienstatic int 1645218822SdimelfNN_ia64_additional_program_headers (bfd *abfd, 1646218822Sdim struct bfd_link_info *info ATTRIBUTE_UNUSED) 164784865Sobrien{ 164884865Sobrien asection *s; 164984865Sobrien int ret = 0; 165084865Sobrien 165184865Sobrien /* See if we need a PT_IA_64_ARCHEXT segment. */ 165284865Sobrien s = bfd_get_section_by_name (abfd, ELF_STRING_ia64_archext); 165384865Sobrien if (s && (s->flags & SEC_LOAD)) 165484865Sobrien ++ret; 165584865Sobrien 165684865Sobrien /* Count how many PT_IA_64_UNWIND segments we need. */ 165784865Sobrien for (s = abfd->sections; s; s = s->next) 165889857Sobrien if (is_unwind_section_name (abfd, s->name) && (s->flags & SEC_LOAD)) 165984865Sobrien ++ret; 166084865Sobrien 166184865Sobrien return ret; 166284865Sobrien} 166384865Sobrien 1664130561Sobrienstatic bfd_boolean 1665218822SdimelfNN_ia64_modify_segment_map (bfd *abfd, 1666218822Sdim struct bfd_link_info *info ATTRIBUTE_UNUSED) 166784865Sobrien{ 166884865Sobrien struct elf_segment_map *m, **pm; 166984865Sobrien Elf_Internal_Shdr *hdr; 167084865Sobrien asection *s; 167184865Sobrien 167284865Sobrien /* If we need a PT_IA_64_ARCHEXT segment, it must come before 167384865Sobrien all PT_LOAD segments. */ 167484865Sobrien s = bfd_get_section_by_name (abfd, ELF_STRING_ia64_archext); 167584865Sobrien if (s && (s->flags & SEC_LOAD)) 167684865Sobrien { 167784865Sobrien for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) 167884865Sobrien if (m->p_type == PT_IA_64_ARCHEXT) 167984865Sobrien break; 168084865Sobrien if (m == NULL) 168184865Sobrien { 168289857Sobrien m = ((struct elf_segment_map *) 168389857Sobrien bfd_zalloc (abfd, (bfd_size_type) sizeof *m)); 168484865Sobrien if (m == NULL) 1685130561Sobrien return FALSE; 168684865Sobrien 168784865Sobrien m->p_type = PT_IA_64_ARCHEXT; 168884865Sobrien m->count = 1; 168984865Sobrien m->sections[0] = s; 169084865Sobrien 169184865Sobrien /* We want to put it after the PHDR and INTERP segments. */ 169284865Sobrien pm = &elf_tdata (abfd)->segment_map; 169384865Sobrien while (*pm != NULL 169484865Sobrien && ((*pm)->p_type == PT_PHDR 169584865Sobrien || (*pm)->p_type == PT_INTERP)) 169684865Sobrien pm = &(*pm)->next; 169784865Sobrien 169884865Sobrien m->next = *pm; 169984865Sobrien *pm = m; 170084865Sobrien } 170184865Sobrien } 170284865Sobrien 170384865Sobrien /* Install PT_IA_64_UNWIND segments, if needed. */ 170484865Sobrien for (s = abfd->sections; s; s = s->next) 170584865Sobrien { 170684865Sobrien hdr = &elf_section_data (s)->this_hdr; 170784865Sobrien if (hdr->sh_type != SHT_IA_64_UNWIND) 170884865Sobrien continue; 170984865Sobrien 171084865Sobrien if (s && (s->flags & SEC_LOAD)) 171184865Sobrien { 171284865Sobrien for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next) 171389857Sobrien if (m->p_type == PT_IA_64_UNWIND) 171489857Sobrien { 1715104834Sobrien int i; 1716104834Sobrien 171789857Sobrien /* Look through all sections in the unwind segment 171889857Sobrien for a match since there may be multiple sections 171989857Sobrien to a segment. */ 1720104834Sobrien for (i = m->count - 1; i >= 0; --i) 1721104834Sobrien if (m->sections[i] == s) 1722104834Sobrien break; 172384865Sobrien 1724104834Sobrien if (i >= 0) 172589857Sobrien break; 172689857Sobrien } 172789857Sobrien 172884865Sobrien if (m == NULL) 172984865Sobrien { 173089857Sobrien m = ((struct elf_segment_map *) 173189857Sobrien bfd_zalloc (abfd, (bfd_size_type) sizeof *m)); 173284865Sobrien if (m == NULL) 1733130561Sobrien return FALSE; 173484865Sobrien 173584865Sobrien m->p_type = PT_IA_64_UNWIND; 173684865Sobrien m->count = 1; 173784865Sobrien m->sections[0] = s; 173884865Sobrien m->next = NULL; 173984865Sobrien 174084865Sobrien /* We want to put it last. */ 174184865Sobrien pm = &elf_tdata (abfd)->segment_map; 174284865Sobrien while (*pm != NULL) 174384865Sobrien pm = &(*pm)->next; 174484865Sobrien *pm = m; 174584865Sobrien } 174684865Sobrien } 174784865Sobrien } 174884865Sobrien 1749218822Sdim return TRUE; 1750218822Sdim} 1751218822Sdim 1752218822Sdim/* Turn on PF_IA_64_NORECOV if needed. This involves traversing all of 1753218822Sdim the input sections for each output section in the segment and testing 1754218822Sdim for SHF_IA_64_NORECOV on each. */ 1755218822Sdim 1756218822Sdimstatic bfd_boolean 1757218822SdimelfNN_ia64_modify_program_headers (bfd *abfd, 1758218822Sdim struct bfd_link_info *info ATTRIBUTE_UNUSED) 1759218822Sdim{ 1760218822Sdim struct elf_obj_tdata *tdata = elf_tdata (abfd); 1761218822Sdim struct elf_segment_map *m; 1762218822Sdim Elf_Internal_Phdr *p; 1763218822Sdim 1764218822Sdim for (p = tdata->phdr, m = tdata->segment_map; m != NULL; m = m->next, p++) 176584865Sobrien if (m->p_type == PT_LOAD) 176684865Sobrien { 176784865Sobrien int i; 176884865Sobrien for (i = m->count - 1; i >= 0; --i) 176984865Sobrien { 1770218822Sdim struct bfd_link_order *order = m->sections[i]->map_head.link_order; 1771218822Sdim 1772218822Sdim while (order != NULL) 177384865Sobrien { 177484865Sobrien if (order->type == bfd_indirect_link_order) 177584865Sobrien { 177684865Sobrien asection *is = order->u.indirect.section; 177784865Sobrien bfd_vma flags = elf_section_data(is)->this_hdr.sh_flags; 177884865Sobrien if (flags & SHF_IA_64_NORECOV) 177984865Sobrien { 1780218822Sdim p->p_flags |= PF_IA_64_NORECOV; 178184865Sobrien goto found; 178284865Sobrien } 178384865Sobrien } 178484865Sobrien order = order->next; 178584865Sobrien } 178684865Sobrien } 178784865Sobrien found:; 178884865Sobrien } 178984865Sobrien 1790130561Sobrien return TRUE; 179184865Sobrien} 179284865Sobrien 179384865Sobrien/* According to the Tahoe assembler spec, all labels starting with a 179484865Sobrien '.' are local. */ 179584865Sobrien 1796130561Sobrienstatic bfd_boolean 179784865SobrienelfNN_ia64_is_local_label_name (abfd, name) 179884865Sobrien bfd *abfd ATTRIBUTE_UNUSED; 179984865Sobrien const char *name; 180084865Sobrien{ 180184865Sobrien return name[0] == '.'; 180284865Sobrien} 180384865Sobrien 180484865Sobrien/* Should we do dynamic things to this symbol? */ 180584865Sobrien 1806130561Sobrienstatic bfd_boolean 1807130561SobrienelfNN_ia64_dynamic_symbol_p (h, info, r_type) 180884865Sobrien struct elf_link_hash_entry *h; 180984865Sobrien struct bfd_link_info *info; 1810130561Sobrien int r_type; 181184865Sobrien{ 1812130561Sobrien bfd_boolean ignore_protected 1813130561Sobrien = ((r_type & 0xf8) == 0x40 /* FPTR relocs */ 1814130561Sobrien || (r_type & 0xf8) == 0x50); /* LTOFF_FPTR relocs */ 181584865Sobrien 1816130561Sobrien return _bfd_elf_dynamic_symbol_p (h, info, ignore_protected); 181784865Sobrien} 181884865Sobrien 181984865Sobrienstatic struct bfd_hash_entry* 182084865SobrienelfNN_ia64_new_elf_hash_entry (entry, table, string) 182184865Sobrien struct bfd_hash_entry *entry; 182284865Sobrien struct bfd_hash_table *table; 182384865Sobrien const char *string; 182484865Sobrien{ 182584865Sobrien struct elfNN_ia64_link_hash_entry *ret; 182684865Sobrien ret = (struct elfNN_ia64_link_hash_entry *) entry; 182784865Sobrien 182884865Sobrien /* Allocate the structure if it has not already been allocated by a 182984865Sobrien subclass. */ 183084865Sobrien if (!ret) 183184865Sobrien ret = bfd_hash_allocate (table, sizeof (*ret)); 183284865Sobrien 183384865Sobrien if (!ret) 183484865Sobrien return 0; 183584865Sobrien 183684865Sobrien /* Call the allocation method of the superclass. */ 183784865Sobrien ret = ((struct elfNN_ia64_link_hash_entry *) 183884865Sobrien _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret, 183984865Sobrien table, string)); 184084865Sobrien 1841218822Sdim ret->info = NULL; 1842218822Sdim ret->count = 0; 1843218822Sdim ret->sorted_count = 0; 1844218822Sdim ret->size = 0; 184584865Sobrien return (struct bfd_hash_entry *) ret; 184684865Sobrien} 184784865Sobrien 184884865Sobrienstatic void 1849218822SdimelfNN_ia64_hash_copy_indirect (info, xdir, xind) 1850218822Sdim struct bfd_link_info *info; 185184865Sobrien struct elf_link_hash_entry *xdir, *xind; 185284865Sobrien{ 185384865Sobrien struct elfNN_ia64_link_hash_entry *dir, *ind; 185484865Sobrien 185589857Sobrien dir = (struct elfNN_ia64_link_hash_entry *) xdir; 185689857Sobrien ind = (struct elfNN_ia64_link_hash_entry *) xind; 185784865Sobrien 185884865Sobrien /* Copy down any references that we may have already seen to the 185984865Sobrien symbol which just became indirect. */ 186084865Sobrien 1861218822Sdim dir->root.ref_dynamic |= ind->root.ref_dynamic; 1862218822Sdim dir->root.ref_regular |= ind->root.ref_regular; 1863218822Sdim dir->root.ref_regular_nonweak |= ind->root.ref_regular_nonweak; 1864218822Sdim dir->root.needs_plt |= ind->root.needs_plt; 186584865Sobrien 186689857Sobrien if (ind->root.root.type != bfd_link_hash_indirect) 186789857Sobrien return; 186889857Sobrien 186984865Sobrien /* Copy over the got and plt data. This would have been done 187084865Sobrien by check_relocs. */ 187184865Sobrien 1872218822Sdim if (ind->info != NULL) 187384865Sobrien { 187484865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 1875218822Sdim unsigned int count; 187684865Sobrien 1877218822Sdim if (dir->info) 1878218822Sdim free (dir->info); 1879218822Sdim 1880218822Sdim dir->info = ind->info; 1881218822Sdim dir->count = ind->count; 1882218822Sdim dir->sorted_count = ind->sorted_count; 1883218822Sdim dir->size = ind->size; 1884218822Sdim 188584865Sobrien ind->info = NULL; 1886218822Sdim ind->count = 0; 1887218822Sdim ind->sorted_count = 0; 1888218822Sdim ind->size = 0; 188984865Sobrien 189084865Sobrien /* Fix up the dyn_sym_info pointers to the global symbol. */ 1891218822Sdim for (count = dir->count, dyn_i = dir->info; 1892218822Sdim count != 0; 1893218822Sdim count--, dyn_i++) 189484865Sobrien dyn_i->h = &dir->root; 189584865Sobrien } 189684865Sobrien 189784865Sobrien /* Copy over the dynindx. */ 189884865Sobrien 1899218822Sdim if (ind->root.dynindx != -1) 190084865Sobrien { 1901218822Sdim if (dir->root.dynindx != -1) 1902218822Sdim _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, 1903218822Sdim dir->root.dynstr_index); 190484865Sobrien dir->root.dynindx = ind->root.dynindx; 190584865Sobrien dir->root.dynstr_index = ind->root.dynstr_index; 190684865Sobrien ind->root.dynindx = -1; 190784865Sobrien ind->root.dynstr_index = 0; 190884865Sobrien } 190984865Sobrien} 191084865Sobrien 191184865Sobrienstatic void 191289857SobrienelfNN_ia64_hash_hide_symbol (info, xh, force_local) 191389857Sobrien struct bfd_link_info *info; 191484865Sobrien struct elf_link_hash_entry *xh; 1915130561Sobrien bfd_boolean force_local; 191684865Sobrien{ 191784865Sobrien struct elfNN_ia64_link_hash_entry *h; 191884865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 1919218822Sdim unsigned int count; 192084865Sobrien 192184865Sobrien h = (struct elfNN_ia64_link_hash_entry *)xh; 192284865Sobrien 192389857Sobrien _bfd_elf_link_hash_hide_symbol (info, &h->root, force_local); 192484865Sobrien 1925218822Sdim for (count = h->count, dyn_i = h->info; 1926218822Sdim count != 0; 1927218822Sdim count--, dyn_i++) 1928130561Sobrien { 1929130561Sobrien dyn_i->want_plt2 = 0; 1930130561Sobrien dyn_i->want_plt = 0; 1931130561Sobrien } 193284865Sobrien} 193384865Sobrien 1934130561Sobrien/* Compute a hash of a local hash entry. */ 1935130561Sobrien 1936130561Sobrienstatic hashval_t 1937130561SobrienelfNN_ia64_local_htab_hash (ptr) 1938130561Sobrien const void *ptr; 1939130561Sobrien{ 1940130561Sobrien struct elfNN_ia64_local_hash_entry *entry 1941130561Sobrien = (struct elfNN_ia64_local_hash_entry *) ptr; 1942130561Sobrien 1943130561Sobrien return (((entry->id & 0xff) << 24) | ((entry->id & 0xff00) << 8)) 1944130561Sobrien ^ entry->r_sym ^ (entry->id >> 16); 1945130561Sobrien} 1946130561Sobrien 1947130561Sobrien/* Compare local hash entries. */ 1948130561Sobrien 1949130561Sobrienstatic int 1950130561SobrienelfNN_ia64_local_htab_eq (ptr1, ptr2) 1951130561Sobrien const void *ptr1, *ptr2; 1952130561Sobrien{ 1953130561Sobrien struct elfNN_ia64_local_hash_entry *entry1 1954130561Sobrien = (struct elfNN_ia64_local_hash_entry *) ptr1; 1955130561Sobrien struct elfNN_ia64_local_hash_entry *entry2 1956130561Sobrien = (struct elfNN_ia64_local_hash_entry *) ptr2; 1957130561Sobrien 1958130561Sobrien return entry1->id == entry2->id && entry1->r_sym == entry2->r_sym; 1959130561Sobrien} 1960130561Sobrien 196184865Sobrien/* Create the derived linker hash table. The IA-64 ELF port uses this 196284865Sobrien derived hash table to keep information specific to the IA-64 ElF 196384865Sobrien linker (without using static variables). */ 196484865Sobrien 196584865Sobrienstatic struct bfd_link_hash_table* 196684865SobrienelfNN_ia64_hash_table_create (abfd) 196784865Sobrien bfd *abfd; 196884865Sobrien{ 196984865Sobrien struct elfNN_ia64_link_hash_table *ret; 197084865Sobrien 1971130561Sobrien ret = bfd_zmalloc ((bfd_size_type) sizeof (*ret)); 197284865Sobrien if (!ret) 197384865Sobrien return 0; 1974130561Sobrien 197584865Sobrien if (!_bfd_elf_link_hash_table_init (&ret->root, abfd, 1976218822Sdim elfNN_ia64_new_elf_hash_entry, 1977218822Sdim sizeof (struct elfNN_ia64_link_hash_entry))) 197884865Sobrien { 1979130561Sobrien free (ret); 198084865Sobrien return 0; 198184865Sobrien } 198284865Sobrien 1983130561Sobrien ret->loc_hash_table = htab_try_create (1024, elfNN_ia64_local_htab_hash, 1984130561Sobrien elfNN_ia64_local_htab_eq, NULL); 1985130561Sobrien ret->loc_hash_memory = objalloc_create (); 1986130561Sobrien if (!ret->loc_hash_table || !ret->loc_hash_memory) 1987130561Sobrien { 1988130561Sobrien free (ret); 1989130561Sobrien return 0; 1990130561Sobrien } 1991130561Sobrien 199284865Sobrien return &ret->root.root; 199384865Sobrien} 199484865Sobrien 1995218822Sdim/* Free the global elfNN_ia64_dyn_sym_info array. */ 1996218822Sdim 1997218822Sdimstatic bfd_boolean 1998218822SdimelfNN_ia64_global_dyn_info_free (void **xentry, 1999218822Sdim PTR unused ATTRIBUTE_UNUSED) 2000218822Sdim{ 2001218822Sdim struct elfNN_ia64_link_hash_entry *entry 2002218822Sdim = (struct elfNN_ia64_link_hash_entry *) xentry; 2003218822Sdim 2004218822Sdim if (entry->root.root.type == bfd_link_hash_warning) 2005218822Sdim entry = (struct elfNN_ia64_link_hash_entry *) entry->root.root.u.i.link; 2006218822Sdim 2007218822Sdim if (entry->info) 2008218822Sdim { 2009218822Sdim free (entry->info); 2010218822Sdim entry->info = NULL; 2011218822Sdim entry->count = 0; 2012218822Sdim entry->sorted_count = 0; 2013218822Sdim entry->size = 0; 2014218822Sdim } 2015218822Sdim 2016218822Sdim return TRUE; 2017218822Sdim} 2018218822Sdim 2019218822Sdim/* Free the local elfNN_ia64_dyn_sym_info array. */ 2020218822Sdim 2021218822Sdimstatic bfd_boolean 2022218822SdimelfNN_ia64_local_dyn_info_free (void **slot, 2023218822Sdim PTR unused ATTRIBUTE_UNUSED) 2024218822Sdim{ 2025218822Sdim struct elfNN_ia64_local_hash_entry *entry 2026218822Sdim = (struct elfNN_ia64_local_hash_entry *) *slot; 2027218822Sdim 2028218822Sdim if (entry->info) 2029218822Sdim { 2030218822Sdim free (entry->info); 2031218822Sdim entry->info = NULL; 2032218822Sdim entry->count = 0; 2033218822Sdim entry->sorted_count = 0; 2034218822Sdim entry->size = 0; 2035218822Sdim } 2036218822Sdim 2037218822Sdim return TRUE; 2038218822Sdim} 2039218822Sdim 2040130561Sobrien/* Destroy IA-64 linker hash table. */ 204184865Sobrien 2042130561Sobrienstatic void 2043130561SobrienelfNN_ia64_hash_table_free (hash) 2044130561Sobrien struct bfd_link_hash_table *hash; 204584865Sobrien{ 2046130561Sobrien struct elfNN_ia64_link_hash_table *ia64_info 2047130561Sobrien = (struct elfNN_ia64_link_hash_table *) hash; 2048130561Sobrien if (ia64_info->loc_hash_table) 2049218822Sdim { 2050218822Sdim htab_traverse (ia64_info->loc_hash_table, 2051218822Sdim elfNN_ia64_local_dyn_info_free, NULL); 2052218822Sdim htab_delete (ia64_info->loc_hash_table); 2053218822Sdim } 2054130561Sobrien if (ia64_info->loc_hash_memory) 2055130561Sobrien objalloc_free ((struct objalloc *) ia64_info->loc_hash_memory); 2056218822Sdim elf_link_hash_traverse (&ia64_info->root, 2057218822Sdim elfNN_ia64_global_dyn_info_free, NULL); 2058130561Sobrien _bfd_generic_link_hash_table_free (hash); 205984865Sobrien} 206084865Sobrien 206184865Sobrien/* Traverse both local and global hash tables. */ 206284865Sobrien 206384865Sobrienstruct elfNN_ia64_dyn_sym_traverse_data 206484865Sobrien{ 2065130561Sobrien bfd_boolean (*func) PARAMS ((struct elfNN_ia64_dyn_sym_info *, PTR)); 206684865Sobrien PTR data; 206784865Sobrien}; 206884865Sobrien 2069130561Sobrienstatic bfd_boolean 207084865SobrienelfNN_ia64_global_dyn_sym_thunk (xentry, xdata) 207184865Sobrien struct bfd_hash_entry *xentry; 207284865Sobrien PTR xdata; 207384865Sobrien{ 207484865Sobrien struct elfNN_ia64_link_hash_entry *entry 207584865Sobrien = (struct elfNN_ia64_link_hash_entry *) xentry; 207684865Sobrien struct elfNN_ia64_dyn_sym_traverse_data *data 207784865Sobrien = (struct elfNN_ia64_dyn_sym_traverse_data *) xdata; 207884865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 2079218822Sdim unsigned int count; 208084865Sobrien 208194536Sobrien if (entry->root.root.type == bfd_link_hash_warning) 208294536Sobrien entry = (struct elfNN_ia64_link_hash_entry *) entry->root.root.u.i.link; 208394536Sobrien 2084218822Sdim for (count = entry->count, dyn_i = entry->info; 2085218822Sdim count != 0; 2086218822Sdim count--, dyn_i++) 208784865Sobrien if (! (*data->func) (dyn_i, data->data)) 2088130561Sobrien return FALSE; 2089130561Sobrien return TRUE; 209084865Sobrien} 209184865Sobrien 2092130561Sobrienstatic bfd_boolean 2093130561SobrienelfNN_ia64_local_dyn_sym_thunk (slot, xdata) 2094130561Sobrien void **slot; 209584865Sobrien PTR xdata; 209684865Sobrien{ 209784865Sobrien struct elfNN_ia64_local_hash_entry *entry 2098130561Sobrien = (struct elfNN_ia64_local_hash_entry *) *slot; 209984865Sobrien struct elfNN_ia64_dyn_sym_traverse_data *data 210084865Sobrien = (struct elfNN_ia64_dyn_sym_traverse_data *) xdata; 210184865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 2102218822Sdim unsigned int count; 210384865Sobrien 2104218822Sdim for (count = entry->count, dyn_i = entry->info; 2105218822Sdim count != 0; 2106218822Sdim count--, dyn_i++) 210784865Sobrien if (! (*data->func) (dyn_i, data->data)) 2108218822Sdim return FALSE; 2109218822Sdim return TRUE; 211084865Sobrien} 211184865Sobrien 211284865Sobrienstatic void 211384865SobrienelfNN_ia64_dyn_sym_traverse (ia64_info, func, data) 211484865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 2115130561Sobrien bfd_boolean (*func) PARAMS ((struct elfNN_ia64_dyn_sym_info *, PTR)); 211684865Sobrien PTR data; 211784865Sobrien{ 211884865Sobrien struct elfNN_ia64_dyn_sym_traverse_data xdata; 211984865Sobrien 212084865Sobrien xdata.func = func; 212184865Sobrien xdata.data = data; 212284865Sobrien 212384865Sobrien elf_link_hash_traverse (&ia64_info->root, 212484865Sobrien elfNN_ia64_global_dyn_sym_thunk, &xdata); 2125130561Sobrien htab_traverse (ia64_info->loc_hash_table, 2126130561Sobrien elfNN_ia64_local_dyn_sym_thunk, &xdata); 212784865Sobrien} 212884865Sobrien 2129130561Sobrienstatic bfd_boolean 213084865SobrienelfNN_ia64_create_dynamic_sections (abfd, info) 213184865Sobrien bfd *abfd; 213284865Sobrien struct bfd_link_info *info; 213384865Sobrien{ 213484865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 213584865Sobrien asection *s; 213684865Sobrien 213784865Sobrien if (! _bfd_elf_create_dynamic_sections (abfd, info)) 2138130561Sobrien return FALSE; 213984865Sobrien 214084865Sobrien ia64_info = elfNN_ia64_hash_table (info); 214184865Sobrien 214284865Sobrien ia64_info->plt_sec = bfd_get_section_by_name (abfd, ".plt"); 214384865Sobrien ia64_info->got_sec = bfd_get_section_by_name (abfd, ".got"); 214484865Sobrien 214584865Sobrien { 214684865Sobrien flagword flags = bfd_get_section_flags (abfd, ia64_info->got_sec); 214784865Sobrien bfd_set_section_flags (abfd, ia64_info->got_sec, SEC_SMALL_DATA | flags); 2148130561Sobrien /* The .got section is always aligned at 8 bytes. */ 2149130561Sobrien bfd_set_section_alignment (abfd, ia64_info->got_sec, 3); 215084865Sobrien } 215184865Sobrien 215284865Sobrien if (!get_pltoff (abfd, info, ia64_info)) 2153130561Sobrien return FALSE; 215484865Sobrien 2155218822Sdim s = bfd_make_section_with_flags (abfd, ".rela.IA_64.pltoff", 2156218822Sdim (SEC_ALLOC | SEC_LOAD 2157218822Sdim | SEC_HAS_CONTENTS 2158218822Sdim | SEC_IN_MEMORY 2159218822Sdim | SEC_LINKER_CREATED 2160218822Sdim | SEC_READONLY)); 216184865Sobrien if (s == NULL 2162218822Sdim || !bfd_set_section_alignment (abfd, s, LOG_SECTION_ALIGN)) 2163130561Sobrien return FALSE; 216484865Sobrien ia64_info->rel_pltoff_sec = s; 216584865Sobrien 2166218822Sdim s = bfd_make_section_with_flags (abfd, ".rela.got", 2167218822Sdim (SEC_ALLOC | SEC_LOAD 2168218822Sdim | SEC_HAS_CONTENTS 2169218822Sdim | SEC_IN_MEMORY 2170218822Sdim | SEC_LINKER_CREATED 2171218822Sdim | SEC_READONLY)); 217284865Sobrien if (s == NULL 2173218822Sdim || !bfd_set_section_alignment (abfd, s, LOG_SECTION_ALIGN)) 2174130561Sobrien return FALSE; 217584865Sobrien ia64_info->rel_got_sec = s; 217684865Sobrien 2177130561Sobrien return TRUE; 217884865Sobrien} 217984865Sobrien 218089857Sobrien/* Find and/or create a hash entry for local symbol. */ 218189857Sobrienstatic struct elfNN_ia64_local_hash_entry * 218289857Sobrienget_local_sym_hash (ia64_info, abfd, rel, create) 218389857Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 218489857Sobrien bfd *abfd; 218589857Sobrien const Elf_Internal_Rela *rel; 2186130561Sobrien bfd_boolean create; 218789857Sobrien{ 2188130561Sobrien struct elfNN_ia64_local_hash_entry e, *ret; 2189130561Sobrien asection *sec = abfd->sections; 2190130561Sobrien hashval_t h = (((sec->id & 0xff) << 24) | ((sec->id & 0xff00) << 8)) 2191130561Sobrien ^ ELFNN_R_SYM (rel->r_info) ^ (sec->id >> 16); 2192130561Sobrien void **slot; 219389857Sobrien 2194130561Sobrien e.id = sec->id; 2195130561Sobrien e.r_sym = ELFNN_R_SYM (rel->r_info); 2196130561Sobrien slot = htab_find_slot_with_hash (ia64_info->loc_hash_table, &e, h, 2197130561Sobrien create ? INSERT : NO_INSERT); 219889857Sobrien 2199130561Sobrien if (!slot) 2200130561Sobrien return NULL; 220189857Sobrien 2202130561Sobrien if (*slot) 2203130561Sobrien return (struct elfNN_ia64_local_hash_entry *) *slot; 220489857Sobrien 2205130561Sobrien ret = (struct elfNN_ia64_local_hash_entry *) 2206130561Sobrien objalloc_alloc ((struct objalloc *) ia64_info->loc_hash_memory, 2207130561Sobrien sizeof (struct elfNN_ia64_local_hash_entry)); 2208130561Sobrien if (ret) 2209130561Sobrien { 2210130561Sobrien memset (ret, 0, sizeof (*ret)); 2211130561Sobrien ret->id = sec->id; 2212130561Sobrien ret->r_sym = ELFNN_R_SYM (rel->r_info); 2213130561Sobrien *slot = ret; 2214130561Sobrien } 221589857Sobrien return ret; 221689857Sobrien} 221789857Sobrien 2218218822Sdim/* Used to sort elfNN_ia64_dyn_sym_info array. */ 2219218822Sdim 2220218822Sdimstatic int 2221218822Sdimaddend_compare (const void *xp, const void *yp) 2222218822Sdim{ 2223218822Sdim const struct elfNN_ia64_dyn_sym_info *x 2224218822Sdim = (const struct elfNN_ia64_dyn_sym_info *) xp; 2225218822Sdim const struct elfNN_ia64_dyn_sym_info *y 2226218822Sdim = (const struct elfNN_ia64_dyn_sym_info *) yp; 2227218822Sdim 2228218822Sdim return x->addend < y->addend ? -1 : x->addend > y->addend ? 1 : 0; 2229218822Sdim} 2230218822Sdim 2231218822Sdim/* Sort elfNN_ia64_dyn_sym_info array and remove duplicates. */ 2232218822Sdim 2233218822Sdimstatic unsigned int 2234218822Sdimsort_dyn_sym_info (struct elfNN_ia64_dyn_sym_info *info, 2235218822Sdim unsigned int count) 2236218822Sdim{ 2237218822Sdim bfd_vma curr, prev, got_offset; 2238218822Sdim unsigned int i, kept, dup, diff, dest, src, len; 2239218822Sdim 2240218822Sdim qsort (info, count, sizeof (*info), addend_compare); 2241218822Sdim 2242218822Sdim /* Find the first duplicate. */ 2243218822Sdim prev = info [0].addend; 2244218822Sdim got_offset = info [0].got_offset; 2245218822Sdim for (i = 1; i < count; i++) 2246218822Sdim { 2247218822Sdim curr = info [i].addend; 2248218822Sdim if (curr == prev) 2249218822Sdim { 2250218822Sdim /* For duplicates, make sure that GOT_OFFSET is valid. */ 2251218822Sdim if (got_offset == (bfd_vma) -1) 2252218822Sdim got_offset = info [i].got_offset; 2253218822Sdim break; 2254218822Sdim } 2255218822Sdim got_offset = info [i].got_offset; 2256218822Sdim prev = curr; 2257218822Sdim } 2258218822Sdim 2259218822Sdim /* We may move a block of elements to here. */ 2260218822Sdim dest = i++; 2261218822Sdim 2262218822Sdim /* Remove duplicates. */ 2263218822Sdim if (i < count) 2264218822Sdim { 2265218822Sdim while (i < count) 2266218822Sdim { 2267218822Sdim /* For duplicates, make sure that the kept one has a valid 2268218822Sdim got_offset. */ 2269218822Sdim kept = dest - 1; 2270218822Sdim if (got_offset != (bfd_vma) -1) 2271218822Sdim info [kept].got_offset = got_offset; 2272218822Sdim 2273218822Sdim curr = info [i].addend; 2274218822Sdim got_offset = info [i].got_offset; 2275218822Sdim 2276218822Sdim /* Move a block of elements whose first one is different from 2277218822Sdim the previous. */ 2278218822Sdim if (curr == prev) 2279218822Sdim { 2280218822Sdim for (src = i + 1; src < count; src++) 2281218822Sdim { 2282218822Sdim if (info [src].addend != curr) 2283218822Sdim break; 2284218822Sdim /* For duplicates, make sure that GOT_OFFSET is 2285218822Sdim valid. */ 2286218822Sdim if (got_offset == (bfd_vma) -1) 2287218822Sdim got_offset = info [src].got_offset; 2288218822Sdim } 2289218822Sdim 2290218822Sdim /* Make sure that the kept one has a valid got_offset. */ 2291218822Sdim if (got_offset != (bfd_vma) -1) 2292218822Sdim info [kept].got_offset = got_offset; 2293218822Sdim } 2294218822Sdim else 2295218822Sdim src = i; 2296218822Sdim 2297218822Sdim if (src >= count) 2298218822Sdim break; 2299218822Sdim 2300218822Sdim /* Find the next duplicate. SRC will be kept. */ 2301218822Sdim prev = info [src].addend; 2302218822Sdim got_offset = info [src].got_offset; 2303218822Sdim for (dup = src + 1; dup < count; dup++) 2304218822Sdim { 2305218822Sdim curr = info [dup].addend; 2306218822Sdim if (curr == prev) 2307218822Sdim { 2308218822Sdim /* Make sure that got_offset is valid. */ 2309218822Sdim if (got_offset == (bfd_vma) -1) 2310218822Sdim got_offset = info [dup].got_offset; 2311218822Sdim 2312218822Sdim /* For duplicates, make sure that the kept one has 2313218822Sdim a valid got_offset. */ 2314218822Sdim if (got_offset != (bfd_vma) -1) 2315218822Sdim info [dup - 1].got_offset = got_offset; 2316218822Sdim break; 2317218822Sdim } 2318218822Sdim got_offset = info [dup].got_offset; 2319218822Sdim prev = curr; 2320218822Sdim } 2321218822Sdim 2322218822Sdim /* How much to move. */ 2323218822Sdim len = dup - src; 2324218822Sdim i = dup + 1; 2325218822Sdim 2326218822Sdim if (len == 1 && dup < count) 2327218822Sdim { 2328218822Sdim /* If we only move 1 element, we combine it with the next 2329218822Sdim one. There must be at least a duplicate. Find the 2330218822Sdim next different one. */ 2331218822Sdim for (diff = dup + 1, src++; diff < count; diff++, src++) 2332218822Sdim { 2333218822Sdim if (info [diff].addend != curr) 2334218822Sdim break; 2335218822Sdim /* Make sure that got_offset is valid. */ 2336218822Sdim if (got_offset == (bfd_vma) -1) 2337218822Sdim got_offset = info [diff].got_offset; 2338218822Sdim } 2339218822Sdim 2340218822Sdim /* Makre sure that the last duplicated one has an valid 2341218822Sdim offset. */ 2342218822Sdim BFD_ASSERT (curr == prev); 2343218822Sdim if (got_offset != (bfd_vma) -1) 2344218822Sdim info [diff - 1].got_offset = got_offset; 2345218822Sdim 2346218822Sdim if (diff < count) 2347218822Sdim { 2348218822Sdim /* Find the next duplicate. Track the current valid 2349218822Sdim offset. */ 2350218822Sdim prev = info [diff].addend; 2351218822Sdim got_offset = info [diff].got_offset; 2352218822Sdim for (dup = diff + 1; dup < count; dup++) 2353218822Sdim { 2354218822Sdim curr = info [dup].addend; 2355218822Sdim if (curr == prev) 2356218822Sdim { 2357218822Sdim /* For duplicates, make sure that GOT_OFFSET 2358218822Sdim is valid. */ 2359218822Sdim if (got_offset == (bfd_vma) -1) 2360218822Sdim got_offset = info [dup].got_offset; 2361218822Sdim break; 2362218822Sdim } 2363218822Sdim got_offset = info [dup].got_offset; 2364218822Sdim prev = curr; 2365218822Sdim diff++; 2366218822Sdim } 2367218822Sdim 2368218822Sdim len = diff - src + 1; 2369218822Sdim i = diff + 1; 2370218822Sdim } 2371218822Sdim } 2372218822Sdim 2373218822Sdim memmove (&info [dest], &info [src], len * sizeof (*info)); 2374218822Sdim 2375218822Sdim dest += len; 2376218822Sdim } 2377218822Sdim 2378218822Sdim count = dest; 2379218822Sdim } 2380218822Sdim else 2381218822Sdim { 2382218822Sdim /* When we get here, either there is no duplicate at all or 2383218822Sdim the only duplicate is the last element. */ 2384218822Sdim if (dest < count) 2385218822Sdim { 2386218822Sdim /* If the last element is a duplicate, make sure that the 2387218822Sdim kept one has a valid got_offset. We also update count. */ 2388218822Sdim if (got_offset != (bfd_vma) -1) 2389218822Sdim info [dest - 1].got_offset = got_offset; 2390218822Sdim count = dest; 2391218822Sdim } 2392218822Sdim } 2393218822Sdim 2394218822Sdim return count; 2395218822Sdim} 2396218822Sdim 239784865Sobrien/* Find and/or create a descriptor for dynamic symbol info. This will 2398218822Sdim vary based on global or local symbol, and the addend to the reloc. 239984865Sobrien 2400218822Sdim We don't sort when inserting. Also, we sort and eliminate 2401218822Sdim duplicates if there is an unsorted section. Typically, this will 2402218822Sdim only happen once, because we do all insertions before lookups. We 2403218822Sdim then use bsearch to do a lookup. This also allows lookups to be 2404218822Sdim fast. So we have fast insertion (O(log N) due to duplicate check), 2405218822Sdim fast lookup (O(log N)) and one sort (O(N log N) expected time). 2406218822Sdim Previously, all lookups were O(N) because of the use of the linked 2407218822Sdim list and also all insertions were O(N) because of the check for 2408218822Sdim duplicates. There are some complications here because the array 2409218822Sdim size grows occasionally, which may add an O(N) factor, but this 2410218822Sdim should be rare. Also, we free the excess array allocation, which 2411218822Sdim requires a copy which is O(N), but this only happens once. */ 2412218822Sdim 241384865Sobrienstatic struct elfNN_ia64_dyn_sym_info * 241484865Sobrienget_dyn_sym_info (ia64_info, h, abfd, rel, create) 241584865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 241684865Sobrien struct elf_link_hash_entry *h; 241784865Sobrien bfd *abfd; 241884865Sobrien const Elf_Internal_Rela *rel; 2419130561Sobrien bfd_boolean create; 242084865Sobrien{ 2421218822Sdim struct elfNN_ia64_dyn_sym_info **info_p, *info, *dyn_i, key; 2422218822Sdim unsigned int *count_p, *sorted_count_p, *size_p; 2423218822Sdim unsigned int count, sorted_count, size; 242484865Sobrien bfd_vma addend = rel ? rel->r_addend : 0; 2425218822Sdim bfd_size_type amt; 242684865Sobrien 242784865Sobrien if (h) 2428218822Sdim { 2429218822Sdim struct elfNN_ia64_link_hash_entry *global_h; 2430218822Sdim 2431218822Sdim global_h = (struct elfNN_ia64_link_hash_entry *) h; 2432218822Sdim info_p = &global_h->info; 2433218822Sdim count_p = &global_h->count; 2434218822Sdim sorted_count_p = &global_h->sorted_count; 2435218822Sdim size_p = &global_h->size; 2436218822Sdim } 243784865Sobrien else 243884865Sobrien { 243984865Sobrien struct elfNN_ia64_local_hash_entry *loc_h; 244084865Sobrien 244189857Sobrien loc_h = get_local_sym_hash (ia64_info, abfd, rel, create); 2442130561Sobrien if (!loc_h) 2443130561Sobrien { 2444130561Sobrien BFD_ASSERT (!create); 2445130561Sobrien return NULL; 2446130561Sobrien } 244784865Sobrien 2448218822Sdim info_p = &loc_h->info; 2449218822Sdim count_p = &loc_h->count; 2450218822Sdim sorted_count_p = &loc_h->sorted_count; 2451218822Sdim size_p = &loc_h->size; 245284865Sobrien } 245384865Sobrien 2454218822Sdim count = *count_p; 2455218822Sdim sorted_count = *sorted_count_p; 2456218822Sdim size = *size_p; 2457218822Sdim info = *info_p; 2458218822Sdim if (create) 2459218822Sdim { 2460218822Sdim /* When we create the array, we don't check for duplicates, 2461218822Sdim except in the previously sorted section if one exists, and 2462218822Sdim against the last inserted entry. This allows insertions to 2463218822Sdim be fast. */ 2464218822Sdim if (info) 2465218822Sdim { 2466218822Sdim if (sorted_count) 2467218822Sdim { 2468218822Sdim /* Try bsearch first on the sorted section. */ 2469218822Sdim key.addend = addend; 2470218822Sdim dyn_i = bsearch (&key, info, sorted_count, 2471218822Sdim sizeof (*info), addend_compare); 247284865Sobrien 2473218822Sdim if (dyn_i) 2474218822Sdim { 2475218822Sdim return dyn_i; 2476218822Sdim } 2477218822Sdim } 2478218822Sdim 2479218822Sdim /* Do a quick check for the last inserted entry. */ 2480218822Sdim dyn_i = info + count - 1; 2481218822Sdim if (dyn_i->addend == addend) 2482218822Sdim { 2483218822Sdim return dyn_i; 2484218822Sdim } 2485218822Sdim } 2486218822Sdim 2487218822Sdim if (size == 0) 2488218822Sdim { 2489218822Sdim /* It is the very first element. We create the array of size 2490218822Sdim 1. */ 2491218822Sdim size = 1; 2492218822Sdim amt = size * sizeof (*info); 2493218822Sdim info = bfd_malloc (amt); 2494218822Sdim } 2495218822Sdim else if (size <= count) 2496218822Sdim { 2497218822Sdim /* We double the array size every time when we reach the 2498218822Sdim size limit. */ 2499218822Sdim size += size; 2500218822Sdim amt = size * sizeof (*info); 2501218822Sdim info = bfd_realloc (info, amt); 2502218822Sdim } 2503218822Sdim else 2504218822Sdim goto has_space; 2505218822Sdim 2506218822Sdim if (info == NULL) 2507218822Sdim return NULL; 2508218822Sdim *size_p = size; 2509218822Sdim *info_p = info; 2510218822Sdim 2511218822Sdimhas_space: 2512218822Sdim /* Append the new one to the array. */ 2513218822Sdim dyn_i = info + count; 2514218822Sdim memset (dyn_i, 0, sizeof (*dyn_i)); 2515218822Sdim dyn_i->got_offset = (bfd_vma) -1; 251684865Sobrien dyn_i->addend = addend; 2517218822Sdim 2518218822Sdim /* We increment count only since the new ones are unsorted and 2519218822Sdim may have duplicate. */ 2520218822Sdim (*count_p)++; 252184865Sobrien } 2522218822Sdim else 2523218822Sdim { 2524218822Sdim /* It is a lookup without insertion. Sort array if part of the 2525218822Sdim array isn't sorted. */ 2526218822Sdim if (count != sorted_count) 2527218822Sdim { 2528218822Sdim count = sort_dyn_sym_info (info, count); 2529218822Sdim *count_p = count; 2530218822Sdim *sorted_count_p = count; 2531218822Sdim } 253284865Sobrien 2533218822Sdim /* Free unused memory. */ 2534218822Sdim if (size != count) 2535218822Sdim { 2536218822Sdim amt = count * sizeof (*info); 2537218822Sdim info = bfd_malloc (amt); 2538218822Sdim if (info != NULL) 2539218822Sdim { 2540218822Sdim memcpy (info, *info_p, amt); 2541218822Sdim free (*info_p); 2542218822Sdim *size_p = count; 2543218822Sdim *info_p = info; 2544218822Sdim } 2545218822Sdim } 2546218822Sdim 2547218822Sdim key.addend = addend; 2548218822Sdim dyn_i = bsearch (&key, info, count, 2549218822Sdim sizeof (*info), addend_compare); 2550218822Sdim } 2551218822Sdim 255284865Sobrien return dyn_i; 255384865Sobrien} 255484865Sobrien 255584865Sobrienstatic asection * 255684865Sobrienget_got (abfd, info, ia64_info) 255784865Sobrien bfd *abfd; 255884865Sobrien struct bfd_link_info *info; 255984865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 256084865Sobrien{ 256184865Sobrien asection *got; 256284865Sobrien bfd *dynobj; 256384865Sobrien 256484865Sobrien got = ia64_info->got_sec; 256584865Sobrien if (!got) 256684865Sobrien { 256784865Sobrien flagword flags; 256884865Sobrien 256984865Sobrien dynobj = ia64_info->root.dynobj; 257084865Sobrien if (!dynobj) 257184865Sobrien ia64_info->root.dynobj = dynobj = abfd; 257284865Sobrien if (!_bfd_elf_create_got_section (dynobj, info)) 257384865Sobrien return 0; 257484865Sobrien 257584865Sobrien got = bfd_get_section_by_name (dynobj, ".got"); 257684865Sobrien BFD_ASSERT (got); 257784865Sobrien ia64_info->got_sec = got; 257884865Sobrien 2579130561Sobrien /* The .got section is always aligned at 8 bytes. */ 2580130561Sobrien if (!bfd_set_section_alignment (abfd, got, 3)) 2581130561Sobrien return 0; 2582130561Sobrien 258384865Sobrien flags = bfd_get_section_flags (abfd, got); 258484865Sobrien bfd_set_section_flags (abfd, got, SEC_SMALL_DATA | flags); 258584865Sobrien } 258684865Sobrien 258784865Sobrien return got; 258884865Sobrien} 258984865Sobrien 259084865Sobrien/* Create function descriptor section (.opd). This section is called .opd 2591130561Sobrien because it contains "official procedure descriptors". The "official" 259284865Sobrien refers to the fact that these descriptors are used when taking the address 259384865Sobrien of a procedure, thus ensuring a unique address for each procedure. */ 259484865Sobrien 259584865Sobrienstatic asection * 259684865Sobrienget_fptr (abfd, info, ia64_info) 259784865Sobrien bfd *abfd; 2598130561Sobrien struct bfd_link_info *info; 259984865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 260084865Sobrien{ 260184865Sobrien asection *fptr; 260284865Sobrien bfd *dynobj; 260384865Sobrien 260484865Sobrien fptr = ia64_info->fptr_sec; 260584865Sobrien if (!fptr) 260684865Sobrien { 260784865Sobrien dynobj = ia64_info->root.dynobj; 260884865Sobrien if (!dynobj) 260984865Sobrien ia64_info->root.dynobj = dynobj = abfd; 261084865Sobrien 2611218822Sdim fptr = bfd_make_section_with_flags (dynobj, ".opd", 2612218822Sdim (SEC_ALLOC 2613218822Sdim | SEC_LOAD 2614218822Sdim | SEC_HAS_CONTENTS 2615218822Sdim | SEC_IN_MEMORY 2616218822Sdim | (info->pie ? 0 : SEC_READONLY) 2617218822Sdim | SEC_LINKER_CREATED)); 261884865Sobrien if (!fptr 261984865Sobrien || !bfd_set_section_alignment (abfd, fptr, 4)) 262084865Sobrien { 262184865Sobrien BFD_ASSERT (0); 262284865Sobrien return NULL; 262384865Sobrien } 262484865Sobrien 262584865Sobrien ia64_info->fptr_sec = fptr; 2626130561Sobrien 2627130561Sobrien if (info->pie) 2628130561Sobrien { 2629130561Sobrien asection *fptr_rel; 2630218822Sdim fptr_rel = bfd_make_section_with_flags (dynobj, ".rela.opd", 2631218822Sdim (SEC_ALLOC | SEC_LOAD 2632218822Sdim | SEC_HAS_CONTENTS 2633218822Sdim | SEC_IN_MEMORY 2634218822Sdim | SEC_LINKER_CREATED 2635218822Sdim | SEC_READONLY)); 2636130561Sobrien if (fptr_rel == NULL 2637218822Sdim || !bfd_set_section_alignment (abfd, fptr_rel, 2638218822Sdim LOG_SECTION_ALIGN)) 2639130561Sobrien { 2640130561Sobrien BFD_ASSERT (0); 2641130561Sobrien return NULL; 2642130561Sobrien } 2643130561Sobrien 2644130561Sobrien ia64_info->rel_fptr_sec = fptr_rel; 2645130561Sobrien } 264684865Sobrien } 264784865Sobrien 264884865Sobrien return fptr; 264984865Sobrien} 265084865Sobrien 265184865Sobrienstatic asection * 265284865Sobrienget_pltoff (abfd, info, ia64_info) 265384865Sobrien bfd *abfd; 265484865Sobrien struct bfd_link_info *info ATTRIBUTE_UNUSED; 265584865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 265684865Sobrien{ 265784865Sobrien asection *pltoff; 265884865Sobrien bfd *dynobj; 265984865Sobrien 266084865Sobrien pltoff = ia64_info->pltoff_sec; 266184865Sobrien if (!pltoff) 266284865Sobrien { 266384865Sobrien dynobj = ia64_info->root.dynobj; 266484865Sobrien if (!dynobj) 266584865Sobrien ia64_info->root.dynobj = dynobj = abfd; 266684865Sobrien 2667218822Sdim pltoff = bfd_make_section_with_flags (dynobj, 2668218822Sdim ELF_STRING_ia64_pltoff, 2669218822Sdim (SEC_ALLOC 2670218822Sdim | SEC_LOAD 2671218822Sdim | SEC_HAS_CONTENTS 2672218822Sdim | SEC_IN_MEMORY 2673218822Sdim | SEC_SMALL_DATA 2674218822Sdim | SEC_LINKER_CREATED)); 267584865Sobrien if (!pltoff 267684865Sobrien || !bfd_set_section_alignment (abfd, pltoff, 4)) 267784865Sobrien { 267884865Sobrien BFD_ASSERT (0); 267984865Sobrien return NULL; 268084865Sobrien } 268184865Sobrien 268284865Sobrien ia64_info->pltoff_sec = pltoff; 268384865Sobrien } 268484865Sobrien 268584865Sobrien return pltoff; 268684865Sobrien} 268784865Sobrien 268884865Sobrienstatic asection * 268984865Sobrienget_reloc_section (abfd, ia64_info, sec, create) 269084865Sobrien bfd *abfd; 269184865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 269284865Sobrien asection *sec; 2693130561Sobrien bfd_boolean create; 269484865Sobrien{ 269584865Sobrien const char *srel_name; 269684865Sobrien asection *srel; 269784865Sobrien bfd *dynobj; 269884865Sobrien 269984865Sobrien srel_name = (bfd_elf_string_from_elf_section 270084865Sobrien (abfd, elf_elfheader(abfd)->e_shstrndx, 270184865Sobrien elf_section_data(sec)->rel_hdr.sh_name)); 270284865Sobrien if (srel_name == NULL) 270384865Sobrien return NULL; 270484865Sobrien 2705218822Sdim BFD_ASSERT ((CONST_STRNEQ (srel_name, ".rela") 270684865Sobrien && strcmp (bfd_get_section_name (abfd, sec), 270784865Sobrien srel_name+5) == 0) 2708218822Sdim || (CONST_STRNEQ (srel_name, ".rel") 270984865Sobrien && strcmp (bfd_get_section_name (abfd, sec), 271084865Sobrien srel_name+4) == 0)); 271184865Sobrien 271284865Sobrien dynobj = ia64_info->root.dynobj; 271384865Sobrien if (!dynobj) 271484865Sobrien ia64_info->root.dynobj = dynobj = abfd; 271584865Sobrien 271684865Sobrien srel = bfd_get_section_by_name (dynobj, srel_name); 271784865Sobrien if (srel == NULL && create) 271884865Sobrien { 2719218822Sdim srel = bfd_make_section_with_flags (dynobj, srel_name, 2720218822Sdim (SEC_ALLOC | SEC_LOAD 2721218822Sdim | SEC_HAS_CONTENTS 2722218822Sdim | SEC_IN_MEMORY 2723218822Sdim | SEC_LINKER_CREATED 2724218822Sdim | SEC_READONLY)); 272584865Sobrien if (srel == NULL 2726218822Sdim || !bfd_set_section_alignment (dynobj, srel, 2727218822Sdim LOG_SECTION_ALIGN)) 272884865Sobrien return NULL; 272984865Sobrien } 273084865Sobrien 273184865Sobrien return srel; 273284865Sobrien} 273384865Sobrien 2734130561Sobrienstatic bfd_boolean 2735130561Sobriencount_dyn_reloc (bfd *abfd, struct elfNN_ia64_dyn_sym_info *dyn_i, 2736130561Sobrien asection *srel, int type, bfd_boolean reltext) 273784865Sobrien{ 273884865Sobrien struct elfNN_ia64_dyn_reloc_entry *rent; 273984865Sobrien 274084865Sobrien for (rent = dyn_i->reloc_entries; rent; rent = rent->next) 274184865Sobrien if (rent->srel == srel && rent->type == type) 274284865Sobrien break; 274384865Sobrien 274484865Sobrien if (!rent) 274584865Sobrien { 274689857Sobrien rent = ((struct elfNN_ia64_dyn_reloc_entry *) 274789857Sobrien bfd_alloc (abfd, (bfd_size_type) sizeof (*rent))); 274884865Sobrien if (!rent) 2749130561Sobrien return FALSE; 275084865Sobrien 275184865Sobrien rent->next = dyn_i->reloc_entries; 275284865Sobrien rent->srel = srel; 275384865Sobrien rent->type = type; 275484865Sobrien rent->count = 0; 275584865Sobrien dyn_i->reloc_entries = rent; 275684865Sobrien } 2757130561Sobrien rent->reltext = reltext; 275884865Sobrien rent->count++; 275984865Sobrien 2760130561Sobrien return TRUE; 276184865Sobrien} 276284865Sobrien 2763130561Sobrienstatic bfd_boolean 276484865SobrienelfNN_ia64_check_relocs (abfd, info, sec, relocs) 276584865Sobrien bfd *abfd; 276684865Sobrien struct bfd_link_info *info; 276784865Sobrien asection *sec; 276884865Sobrien const Elf_Internal_Rela *relocs; 276984865Sobrien{ 277084865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 277184865Sobrien const Elf_Internal_Rela *relend; 277284865Sobrien Elf_Internal_Shdr *symtab_hdr; 277384865Sobrien const Elf_Internal_Rela *rel; 2774218822Sdim asection *got, *fptr, *srel, *pltoff; 2775218822Sdim enum { 2776218822Sdim NEED_GOT = 1, 2777218822Sdim NEED_GOTX = 2, 2778218822Sdim NEED_FPTR = 4, 2779218822Sdim NEED_PLTOFF = 8, 2780218822Sdim NEED_MIN_PLT = 16, 2781218822Sdim NEED_FULL_PLT = 32, 2782218822Sdim NEED_DYNREL = 64, 2783218822Sdim NEED_LTOFF_FPTR = 128, 2784218822Sdim NEED_TPREL = 256, 2785218822Sdim NEED_DTPMOD = 512, 2786218822Sdim NEED_DTPREL = 1024 2787218822Sdim }; 2788218822Sdim int need_entry; 2789218822Sdim struct elf_link_hash_entry *h; 2790218822Sdim unsigned long r_symndx; 2791218822Sdim bfd_boolean maybe_dynamic; 279284865Sobrien 2793130561Sobrien if (info->relocatable) 2794130561Sobrien return TRUE; 279584865Sobrien 279684865Sobrien symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 279784865Sobrien ia64_info = elfNN_ia64_hash_table (info); 279884865Sobrien 2799218822Sdim got = fptr = srel = pltoff = NULL; 280084865Sobrien 280184865Sobrien relend = relocs + sec->reloc_count; 2802218822Sdim 2803218822Sdim /* We scan relocations first to create dynamic relocation arrays. We 2804218822Sdim modified get_dyn_sym_info to allow fast insertion and support fast 2805218822Sdim lookup in the next loop. */ 280684865Sobrien for (rel = relocs; rel < relend; ++rel) 280784865Sobrien { 2808218822Sdim r_symndx = ELFNN_R_SYM (rel->r_info); 280984865Sobrien if (r_symndx >= symtab_hdr->sh_info) 281084865Sobrien { 281184865Sobrien long indx = r_symndx - symtab_hdr->sh_info; 281284865Sobrien h = elf_sym_hashes (abfd)[indx]; 281384865Sobrien while (h->root.type == bfd_link_hash_indirect 281484865Sobrien || h->root.type == bfd_link_hash_warning) 281584865Sobrien h = (struct elf_link_hash_entry *) h->root.u.i.link; 281684865Sobrien } 2817218822Sdim else 2818218822Sdim h = NULL; 281984865Sobrien 282084865Sobrien /* We can only get preliminary data on whether a symbol is 282184865Sobrien locally or externally defined, as not all of the input files 282284865Sobrien have yet been processed. Do something with what we know, as 282384865Sobrien this may help reduce memory usage and processing time later. */ 2824218822Sdim maybe_dynamic = (h && ((!info->executable 2825218822Sdim && (!SYMBOLIC_BIND (info, h) 2826218822Sdim || info->unresolved_syms_in_shared_libs == RM_IGNORE)) 2827218822Sdim || !h->def_regular 2828218822Sdim || h->root.type == bfd_link_hash_defweak)); 282984865Sobrien 283084865Sobrien need_entry = 0; 283184865Sobrien switch (ELFNN_R_TYPE (rel->r_info)) 283284865Sobrien { 283384865Sobrien case R_IA64_TPREL64MSB: 283484865Sobrien case R_IA64_TPREL64LSB: 2835104834Sobrien if (info->shared || maybe_dynamic) 2836104834Sobrien need_entry = NEED_DYNREL; 2837104834Sobrien break; 283884865Sobrien 2839104834Sobrien case R_IA64_LTOFF_TPREL22: 2840104834Sobrien need_entry = NEED_TPREL; 2841104834Sobrien if (info->shared) 2842104834Sobrien info->flags |= DF_STATIC_TLS; 2843104834Sobrien break; 2844104834Sobrien 2845218822Sdim case R_IA64_DTPREL32MSB: 2846218822Sdim case R_IA64_DTPREL32LSB: 2847104834Sobrien case R_IA64_DTPREL64MSB: 2848104834Sobrien case R_IA64_DTPREL64LSB: 2849104834Sobrien if (info->shared || maybe_dynamic) 2850104834Sobrien need_entry = NEED_DYNREL; 2851104834Sobrien break; 2852104834Sobrien 2853104834Sobrien case R_IA64_LTOFF_DTPREL22: 2854104834Sobrien need_entry = NEED_DTPREL; 2855104834Sobrien break; 2856104834Sobrien 2857104834Sobrien case R_IA64_DTPMOD64MSB: 2858104834Sobrien case R_IA64_DTPMOD64LSB: 2859104834Sobrien if (info->shared || maybe_dynamic) 2860104834Sobrien need_entry = NEED_DYNREL; 2861104834Sobrien break; 2862104834Sobrien 2863104834Sobrien case R_IA64_LTOFF_DTPMOD22: 2864104834Sobrien need_entry = NEED_DTPMOD; 2865104834Sobrien break; 2866104834Sobrien 286784865Sobrien case R_IA64_LTOFF_FPTR22: 286884865Sobrien case R_IA64_LTOFF_FPTR64I: 286989857Sobrien case R_IA64_LTOFF_FPTR32MSB: 287089857Sobrien case R_IA64_LTOFF_FPTR32LSB: 287184865Sobrien case R_IA64_LTOFF_FPTR64MSB: 287284865Sobrien case R_IA64_LTOFF_FPTR64LSB: 287384865Sobrien need_entry = NEED_FPTR | NEED_GOT | NEED_LTOFF_FPTR; 287484865Sobrien break; 287584865Sobrien 287684865Sobrien case R_IA64_FPTR64I: 287784865Sobrien case R_IA64_FPTR32MSB: 287884865Sobrien case R_IA64_FPTR32LSB: 287984865Sobrien case R_IA64_FPTR64MSB: 288084865Sobrien case R_IA64_FPTR64LSB: 2881130561Sobrien if (info->shared || h) 288284865Sobrien need_entry = NEED_FPTR | NEED_DYNREL; 288384865Sobrien else 288484865Sobrien need_entry = NEED_FPTR; 288584865Sobrien break; 288684865Sobrien 288784865Sobrien case R_IA64_LTOFF22: 288884865Sobrien case R_IA64_LTOFF64I: 288984865Sobrien need_entry = NEED_GOT; 289084865Sobrien break; 289184865Sobrien 2892130561Sobrien case R_IA64_LTOFF22X: 2893130561Sobrien need_entry = NEED_GOTX; 2894130561Sobrien break; 2895130561Sobrien 289684865Sobrien case R_IA64_PLTOFF22: 289784865Sobrien case R_IA64_PLTOFF64I: 289884865Sobrien case R_IA64_PLTOFF64MSB: 289984865Sobrien case R_IA64_PLTOFF64LSB: 290084865Sobrien need_entry = NEED_PLTOFF; 290184865Sobrien if (h) 290284865Sobrien { 290384865Sobrien if (maybe_dynamic) 290484865Sobrien need_entry |= NEED_MIN_PLT; 290584865Sobrien } 290684865Sobrien else 290784865Sobrien { 290884865Sobrien (*info->callbacks->warning) 290984865Sobrien (info, _("@pltoff reloc against local symbol"), 0, 291089857Sobrien abfd, 0, (bfd_vma) 0); 291184865Sobrien } 291284865Sobrien break; 291384865Sobrien 291484865Sobrien case R_IA64_PCREL21B: 291584865Sobrien case R_IA64_PCREL60B: 291684865Sobrien /* Depending on where this symbol is defined, we may or may not 291784865Sobrien need a full plt entry. Only skip if we know we'll not need 291884865Sobrien the entry -- static or symbolic, and the symbol definition 291984865Sobrien has already been seen. */ 292084865Sobrien if (maybe_dynamic && rel->r_addend == 0) 292184865Sobrien need_entry = NEED_FULL_PLT; 292284865Sobrien break; 292384865Sobrien 292484865Sobrien case R_IA64_IMM14: 292584865Sobrien case R_IA64_IMM22: 292684865Sobrien case R_IA64_IMM64: 292784865Sobrien case R_IA64_DIR32MSB: 292884865Sobrien case R_IA64_DIR32LSB: 292984865Sobrien case R_IA64_DIR64MSB: 293084865Sobrien case R_IA64_DIR64LSB: 293184865Sobrien /* Shared objects will always need at least a REL relocation. */ 2932130561Sobrien if (info->shared || maybe_dynamic) 293384865Sobrien need_entry = NEED_DYNREL; 293484865Sobrien break; 293584865Sobrien 293684865Sobrien case R_IA64_IPLTMSB: 293784865Sobrien case R_IA64_IPLTLSB: 293884865Sobrien /* Shared objects will always need at least a REL relocation. */ 293984865Sobrien if (info->shared || maybe_dynamic) 294084865Sobrien need_entry = NEED_DYNREL; 294184865Sobrien break; 294284865Sobrien 294384865Sobrien case R_IA64_PCREL22: 294484865Sobrien case R_IA64_PCREL64I: 294584865Sobrien case R_IA64_PCREL32MSB: 294684865Sobrien case R_IA64_PCREL32LSB: 294784865Sobrien case R_IA64_PCREL64MSB: 294884865Sobrien case R_IA64_PCREL64LSB: 294984865Sobrien if (maybe_dynamic) 295084865Sobrien need_entry = NEED_DYNREL; 295184865Sobrien break; 295284865Sobrien } 295384865Sobrien 295484865Sobrien if (!need_entry) 295584865Sobrien continue; 295684865Sobrien 295784865Sobrien if ((need_entry & NEED_FPTR) != 0 295884865Sobrien && rel->r_addend) 295984865Sobrien { 296084865Sobrien (*info->callbacks->warning) 296184865Sobrien (info, _("non-zero addend in @fptr reloc"), 0, 296289857Sobrien abfd, 0, (bfd_vma) 0); 296384865Sobrien } 296484865Sobrien 2965218822Sdim if (get_dyn_sym_info (ia64_info, h, abfd, rel, TRUE) == NULL) 2966218822Sdim return FALSE; 2967218822Sdim } 296884865Sobrien 2969218822Sdim /* Now, we only do lookup without insertion, which is very fast 2970218822Sdim with the modified get_dyn_sym_info. */ 2971218822Sdim for (rel = relocs; rel < relend; ++rel) 2972218822Sdim { 2973218822Sdim struct elfNN_ia64_dyn_sym_info *dyn_i; 2974218822Sdim int dynrel_type = R_IA64_NONE; 2975218822Sdim 2976218822Sdim r_symndx = ELFNN_R_SYM (rel->r_info); 2977218822Sdim if (r_symndx >= symtab_hdr->sh_info) 2978218822Sdim { 2979218822Sdim /* We're dealing with a global symbol -- find its hash entry 2980218822Sdim and mark it as being referenced. */ 2981218822Sdim long indx = r_symndx - symtab_hdr->sh_info; 2982218822Sdim h = elf_sym_hashes (abfd)[indx]; 2983218822Sdim while (h->root.type == bfd_link_hash_indirect 2984218822Sdim || h->root.type == bfd_link_hash_warning) 2985218822Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 2986218822Sdim 2987218822Sdim h->ref_regular = 1; 2988218822Sdim } 2989218822Sdim else 2990218822Sdim h = NULL; 2991218822Sdim 2992218822Sdim /* We can only get preliminary data on whether a symbol is 2993218822Sdim locally or externally defined, as not all of the input files 2994218822Sdim have yet been processed. Do something with what we know, as 2995218822Sdim this may help reduce memory usage and processing time later. */ 2996218822Sdim maybe_dynamic = (h && ((!info->executable 2997218822Sdim && (!SYMBOLIC_BIND (info, h) 2998218822Sdim || info->unresolved_syms_in_shared_libs == RM_IGNORE)) 2999218822Sdim || !h->def_regular 3000218822Sdim || h->root.type == bfd_link_hash_defweak)); 3001218822Sdim 3002218822Sdim need_entry = 0; 3003218822Sdim switch (ELFNN_R_TYPE (rel->r_info)) 3004218822Sdim { 3005218822Sdim case R_IA64_TPREL64MSB: 3006218822Sdim case R_IA64_TPREL64LSB: 3007218822Sdim if (info->shared || maybe_dynamic) 3008218822Sdim need_entry = NEED_DYNREL; 3009218822Sdim dynrel_type = R_IA64_TPREL64LSB; 3010218822Sdim if (info->shared) 3011218822Sdim info->flags |= DF_STATIC_TLS; 3012218822Sdim break; 3013218822Sdim 3014218822Sdim case R_IA64_LTOFF_TPREL22: 3015218822Sdim need_entry = NEED_TPREL; 3016218822Sdim if (info->shared) 3017218822Sdim info->flags |= DF_STATIC_TLS; 3018218822Sdim break; 3019218822Sdim 3020218822Sdim case R_IA64_DTPREL32MSB: 3021218822Sdim case R_IA64_DTPREL32LSB: 3022218822Sdim case R_IA64_DTPREL64MSB: 3023218822Sdim case R_IA64_DTPREL64LSB: 3024218822Sdim if (info->shared || maybe_dynamic) 3025218822Sdim need_entry = NEED_DYNREL; 3026218822Sdim dynrel_type = R_IA64_DTPRELNNLSB; 3027218822Sdim break; 3028218822Sdim 3029218822Sdim case R_IA64_LTOFF_DTPREL22: 3030218822Sdim need_entry = NEED_DTPREL; 3031218822Sdim break; 3032218822Sdim 3033218822Sdim case R_IA64_DTPMOD64MSB: 3034218822Sdim case R_IA64_DTPMOD64LSB: 3035218822Sdim if (info->shared || maybe_dynamic) 3036218822Sdim need_entry = NEED_DYNREL; 3037218822Sdim dynrel_type = R_IA64_DTPMOD64LSB; 3038218822Sdim break; 3039218822Sdim 3040218822Sdim case R_IA64_LTOFF_DTPMOD22: 3041218822Sdim need_entry = NEED_DTPMOD; 3042218822Sdim break; 3043218822Sdim 3044218822Sdim case R_IA64_LTOFF_FPTR22: 3045218822Sdim case R_IA64_LTOFF_FPTR64I: 3046218822Sdim case R_IA64_LTOFF_FPTR32MSB: 3047218822Sdim case R_IA64_LTOFF_FPTR32LSB: 3048218822Sdim case R_IA64_LTOFF_FPTR64MSB: 3049218822Sdim case R_IA64_LTOFF_FPTR64LSB: 3050218822Sdim need_entry = NEED_FPTR | NEED_GOT | NEED_LTOFF_FPTR; 3051218822Sdim break; 3052218822Sdim 3053218822Sdim case R_IA64_FPTR64I: 3054218822Sdim case R_IA64_FPTR32MSB: 3055218822Sdim case R_IA64_FPTR32LSB: 3056218822Sdim case R_IA64_FPTR64MSB: 3057218822Sdim case R_IA64_FPTR64LSB: 3058218822Sdim if (info->shared || h) 3059218822Sdim need_entry = NEED_FPTR | NEED_DYNREL; 3060218822Sdim else 3061218822Sdim need_entry = NEED_FPTR; 3062218822Sdim dynrel_type = R_IA64_FPTRNNLSB; 3063218822Sdim break; 3064218822Sdim 3065218822Sdim case R_IA64_LTOFF22: 3066218822Sdim case R_IA64_LTOFF64I: 3067218822Sdim need_entry = NEED_GOT; 3068218822Sdim break; 3069218822Sdim 3070218822Sdim case R_IA64_LTOFF22X: 3071218822Sdim need_entry = NEED_GOTX; 3072218822Sdim break; 3073218822Sdim 3074218822Sdim case R_IA64_PLTOFF22: 3075218822Sdim case R_IA64_PLTOFF64I: 3076218822Sdim case R_IA64_PLTOFF64MSB: 3077218822Sdim case R_IA64_PLTOFF64LSB: 3078218822Sdim need_entry = NEED_PLTOFF; 3079218822Sdim if (h) 3080218822Sdim { 3081218822Sdim if (maybe_dynamic) 3082218822Sdim need_entry |= NEED_MIN_PLT; 3083218822Sdim } 3084218822Sdim break; 3085218822Sdim 3086218822Sdim case R_IA64_PCREL21B: 3087218822Sdim case R_IA64_PCREL60B: 3088218822Sdim /* Depending on where this symbol is defined, we may or may not 3089218822Sdim need a full plt entry. Only skip if we know we'll not need 3090218822Sdim the entry -- static or symbolic, and the symbol definition 3091218822Sdim has already been seen. */ 3092218822Sdim if (maybe_dynamic && rel->r_addend == 0) 3093218822Sdim need_entry = NEED_FULL_PLT; 3094218822Sdim break; 3095218822Sdim 3096218822Sdim case R_IA64_IMM14: 3097218822Sdim case R_IA64_IMM22: 3098218822Sdim case R_IA64_IMM64: 3099218822Sdim case R_IA64_DIR32MSB: 3100218822Sdim case R_IA64_DIR32LSB: 3101218822Sdim case R_IA64_DIR64MSB: 3102218822Sdim case R_IA64_DIR64LSB: 3103218822Sdim /* Shared objects will always need at least a REL relocation. */ 3104218822Sdim if (info->shared || maybe_dynamic) 3105218822Sdim need_entry = NEED_DYNREL; 3106218822Sdim dynrel_type = R_IA64_DIRNNLSB; 3107218822Sdim break; 3108218822Sdim 3109218822Sdim case R_IA64_IPLTMSB: 3110218822Sdim case R_IA64_IPLTLSB: 3111218822Sdim /* Shared objects will always need at least a REL relocation. */ 3112218822Sdim if (info->shared || maybe_dynamic) 3113218822Sdim need_entry = NEED_DYNREL; 3114218822Sdim dynrel_type = R_IA64_IPLTLSB; 3115218822Sdim break; 3116218822Sdim 3117218822Sdim case R_IA64_PCREL22: 3118218822Sdim case R_IA64_PCREL64I: 3119218822Sdim case R_IA64_PCREL32MSB: 3120218822Sdim case R_IA64_PCREL32LSB: 3121218822Sdim case R_IA64_PCREL64MSB: 3122218822Sdim case R_IA64_PCREL64LSB: 3123218822Sdim if (maybe_dynamic) 3124218822Sdim need_entry = NEED_DYNREL; 3125218822Sdim dynrel_type = R_IA64_PCRELNNLSB; 3126218822Sdim break; 3127218822Sdim } 3128218822Sdim 3129218822Sdim if (!need_entry) 3130218822Sdim continue; 3131218822Sdim 3132218822Sdim dyn_i = get_dyn_sym_info (ia64_info, h, abfd, rel, FALSE); 3133218822Sdim 313484865Sobrien /* Record whether or not this is a local symbol. */ 313584865Sobrien dyn_i->h = h; 313684865Sobrien 313784865Sobrien /* Create what's needed. */ 3138130561Sobrien if (need_entry & (NEED_GOT | NEED_GOTX | NEED_TPREL 3139130561Sobrien | NEED_DTPMOD | NEED_DTPREL)) 314084865Sobrien { 314184865Sobrien if (!got) 314284865Sobrien { 314384865Sobrien got = get_got (abfd, info, ia64_info); 314484865Sobrien if (!got) 3145130561Sobrien return FALSE; 314684865Sobrien } 3147104834Sobrien if (need_entry & NEED_GOT) 3148104834Sobrien dyn_i->want_got = 1; 3149130561Sobrien if (need_entry & NEED_GOTX) 3150130561Sobrien dyn_i->want_gotx = 1; 3151104834Sobrien if (need_entry & NEED_TPREL) 3152104834Sobrien dyn_i->want_tprel = 1; 3153104834Sobrien if (need_entry & NEED_DTPMOD) 3154104834Sobrien dyn_i->want_dtpmod = 1; 3155104834Sobrien if (need_entry & NEED_DTPREL) 3156104834Sobrien dyn_i->want_dtprel = 1; 315784865Sobrien } 315884865Sobrien if (need_entry & NEED_FPTR) 315984865Sobrien { 316084865Sobrien if (!fptr) 316184865Sobrien { 316284865Sobrien fptr = get_fptr (abfd, info, ia64_info); 316384865Sobrien if (!fptr) 3164130561Sobrien return FALSE; 316584865Sobrien } 316684865Sobrien 316784865Sobrien /* FPTRs for shared libraries are allocated by the dynamic 316884865Sobrien linker. Make sure this local symbol will appear in the 316984865Sobrien dynamic symbol table. */ 3170130561Sobrien if (!h && info->shared) 317184865Sobrien { 3172130561Sobrien if (! (bfd_elf_link_record_local_dynamic_symbol 317389857Sobrien (info, abfd, (long) r_symndx))) 3174130561Sobrien return FALSE; 317584865Sobrien } 317684865Sobrien 317784865Sobrien dyn_i->want_fptr = 1; 317884865Sobrien } 317984865Sobrien if (need_entry & NEED_LTOFF_FPTR) 318084865Sobrien dyn_i->want_ltoff_fptr = 1; 318184865Sobrien if (need_entry & (NEED_MIN_PLT | NEED_FULL_PLT)) 318284865Sobrien { 318384865Sobrien if (!ia64_info->root.dynobj) 318484865Sobrien ia64_info->root.dynobj = abfd; 3185218822Sdim h->needs_plt = 1; 318684865Sobrien dyn_i->want_plt = 1; 318784865Sobrien } 318884865Sobrien if (need_entry & NEED_FULL_PLT) 318984865Sobrien dyn_i->want_plt2 = 1; 319084865Sobrien if (need_entry & NEED_PLTOFF) 3191218822Sdim { 3192218822Sdim /* This is needed here, in case @pltoff is used in a non-shared 3193218822Sdim link. */ 3194218822Sdim if (!pltoff) 3195218822Sdim { 3196218822Sdim pltoff = get_pltoff (abfd, info, ia64_info); 3197218822Sdim if (!pltoff) 3198218822Sdim return FALSE; 3199218822Sdim } 3200218822Sdim 3201218822Sdim dyn_i->want_pltoff = 1; 3202218822Sdim } 320384865Sobrien if ((need_entry & NEED_DYNREL) && (sec->flags & SEC_ALLOC)) 320484865Sobrien { 320584865Sobrien if (!srel) 320684865Sobrien { 3207130561Sobrien srel = get_reloc_section (abfd, ia64_info, sec, TRUE); 320884865Sobrien if (!srel) 3209130561Sobrien return FALSE; 321084865Sobrien } 3211130561Sobrien if (!count_dyn_reloc (abfd, dyn_i, srel, dynrel_type, 3212130561Sobrien (sec->flags & SEC_READONLY) != 0)) 3213130561Sobrien return FALSE; 321484865Sobrien } 321584865Sobrien } 321684865Sobrien 3217130561Sobrien return TRUE; 321884865Sobrien} 321984865Sobrien 322084865Sobrien/* For cleanliness, and potentially faster dynamic loading, allocate 322184865Sobrien external GOT entries first. */ 322284865Sobrien 3223130561Sobrienstatic bfd_boolean 322484865Sobrienallocate_global_data_got (dyn_i, data) 322584865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 322684865Sobrien PTR data; 322784865Sobrien{ 322884865Sobrien struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; 322984865Sobrien 3230130561Sobrien if ((dyn_i->want_got || dyn_i->want_gotx) 323184865Sobrien && ! dyn_i->want_fptr 3232130561Sobrien && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0)) 323384865Sobrien { 323484865Sobrien dyn_i->got_offset = x->ofs; 323584865Sobrien x->ofs += 8; 323684865Sobrien } 3237104834Sobrien if (dyn_i->want_tprel) 3238104834Sobrien { 3239104834Sobrien dyn_i->tprel_offset = x->ofs; 3240104834Sobrien x->ofs += 8; 3241104834Sobrien } 3242104834Sobrien if (dyn_i->want_dtpmod) 3243104834Sobrien { 3244130561Sobrien if (elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0)) 3245130561Sobrien { 3246130561Sobrien dyn_i->dtpmod_offset = x->ofs; 3247130561Sobrien x->ofs += 8; 3248130561Sobrien } 3249130561Sobrien else 3250130561Sobrien { 3251130561Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 3252130561Sobrien 3253130561Sobrien ia64_info = elfNN_ia64_hash_table (x->info); 3254130561Sobrien if (ia64_info->self_dtpmod_offset == (bfd_vma) -1) 3255130561Sobrien { 3256130561Sobrien ia64_info->self_dtpmod_offset = x->ofs; 3257130561Sobrien x->ofs += 8; 3258130561Sobrien } 3259130561Sobrien dyn_i->dtpmod_offset = ia64_info->self_dtpmod_offset; 3260130561Sobrien } 3261104834Sobrien } 3262104834Sobrien if (dyn_i->want_dtprel) 3263104834Sobrien { 3264104834Sobrien dyn_i->dtprel_offset = x->ofs; 3265104834Sobrien x->ofs += 8; 3266104834Sobrien } 3267130561Sobrien return TRUE; 326884865Sobrien} 326984865Sobrien 327084865Sobrien/* Next, allocate all the GOT entries used by LTOFF_FPTR relocs. */ 327184865Sobrien 3272130561Sobrienstatic bfd_boolean 327384865Sobrienallocate_global_fptr_got (dyn_i, data) 327484865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 327584865Sobrien PTR data; 327684865Sobrien{ 327784865Sobrien struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; 327884865Sobrien 327984865Sobrien if (dyn_i->want_got 328084865Sobrien && dyn_i->want_fptr 3281218822Sdim && elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, R_IA64_FPTRNNLSB)) 328284865Sobrien { 328384865Sobrien dyn_i->got_offset = x->ofs; 328484865Sobrien x->ofs += 8; 328584865Sobrien } 3286130561Sobrien return TRUE; 328784865Sobrien} 328884865Sobrien 328984865Sobrien/* Lastly, allocate all the GOT entries for local data. */ 329084865Sobrien 3291130561Sobrienstatic bfd_boolean 329284865Sobrienallocate_local_got (dyn_i, data) 329384865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 329484865Sobrien PTR data; 329584865Sobrien{ 329684865Sobrien struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; 329784865Sobrien 3298130561Sobrien if ((dyn_i->want_got || dyn_i->want_gotx) 3299130561Sobrien && !elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0)) 330084865Sobrien { 330184865Sobrien dyn_i->got_offset = x->ofs; 330284865Sobrien x->ofs += 8; 330384865Sobrien } 3304130561Sobrien return TRUE; 330584865Sobrien} 330684865Sobrien 330784865Sobrien/* Search for the index of a global symbol in it's defining object file. */ 330884865Sobrien 330989857Sobrienstatic long 331084865Sobrienglobal_sym_index (h) 331184865Sobrien struct elf_link_hash_entry *h; 331284865Sobrien{ 331384865Sobrien struct elf_link_hash_entry **p; 331484865Sobrien bfd *obj; 331584865Sobrien 331684865Sobrien BFD_ASSERT (h->root.type == bfd_link_hash_defined 331784865Sobrien || h->root.type == bfd_link_hash_defweak); 331884865Sobrien 331984865Sobrien obj = h->root.u.def.section->owner; 332084865Sobrien for (p = elf_sym_hashes (obj); *p != h; ++p) 332184865Sobrien continue; 332284865Sobrien 332384865Sobrien return p - elf_sym_hashes (obj) + elf_tdata (obj)->symtab_hdr.sh_info; 332484865Sobrien} 332584865Sobrien 332684865Sobrien/* Allocate function descriptors. We can do these for every function 332784865Sobrien in a main executable that is not exported. */ 332884865Sobrien 3329130561Sobrienstatic bfd_boolean 333084865Sobrienallocate_fptr (dyn_i, data) 333184865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 333284865Sobrien PTR data; 333384865Sobrien{ 333484865Sobrien struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; 333584865Sobrien 333684865Sobrien if (dyn_i->want_fptr) 333784865Sobrien { 333884865Sobrien struct elf_link_hash_entry *h = dyn_i->h; 333984865Sobrien 334084865Sobrien if (h) 334184865Sobrien while (h->root.type == bfd_link_hash_indirect 334284865Sobrien || h->root.type == bfd_link_hash_warning) 334384865Sobrien h = (struct elf_link_hash_entry *) h->root.u.i.link; 334484865Sobrien 3345130561Sobrien if (!x->info->executable 3346130561Sobrien && (!h 3347130561Sobrien || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT 3348218822Sdim || (h->root.type != bfd_link_hash_undefweak 3349218822Sdim && h->root.type != bfd_link_hash_undefined))) 335084865Sobrien { 335184865Sobrien if (h && h->dynindx == -1) 335284865Sobrien { 335384865Sobrien BFD_ASSERT ((h->root.type == bfd_link_hash_defined) 335484865Sobrien || (h->root.type == bfd_link_hash_defweak)); 335584865Sobrien 3356130561Sobrien if (!bfd_elf_link_record_local_dynamic_symbol 335784865Sobrien (x->info, h->root.u.def.section->owner, 335884865Sobrien global_sym_index (h))) 3359130561Sobrien return FALSE; 336084865Sobrien } 336184865Sobrien 336284865Sobrien dyn_i->want_fptr = 0; 336384865Sobrien } 336484865Sobrien else if (h == NULL || h->dynindx == -1) 336584865Sobrien { 336684865Sobrien dyn_i->fptr_offset = x->ofs; 336784865Sobrien x->ofs += 16; 336884865Sobrien } 336984865Sobrien else 337084865Sobrien dyn_i->want_fptr = 0; 337184865Sobrien } 3372130561Sobrien return TRUE; 337384865Sobrien} 337484865Sobrien 337584865Sobrien/* Allocate all the minimal PLT entries. */ 337684865Sobrien 3377130561Sobrienstatic bfd_boolean 337884865Sobrienallocate_plt_entries (dyn_i, data) 337984865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 338084865Sobrien PTR data; 338184865Sobrien{ 338284865Sobrien struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; 338384865Sobrien 338484865Sobrien if (dyn_i->want_plt) 338584865Sobrien { 338684865Sobrien struct elf_link_hash_entry *h = dyn_i->h; 338784865Sobrien 338884865Sobrien if (h) 338984865Sobrien while (h->root.type == bfd_link_hash_indirect 339084865Sobrien || h->root.type == bfd_link_hash_warning) 339184865Sobrien h = (struct elf_link_hash_entry *) h->root.u.i.link; 339284865Sobrien 3393218822Sdim /* ??? Versioned symbols seem to lose NEEDS_PLT. */ 3394130561Sobrien if (elfNN_ia64_dynamic_symbol_p (h, x->info, 0)) 339584865Sobrien { 339684865Sobrien bfd_size_type offset = x->ofs; 339784865Sobrien if (offset == 0) 339884865Sobrien offset = PLT_HEADER_SIZE; 339984865Sobrien dyn_i->plt_offset = offset; 340084865Sobrien x->ofs = offset + PLT_MIN_ENTRY_SIZE; 340184865Sobrien 340284865Sobrien dyn_i->want_pltoff = 1; 340384865Sobrien } 340484865Sobrien else 340584865Sobrien { 340684865Sobrien dyn_i->want_plt = 0; 340784865Sobrien dyn_i->want_plt2 = 0; 340884865Sobrien } 340984865Sobrien } 3410130561Sobrien return TRUE; 341184865Sobrien} 341284865Sobrien 341384865Sobrien/* Allocate all the full PLT entries. */ 341484865Sobrien 3415130561Sobrienstatic bfd_boolean 341684865Sobrienallocate_plt2_entries (dyn_i, data) 341784865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 341884865Sobrien PTR data; 341984865Sobrien{ 342084865Sobrien struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; 342184865Sobrien 342284865Sobrien if (dyn_i->want_plt2) 342384865Sobrien { 342484865Sobrien struct elf_link_hash_entry *h = dyn_i->h; 342584865Sobrien bfd_size_type ofs = x->ofs; 342684865Sobrien 342784865Sobrien dyn_i->plt2_offset = ofs; 342884865Sobrien x->ofs = ofs + PLT_FULL_ENTRY_SIZE; 342984865Sobrien 343084865Sobrien while (h->root.type == bfd_link_hash_indirect 343184865Sobrien || h->root.type == bfd_link_hash_warning) 343284865Sobrien h = (struct elf_link_hash_entry *) h->root.u.i.link; 343384865Sobrien dyn_i->h->plt.offset = ofs; 343484865Sobrien } 3435130561Sobrien return TRUE; 343684865Sobrien} 343784865Sobrien 343884865Sobrien/* Allocate all the PLTOFF entries requested by relocations and 343984865Sobrien plt entries. We can't share space with allocated FPTR entries, 344084865Sobrien because the latter are not necessarily addressable by the GP. 344184865Sobrien ??? Relaxation might be able to determine that they are. */ 344284865Sobrien 3443130561Sobrienstatic bfd_boolean 344484865Sobrienallocate_pltoff_entries (dyn_i, data) 344584865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 344684865Sobrien PTR data; 344784865Sobrien{ 344884865Sobrien struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; 344984865Sobrien 345084865Sobrien if (dyn_i->want_pltoff) 345184865Sobrien { 345284865Sobrien dyn_i->pltoff_offset = x->ofs; 345384865Sobrien x->ofs += 16; 345484865Sobrien } 3455130561Sobrien return TRUE; 345684865Sobrien} 345784865Sobrien 345884865Sobrien/* Allocate dynamic relocations for those symbols that turned out 345984865Sobrien to be dynamic. */ 346084865Sobrien 3461130561Sobrienstatic bfd_boolean 346284865Sobrienallocate_dynrel_entries (dyn_i, data) 346384865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 346484865Sobrien PTR data; 346584865Sobrien{ 346684865Sobrien struct elfNN_ia64_allocate_data *x = (struct elfNN_ia64_allocate_data *)data; 346784865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 346884865Sobrien struct elfNN_ia64_dyn_reloc_entry *rent; 3469130561Sobrien bfd_boolean dynamic_symbol, shared, resolved_zero; 347084865Sobrien 347184865Sobrien ia64_info = elfNN_ia64_hash_table (x->info); 3472130561Sobrien 3473130561Sobrien /* Note that this can't be used in relation to FPTR relocs below. */ 3474130561Sobrien dynamic_symbol = elfNN_ia64_dynamic_symbol_p (dyn_i->h, x->info, 0); 3475130561Sobrien 347684865Sobrien shared = x->info->shared; 3477130561Sobrien resolved_zero = (dyn_i->h 3478130561Sobrien && ELF_ST_VISIBILITY (dyn_i->h->other) 3479130561Sobrien && dyn_i->h->root.type == bfd_link_hash_undefweak); 348084865Sobrien 3481218822Sdim /* Take care of the GOT and PLT relocations. */ 3482218822Sdim 3483218822Sdim if ((!resolved_zero 3484218822Sdim && (dynamic_symbol || shared) 3485218822Sdim && (dyn_i->want_got || dyn_i->want_gotx)) 3486218822Sdim || (dyn_i->want_ltoff_fptr 3487218822Sdim && dyn_i->h 3488218822Sdim && dyn_i->h->dynindx != -1)) 3489218822Sdim { 3490218822Sdim if (!dyn_i->want_ltoff_fptr 3491218822Sdim || !x->info->pie 3492218822Sdim || dyn_i->h == NULL 3493218822Sdim || dyn_i->h->root.type != bfd_link_hash_undefweak) 3494218822Sdim ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela); 3495218822Sdim } 3496218822Sdim if ((dynamic_symbol || shared) && dyn_i->want_tprel) 3497218822Sdim ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela); 3498218822Sdim if (dynamic_symbol && dyn_i->want_dtpmod) 3499218822Sdim ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela); 3500218822Sdim if (dynamic_symbol && dyn_i->want_dtprel) 3501218822Sdim ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela); 3502218822Sdim 3503218822Sdim if (x->only_got) 3504218822Sdim return TRUE; 3505218822Sdim 3506218822Sdim if (ia64_info->rel_fptr_sec && dyn_i->want_fptr) 3507218822Sdim { 3508218822Sdim if (dyn_i->h == NULL || dyn_i->h->root.type != bfd_link_hash_undefweak) 3509218822Sdim ia64_info->rel_fptr_sec->size += sizeof (ElfNN_External_Rela); 3510218822Sdim } 3511218822Sdim 3512218822Sdim if (!resolved_zero && dyn_i->want_pltoff) 3513218822Sdim { 3514218822Sdim bfd_size_type t = 0; 3515218822Sdim 3516218822Sdim /* Dynamic symbols get one IPLT relocation. Local symbols in 3517218822Sdim shared libraries get two REL relocations. Local symbols in 3518218822Sdim main applications get nothing. */ 3519218822Sdim if (dynamic_symbol) 3520218822Sdim t = sizeof (ElfNN_External_Rela); 3521218822Sdim else if (shared) 3522218822Sdim t = 2 * sizeof (ElfNN_External_Rela); 3523218822Sdim 3524218822Sdim ia64_info->rel_pltoff_sec->size += t; 3525218822Sdim } 3526218822Sdim 352784865Sobrien /* Take care of the normal data relocations. */ 352884865Sobrien 352984865Sobrien for (rent = dyn_i->reloc_entries; rent; rent = rent->next) 353084865Sobrien { 353184865Sobrien int count = rent->count; 353284865Sobrien 353384865Sobrien switch (rent->type) 353484865Sobrien { 3535218822Sdim case R_IA64_FPTR32LSB: 353684865Sobrien case R_IA64_FPTR64LSB: 3537130561Sobrien /* Allocate one iff !want_fptr and not PIE, which by this point 3538130561Sobrien will be true only if we're actually allocating one statically 3539130561Sobrien in the main executable. Position independent executables 3540130561Sobrien need a relative reloc. */ 3541130561Sobrien if (dyn_i->want_fptr && !x->info->pie) 354284865Sobrien continue; 354384865Sobrien break; 3544218822Sdim case R_IA64_PCREL32LSB: 354584865Sobrien case R_IA64_PCREL64LSB: 354684865Sobrien if (!dynamic_symbol) 354784865Sobrien continue; 354884865Sobrien break; 3549218822Sdim case R_IA64_DIR32LSB: 355084865Sobrien case R_IA64_DIR64LSB: 355184865Sobrien if (!dynamic_symbol && !shared) 355284865Sobrien continue; 355384865Sobrien break; 355484865Sobrien case R_IA64_IPLTLSB: 355584865Sobrien if (!dynamic_symbol && !shared) 355684865Sobrien continue; 355784865Sobrien /* Use two REL relocations for IPLT relocations 355884865Sobrien against local symbols. */ 355984865Sobrien if (!dynamic_symbol) 356084865Sobrien count *= 2; 356184865Sobrien break; 3562218822Sdim case R_IA64_DTPREL32LSB: 3563104834Sobrien case R_IA64_TPREL64LSB: 3564104834Sobrien case R_IA64_DTPREL64LSB: 3565104834Sobrien case R_IA64_DTPMOD64LSB: 3566104834Sobrien break; 356784865Sobrien default: 356884865Sobrien abort (); 356984865Sobrien } 3570130561Sobrien if (rent->reltext) 3571130561Sobrien ia64_info->reltext = 1; 3572218822Sdim rent->srel->size += sizeof (ElfNN_External_Rela) * count; 357384865Sobrien } 357484865Sobrien 3575130561Sobrien return TRUE; 357684865Sobrien} 357784865Sobrien 3578130561Sobrienstatic bfd_boolean 357984865SobrienelfNN_ia64_adjust_dynamic_symbol (info, h) 358084865Sobrien struct bfd_link_info *info ATTRIBUTE_UNUSED; 358184865Sobrien struct elf_link_hash_entry *h; 358284865Sobrien{ 358384865Sobrien /* ??? Undefined symbols with PLT entries should be re-defined 358484865Sobrien to be the PLT entry. */ 358584865Sobrien 358684865Sobrien /* If this is a weak symbol, and there is a real definition, the 358784865Sobrien processor independent code will have arranged for us to see the 358884865Sobrien real definition first, and we can just use the same value. */ 3589218822Sdim if (h->u.weakdef != NULL) 359084865Sobrien { 3591218822Sdim BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined 3592218822Sdim || h->u.weakdef->root.type == bfd_link_hash_defweak); 3593218822Sdim h->root.u.def.section = h->u.weakdef->root.u.def.section; 3594218822Sdim h->root.u.def.value = h->u.weakdef->root.u.def.value; 3595130561Sobrien return TRUE; 359684865Sobrien } 359784865Sobrien 359884865Sobrien /* If this is a reference to a symbol defined by a dynamic object which 359984865Sobrien is not a function, we might allocate the symbol in our .dynbss section 360084865Sobrien and allocate a COPY dynamic relocation. 360184865Sobrien 360284865Sobrien But IA-64 code is canonically PIC, so as a rule we can avoid this sort 360384865Sobrien of hackery. */ 360484865Sobrien 3605130561Sobrien return TRUE; 360684865Sobrien} 360784865Sobrien 3608130561Sobrienstatic bfd_boolean 360984865SobrienelfNN_ia64_size_dynamic_sections (output_bfd, info) 3610130561Sobrien bfd *output_bfd ATTRIBUTE_UNUSED; 361184865Sobrien struct bfd_link_info *info; 361284865Sobrien{ 361384865Sobrien struct elfNN_ia64_allocate_data data; 361484865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 361584865Sobrien asection *sec; 361684865Sobrien bfd *dynobj; 3617130561Sobrien bfd_boolean relplt = FALSE; 361884865Sobrien 361984865Sobrien dynobj = elf_hash_table(info)->dynobj; 362084865Sobrien ia64_info = elfNN_ia64_hash_table (info); 3621130561Sobrien ia64_info->self_dtpmod_offset = (bfd_vma) -1; 362284865Sobrien BFD_ASSERT(dynobj != NULL); 362384865Sobrien data.info = info; 362484865Sobrien 362584865Sobrien /* Set the contents of the .interp section to the interpreter. */ 362684865Sobrien if (ia64_info->root.dynamic_sections_created 3627130561Sobrien && info->executable) 362884865Sobrien { 362984865Sobrien sec = bfd_get_section_by_name (dynobj, ".interp"); 363084865Sobrien BFD_ASSERT (sec != NULL); 3631130561Sobrien sec->contents = (bfd_byte *) ELF_DYNAMIC_INTERPRETER; 3632218822Sdim sec->size = strlen (ELF_DYNAMIC_INTERPRETER) + 1; 363384865Sobrien } 363484865Sobrien 363584865Sobrien /* Allocate the GOT entries. */ 363684865Sobrien 363784865Sobrien if (ia64_info->got_sec) 363884865Sobrien { 363984865Sobrien data.ofs = 0; 364084865Sobrien elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_data_got, &data); 364184865Sobrien elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_global_fptr_got, &data); 364284865Sobrien elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_local_got, &data); 3643218822Sdim ia64_info->got_sec->size = data.ofs; 364484865Sobrien } 364584865Sobrien 364684865Sobrien /* Allocate the FPTR entries. */ 364784865Sobrien 364884865Sobrien if (ia64_info->fptr_sec) 364984865Sobrien { 365084865Sobrien data.ofs = 0; 365184865Sobrien elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_fptr, &data); 3652218822Sdim ia64_info->fptr_sec->size = data.ofs; 365384865Sobrien } 365484865Sobrien 365584865Sobrien /* Now that we've seen all of the input files, we can decide which 365684865Sobrien symbols need plt entries. Allocate the minimal PLT entries first. 3657130561Sobrien We do this even though dynamic_sections_created may be FALSE, because 365884865Sobrien this has the side-effect of clearing want_plt and want_plt2. */ 365984865Sobrien 366084865Sobrien data.ofs = 0; 366184865Sobrien elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_plt_entries, &data); 366284865Sobrien 366384865Sobrien ia64_info->minplt_entries = 0; 366484865Sobrien if (data.ofs) 366584865Sobrien { 366684865Sobrien ia64_info->minplt_entries 366784865Sobrien = (data.ofs - PLT_HEADER_SIZE) / PLT_MIN_ENTRY_SIZE; 366884865Sobrien } 366984865Sobrien 367084865Sobrien /* Align the pointer for the plt2 entries. */ 367189857Sobrien data.ofs = (data.ofs + 31) & (bfd_vma) -32; 367284865Sobrien 367384865Sobrien elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_plt2_entries, &data); 3674130561Sobrien if (data.ofs != 0 || ia64_info->root.dynamic_sections_created) 367584865Sobrien { 3676130561Sobrien /* FIXME: we always reserve the memory for dynamic linker even if 3677130561Sobrien there are no PLT entries since dynamic linker may assume the 3678130561Sobrien reserved memory always exists. */ 3679130561Sobrien 368084865Sobrien BFD_ASSERT (ia64_info->root.dynamic_sections_created); 368184865Sobrien 3682218822Sdim ia64_info->plt_sec->size = data.ofs; 368384865Sobrien 368484865Sobrien /* If we've got a .plt, we need some extra memory for the dynamic 368584865Sobrien linker. We stuff these in .got.plt. */ 368684865Sobrien sec = bfd_get_section_by_name (dynobj, ".got.plt"); 3687218822Sdim sec->size = 8 * PLT_RESERVED_WORDS; 368884865Sobrien } 368984865Sobrien 369084865Sobrien /* Allocate the PLTOFF entries. */ 369184865Sobrien 369284865Sobrien if (ia64_info->pltoff_sec) 369384865Sobrien { 369484865Sobrien data.ofs = 0; 369584865Sobrien elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_pltoff_entries, &data); 3696218822Sdim ia64_info->pltoff_sec->size = data.ofs; 369784865Sobrien } 369884865Sobrien 369984865Sobrien if (ia64_info->root.dynamic_sections_created) 370084865Sobrien { 370184865Sobrien /* Allocate space for the dynamic relocations that turned out to be 370284865Sobrien required. */ 370384865Sobrien 3704130561Sobrien if (info->shared && ia64_info->self_dtpmod_offset != (bfd_vma) -1) 3705218822Sdim ia64_info->rel_got_sec->size += sizeof (ElfNN_External_Rela); 3706218822Sdim data.only_got = FALSE; 370784865Sobrien elfNN_ia64_dyn_sym_traverse (ia64_info, allocate_dynrel_entries, &data); 370884865Sobrien } 370984865Sobrien 371084865Sobrien /* We have now determined the sizes of the various dynamic sections. 371184865Sobrien Allocate memory for them. */ 371284865Sobrien for (sec = dynobj->sections; sec != NULL; sec = sec->next) 371384865Sobrien { 3714130561Sobrien bfd_boolean strip; 371584865Sobrien 371684865Sobrien if (!(sec->flags & SEC_LINKER_CREATED)) 371784865Sobrien continue; 371884865Sobrien 371984865Sobrien /* If we don't need this section, strip it from the output file. 372084865Sobrien There were several sections primarily related to dynamic 372184865Sobrien linking that must be create before the linker maps input 372284865Sobrien sections to output sections. The linker does that before 372384865Sobrien bfd_elf_size_dynamic_sections is called, and it is that 372484865Sobrien function which decides whether anything needs to go into 372584865Sobrien these sections. */ 372684865Sobrien 3727218822Sdim strip = (sec->size == 0); 372884865Sobrien 372984865Sobrien if (sec == ia64_info->got_sec) 3730130561Sobrien strip = FALSE; 373184865Sobrien else if (sec == ia64_info->rel_got_sec) 373284865Sobrien { 373384865Sobrien if (strip) 373484865Sobrien ia64_info->rel_got_sec = NULL; 373584865Sobrien else 373684865Sobrien /* We use the reloc_count field as a counter if we need to 373784865Sobrien copy relocs into the output file. */ 373884865Sobrien sec->reloc_count = 0; 373984865Sobrien } 374084865Sobrien else if (sec == ia64_info->fptr_sec) 374184865Sobrien { 374284865Sobrien if (strip) 374384865Sobrien ia64_info->fptr_sec = NULL; 374484865Sobrien } 3745130561Sobrien else if (sec == ia64_info->rel_fptr_sec) 3746130561Sobrien { 3747130561Sobrien if (strip) 3748130561Sobrien ia64_info->rel_fptr_sec = NULL; 3749130561Sobrien else 3750130561Sobrien /* We use the reloc_count field as a counter if we need to 3751130561Sobrien copy relocs into the output file. */ 3752130561Sobrien sec->reloc_count = 0; 3753130561Sobrien } 375484865Sobrien else if (sec == ia64_info->plt_sec) 375584865Sobrien { 375684865Sobrien if (strip) 375784865Sobrien ia64_info->plt_sec = NULL; 375884865Sobrien } 375984865Sobrien else if (sec == ia64_info->pltoff_sec) 376084865Sobrien { 376184865Sobrien if (strip) 376284865Sobrien ia64_info->pltoff_sec = NULL; 376384865Sobrien } 376484865Sobrien else if (sec == ia64_info->rel_pltoff_sec) 376584865Sobrien { 376684865Sobrien if (strip) 376784865Sobrien ia64_info->rel_pltoff_sec = NULL; 376884865Sobrien else 376984865Sobrien { 3770130561Sobrien relplt = TRUE; 377184865Sobrien /* We use the reloc_count field as a counter if we need to 377284865Sobrien copy relocs into the output file. */ 377384865Sobrien sec->reloc_count = 0; 377484865Sobrien } 377584865Sobrien } 377684865Sobrien else 377784865Sobrien { 377884865Sobrien const char *name; 377984865Sobrien 378084865Sobrien /* It's OK to base decisions on the section name, because none 378184865Sobrien of the dynobj section names depend upon the input files. */ 378284865Sobrien name = bfd_get_section_name (dynobj, sec); 378384865Sobrien 378484865Sobrien if (strcmp (name, ".got.plt") == 0) 3785130561Sobrien strip = FALSE; 3786218822Sdim else if (CONST_STRNEQ (name, ".rel")) 378784865Sobrien { 378884865Sobrien if (!strip) 378984865Sobrien { 379084865Sobrien /* We use the reloc_count field as a counter if we need to 379184865Sobrien copy relocs into the output file. */ 379284865Sobrien sec->reloc_count = 0; 379384865Sobrien } 379484865Sobrien } 379584865Sobrien else 379684865Sobrien continue; 379784865Sobrien } 379884865Sobrien 379984865Sobrien if (strip) 3800218822Sdim sec->flags |= SEC_EXCLUDE; 380184865Sobrien else 380284865Sobrien { 380384865Sobrien /* Allocate memory for the section contents. */ 3804218822Sdim sec->contents = (bfd_byte *) bfd_zalloc (dynobj, sec->size); 3805218822Sdim if (sec->contents == NULL && sec->size != 0) 3806130561Sobrien return FALSE; 380784865Sobrien } 380884865Sobrien } 380984865Sobrien 381084865Sobrien if (elf_hash_table (info)->dynamic_sections_created) 381184865Sobrien { 381284865Sobrien /* Add some entries to the .dynamic section. We fill in the values 381384865Sobrien later (in finish_dynamic_sections) but we must add the entries now 381484865Sobrien so that we get the correct size for the .dynamic section. */ 381584865Sobrien 3816130561Sobrien if (info->executable) 381784865Sobrien { 381884865Sobrien /* The DT_DEBUG entry is filled in by the dynamic linker and used 381984865Sobrien by the debugger. */ 382089857Sobrien#define add_dynamic_entry(TAG, VAL) \ 3821130561Sobrien _bfd_elf_add_dynamic_entry (info, TAG, VAL) 382289857Sobrien 382389857Sobrien if (!add_dynamic_entry (DT_DEBUG, 0)) 3824130561Sobrien return FALSE; 382584865Sobrien } 382684865Sobrien 382789857Sobrien if (!add_dynamic_entry (DT_IA_64_PLT_RESERVE, 0)) 3828130561Sobrien return FALSE; 382989857Sobrien if (!add_dynamic_entry (DT_PLTGOT, 0)) 3830130561Sobrien return FALSE; 383184865Sobrien 383284865Sobrien if (relplt) 383384865Sobrien { 383489857Sobrien if (!add_dynamic_entry (DT_PLTRELSZ, 0) 383589857Sobrien || !add_dynamic_entry (DT_PLTREL, DT_RELA) 383689857Sobrien || !add_dynamic_entry (DT_JMPREL, 0)) 3837130561Sobrien return FALSE; 383884865Sobrien } 383984865Sobrien 384089857Sobrien if (!add_dynamic_entry (DT_RELA, 0) 384189857Sobrien || !add_dynamic_entry (DT_RELASZ, 0) 384289857Sobrien || !add_dynamic_entry (DT_RELAENT, sizeof (ElfNN_External_Rela))) 3843130561Sobrien return FALSE; 384484865Sobrien 384589857Sobrien if (ia64_info->reltext) 384684865Sobrien { 384789857Sobrien if (!add_dynamic_entry (DT_TEXTREL, 0)) 3848130561Sobrien return FALSE; 384984865Sobrien info->flags |= DF_TEXTREL; 385084865Sobrien } 385184865Sobrien } 385284865Sobrien 385384865Sobrien /* ??? Perhaps force __gp local. */ 385484865Sobrien 3855130561Sobrien return TRUE; 385684865Sobrien} 385784865Sobrien 385884865Sobrienstatic bfd_reloc_status_type 3859218822SdimelfNN_ia64_install_value (hit_addr, v, r_type) 386084865Sobrien bfd_byte *hit_addr; 386189857Sobrien bfd_vma v; 386284865Sobrien unsigned int r_type; 386384865Sobrien{ 386484865Sobrien const struct ia64_operand *op; 386584865Sobrien int bigendian = 0, shift = 0; 3866218822Sdim bfd_vma t0, t1, dword; 3867218822Sdim ia64_insn insn; 386884865Sobrien enum ia64_opnd opnd; 386984865Sobrien const char *err; 387084865Sobrien size_t size = 8; 387189857Sobrien#ifdef BFD_HOST_U_64_BIT 387289857Sobrien BFD_HOST_U_64_BIT val = (BFD_HOST_U_64_BIT) v; 387389857Sobrien#else 387489857Sobrien bfd_vma val = v; 387589857Sobrien#endif 387684865Sobrien 387784865Sobrien opnd = IA64_OPND_NIL; 387884865Sobrien switch (r_type) 387984865Sobrien { 388084865Sobrien case R_IA64_NONE: 388184865Sobrien case R_IA64_LDXMOV: 388284865Sobrien return bfd_reloc_ok; 388384865Sobrien 388484865Sobrien /* Instruction relocations. */ 388584865Sobrien 3886104834Sobrien case R_IA64_IMM14: 3887104834Sobrien case R_IA64_TPREL14: 3888104834Sobrien case R_IA64_DTPREL14: 3889104834Sobrien opnd = IA64_OPND_IMM14; 3890104834Sobrien break; 389184865Sobrien 389284865Sobrien case R_IA64_PCREL21F: opnd = IA64_OPND_TGT25; break; 389384865Sobrien case R_IA64_PCREL21M: opnd = IA64_OPND_TGT25b; break; 389484865Sobrien case R_IA64_PCREL60B: opnd = IA64_OPND_TGT64; break; 389584865Sobrien case R_IA64_PCREL21B: 389684865Sobrien case R_IA64_PCREL21BI: 389784865Sobrien opnd = IA64_OPND_TGT25c; 389884865Sobrien break; 389984865Sobrien 390084865Sobrien case R_IA64_IMM22: 390184865Sobrien case R_IA64_GPREL22: 390284865Sobrien case R_IA64_LTOFF22: 390384865Sobrien case R_IA64_LTOFF22X: 390484865Sobrien case R_IA64_PLTOFF22: 390584865Sobrien case R_IA64_PCREL22: 390684865Sobrien case R_IA64_LTOFF_FPTR22: 3907104834Sobrien case R_IA64_TPREL22: 3908104834Sobrien case R_IA64_DTPREL22: 3909104834Sobrien case R_IA64_LTOFF_TPREL22: 3910104834Sobrien case R_IA64_LTOFF_DTPMOD22: 3911104834Sobrien case R_IA64_LTOFF_DTPREL22: 391284865Sobrien opnd = IA64_OPND_IMM22; 391384865Sobrien break; 391484865Sobrien 391584865Sobrien case R_IA64_IMM64: 391684865Sobrien case R_IA64_GPREL64I: 391784865Sobrien case R_IA64_LTOFF64I: 391884865Sobrien case R_IA64_PLTOFF64I: 391984865Sobrien case R_IA64_PCREL64I: 392084865Sobrien case R_IA64_FPTR64I: 392184865Sobrien case R_IA64_LTOFF_FPTR64I: 3922104834Sobrien case R_IA64_TPREL64I: 3923104834Sobrien case R_IA64_DTPREL64I: 392484865Sobrien opnd = IA64_OPND_IMMU64; 392584865Sobrien break; 392684865Sobrien 392784865Sobrien /* Data relocations. */ 392884865Sobrien 392984865Sobrien case R_IA64_DIR32MSB: 393084865Sobrien case R_IA64_GPREL32MSB: 393184865Sobrien case R_IA64_FPTR32MSB: 393284865Sobrien case R_IA64_PCREL32MSB: 393389857Sobrien case R_IA64_LTOFF_FPTR32MSB: 393484865Sobrien case R_IA64_SEGREL32MSB: 393584865Sobrien case R_IA64_SECREL32MSB: 393684865Sobrien case R_IA64_LTV32MSB: 3937104834Sobrien case R_IA64_DTPREL32MSB: 393884865Sobrien size = 4; bigendian = 1; 393984865Sobrien break; 394084865Sobrien 394184865Sobrien case R_IA64_DIR32LSB: 394284865Sobrien case R_IA64_GPREL32LSB: 394384865Sobrien case R_IA64_FPTR32LSB: 394484865Sobrien case R_IA64_PCREL32LSB: 394589857Sobrien case R_IA64_LTOFF_FPTR32LSB: 394684865Sobrien case R_IA64_SEGREL32LSB: 394784865Sobrien case R_IA64_SECREL32LSB: 394884865Sobrien case R_IA64_LTV32LSB: 3949104834Sobrien case R_IA64_DTPREL32LSB: 395084865Sobrien size = 4; bigendian = 0; 395184865Sobrien break; 395284865Sobrien 395384865Sobrien case R_IA64_DIR64MSB: 395484865Sobrien case R_IA64_GPREL64MSB: 395584865Sobrien case R_IA64_PLTOFF64MSB: 395684865Sobrien case R_IA64_FPTR64MSB: 395784865Sobrien case R_IA64_PCREL64MSB: 395884865Sobrien case R_IA64_LTOFF_FPTR64MSB: 395984865Sobrien case R_IA64_SEGREL64MSB: 396084865Sobrien case R_IA64_SECREL64MSB: 396184865Sobrien case R_IA64_LTV64MSB: 3962104834Sobrien case R_IA64_TPREL64MSB: 3963104834Sobrien case R_IA64_DTPMOD64MSB: 3964104834Sobrien case R_IA64_DTPREL64MSB: 396584865Sobrien size = 8; bigendian = 1; 396684865Sobrien break; 396784865Sobrien 396884865Sobrien case R_IA64_DIR64LSB: 396984865Sobrien case R_IA64_GPREL64LSB: 397084865Sobrien case R_IA64_PLTOFF64LSB: 397184865Sobrien case R_IA64_FPTR64LSB: 397284865Sobrien case R_IA64_PCREL64LSB: 397384865Sobrien case R_IA64_LTOFF_FPTR64LSB: 397484865Sobrien case R_IA64_SEGREL64LSB: 397584865Sobrien case R_IA64_SECREL64LSB: 397684865Sobrien case R_IA64_LTV64LSB: 3977104834Sobrien case R_IA64_TPREL64LSB: 3978104834Sobrien case R_IA64_DTPMOD64LSB: 3979104834Sobrien case R_IA64_DTPREL64LSB: 398084865Sobrien size = 8; bigendian = 0; 398184865Sobrien break; 398284865Sobrien 398384865Sobrien /* Unsupported / Dynamic relocations. */ 398484865Sobrien default: 398584865Sobrien return bfd_reloc_notsupported; 398684865Sobrien } 398784865Sobrien 398884865Sobrien switch (opnd) 398984865Sobrien { 399084865Sobrien case IA64_OPND_IMMU64: 399184865Sobrien hit_addr -= (long) hit_addr & 0x3; 3992218822Sdim t0 = bfd_getl64 (hit_addr); 3993218822Sdim t1 = bfd_getl64 (hit_addr + 8); 399484865Sobrien 399584865Sobrien /* tmpl/s: bits 0.. 5 in t0 399684865Sobrien slot 0: bits 5..45 in t0 399784865Sobrien slot 1: bits 46..63 in t0, bits 0..22 in t1 399884865Sobrien slot 2: bits 23..63 in t1 */ 399984865Sobrien 400084865Sobrien /* First, clear the bits that form the 64 bit constant. */ 400184865Sobrien t0 &= ~(0x3ffffLL << 46); 400284865Sobrien t1 &= ~(0x7fffffLL 400384865Sobrien | (( (0x07fLL << 13) | (0x1ffLL << 27) 400484865Sobrien | (0x01fLL << 22) | (0x001LL << 21) 400584865Sobrien | (0x001LL << 36)) << 23)); 400684865Sobrien 400784865Sobrien t0 |= ((val >> 22) & 0x03ffffLL) << 46; /* 18 lsbs of imm41 */ 400884865Sobrien t1 |= ((val >> 40) & 0x7fffffLL) << 0; /* 23 msbs of imm41 */ 400984865Sobrien t1 |= ( (((val >> 0) & 0x07f) << 13) /* imm7b */ 401084865Sobrien | (((val >> 7) & 0x1ff) << 27) /* imm9d */ 401184865Sobrien | (((val >> 16) & 0x01f) << 22) /* imm5c */ 401284865Sobrien | (((val >> 21) & 0x001) << 21) /* ic */ 401384865Sobrien | (((val >> 63) & 0x001) << 36)) << 23; /* i */ 401484865Sobrien 4015218822Sdim bfd_putl64 (t0, hit_addr); 4016218822Sdim bfd_putl64 (t1, hit_addr + 8); 401784865Sobrien break; 401884865Sobrien 401984865Sobrien case IA64_OPND_TGT64: 402084865Sobrien hit_addr -= (long) hit_addr & 0x3; 4021218822Sdim t0 = bfd_getl64 (hit_addr); 4022218822Sdim t1 = bfd_getl64 (hit_addr + 8); 402384865Sobrien 402484865Sobrien /* tmpl/s: bits 0.. 5 in t0 402584865Sobrien slot 0: bits 5..45 in t0 402684865Sobrien slot 1: bits 46..63 in t0, bits 0..22 in t1 402784865Sobrien slot 2: bits 23..63 in t1 */ 402884865Sobrien 402984865Sobrien /* First, clear the bits that form the 64 bit constant. */ 403084865Sobrien t0 &= ~(0x3ffffLL << 46); 403184865Sobrien t1 &= ~(0x7fffffLL 403284865Sobrien | ((1LL << 36 | 0xfffffLL << 13) << 23)); 403384865Sobrien 403484865Sobrien val >>= 4; 403584865Sobrien t0 |= ((val >> 20) & 0xffffLL) << 2 << 46; /* 16 lsbs of imm39 */ 403684865Sobrien t1 |= ((val >> 36) & 0x7fffffLL) << 0; /* 23 msbs of imm39 */ 403784865Sobrien t1 |= ((((val >> 0) & 0xfffffLL) << 13) /* imm20b */ 403884865Sobrien | (((val >> 59) & 0x1LL) << 36)) << 23; /* i */ 403984865Sobrien 4040218822Sdim bfd_putl64 (t0, hit_addr); 4041218822Sdim bfd_putl64 (t1, hit_addr + 8); 404284865Sobrien break; 404384865Sobrien 404484865Sobrien default: 404584865Sobrien switch ((long) hit_addr & 0x3) 404684865Sobrien { 404784865Sobrien case 0: shift = 5; break; 404884865Sobrien case 1: shift = 14; hit_addr += 3; break; 404984865Sobrien case 2: shift = 23; hit_addr += 6; break; 405084865Sobrien case 3: return bfd_reloc_notsupported; /* shouldn't happen... */ 405184865Sobrien } 4052218822Sdim dword = bfd_getl64 (hit_addr); 405384865Sobrien insn = (dword >> shift) & 0x1ffffffffffLL; 405484865Sobrien 405584865Sobrien op = elf64_ia64_operands + opnd; 4056218822Sdim err = (*op->insert) (op, val, &insn); 405784865Sobrien if (err) 405884865Sobrien return bfd_reloc_overflow; 405984865Sobrien 406084865Sobrien dword &= ~(0x1ffffffffffLL << shift); 406184865Sobrien dword |= (insn << shift); 4062218822Sdim bfd_putl64 (dword, hit_addr); 406384865Sobrien break; 406484865Sobrien 406584865Sobrien case IA64_OPND_NIL: 406684865Sobrien /* A data relocation. */ 406784865Sobrien if (bigendian) 406884865Sobrien if (size == 4) 406984865Sobrien bfd_putb32 (val, hit_addr); 407084865Sobrien else 407184865Sobrien bfd_putb64 (val, hit_addr); 407284865Sobrien else 407384865Sobrien if (size == 4) 407484865Sobrien bfd_putl32 (val, hit_addr); 407584865Sobrien else 407684865Sobrien bfd_putl64 (val, hit_addr); 407784865Sobrien break; 407884865Sobrien } 407984865Sobrien 408084865Sobrien return bfd_reloc_ok; 408184865Sobrien} 408284865Sobrien 408384865Sobrienstatic void 408484865SobrienelfNN_ia64_install_dyn_reloc (abfd, info, sec, srel, offset, type, 408584865Sobrien dynindx, addend) 408684865Sobrien bfd *abfd; 408784865Sobrien struct bfd_link_info *info; 408884865Sobrien asection *sec; 408984865Sobrien asection *srel; 409084865Sobrien bfd_vma offset; 409184865Sobrien unsigned int type; 409284865Sobrien long dynindx; 409384865Sobrien bfd_vma addend; 409484865Sobrien{ 409584865Sobrien Elf_Internal_Rela outrel; 4096130561Sobrien bfd_byte *loc; 409784865Sobrien 409884865Sobrien BFD_ASSERT (dynindx != -1); 409984865Sobrien outrel.r_info = ELFNN_R_INFO (dynindx, type); 410084865Sobrien outrel.r_addend = addend; 410189857Sobrien outrel.r_offset = _bfd_elf_section_offset (abfd, info, sec, offset); 4102130561Sobrien if (outrel.r_offset >= (bfd_vma) -2) 410384865Sobrien { 410489857Sobrien /* Run for the hills. We shouldn't be outputting a relocation 410589857Sobrien for this. So do what everyone else does and output a no-op. */ 410689857Sobrien outrel.r_info = ELFNN_R_INFO (0, R_IA64_NONE); 410789857Sobrien outrel.r_addend = 0; 410889857Sobrien outrel.r_offset = 0; 410984865Sobrien } 4110130561Sobrien else 4111130561Sobrien outrel.r_offset += sec->output_section->vma + sec->output_offset; 411284865Sobrien 4113130561Sobrien loc = srel->contents; 4114130561Sobrien loc += srel->reloc_count++ * sizeof (ElfNN_External_Rela); 4115130561Sobrien bfd_elfNN_swap_reloca_out (abfd, &outrel, loc); 4116218822Sdim BFD_ASSERT (sizeof (ElfNN_External_Rela) * srel->reloc_count <= srel->size); 411784865Sobrien} 411884865Sobrien 411984865Sobrien/* Store an entry for target address TARGET_ADDR in the linkage table 412084865Sobrien and return the gp-relative address of the linkage table entry. */ 412184865Sobrien 412284865Sobrienstatic bfd_vma 412384865Sobrienset_got_entry (abfd, info, dyn_i, dynindx, addend, value, dyn_r_type) 412484865Sobrien bfd *abfd; 412584865Sobrien struct bfd_link_info *info; 412684865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 412784865Sobrien long dynindx; 412884865Sobrien bfd_vma addend; 412984865Sobrien bfd_vma value; 413084865Sobrien unsigned int dyn_r_type; 413184865Sobrien{ 413284865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 413384865Sobrien asection *got_sec; 4134130561Sobrien bfd_boolean done; 4135104834Sobrien bfd_vma got_offset; 413684865Sobrien 413784865Sobrien ia64_info = elfNN_ia64_hash_table (info); 413884865Sobrien got_sec = ia64_info->got_sec; 413984865Sobrien 4140104834Sobrien switch (dyn_r_type) 414184865Sobrien { 4142104834Sobrien case R_IA64_TPREL64LSB: 4143104834Sobrien done = dyn_i->tprel_done; 4144130561Sobrien dyn_i->tprel_done = TRUE; 4145104834Sobrien got_offset = dyn_i->tprel_offset; 4146104834Sobrien break; 4147104834Sobrien case R_IA64_DTPMOD64LSB: 4148130561Sobrien if (dyn_i->dtpmod_offset != ia64_info->self_dtpmod_offset) 4149130561Sobrien { 4150130561Sobrien done = dyn_i->dtpmod_done; 4151130561Sobrien dyn_i->dtpmod_done = TRUE; 4152130561Sobrien } 4153130561Sobrien else 4154130561Sobrien { 4155130561Sobrien done = ia64_info->self_dtpmod_done; 4156130561Sobrien ia64_info->self_dtpmod_done = TRUE; 4157130561Sobrien dynindx = 0; 4158130561Sobrien } 4159104834Sobrien got_offset = dyn_i->dtpmod_offset; 4160104834Sobrien break; 4161218822Sdim case R_IA64_DTPREL32LSB: 4162104834Sobrien case R_IA64_DTPREL64LSB: 4163104834Sobrien done = dyn_i->dtprel_done; 4164130561Sobrien dyn_i->dtprel_done = TRUE; 4165104834Sobrien got_offset = dyn_i->dtprel_offset; 4166104834Sobrien break; 4167104834Sobrien default: 4168104834Sobrien done = dyn_i->got_done; 4169130561Sobrien dyn_i->got_done = TRUE; 4170104834Sobrien got_offset = dyn_i->got_offset; 4171104834Sobrien break; 4172104834Sobrien } 417384865Sobrien 4174104834Sobrien BFD_ASSERT ((got_offset & 7) == 0); 4175104834Sobrien 4176104834Sobrien if (! done) 4177104834Sobrien { 417884865Sobrien /* Store the target address in the linkage table entry. */ 4179104834Sobrien bfd_put_64 (abfd, value, got_sec->contents + got_offset); 418084865Sobrien 418184865Sobrien /* Install a dynamic relocation if needed. */ 4182130561Sobrien if (((info->shared 4183130561Sobrien && (!dyn_i->h 4184130561Sobrien || ELF_ST_VISIBILITY (dyn_i->h->other) == STV_DEFAULT 4185130561Sobrien || dyn_i->h->root.type != bfd_link_hash_undefweak) 4186218822Sdim && dyn_r_type != R_IA64_DTPREL32LSB 4187130561Sobrien && dyn_r_type != R_IA64_DTPREL64LSB) 4188130561Sobrien || elfNN_ia64_dynamic_symbol_p (dyn_i->h, info, dyn_r_type) 4189218822Sdim || (dynindx != -1 4190218822Sdim && (dyn_r_type == R_IA64_FPTR32LSB 4191218822Sdim || dyn_r_type == R_IA64_FPTR64LSB))) 4192130561Sobrien && (!dyn_i->want_ltoff_fptr 4193130561Sobrien || !info->pie 4194130561Sobrien || !dyn_i->h 4195130561Sobrien || dyn_i->h->root.type != bfd_link_hash_undefweak)) 419684865Sobrien { 4197104834Sobrien if (dynindx == -1 4198104834Sobrien && dyn_r_type != R_IA64_TPREL64LSB 4199104834Sobrien && dyn_r_type != R_IA64_DTPMOD64LSB 4200218822Sdim && dyn_r_type != R_IA64_DTPREL32LSB 4201104834Sobrien && dyn_r_type != R_IA64_DTPREL64LSB) 420284865Sobrien { 4203218822Sdim dyn_r_type = R_IA64_RELNNLSB; 420484865Sobrien dynindx = 0; 420584865Sobrien addend = value; 420684865Sobrien } 420784865Sobrien 420884865Sobrien if (bfd_big_endian (abfd)) 420984865Sobrien { 421084865Sobrien switch (dyn_r_type) 421184865Sobrien { 4212218822Sdim case R_IA64_REL32LSB: 4213218822Sdim dyn_r_type = R_IA64_REL32MSB; 4214218822Sdim break; 4215218822Sdim case R_IA64_DIR32LSB: 4216218822Sdim dyn_r_type = R_IA64_DIR32MSB; 4217218822Sdim break; 4218218822Sdim case R_IA64_FPTR32LSB: 4219218822Sdim dyn_r_type = R_IA64_FPTR32MSB; 4220218822Sdim break; 4221218822Sdim case R_IA64_DTPREL32LSB: 4222218822Sdim dyn_r_type = R_IA64_DTPREL32MSB; 4223218822Sdim break; 422484865Sobrien case R_IA64_REL64LSB: 422584865Sobrien dyn_r_type = R_IA64_REL64MSB; 422684865Sobrien break; 422784865Sobrien case R_IA64_DIR64LSB: 422884865Sobrien dyn_r_type = R_IA64_DIR64MSB; 422984865Sobrien break; 423084865Sobrien case R_IA64_FPTR64LSB: 423184865Sobrien dyn_r_type = R_IA64_FPTR64MSB; 423284865Sobrien break; 4233104834Sobrien case R_IA64_TPREL64LSB: 4234104834Sobrien dyn_r_type = R_IA64_TPREL64MSB; 4235104834Sobrien break; 4236104834Sobrien case R_IA64_DTPMOD64LSB: 4237104834Sobrien dyn_r_type = R_IA64_DTPMOD64MSB; 4238104834Sobrien break; 4239104834Sobrien case R_IA64_DTPREL64LSB: 4240104834Sobrien dyn_r_type = R_IA64_DTPREL64MSB; 4241104834Sobrien break; 424284865Sobrien default: 4243130561Sobrien BFD_ASSERT (FALSE); 424484865Sobrien break; 424584865Sobrien } 424684865Sobrien } 424784865Sobrien 424884865Sobrien elfNN_ia64_install_dyn_reloc (abfd, NULL, got_sec, 424984865Sobrien ia64_info->rel_got_sec, 4250104834Sobrien got_offset, dyn_r_type, 425184865Sobrien dynindx, addend); 425284865Sobrien } 425384865Sobrien } 425484865Sobrien 425584865Sobrien /* Return the address of the linkage table entry. */ 425684865Sobrien value = (got_sec->output_section->vma 425784865Sobrien + got_sec->output_offset 4258104834Sobrien + got_offset); 425984865Sobrien 426084865Sobrien return value; 426184865Sobrien} 426284865Sobrien 426384865Sobrien/* Fill in a function descriptor consisting of the function's code 426484865Sobrien address and its global pointer. Return the descriptor's address. */ 426584865Sobrien 426684865Sobrienstatic bfd_vma 426784865Sobrienset_fptr_entry (abfd, info, dyn_i, value) 426884865Sobrien bfd *abfd; 426984865Sobrien struct bfd_link_info *info; 427084865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 427184865Sobrien bfd_vma value; 427284865Sobrien{ 427384865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 427484865Sobrien asection *fptr_sec; 427584865Sobrien 427684865Sobrien ia64_info = elfNN_ia64_hash_table (info); 427784865Sobrien fptr_sec = ia64_info->fptr_sec; 427884865Sobrien 427984865Sobrien if (!dyn_i->fptr_done) 428084865Sobrien { 428184865Sobrien dyn_i->fptr_done = 1; 428284865Sobrien 428384865Sobrien /* Fill in the function descriptor. */ 428484865Sobrien bfd_put_64 (abfd, value, fptr_sec->contents + dyn_i->fptr_offset); 428584865Sobrien bfd_put_64 (abfd, _bfd_get_gp_value (abfd), 428684865Sobrien fptr_sec->contents + dyn_i->fptr_offset + 8); 4287130561Sobrien if (ia64_info->rel_fptr_sec) 4288130561Sobrien { 4289130561Sobrien Elf_Internal_Rela outrel; 4290130561Sobrien bfd_byte *loc; 4291130561Sobrien 4292130561Sobrien if (bfd_little_endian (abfd)) 4293130561Sobrien outrel.r_info = ELFNN_R_INFO (0, R_IA64_IPLTLSB); 4294130561Sobrien else 4295130561Sobrien outrel.r_info = ELFNN_R_INFO (0, R_IA64_IPLTMSB); 4296130561Sobrien outrel.r_addend = value; 4297130561Sobrien outrel.r_offset = (fptr_sec->output_section->vma 4298130561Sobrien + fptr_sec->output_offset 4299130561Sobrien + dyn_i->fptr_offset); 4300130561Sobrien loc = ia64_info->rel_fptr_sec->contents; 4301130561Sobrien loc += ia64_info->rel_fptr_sec->reloc_count++ 4302130561Sobrien * sizeof (ElfNN_External_Rela); 4303130561Sobrien bfd_elfNN_swap_reloca_out (abfd, &outrel, loc); 4304130561Sobrien } 430584865Sobrien } 430684865Sobrien 430784865Sobrien /* Return the descriptor's address. */ 430884865Sobrien value = (fptr_sec->output_section->vma 430984865Sobrien + fptr_sec->output_offset 431084865Sobrien + dyn_i->fptr_offset); 431184865Sobrien 431284865Sobrien return value; 431384865Sobrien} 431484865Sobrien 431584865Sobrien/* Fill in a PLTOFF entry consisting of the function's code address 431684865Sobrien and its global pointer. Return the descriptor's address. */ 431784865Sobrien 431884865Sobrienstatic bfd_vma 431984865Sobrienset_pltoff_entry (abfd, info, dyn_i, value, is_plt) 432084865Sobrien bfd *abfd; 432184865Sobrien struct bfd_link_info *info; 432284865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 432384865Sobrien bfd_vma value; 4324130561Sobrien bfd_boolean is_plt; 432584865Sobrien{ 432684865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 432784865Sobrien asection *pltoff_sec; 432884865Sobrien 432984865Sobrien ia64_info = elfNN_ia64_hash_table (info); 433084865Sobrien pltoff_sec = ia64_info->pltoff_sec; 433184865Sobrien 433284865Sobrien /* Don't do anything if this symbol uses a real PLT entry. In 433384865Sobrien that case, we'll fill this in during finish_dynamic_symbol. */ 433484865Sobrien if ((! dyn_i->want_plt || is_plt) 433584865Sobrien && !dyn_i->pltoff_done) 433684865Sobrien { 433784865Sobrien bfd_vma gp = _bfd_get_gp_value (abfd); 433884865Sobrien 433984865Sobrien /* Fill in the function descriptor. */ 434084865Sobrien bfd_put_64 (abfd, value, pltoff_sec->contents + dyn_i->pltoff_offset); 434184865Sobrien bfd_put_64 (abfd, gp, pltoff_sec->contents + dyn_i->pltoff_offset + 8); 434284865Sobrien 434384865Sobrien /* Install dynamic relocations if needed. */ 4344130561Sobrien if (!is_plt 4345130561Sobrien && info->shared 4346130561Sobrien && (!dyn_i->h 4347130561Sobrien || ELF_ST_VISIBILITY (dyn_i->h->other) == STV_DEFAULT 4348130561Sobrien || dyn_i->h->root.type != bfd_link_hash_undefweak)) 434984865Sobrien { 435084865Sobrien unsigned int dyn_r_type; 435184865Sobrien 435284865Sobrien if (bfd_big_endian (abfd)) 4353218822Sdim dyn_r_type = R_IA64_RELNNMSB; 435484865Sobrien else 4355218822Sdim dyn_r_type = R_IA64_RELNNLSB; 435684865Sobrien 435784865Sobrien elfNN_ia64_install_dyn_reloc (abfd, NULL, pltoff_sec, 435884865Sobrien ia64_info->rel_pltoff_sec, 435984865Sobrien dyn_i->pltoff_offset, 436084865Sobrien dyn_r_type, 0, value); 436184865Sobrien elfNN_ia64_install_dyn_reloc (abfd, NULL, pltoff_sec, 436284865Sobrien ia64_info->rel_pltoff_sec, 4363218822Sdim dyn_i->pltoff_offset + ARCH_SIZE / 8, 436484865Sobrien dyn_r_type, 0, gp); 436584865Sobrien } 436684865Sobrien 436784865Sobrien dyn_i->pltoff_done = 1; 436884865Sobrien } 436984865Sobrien 437084865Sobrien /* Return the descriptor's address. */ 437184865Sobrien value = (pltoff_sec->output_section->vma 437284865Sobrien + pltoff_sec->output_offset 437384865Sobrien + dyn_i->pltoff_offset); 437484865Sobrien 437584865Sobrien return value; 437684865Sobrien} 437784865Sobrien 4378104834Sobrien/* Return the base VMA address which should be subtracted from real addresses 4379104834Sobrien when resolving @tprel() relocation. 4380104834Sobrien Main program TLS (whose template starts at PT_TLS p_vaddr) 4381218822Sdim is assigned offset round(2 * size of pointer, PT_TLS p_align). */ 4382104834Sobrien 4383104834Sobrienstatic bfd_vma 4384104834SobrienelfNN_ia64_tprel_base (info) 4385104834Sobrien struct bfd_link_info *info; 4386104834Sobrien{ 4387130561Sobrien asection *tls_sec = elf_hash_table (info)->tls_sec; 4388104834Sobrien 4389130561Sobrien BFD_ASSERT (tls_sec != NULL); 4390218822Sdim return tls_sec->vma - align_power ((bfd_vma) ARCH_SIZE / 4, 4391218822Sdim tls_sec->alignment_power); 4392104834Sobrien} 4393104834Sobrien 4394104834Sobrien/* Return the base VMA address which should be subtracted from real addresses 4395104834Sobrien when resolving @dtprel() relocation. 4396104834Sobrien This is PT_TLS segment p_vaddr. */ 4397104834Sobrien 4398104834Sobrienstatic bfd_vma 4399104834SobrienelfNN_ia64_dtprel_base (info) 4400104834Sobrien struct bfd_link_info *info; 4401104834Sobrien{ 4402130561Sobrien BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL); 4403130561Sobrien return elf_hash_table (info)->tls_sec->vma; 4404104834Sobrien} 4405104834Sobrien 440684865Sobrien/* Called through qsort to sort the .IA_64.unwind section during a 440784865Sobrien non-relocatable link. Set elfNN_ia64_unwind_entry_compare_bfd 440884865Sobrien to the output bfd so we can do proper endianness frobbing. */ 440984865Sobrien 441084865Sobrienstatic bfd *elfNN_ia64_unwind_entry_compare_bfd; 441184865Sobrien 441284865Sobrienstatic int 441384865SobrienelfNN_ia64_unwind_entry_compare (a, b) 441489857Sobrien const PTR a; 441589857Sobrien const PTR b; 441684865Sobrien{ 441784865Sobrien bfd_vma av, bv; 441884865Sobrien 441984865Sobrien av = bfd_get_64 (elfNN_ia64_unwind_entry_compare_bfd, a); 442084865Sobrien bv = bfd_get_64 (elfNN_ia64_unwind_entry_compare_bfd, b); 442184865Sobrien 442284865Sobrien return (av < bv ? -1 : av > bv ? 1 : 0); 442384865Sobrien} 442484865Sobrien 4425130561Sobrien/* Make sure we've got ourselves a nice fat __gp value. */ 4426130561Sobrienstatic bfd_boolean 4427130561SobrienelfNN_ia64_choose_gp (abfd, info) 442884865Sobrien bfd *abfd; 442984865Sobrien struct bfd_link_info *info; 443084865Sobrien{ 4431130561Sobrien bfd_vma min_vma = (bfd_vma) -1, max_vma = 0; 4432130561Sobrien bfd_vma min_short_vma = min_vma, max_short_vma = 0; 4433130561Sobrien struct elf_link_hash_entry *gp; 4434130561Sobrien bfd_vma gp_val; 4435130561Sobrien asection *os; 443684865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 443784865Sobrien 443884865Sobrien ia64_info = elfNN_ia64_hash_table (info); 443984865Sobrien 4440130561Sobrien /* Find the min and max vma of all sections marked short. Also collect 4441130561Sobrien min and max vma of any type, for use in selecting a nice gp. */ 4442130561Sobrien for (os = abfd->sections; os ; os = os->next) 444384865Sobrien { 4444130561Sobrien bfd_vma lo, hi; 444584865Sobrien 4446130561Sobrien if ((os->flags & SEC_ALLOC) == 0) 4447130561Sobrien continue; 4448130561Sobrien 4449130561Sobrien lo = os->vma; 4450218822Sdim hi = os->vma + (os->rawsize ? os->rawsize : os->size); 4451130561Sobrien if (hi < lo) 4452130561Sobrien hi = (bfd_vma) -1; 4453130561Sobrien 4454130561Sobrien if (min_vma > lo) 4455130561Sobrien min_vma = lo; 4456130561Sobrien if (max_vma < hi) 4457130561Sobrien max_vma = hi; 4458130561Sobrien if (os->flags & SEC_SMALL_DATA) 445984865Sobrien { 4460130561Sobrien if (min_short_vma > lo) 4461130561Sobrien min_short_vma = lo; 4462130561Sobrien if (max_short_vma < hi) 4463130561Sobrien max_short_vma = hi; 4464130561Sobrien } 4465130561Sobrien } 446684865Sobrien 4467130561Sobrien /* See if the user wants to force a value. */ 4468130561Sobrien gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE, 4469130561Sobrien FALSE, FALSE); 447084865Sobrien 4471130561Sobrien if (gp 4472130561Sobrien && (gp->root.type == bfd_link_hash_defined 4473130561Sobrien || gp->root.type == bfd_link_hash_defweak)) 4474130561Sobrien { 4475130561Sobrien asection *gp_sec = gp->root.u.def.section; 4476130561Sobrien gp_val = (gp->root.u.def.value 4477130561Sobrien + gp_sec->output_section->vma 4478130561Sobrien + gp_sec->output_offset); 4479130561Sobrien } 4480130561Sobrien else 4481130561Sobrien { 4482130561Sobrien /* Pick a sensible value. */ 448384865Sobrien 4484130561Sobrien asection *got_sec = ia64_info->got_sec; 4485130561Sobrien 4486130561Sobrien /* Start with just the address of the .got. */ 4487130561Sobrien if (got_sec) 4488130561Sobrien gp_val = got_sec->output_section->vma; 4489130561Sobrien else if (max_short_vma != 0) 4490130561Sobrien gp_val = min_short_vma; 4491218822Sdim else if (max_vma - min_vma < 0x200000) 4492218822Sdim gp_val = min_vma; 4493130561Sobrien else 4494218822Sdim gp_val = max_vma - 0x200000 + 8; 4495130561Sobrien 4496130561Sobrien /* If it is possible to address the entire image, but we 4497130561Sobrien don't with the choice above, adjust. */ 4498130561Sobrien if (max_vma - min_vma < 0x400000 4499218822Sdim && (max_vma - gp_val >= 0x200000 4500218822Sdim || gp_val - min_vma > 0x200000)) 4501130561Sobrien gp_val = min_vma + 0x200000; 4502130561Sobrien else if (max_short_vma != 0) 4503130561Sobrien { 4504130561Sobrien /* If we don't cover all the short data, adjust. */ 4505130561Sobrien if (max_short_vma - gp_val >= 0x200000) 4506130561Sobrien gp_val = min_short_vma + 0x200000; 4507130561Sobrien 4508130561Sobrien /* If we're addressing stuff past the end, adjust back. */ 4509130561Sobrien if (gp_val > max_vma) 4510130561Sobrien gp_val = max_vma - 0x200000 + 8; 451184865Sobrien } 4512130561Sobrien } 451384865Sobrien 4514130561Sobrien /* Validate whether all SHF_IA_64_SHORT sections are within 4515130561Sobrien range of the chosen GP. */ 451684865Sobrien 4517130561Sobrien if (max_short_vma != 0) 4518130561Sobrien { 4519130561Sobrien if (max_short_vma - min_short_vma >= 0x400000) 452084865Sobrien { 4521130561Sobrien (*_bfd_error_handler) 4522130561Sobrien (_("%s: short data segment overflowed (0x%lx >= 0x400000)"), 4523130561Sobrien bfd_get_filename (abfd), 4524130561Sobrien (unsigned long) (max_short_vma - min_short_vma)); 4525130561Sobrien return FALSE; 452684865Sobrien } 4527130561Sobrien else if ((gp_val > min_short_vma 4528130561Sobrien && gp_val - min_short_vma > 0x200000) 4529130561Sobrien || (gp_val < max_short_vma 4530130561Sobrien && max_short_vma - gp_val >= 0x200000)) 453184865Sobrien { 4532130561Sobrien (*_bfd_error_handler) 4533130561Sobrien (_("%s: __gp does not cover short data segment"), 4534130561Sobrien bfd_get_filename (abfd)); 4535130561Sobrien return FALSE; 4536130561Sobrien } 4537130561Sobrien } 453884865Sobrien 4539130561Sobrien _bfd_set_gp_value (abfd, gp_val); 454084865Sobrien 4541130561Sobrien return TRUE; 4542130561Sobrien} 454384865Sobrien 4544130561Sobrienstatic bfd_boolean 4545130561SobrienelfNN_ia64_final_link (abfd, info) 4546130561Sobrien bfd *abfd; 4547130561Sobrien struct bfd_link_info *info; 4548130561Sobrien{ 4549130561Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 4550130561Sobrien asection *unwind_output_sec; 455184865Sobrien 4552130561Sobrien ia64_info = elfNN_ia64_hash_table (info); 455384865Sobrien 4554130561Sobrien /* Make sure we've got ourselves a nice fat __gp value. */ 4555130561Sobrien if (!info->relocatable) 4556130561Sobrien { 4557218822Sdim bfd_vma gp_val; 4558130561Sobrien struct elf_link_hash_entry *gp; 455984865Sobrien 4560218822Sdim /* We assume after gp is set, section size will only decrease. We 4561218822Sdim need to adjust gp for it. */ 4562218822Sdim _bfd_set_gp_value (abfd, 0); 4563218822Sdim if (! elfNN_ia64_choose_gp (abfd, info)) 4564218822Sdim return FALSE; 4565218822Sdim gp_val = _bfd_get_gp_value (abfd); 456684865Sobrien 4567130561Sobrien gp = elf_link_hash_lookup (elf_hash_table (info), "__gp", FALSE, 4568130561Sobrien FALSE, FALSE); 456984865Sobrien if (gp) 457084865Sobrien { 457184865Sobrien gp->root.type = bfd_link_hash_defined; 457284865Sobrien gp->root.u.def.value = gp_val; 457384865Sobrien gp->root.u.def.section = bfd_abs_section_ptr; 457484865Sobrien } 457584865Sobrien } 457684865Sobrien 457784865Sobrien /* If we're producing a final executable, we need to sort the contents 457884865Sobrien of the .IA_64.unwind section. Force this section to be relocated 457984865Sobrien into memory rather than written immediately to the output file. */ 458084865Sobrien unwind_output_sec = NULL; 4581130561Sobrien if (!info->relocatable) 458284865Sobrien { 458384865Sobrien asection *s = bfd_get_section_by_name (abfd, ELF_STRING_ia64_unwind); 458484865Sobrien if (s) 458584865Sobrien { 458684865Sobrien unwind_output_sec = s->output_section; 458784865Sobrien unwind_output_sec->contents 4588218822Sdim = bfd_malloc (unwind_output_sec->size); 458984865Sobrien if (unwind_output_sec->contents == NULL) 4590130561Sobrien return FALSE; 459184865Sobrien } 459284865Sobrien } 459384865Sobrien 459484865Sobrien /* Invoke the regular ELF backend linker to do all the work. */ 4595130561Sobrien if (!bfd_elf_final_link (abfd, info)) 4596130561Sobrien return FALSE; 459784865Sobrien 459884865Sobrien if (unwind_output_sec) 459984865Sobrien { 460084865Sobrien elfNN_ia64_unwind_entry_compare_bfd = abfd; 460189857Sobrien qsort (unwind_output_sec->contents, 4602218822Sdim (size_t) (unwind_output_sec->size / 24), 460389857Sobrien 24, 460489857Sobrien elfNN_ia64_unwind_entry_compare); 460584865Sobrien 460684865Sobrien if (! bfd_set_section_contents (abfd, unwind_output_sec, 460789857Sobrien unwind_output_sec->contents, (bfd_vma) 0, 4608218822Sdim unwind_output_sec->size)) 4609130561Sobrien return FALSE; 461084865Sobrien } 461184865Sobrien 4612130561Sobrien return TRUE; 461384865Sobrien} 461484865Sobrien 4615130561Sobrienstatic bfd_boolean 461684865SobrienelfNN_ia64_relocate_section (output_bfd, info, input_bfd, input_section, 461784865Sobrien contents, relocs, local_syms, local_sections) 461884865Sobrien bfd *output_bfd; 461984865Sobrien struct bfd_link_info *info; 462084865Sobrien bfd *input_bfd; 462184865Sobrien asection *input_section; 462284865Sobrien bfd_byte *contents; 462384865Sobrien Elf_Internal_Rela *relocs; 462484865Sobrien Elf_Internal_Sym *local_syms; 462584865Sobrien asection **local_sections; 462684865Sobrien{ 462784865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 462884865Sobrien Elf_Internal_Shdr *symtab_hdr; 462984865Sobrien Elf_Internal_Rela *rel; 463084865Sobrien Elf_Internal_Rela *relend; 463184865Sobrien asection *srel; 4632130561Sobrien bfd_boolean ret_val = TRUE; /* for non-fatal errors */ 463384865Sobrien bfd_vma gp_val; 463484865Sobrien 463584865Sobrien symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; 463684865Sobrien ia64_info = elfNN_ia64_hash_table (info); 463784865Sobrien 463884865Sobrien /* Infect various flags from the input section to the output section. */ 4639130561Sobrien if (info->relocatable) 464084865Sobrien { 464184865Sobrien bfd_vma flags; 464284865Sobrien 464384865Sobrien flags = elf_section_data(input_section)->this_hdr.sh_flags; 464484865Sobrien flags &= SHF_IA_64_NORECOV; 464584865Sobrien 464684865Sobrien elf_section_data(input_section->output_section) 464784865Sobrien ->this_hdr.sh_flags |= flags; 464884865Sobrien } 464984865Sobrien 465084865Sobrien gp_val = _bfd_get_gp_value (output_bfd); 4651130561Sobrien srel = get_reloc_section (input_bfd, ia64_info, input_section, FALSE); 465284865Sobrien 465384865Sobrien rel = relocs; 465484865Sobrien relend = relocs + input_section->reloc_count; 465584865Sobrien for (; rel < relend; ++rel) 465684865Sobrien { 465784865Sobrien struct elf_link_hash_entry *h; 465884865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 465984865Sobrien bfd_reloc_status_type r; 466084865Sobrien reloc_howto_type *howto; 466184865Sobrien unsigned long r_symndx; 466284865Sobrien Elf_Internal_Sym *sym; 466384865Sobrien unsigned int r_type; 466484865Sobrien bfd_vma value; 466584865Sobrien asection *sym_sec; 466684865Sobrien bfd_byte *hit_addr; 4667130561Sobrien bfd_boolean dynamic_symbol_p; 4668130561Sobrien bfd_boolean undef_weak_ref; 466984865Sobrien 467084865Sobrien r_type = ELFNN_R_TYPE (rel->r_info); 467184865Sobrien if (r_type > R_IA64_MAX_RELOC_CODE) 467284865Sobrien { 467384865Sobrien (*_bfd_error_handler) 4674218822Sdim (_("%B: unknown relocation type %d"), 4675218822Sdim input_bfd, (int) r_type); 467684865Sobrien bfd_set_error (bfd_error_bad_value); 4677130561Sobrien ret_val = FALSE; 467884865Sobrien continue; 467984865Sobrien } 468099461Sobrien 468184865Sobrien howto = lookup_howto (r_type); 468284865Sobrien r_symndx = ELFNN_R_SYM (rel->r_info); 468384865Sobrien h = NULL; 468484865Sobrien sym = NULL; 468584865Sobrien sym_sec = NULL; 4686130561Sobrien undef_weak_ref = FALSE; 468784865Sobrien 468884865Sobrien if (r_symndx < symtab_hdr->sh_info) 468984865Sobrien { 469084865Sobrien /* Reloc against local symbol. */ 4691130561Sobrien asection *msec; 469284865Sobrien sym = local_syms + r_symndx; 469384865Sobrien sym_sec = local_sections[r_symndx]; 4694130561Sobrien msec = sym_sec; 4695130561Sobrien value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel); 4696218822Sdim if (!info->relocatable 4697218822Sdim && (sym_sec->flags & SEC_MERGE) != 0 469889857Sobrien && ELF_ST_TYPE (sym->st_info) == STT_SECTION 4699130561Sobrien && sym_sec->sec_info_type == ELF_INFO_TYPE_MERGE) 470089857Sobrien { 470189857Sobrien struct elfNN_ia64_local_hash_entry *loc_h; 4702130561Sobrien 4703130561Sobrien loc_h = get_local_sym_hash (ia64_info, input_bfd, rel, FALSE); 470489857Sobrien if (loc_h && ! loc_h->sec_merge_done) 470589857Sobrien { 470689857Sobrien struct elfNN_ia64_dyn_sym_info *dynent; 4707218822Sdim unsigned int count; 470889857Sobrien 4709218822Sdim for (count = loc_h->count, dynent = loc_h->info; 4710218822Sdim count != 0; 4711218822Sdim count--, dynent++) 471289857Sobrien { 471389857Sobrien msec = sym_sec; 471489857Sobrien dynent->addend = 471589857Sobrien _bfd_merged_section_offset (output_bfd, &msec, 471689857Sobrien elf_section_data (msec)-> 471789857Sobrien sec_info, 471889857Sobrien sym->st_value 4719218822Sdim + dynent->addend); 472089857Sobrien dynent->addend -= sym->st_value; 472189857Sobrien dynent->addend += msec->output_section->vma 472289857Sobrien + msec->output_offset 472389857Sobrien - sym_sec->output_section->vma 472489857Sobrien - sym_sec->output_offset; 472589857Sobrien } 4726218822Sdim 4727218822Sdim /* We may have introduced duplicated entries. We need 4728218822Sdim to remove them properly. */ 4729218822Sdim count = sort_dyn_sym_info (loc_h->info, loc_h->count); 4730218822Sdim if (count != loc_h->count) 4731218822Sdim { 4732218822Sdim loc_h->count = count; 4733218822Sdim loc_h->sorted_count = count; 4734218822Sdim } 4735218822Sdim 473689857Sobrien loc_h->sec_merge_done = 1; 473789857Sobrien } 473889857Sobrien } 473984865Sobrien } 474084865Sobrien else 474184865Sobrien { 4742130561Sobrien bfd_boolean unresolved_reloc; 4743130561Sobrien bfd_boolean warned; 4744130561Sobrien struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd); 474584865Sobrien 4746130561Sobrien RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, 4747130561Sobrien r_symndx, symtab_hdr, sym_hashes, 4748130561Sobrien h, sym_sec, value, 4749130561Sobrien unresolved_reloc, warned); 475084865Sobrien 4751130561Sobrien if (h->root.type == bfd_link_hash_undefweak) 4752130561Sobrien undef_weak_ref = TRUE; 4753130561Sobrien else if (warned) 4754130561Sobrien continue; 475584865Sobrien } 475684865Sobrien 4757218822Sdim /* For relocs against symbols from removed linkonce sections, 4758218822Sdim or sections discarded by a linker script, we just want the 4759218822Sdim section contents zeroed. Avoid any special processing. */ 4760218822Sdim if (sym_sec != NULL && elf_discarded_section (sym_sec)) 4761218822Sdim { 4762218822Sdim _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); 4763218822Sdim rel->r_info = 0; 4764218822Sdim rel->r_addend = 0; 4765218822Sdim continue; 4766218822Sdim } 4767218822Sdim 4768218822Sdim if (info->relocatable) 4769218822Sdim continue; 4770218822Sdim 477184865Sobrien hit_addr = contents + rel->r_offset; 477284865Sobrien value += rel->r_addend; 4773130561Sobrien dynamic_symbol_p = elfNN_ia64_dynamic_symbol_p (h, info, r_type); 477484865Sobrien 477584865Sobrien switch (r_type) 477684865Sobrien { 477784865Sobrien case R_IA64_NONE: 477884865Sobrien case R_IA64_LDXMOV: 477984865Sobrien continue; 478084865Sobrien 478184865Sobrien case R_IA64_IMM14: 478284865Sobrien case R_IA64_IMM22: 478384865Sobrien case R_IA64_IMM64: 478484865Sobrien case R_IA64_DIR32MSB: 478584865Sobrien case R_IA64_DIR32LSB: 478684865Sobrien case R_IA64_DIR64MSB: 478784865Sobrien case R_IA64_DIR64LSB: 478884865Sobrien /* Install a dynamic relocation for this reloc. */ 4789130561Sobrien if ((dynamic_symbol_p || info->shared) 479089857Sobrien && r_symndx != 0 479184865Sobrien && (input_section->flags & SEC_ALLOC) != 0) 479284865Sobrien { 479384865Sobrien unsigned int dyn_r_type; 479484865Sobrien long dynindx; 479584865Sobrien bfd_vma addend; 479684865Sobrien 479784865Sobrien BFD_ASSERT (srel != NULL); 479884865Sobrien 4799130561Sobrien switch (r_type) 4800130561Sobrien { 4801130561Sobrien case R_IA64_IMM14: 4802130561Sobrien case R_IA64_IMM22: 4803130561Sobrien case R_IA64_IMM64: 4804130561Sobrien /* ??? People shouldn't be doing non-pic code in 4805130561Sobrien shared libraries nor dynamic executables. */ 4806130561Sobrien (*_bfd_error_handler) 4807218822Sdim (_("%B: non-pic code with imm relocation against dynamic symbol `%s'"), 4808218822Sdim input_bfd, 4809218822Sdim h ? h->root.root.string 4810218822Sdim : bfd_elf_sym_name (input_bfd, symtab_hdr, sym, 4811218822Sdim sym_sec)); 4812130561Sobrien ret_val = FALSE; 4813130561Sobrien continue; 4814130561Sobrien 4815130561Sobrien default: 4816130561Sobrien break; 4817130561Sobrien } 4818130561Sobrien 481984865Sobrien /* If we don't need dynamic symbol lookup, find a 482084865Sobrien matching RELATIVE relocation. */ 482184865Sobrien dyn_r_type = r_type; 482284865Sobrien if (dynamic_symbol_p) 482384865Sobrien { 482484865Sobrien dynindx = h->dynindx; 482584865Sobrien addend = rel->r_addend; 482684865Sobrien value = 0; 482784865Sobrien } 482884865Sobrien else 482984865Sobrien { 483084865Sobrien switch (r_type) 483184865Sobrien { 483284865Sobrien case R_IA64_DIR32MSB: 483384865Sobrien dyn_r_type = R_IA64_REL32MSB; 483484865Sobrien break; 483584865Sobrien case R_IA64_DIR32LSB: 483684865Sobrien dyn_r_type = R_IA64_REL32LSB; 483784865Sobrien break; 483884865Sobrien case R_IA64_DIR64MSB: 483984865Sobrien dyn_r_type = R_IA64_REL64MSB; 484084865Sobrien break; 484184865Sobrien case R_IA64_DIR64LSB: 484284865Sobrien dyn_r_type = R_IA64_REL64LSB; 484384865Sobrien break; 484484865Sobrien 484584865Sobrien default: 4846130561Sobrien break; 484784865Sobrien } 484884865Sobrien dynindx = 0; 484984865Sobrien addend = value; 485084865Sobrien } 485184865Sobrien 485284865Sobrien elfNN_ia64_install_dyn_reloc (output_bfd, info, input_section, 485384865Sobrien srel, rel->r_offset, dyn_r_type, 485484865Sobrien dynindx, addend); 485584865Sobrien } 4856130561Sobrien /* Fall through. */ 485784865Sobrien 485884865Sobrien case R_IA64_LTV32MSB: 485984865Sobrien case R_IA64_LTV32LSB: 486084865Sobrien case R_IA64_LTV64MSB: 486184865Sobrien case R_IA64_LTV64LSB: 4862218822Sdim r = elfNN_ia64_install_value (hit_addr, value, r_type); 486384865Sobrien break; 486484865Sobrien 486584865Sobrien case R_IA64_GPREL22: 486684865Sobrien case R_IA64_GPREL64I: 486784865Sobrien case R_IA64_GPREL32MSB: 486884865Sobrien case R_IA64_GPREL32LSB: 486984865Sobrien case R_IA64_GPREL64MSB: 487084865Sobrien case R_IA64_GPREL64LSB: 487184865Sobrien if (dynamic_symbol_p) 487284865Sobrien { 487384865Sobrien (*_bfd_error_handler) 4874218822Sdim (_("%B: @gprel relocation against dynamic symbol %s"), 4875218822Sdim input_bfd, 4876218822Sdim h ? h->root.root.string 4877218822Sdim : bfd_elf_sym_name (input_bfd, symtab_hdr, sym, 4878218822Sdim sym_sec)); 4879130561Sobrien ret_val = FALSE; 488084865Sobrien continue; 488184865Sobrien } 488284865Sobrien value -= gp_val; 4883218822Sdim r = elfNN_ia64_install_value (hit_addr, value, r_type); 488484865Sobrien break; 488584865Sobrien 488684865Sobrien case R_IA64_LTOFF22: 488784865Sobrien case R_IA64_LTOFF22X: 488884865Sobrien case R_IA64_LTOFF64I: 4889130561Sobrien dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE); 489084865Sobrien value = set_got_entry (input_bfd, info, dyn_i, (h ? h->dynindx : -1), 4891218822Sdim rel->r_addend, value, R_IA64_DIRNNLSB); 489284865Sobrien value -= gp_val; 4893218822Sdim r = elfNN_ia64_install_value (hit_addr, value, r_type); 489484865Sobrien break; 489584865Sobrien 489684865Sobrien case R_IA64_PLTOFF22: 489784865Sobrien case R_IA64_PLTOFF64I: 489884865Sobrien case R_IA64_PLTOFF64MSB: 489984865Sobrien case R_IA64_PLTOFF64LSB: 4900130561Sobrien dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE); 4901130561Sobrien value = set_pltoff_entry (output_bfd, info, dyn_i, value, FALSE); 490284865Sobrien value -= gp_val; 4903218822Sdim r = elfNN_ia64_install_value (hit_addr, value, r_type); 490484865Sobrien break; 490584865Sobrien 490684865Sobrien case R_IA64_FPTR64I: 490784865Sobrien case R_IA64_FPTR32MSB: 490884865Sobrien case R_IA64_FPTR32LSB: 490984865Sobrien case R_IA64_FPTR64MSB: 491084865Sobrien case R_IA64_FPTR64LSB: 4911130561Sobrien dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE); 491284865Sobrien if (dyn_i->want_fptr) 491384865Sobrien { 491484865Sobrien if (!undef_weak_ref) 491584865Sobrien value = set_fptr_entry (output_bfd, info, dyn_i, value); 491684865Sobrien } 4917130561Sobrien if (!dyn_i->want_fptr || info->pie) 491884865Sobrien { 491984865Sobrien long dynindx; 4920130561Sobrien unsigned int dyn_r_type = r_type; 4921130561Sobrien bfd_vma addend = rel->r_addend; 492284865Sobrien 492384865Sobrien /* Otherwise, we expect the dynamic linker to create 492484865Sobrien the entry. */ 492584865Sobrien 4926130561Sobrien if (dyn_i->want_fptr) 492784865Sobrien { 4928130561Sobrien if (r_type == R_IA64_FPTR64I) 4929130561Sobrien { 4930130561Sobrien /* We can't represent this without a dynamic symbol. 4931130561Sobrien Adjust the relocation to be against an output 4932130561Sobrien section symbol, which are always present in the 4933130561Sobrien dynamic symbol table. */ 4934130561Sobrien /* ??? People shouldn't be doing non-pic code in 4935130561Sobrien shared libraries. Hork. */ 4936130561Sobrien (*_bfd_error_handler) 4937218822Sdim (_("%B: linking non-pic code in a position independent executable"), 4938218822Sdim input_bfd); 4939130561Sobrien ret_val = FALSE; 4940130561Sobrien continue; 4941130561Sobrien } 4942130561Sobrien dynindx = 0; 4943130561Sobrien addend = value; 4944218822Sdim dyn_r_type = r_type + R_IA64_RELNNLSB - R_IA64_FPTRNNLSB; 4945130561Sobrien } 4946130561Sobrien else if (h) 4947130561Sobrien { 494884865Sobrien if (h->dynindx != -1) 494984865Sobrien dynindx = h->dynindx; 495084865Sobrien else 495184865Sobrien dynindx = (_bfd_elf_link_lookup_local_dynindx 495284865Sobrien (info, h->root.u.def.section->owner, 495384865Sobrien global_sym_index (h))); 4954130561Sobrien value = 0; 495584865Sobrien } 495684865Sobrien else 495784865Sobrien { 495884865Sobrien dynindx = (_bfd_elf_link_lookup_local_dynindx 495989857Sobrien (info, input_bfd, (long) r_symndx)); 4960130561Sobrien value = 0; 496184865Sobrien } 496284865Sobrien 496384865Sobrien elfNN_ia64_install_dyn_reloc (output_bfd, info, input_section, 4964130561Sobrien srel, rel->r_offset, dyn_r_type, 4965130561Sobrien dynindx, addend); 496684865Sobrien } 496784865Sobrien 4968218822Sdim r = elfNN_ia64_install_value (hit_addr, value, r_type); 496984865Sobrien break; 497084865Sobrien 497184865Sobrien case R_IA64_LTOFF_FPTR22: 497284865Sobrien case R_IA64_LTOFF_FPTR64I: 497389857Sobrien case R_IA64_LTOFF_FPTR32MSB: 497489857Sobrien case R_IA64_LTOFF_FPTR32LSB: 497584865Sobrien case R_IA64_LTOFF_FPTR64MSB: 497684865Sobrien case R_IA64_LTOFF_FPTR64LSB: 497784865Sobrien { 497884865Sobrien long dynindx; 497984865Sobrien 4980130561Sobrien dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE); 498184865Sobrien if (dyn_i->want_fptr) 498284865Sobrien { 4983218822Sdim BFD_ASSERT (h == NULL || h->dynindx == -1); 498484865Sobrien if (!undef_weak_ref) 498584865Sobrien value = set_fptr_entry (output_bfd, info, dyn_i, value); 498684865Sobrien dynindx = -1; 498784865Sobrien } 498884865Sobrien else 498984865Sobrien { 499084865Sobrien /* Otherwise, we expect the dynamic linker to create 499184865Sobrien the entry. */ 499284865Sobrien if (h) 499384865Sobrien { 499484865Sobrien if (h->dynindx != -1) 499584865Sobrien dynindx = h->dynindx; 499684865Sobrien else 499784865Sobrien dynindx = (_bfd_elf_link_lookup_local_dynindx 499884865Sobrien (info, h->root.u.def.section->owner, 499984865Sobrien global_sym_index (h))); 500084865Sobrien } 500184865Sobrien else 500284865Sobrien dynindx = (_bfd_elf_link_lookup_local_dynindx 500389857Sobrien (info, input_bfd, (long) r_symndx)); 500484865Sobrien value = 0; 500584865Sobrien } 500684865Sobrien 500784865Sobrien value = set_got_entry (output_bfd, info, dyn_i, dynindx, 5008218822Sdim rel->r_addend, value, R_IA64_FPTRNNLSB); 500984865Sobrien value -= gp_val; 5010218822Sdim r = elfNN_ia64_install_value (hit_addr, value, r_type); 501184865Sobrien } 501284865Sobrien break; 501384865Sobrien 501484865Sobrien case R_IA64_PCREL32MSB: 501584865Sobrien case R_IA64_PCREL32LSB: 501684865Sobrien case R_IA64_PCREL64MSB: 501784865Sobrien case R_IA64_PCREL64LSB: 501884865Sobrien /* Install a dynamic relocation for this reloc. */ 5019130561Sobrien if (dynamic_symbol_p && r_symndx != 0) 502084865Sobrien { 502184865Sobrien BFD_ASSERT (srel != NULL); 502284865Sobrien 502384865Sobrien elfNN_ia64_install_dyn_reloc (output_bfd, info, input_section, 502484865Sobrien srel, rel->r_offset, r_type, 502584865Sobrien h->dynindx, rel->r_addend); 502684865Sobrien } 502784865Sobrien goto finish_pcrel; 502884865Sobrien 502984865Sobrien case R_IA64_PCREL21B: 503084865Sobrien case R_IA64_PCREL60B: 503184865Sobrien /* We should have created a PLT entry for any dynamic symbol. */ 503284865Sobrien dyn_i = NULL; 503384865Sobrien if (h) 5034130561Sobrien dyn_i = get_dyn_sym_info (ia64_info, h, NULL, NULL, FALSE); 503584865Sobrien 503684865Sobrien if (dyn_i && dyn_i->want_plt2) 503784865Sobrien { 503884865Sobrien /* Should have caught this earlier. */ 503984865Sobrien BFD_ASSERT (rel->r_addend == 0); 504084865Sobrien 504184865Sobrien value = (ia64_info->plt_sec->output_section->vma 504284865Sobrien + ia64_info->plt_sec->output_offset 504384865Sobrien + dyn_i->plt2_offset); 504484865Sobrien } 504584865Sobrien else 504684865Sobrien { 504784865Sobrien /* Since there's no PLT entry, Validate that this is 504884865Sobrien locally defined. */ 504984865Sobrien BFD_ASSERT (undef_weak_ref || sym_sec->output_section != NULL); 505084865Sobrien 505184865Sobrien /* If the symbol is undef_weak, we shouldn't be trying 505284865Sobrien to call it. There's every chance that we'd wind up 505384865Sobrien with an out-of-range fixup here. Don't bother setting 505484865Sobrien any value at all. */ 505584865Sobrien if (undef_weak_ref) 505684865Sobrien continue; 505784865Sobrien } 505884865Sobrien goto finish_pcrel; 505984865Sobrien 5060130561Sobrien case R_IA64_PCREL21BI: 5061130561Sobrien case R_IA64_PCREL21F: 5062130561Sobrien case R_IA64_PCREL21M: 506384865Sobrien case R_IA64_PCREL22: 506484865Sobrien case R_IA64_PCREL64I: 5065130561Sobrien /* The PCREL21BI reloc is specifically not intended for use with 5066130561Sobrien dynamic relocs. PCREL21F and PCREL21M are used for speculation 5067218822Sdim fixup code, and thus probably ought not be dynamic. The 5068130561Sobrien PCREL22 and PCREL64I relocs aren't emitted as dynamic relocs. */ 5069130561Sobrien if (dynamic_symbol_p) 5070130561Sobrien { 5071130561Sobrien const char *msg; 5072130561Sobrien 5073130561Sobrien if (r_type == R_IA64_PCREL21BI) 5074218822Sdim msg = _("%B: @internal branch to dynamic symbol %s"); 5075130561Sobrien else if (r_type == R_IA64_PCREL21F || r_type == R_IA64_PCREL21M) 5076218822Sdim msg = _("%B: speculation fixup to dynamic symbol %s"); 5077130561Sobrien else 5078218822Sdim msg = _("%B: @pcrel relocation against dynamic symbol %s"); 5079218822Sdim (*_bfd_error_handler) (msg, input_bfd, 5080218822Sdim h ? h->root.root.string 5081218822Sdim : bfd_elf_sym_name (input_bfd, 5082218822Sdim symtab_hdr, 5083218822Sdim sym, 5084218822Sdim sym_sec)); 5085130561Sobrien ret_val = FALSE; 5086130561Sobrien continue; 5087130561Sobrien } 5088130561Sobrien goto finish_pcrel; 5089130561Sobrien 509084865Sobrien finish_pcrel: 509184865Sobrien /* Make pc-relative. */ 509284865Sobrien value -= (input_section->output_section->vma 509384865Sobrien + input_section->output_offset 509484865Sobrien + rel->r_offset) & ~ (bfd_vma) 0x3; 5095218822Sdim r = elfNN_ia64_install_value (hit_addr, value, r_type); 509684865Sobrien break; 509784865Sobrien 509884865Sobrien case R_IA64_SEGREL32MSB: 509984865Sobrien case R_IA64_SEGREL32LSB: 510084865Sobrien case R_IA64_SEGREL64MSB: 510184865Sobrien case R_IA64_SEGREL64LSB: 510289857Sobrien { 510389857Sobrien struct elf_segment_map *m; 510489857Sobrien Elf_Internal_Phdr *p; 510584865Sobrien 510689857Sobrien /* Find the segment that contains the output_section. */ 510789857Sobrien for (m = elf_tdata (output_bfd)->segment_map, 510889857Sobrien p = elf_tdata (output_bfd)->phdr; 510989857Sobrien m != NULL; 511089857Sobrien m = m->next, p++) 511189857Sobrien { 511289857Sobrien int i; 511389857Sobrien for (i = m->count - 1; i >= 0; i--) 5114130561Sobrien if (m->sections[i] == input_section->output_section) 511589857Sobrien break; 511689857Sobrien if (i >= 0) 511784865Sobrien break; 511889857Sobrien } 511984865Sobrien 512089857Sobrien if (m == NULL) 512189857Sobrien { 512284865Sobrien r = bfd_reloc_notsupported; 512389857Sobrien } 512489857Sobrien else 512589857Sobrien { 512689857Sobrien /* The VMA of the segment is the vaddr of the associated 512789857Sobrien program header. */ 512889857Sobrien if (value > p->p_vaddr) 512989857Sobrien value -= p->p_vaddr; 513089857Sobrien else 513189857Sobrien value = 0; 5132218822Sdim r = elfNN_ia64_install_value (hit_addr, value, r_type); 513389857Sobrien } 513489857Sobrien break; 513589857Sobrien } 513684865Sobrien 513784865Sobrien case R_IA64_SECREL32MSB: 513884865Sobrien case R_IA64_SECREL32LSB: 513984865Sobrien case R_IA64_SECREL64MSB: 514084865Sobrien case R_IA64_SECREL64LSB: 5141218822Sdim /* Make output-section relative to section where the symbol 5142218822Sdim is defined. PR 475 */ 5143218822Sdim if (sym_sec) 5144218822Sdim value -= sym_sec->output_section->vma; 5145218822Sdim r = elfNN_ia64_install_value (hit_addr, value, r_type); 514684865Sobrien break; 514784865Sobrien 514884865Sobrien case R_IA64_IPLTMSB: 514984865Sobrien case R_IA64_IPLTLSB: 515084865Sobrien /* Install a dynamic relocation for this reloc. */ 515184865Sobrien if ((dynamic_symbol_p || info->shared) 515284865Sobrien && (input_section->flags & SEC_ALLOC) != 0) 515384865Sobrien { 515484865Sobrien BFD_ASSERT (srel != NULL); 515584865Sobrien 515684865Sobrien /* If we don't need dynamic symbol lookup, install two 515784865Sobrien RELATIVE relocations. */ 5158130561Sobrien if (!dynamic_symbol_p) 515984865Sobrien { 516084865Sobrien unsigned int dyn_r_type; 516184865Sobrien 516284865Sobrien if (r_type == R_IA64_IPLTMSB) 516384865Sobrien dyn_r_type = R_IA64_REL64MSB; 516484865Sobrien else 516584865Sobrien dyn_r_type = R_IA64_REL64LSB; 516684865Sobrien 516784865Sobrien elfNN_ia64_install_dyn_reloc (output_bfd, info, 516884865Sobrien input_section, 516984865Sobrien srel, rel->r_offset, 517084865Sobrien dyn_r_type, 0, value); 517184865Sobrien elfNN_ia64_install_dyn_reloc (output_bfd, info, 517284865Sobrien input_section, 517384865Sobrien srel, rel->r_offset + 8, 517484865Sobrien dyn_r_type, 0, gp_val); 517584865Sobrien } 517684865Sobrien else 517784865Sobrien elfNN_ia64_install_dyn_reloc (output_bfd, info, input_section, 517884865Sobrien srel, rel->r_offset, r_type, 517984865Sobrien h->dynindx, rel->r_addend); 518084865Sobrien } 518184865Sobrien 518284865Sobrien if (r_type == R_IA64_IPLTMSB) 518384865Sobrien r_type = R_IA64_DIR64MSB; 518484865Sobrien else 518584865Sobrien r_type = R_IA64_DIR64LSB; 5186218822Sdim elfNN_ia64_install_value (hit_addr, value, r_type); 5187218822Sdim r = elfNN_ia64_install_value (hit_addr + 8, gp_val, r_type); 518884865Sobrien break; 518984865Sobrien 5190104834Sobrien case R_IA64_TPREL14: 5191104834Sobrien case R_IA64_TPREL22: 5192104834Sobrien case R_IA64_TPREL64I: 5193104834Sobrien value -= elfNN_ia64_tprel_base (info); 5194218822Sdim r = elfNN_ia64_install_value (hit_addr, value, r_type); 5195104834Sobrien break; 5196104834Sobrien 5197104834Sobrien case R_IA64_DTPREL14: 5198104834Sobrien case R_IA64_DTPREL22: 5199104834Sobrien case R_IA64_DTPREL64I: 5200218822Sdim case R_IA64_DTPREL32LSB: 5201218822Sdim case R_IA64_DTPREL32MSB: 5202130561Sobrien case R_IA64_DTPREL64LSB: 5203130561Sobrien case R_IA64_DTPREL64MSB: 5204104834Sobrien value -= elfNN_ia64_dtprel_base (info); 5205218822Sdim r = elfNN_ia64_install_value (hit_addr, value, r_type); 5206104834Sobrien break; 5207104834Sobrien 5208104834Sobrien case R_IA64_LTOFF_TPREL22: 5209104834Sobrien case R_IA64_LTOFF_DTPMOD22: 5210104834Sobrien case R_IA64_LTOFF_DTPREL22: 5211104834Sobrien { 5212104834Sobrien int got_r_type; 5213130561Sobrien long dynindx = h ? h->dynindx : -1; 5214130561Sobrien bfd_vma r_addend = rel->r_addend; 5215104834Sobrien 5216104834Sobrien switch (r_type) 5217104834Sobrien { 5218104834Sobrien default: 5219104834Sobrien case R_IA64_LTOFF_TPREL22: 5220130561Sobrien if (!dynamic_symbol_p) 5221130561Sobrien { 5222130561Sobrien if (!info->shared) 5223130561Sobrien value -= elfNN_ia64_tprel_base (info); 5224130561Sobrien else 5225130561Sobrien { 5226130561Sobrien r_addend += value - elfNN_ia64_dtprel_base (info); 5227130561Sobrien dynindx = 0; 5228130561Sobrien } 5229130561Sobrien } 5230104834Sobrien got_r_type = R_IA64_TPREL64LSB; 5231104834Sobrien break; 5232104834Sobrien case R_IA64_LTOFF_DTPMOD22: 5233104834Sobrien if (!dynamic_symbol_p && !info->shared) 5234104834Sobrien value = 1; 5235104834Sobrien got_r_type = R_IA64_DTPMOD64LSB; 5236104834Sobrien break; 5237104834Sobrien case R_IA64_LTOFF_DTPREL22: 5238104834Sobrien if (!dynamic_symbol_p) 5239104834Sobrien value -= elfNN_ia64_dtprel_base (info); 5240218822Sdim got_r_type = R_IA64_DTPRELNNLSB; 5241104834Sobrien break; 5242104834Sobrien } 5243130561Sobrien dyn_i = get_dyn_sym_info (ia64_info, h, input_bfd, rel, FALSE); 5244130561Sobrien value = set_got_entry (input_bfd, info, dyn_i, dynindx, r_addend, 5245104834Sobrien value, got_r_type); 5246104834Sobrien value -= gp_val; 5247218822Sdim r = elfNN_ia64_install_value (hit_addr, value, r_type); 5248104834Sobrien } 5249104834Sobrien break; 5250104834Sobrien 525184865Sobrien default: 525284865Sobrien r = bfd_reloc_notsupported; 525384865Sobrien break; 525484865Sobrien } 525584865Sobrien 525684865Sobrien switch (r) 525784865Sobrien { 525884865Sobrien case bfd_reloc_ok: 525984865Sobrien break; 526084865Sobrien 526184865Sobrien case bfd_reloc_undefined: 526284865Sobrien /* This can happen for global table relative relocs if 526384865Sobrien __gp is undefined. This is a panic situation so we 526484865Sobrien don't try to continue. */ 526584865Sobrien (*info->callbacks->undefined_symbol) 526684865Sobrien (info, "__gp", input_bfd, input_section, rel->r_offset, 1); 5267130561Sobrien return FALSE; 526884865Sobrien 526984865Sobrien case bfd_reloc_notsupported: 527084865Sobrien { 527184865Sobrien const char *name; 527284865Sobrien 527384865Sobrien if (h) 527484865Sobrien name = h->root.root.string; 527584865Sobrien else 5276218822Sdim name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, 5277218822Sdim sym_sec); 527884865Sobrien if (!(*info->callbacks->warning) (info, _("unsupported reloc"), 527984865Sobrien name, input_bfd, 528084865Sobrien input_section, rel->r_offset)) 5281130561Sobrien return FALSE; 5282130561Sobrien ret_val = FALSE; 528384865Sobrien } 528484865Sobrien break; 528584865Sobrien 528684865Sobrien case bfd_reloc_dangerous: 528784865Sobrien case bfd_reloc_outofrange: 528884865Sobrien case bfd_reloc_overflow: 528984865Sobrien default: 529084865Sobrien { 529184865Sobrien const char *name; 529284865Sobrien 529384865Sobrien if (h) 529484865Sobrien name = h->root.root.string; 529584865Sobrien else 5296218822Sdim name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, 5297218822Sdim sym_sec); 5298218822Sdim 5299218822Sdim switch (r_type) 530084865Sobrien { 5301218822Sdim case R_IA64_PCREL21B: 5302218822Sdim case R_IA64_PCREL21BI: 5303218822Sdim case R_IA64_PCREL21M: 5304218822Sdim case R_IA64_PCREL21F: 5305218822Sdim if (is_elf_hash_table (info->hash)) 5306218822Sdim { 5307218822Sdim /* Relaxtion is always performed for ELF output. 5308218822Sdim Overflow failures for those relocations mean 5309218822Sdim that the section is too big to relax. */ 5310218822Sdim (*_bfd_error_handler) 5311218822Sdim (_("%B: Can't relax br (%s) to `%s' at 0x%lx in section `%A' with size 0x%lx (> 0x1000000)."), 5312218822Sdim input_bfd, input_section, howto->name, name, 5313218822Sdim rel->r_offset, input_section->size); 5314218822Sdim break; 5315218822Sdim } 5316218822Sdim default: 5317218822Sdim if (!(*info->callbacks->reloc_overflow) (info, 5318218822Sdim &h->root, 5319218822Sdim name, 5320218822Sdim howto->name, 5321218822Sdim (bfd_vma) 0, 5322218822Sdim input_bfd, 5323218822Sdim input_section, 5324218822Sdim rel->r_offset)) 5325130561Sobrien return FALSE; 5326218822Sdim break; 532784865Sobrien } 5328218822Sdim 5329130561Sobrien ret_val = FALSE; 533084865Sobrien } 533184865Sobrien break; 533284865Sobrien } 533384865Sobrien } 533484865Sobrien 533584865Sobrien return ret_val; 533684865Sobrien} 533784865Sobrien 5338130561Sobrienstatic bfd_boolean 533984865SobrienelfNN_ia64_finish_dynamic_symbol (output_bfd, info, h, sym) 534084865Sobrien bfd *output_bfd; 534184865Sobrien struct bfd_link_info *info; 534284865Sobrien struct elf_link_hash_entry *h; 534384865Sobrien Elf_Internal_Sym *sym; 534484865Sobrien{ 534584865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 534684865Sobrien struct elfNN_ia64_dyn_sym_info *dyn_i; 534784865Sobrien 534884865Sobrien ia64_info = elfNN_ia64_hash_table (info); 5349130561Sobrien dyn_i = get_dyn_sym_info (ia64_info, h, NULL, NULL, FALSE); 535084865Sobrien 535184865Sobrien /* Fill in the PLT data, if required. */ 535284865Sobrien if (dyn_i && dyn_i->want_plt) 535384865Sobrien { 535484865Sobrien Elf_Internal_Rela outrel; 535584865Sobrien bfd_byte *loc; 535684865Sobrien asection *plt_sec; 535784865Sobrien bfd_vma plt_addr, pltoff_addr, gp_val, index; 535884865Sobrien 535984865Sobrien gp_val = _bfd_get_gp_value (output_bfd); 536084865Sobrien 536184865Sobrien /* Initialize the minimal PLT entry. */ 536284865Sobrien 536384865Sobrien index = (dyn_i->plt_offset - PLT_HEADER_SIZE) / PLT_MIN_ENTRY_SIZE; 536484865Sobrien plt_sec = ia64_info->plt_sec; 536584865Sobrien loc = plt_sec->contents + dyn_i->plt_offset; 536684865Sobrien 536784865Sobrien memcpy (loc, plt_min_entry, PLT_MIN_ENTRY_SIZE); 5368218822Sdim elfNN_ia64_install_value (loc, index, R_IA64_IMM22); 5369218822Sdim elfNN_ia64_install_value (loc+2, -dyn_i->plt_offset, R_IA64_PCREL21B); 537084865Sobrien 537184865Sobrien plt_addr = (plt_sec->output_section->vma 537284865Sobrien + plt_sec->output_offset 537384865Sobrien + dyn_i->plt_offset); 5374130561Sobrien pltoff_addr = set_pltoff_entry (output_bfd, info, dyn_i, plt_addr, TRUE); 537584865Sobrien 537684865Sobrien /* Initialize the FULL PLT entry, if needed. */ 537784865Sobrien if (dyn_i->want_plt2) 537884865Sobrien { 537984865Sobrien loc = plt_sec->contents + dyn_i->plt2_offset; 538084865Sobrien 538184865Sobrien memcpy (loc, plt_full_entry, PLT_FULL_ENTRY_SIZE); 5382218822Sdim elfNN_ia64_install_value (loc, pltoff_addr - gp_val, R_IA64_IMM22); 538384865Sobrien 538484865Sobrien /* Mark the symbol as undefined, rather than as defined in the 538584865Sobrien plt section. Leave the value alone. */ 538684865Sobrien /* ??? We didn't redefine it in adjust_dynamic_symbol in the 5387130561Sobrien first place. But perhaps elflink.c did some for us. */ 5388218822Sdim if (!h->def_regular) 538984865Sobrien sym->st_shndx = SHN_UNDEF; 539084865Sobrien } 539184865Sobrien 539284865Sobrien /* Create the dynamic relocation. */ 539384865Sobrien outrel.r_offset = pltoff_addr; 539484865Sobrien if (bfd_little_endian (output_bfd)) 539584865Sobrien outrel.r_info = ELFNN_R_INFO (h->dynindx, R_IA64_IPLTLSB); 539684865Sobrien else 539784865Sobrien outrel.r_info = ELFNN_R_INFO (h->dynindx, R_IA64_IPLTMSB); 539884865Sobrien outrel.r_addend = 0; 539984865Sobrien 540084865Sobrien /* This is fun. In the .IA_64.pltoff section, we've got entries 540184865Sobrien that correspond both to real PLT entries, and those that 540284865Sobrien happened to resolve to local symbols but need to be created 540384865Sobrien to satisfy @pltoff relocations. The .rela.IA_64.pltoff 540484865Sobrien relocations for the real PLT should come at the end of the 540584865Sobrien section, so that they can be indexed by plt entry at runtime. 540684865Sobrien 540784865Sobrien We emitted all of the relocations for the non-PLT @pltoff 540884865Sobrien entries during relocate_section. So we can consider the 540984865Sobrien existing sec->reloc_count to be the base of the array of 541084865Sobrien PLT relocations. */ 541184865Sobrien 5412130561Sobrien loc = ia64_info->rel_pltoff_sec->contents; 5413130561Sobrien loc += ((ia64_info->rel_pltoff_sec->reloc_count + index) 5414130561Sobrien * sizeof (ElfNN_External_Rela)); 5415130561Sobrien bfd_elfNN_swap_reloca_out (output_bfd, &outrel, loc); 541684865Sobrien } 541784865Sobrien 541884865Sobrien /* Mark some specially defined symbols as absolute. */ 541984865Sobrien if (strcmp (h->root.root.string, "_DYNAMIC") == 0 5420218822Sdim || h == ia64_info->root.hgot 5421218822Sdim || h == ia64_info->root.hplt) 542284865Sobrien sym->st_shndx = SHN_ABS; 542384865Sobrien 5424130561Sobrien return TRUE; 542584865Sobrien} 542684865Sobrien 5427130561Sobrienstatic bfd_boolean 542884865SobrienelfNN_ia64_finish_dynamic_sections (abfd, info) 542984865Sobrien bfd *abfd; 543084865Sobrien struct bfd_link_info *info; 543184865Sobrien{ 543284865Sobrien struct elfNN_ia64_link_hash_table *ia64_info; 543384865Sobrien bfd *dynobj; 543484865Sobrien 543584865Sobrien ia64_info = elfNN_ia64_hash_table (info); 543684865Sobrien dynobj = ia64_info->root.dynobj; 543784865Sobrien 543884865Sobrien if (elf_hash_table (info)->dynamic_sections_created) 543984865Sobrien { 544084865Sobrien ElfNN_External_Dyn *dyncon, *dynconend; 544184865Sobrien asection *sdyn, *sgotplt; 544284865Sobrien bfd_vma gp_val; 544384865Sobrien 544484865Sobrien sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); 544584865Sobrien sgotplt = bfd_get_section_by_name (dynobj, ".got.plt"); 544684865Sobrien BFD_ASSERT (sdyn != NULL); 544784865Sobrien dyncon = (ElfNN_External_Dyn *) sdyn->contents; 5448218822Sdim dynconend = (ElfNN_External_Dyn *) (sdyn->contents + sdyn->size); 544984865Sobrien 545084865Sobrien gp_val = _bfd_get_gp_value (abfd); 545184865Sobrien 545284865Sobrien for (; dyncon < dynconend; dyncon++) 545384865Sobrien { 545484865Sobrien Elf_Internal_Dyn dyn; 545584865Sobrien 545684865Sobrien bfd_elfNN_swap_dyn_in (dynobj, dyncon, &dyn); 545784865Sobrien 545884865Sobrien switch (dyn.d_tag) 545984865Sobrien { 546084865Sobrien case DT_PLTGOT: 546184865Sobrien dyn.d_un.d_ptr = gp_val; 546284865Sobrien break; 546384865Sobrien 546484865Sobrien case DT_PLTRELSZ: 546584865Sobrien dyn.d_un.d_val = (ia64_info->minplt_entries 546684865Sobrien * sizeof (ElfNN_External_Rela)); 546784865Sobrien break; 546884865Sobrien 546984865Sobrien case DT_JMPREL: 547084865Sobrien /* See the comment above in finish_dynamic_symbol. */ 547184865Sobrien dyn.d_un.d_ptr = (ia64_info->rel_pltoff_sec->output_section->vma 547284865Sobrien + ia64_info->rel_pltoff_sec->output_offset 547384865Sobrien + (ia64_info->rel_pltoff_sec->reloc_count 547484865Sobrien * sizeof (ElfNN_External_Rela))); 547584865Sobrien break; 547684865Sobrien 547784865Sobrien case DT_IA_64_PLT_RESERVE: 547884865Sobrien dyn.d_un.d_ptr = (sgotplt->output_section->vma 547984865Sobrien + sgotplt->output_offset); 548084865Sobrien break; 548184865Sobrien 548284865Sobrien case DT_RELASZ: 548384865Sobrien /* Do not have RELASZ include JMPREL. This makes things 548484865Sobrien easier on ld.so. This is not what the rest of BFD set up. */ 548584865Sobrien dyn.d_un.d_val -= (ia64_info->minplt_entries 548684865Sobrien * sizeof (ElfNN_External_Rela)); 548784865Sobrien break; 548884865Sobrien } 548984865Sobrien 549084865Sobrien bfd_elfNN_swap_dyn_out (abfd, &dyn, dyncon); 549184865Sobrien } 549284865Sobrien 5493130561Sobrien /* Initialize the PLT0 entry. */ 549484865Sobrien if (ia64_info->plt_sec) 549584865Sobrien { 549684865Sobrien bfd_byte *loc = ia64_info->plt_sec->contents; 549784865Sobrien bfd_vma pltres; 549884865Sobrien 549984865Sobrien memcpy (loc, plt_header, PLT_HEADER_SIZE); 550084865Sobrien 550184865Sobrien pltres = (sgotplt->output_section->vma 550284865Sobrien + sgotplt->output_offset 550384865Sobrien - gp_val); 550484865Sobrien 5505218822Sdim elfNN_ia64_install_value (loc+1, pltres, R_IA64_GPREL22); 550684865Sobrien } 550784865Sobrien } 550884865Sobrien 5509130561Sobrien return TRUE; 551084865Sobrien} 551184865Sobrien 5512130561Sobrien/* ELF file flag handling: */ 551384865Sobrien 551484865Sobrien/* Function to keep IA-64 specific file flags. */ 5515130561Sobrienstatic bfd_boolean 551684865SobrienelfNN_ia64_set_private_flags (abfd, flags) 551784865Sobrien bfd *abfd; 551884865Sobrien flagword flags; 551984865Sobrien{ 552084865Sobrien BFD_ASSERT (!elf_flags_init (abfd) 552184865Sobrien || elf_elfheader (abfd)->e_flags == flags); 552284865Sobrien 552384865Sobrien elf_elfheader (abfd)->e_flags = flags; 5524130561Sobrien elf_flags_init (abfd) = TRUE; 5525130561Sobrien return TRUE; 552684865Sobrien} 552784865Sobrien 552884865Sobrien/* Merge backend specific data from an object file to the output 552984865Sobrien object file when linking. */ 5530130561Sobrienstatic bfd_boolean 553184865SobrienelfNN_ia64_merge_private_bfd_data (ibfd, obfd) 553284865Sobrien bfd *ibfd, *obfd; 553384865Sobrien{ 553484865Sobrien flagword out_flags; 553584865Sobrien flagword in_flags; 5536130561Sobrien bfd_boolean ok = TRUE; 553784865Sobrien 553884865Sobrien /* Don't even pretend to support mixed-format linking. */ 553984865Sobrien if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour 554084865Sobrien || bfd_get_flavour (obfd) != bfd_target_elf_flavour) 5541130561Sobrien return FALSE; 554284865Sobrien 554384865Sobrien in_flags = elf_elfheader (ibfd)->e_flags; 554484865Sobrien out_flags = elf_elfheader (obfd)->e_flags; 554584865Sobrien 554684865Sobrien if (! elf_flags_init (obfd)) 554784865Sobrien { 5548130561Sobrien elf_flags_init (obfd) = TRUE; 554984865Sobrien elf_elfheader (obfd)->e_flags = in_flags; 555084865Sobrien 555184865Sobrien if (bfd_get_arch (obfd) == bfd_get_arch (ibfd) 555284865Sobrien && bfd_get_arch_info (obfd)->the_default) 555384865Sobrien { 555484865Sobrien return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), 555584865Sobrien bfd_get_mach (ibfd)); 555684865Sobrien } 555784865Sobrien 5558130561Sobrien return TRUE; 555984865Sobrien } 556084865Sobrien 556184865Sobrien /* Check flag compatibility. */ 556284865Sobrien if (in_flags == out_flags) 5563130561Sobrien return TRUE; 556484865Sobrien 556584865Sobrien /* Output has EF_IA_64_REDUCEDFP set only if all inputs have it set. */ 556684865Sobrien if (!(in_flags & EF_IA_64_REDUCEDFP) && (out_flags & EF_IA_64_REDUCEDFP)) 556784865Sobrien elf_elfheader (obfd)->e_flags &= ~EF_IA_64_REDUCEDFP; 556884865Sobrien 556984865Sobrien if ((in_flags & EF_IA_64_TRAPNIL) != (out_flags & EF_IA_64_TRAPNIL)) 557084865Sobrien { 557184865Sobrien (*_bfd_error_handler) 5572218822Sdim (_("%B: linking trap-on-NULL-dereference with non-trapping files"), 5573218822Sdim ibfd); 557484865Sobrien 557584865Sobrien bfd_set_error (bfd_error_bad_value); 5576130561Sobrien ok = FALSE; 557784865Sobrien } 557884865Sobrien if ((in_flags & EF_IA_64_BE) != (out_flags & EF_IA_64_BE)) 557984865Sobrien { 558084865Sobrien (*_bfd_error_handler) 5581218822Sdim (_("%B: linking big-endian files with little-endian files"), 5582218822Sdim ibfd); 558384865Sobrien 558484865Sobrien bfd_set_error (bfd_error_bad_value); 5585130561Sobrien ok = FALSE; 558684865Sobrien } 558784865Sobrien if ((in_flags & EF_IA_64_ABI64) != (out_flags & EF_IA_64_ABI64)) 558884865Sobrien { 558984865Sobrien (*_bfd_error_handler) 5590218822Sdim (_("%B: linking 64-bit files with 32-bit files"), 5591218822Sdim ibfd); 559284865Sobrien 559384865Sobrien bfd_set_error (bfd_error_bad_value); 5594130561Sobrien ok = FALSE; 559584865Sobrien } 559684865Sobrien if ((in_flags & EF_IA_64_CONS_GP) != (out_flags & EF_IA_64_CONS_GP)) 559784865Sobrien { 559884865Sobrien (*_bfd_error_handler) 5599218822Sdim (_("%B: linking constant-gp files with non-constant-gp files"), 5600218822Sdim ibfd); 560184865Sobrien 560284865Sobrien bfd_set_error (bfd_error_bad_value); 5603130561Sobrien ok = FALSE; 560484865Sobrien } 560584865Sobrien if ((in_flags & EF_IA_64_NOFUNCDESC_CONS_GP) 560684865Sobrien != (out_flags & EF_IA_64_NOFUNCDESC_CONS_GP)) 560784865Sobrien { 560884865Sobrien (*_bfd_error_handler) 5609218822Sdim (_("%B: linking auto-pic files with non-auto-pic files"), 5610218822Sdim ibfd); 561184865Sobrien 561284865Sobrien bfd_set_error (bfd_error_bad_value); 5613130561Sobrien ok = FALSE; 561484865Sobrien } 561584865Sobrien 561684865Sobrien return ok; 561784865Sobrien} 561884865Sobrien 5619130561Sobrienstatic bfd_boolean 562084865SobrienelfNN_ia64_print_private_bfd_data (abfd, ptr) 562184865Sobrien bfd *abfd; 562284865Sobrien PTR ptr; 562384865Sobrien{ 562484865Sobrien FILE *file = (FILE *) ptr; 562584865Sobrien flagword flags = elf_elfheader (abfd)->e_flags; 562684865Sobrien 562784865Sobrien BFD_ASSERT (abfd != NULL && ptr != NULL); 562884865Sobrien 562984865Sobrien fprintf (file, "private flags = %s%s%s%s%s%s%s%s\n", 563084865Sobrien (flags & EF_IA_64_TRAPNIL) ? "TRAPNIL, " : "", 563184865Sobrien (flags & EF_IA_64_EXT) ? "EXT, " : "", 563284865Sobrien (flags & EF_IA_64_BE) ? "BE, " : "LE, ", 563384865Sobrien (flags & EF_IA_64_REDUCEDFP) ? "REDUCEDFP, " : "", 563484865Sobrien (flags & EF_IA_64_CONS_GP) ? "CONS_GP, " : "", 563584865Sobrien (flags & EF_IA_64_NOFUNCDESC_CONS_GP) ? "NOFUNCDESC_CONS_GP, " : "", 563684865Sobrien (flags & EF_IA_64_ABSOLUTE) ? "ABSOLUTE, " : "", 563784865Sobrien (flags & EF_IA_64_ABI64) ? "ABI64" : "ABI32"); 563884865Sobrien 563984865Sobrien _bfd_elf_print_private_bfd_data (abfd, ptr); 5640130561Sobrien return TRUE; 564184865Sobrien} 564289857Sobrien 564389857Sobrienstatic enum elf_reloc_type_class 564489857SobrienelfNN_ia64_reloc_type_class (rela) 564589857Sobrien const Elf_Internal_Rela *rela; 564689857Sobrien{ 564789857Sobrien switch ((int) ELFNN_R_TYPE (rela->r_info)) 564889857Sobrien { 564989857Sobrien case R_IA64_REL32MSB: 565089857Sobrien case R_IA64_REL32LSB: 565189857Sobrien case R_IA64_REL64MSB: 565289857Sobrien case R_IA64_REL64LSB: 565389857Sobrien return reloc_class_relative; 565489857Sobrien case R_IA64_IPLTMSB: 565589857Sobrien case R_IA64_IPLTLSB: 565689857Sobrien return reloc_class_plt; 565789857Sobrien case R_IA64_COPY: 565889857Sobrien return reloc_class_copy; 565989857Sobrien default: 566089857Sobrien return reloc_class_normal; 566189857Sobrien } 566289857Sobrien} 566389857Sobrien 5664218822Sdimstatic const struct bfd_elf_special_section elfNN_ia64_special_sections[] = 5665130561Sobrien{ 5666218822Sdim { STRING_COMMA_LEN (".sbss"), -1, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT }, 5667218822Sdim { STRING_COMMA_LEN (".sdata"), -1, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_IA_64_SHORT }, 5668218822Sdim { NULL, 0, 0, 0, 0 } 5669130561Sobrien}; 5670130561Sobrien 5671130561Sobrienstatic bfd_boolean 5672218822SdimelfNN_ia64_object_p (bfd *abfd) 5673218822Sdim{ 5674218822Sdim asection *sec; 5675218822Sdim asection *group, *unwi, *unw; 5676218822Sdim flagword flags; 5677218822Sdim const char *name; 5678218822Sdim char *unwi_name, *unw_name; 5679218822Sdim bfd_size_type amt; 5680218822Sdim 5681218822Sdim if (abfd->flags & DYNAMIC) 5682218822Sdim return TRUE; 5683218822Sdim 5684218822Sdim /* Flags for fake group section. */ 5685218822Sdim flags = (SEC_LINKER_CREATED | SEC_GROUP | SEC_LINK_ONCE 5686218822Sdim | SEC_EXCLUDE); 5687218822Sdim 5688218822Sdim /* We add a fake section group for each .gnu.linkonce.t.* section, 5689218822Sdim which isn't in a section group, and its unwind sections. */ 5690218822Sdim for (sec = abfd->sections; sec != NULL; sec = sec->next) 5691218822Sdim { 5692218822Sdim if (elf_sec_group (sec) == NULL 5693218822Sdim && ((sec->flags & (SEC_LINK_ONCE | SEC_CODE | SEC_GROUP)) 5694218822Sdim == (SEC_LINK_ONCE | SEC_CODE)) 5695218822Sdim && CONST_STRNEQ (sec->name, ".gnu.linkonce.t.")) 5696218822Sdim { 5697218822Sdim name = sec->name + 16; 5698218822Sdim 5699218822Sdim amt = strlen (name) + sizeof (".gnu.linkonce.ia64unwi."); 5700218822Sdim unwi_name = bfd_alloc (abfd, amt); 5701218822Sdim if (!unwi_name) 5702218822Sdim return FALSE; 5703218822Sdim 5704218822Sdim strcpy (stpcpy (unwi_name, ".gnu.linkonce.ia64unwi."), name); 5705218822Sdim unwi = bfd_get_section_by_name (abfd, unwi_name); 5706218822Sdim 5707218822Sdim amt = strlen (name) + sizeof (".gnu.linkonce.ia64unw."); 5708218822Sdim unw_name = bfd_alloc (abfd, amt); 5709218822Sdim if (!unw_name) 5710218822Sdim return FALSE; 5711218822Sdim 5712218822Sdim strcpy (stpcpy (unw_name, ".gnu.linkonce.ia64unw."), name); 5713218822Sdim unw = bfd_get_section_by_name (abfd, unw_name); 5714218822Sdim 5715218822Sdim /* We need to create a fake group section for it and its 5716218822Sdim unwind sections. */ 5717218822Sdim group = bfd_make_section_anyway_with_flags (abfd, name, 5718218822Sdim flags); 5719218822Sdim if (group == NULL) 5720218822Sdim return FALSE; 5721218822Sdim 5722218822Sdim /* Move the fake group section to the beginning. */ 5723218822Sdim bfd_section_list_remove (abfd, group); 5724218822Sdim bfd_section_list_prepend (abfd, group); 5725218822Sdim 5726218822Sdim elf_next_in_group (group) = sec; 5727218822Sdim 5728218822Sdim elf_group_name (sec) = name; 5729218822Sdim elf_next_in_group (sec) = sec; 5730218822Sdim elf_sec_group (sec) = group; 5731218822Sdim 5732218822Sdim if (unwi) 5733218822Sdim { 5734218822Sdim elf_group_name (unwi) = name; 5735218822Sdim elf_next_in_group (unwi) = sec; 5736218822Sdim elf_next_in_group (sec) = unwi; 5737218822Sdim elf_sec_group (unwi) = group; 5738218822Sdim } 5739218822Sdim 5740218822Sdim if (unw) 5741218822Sdim { 5742218822Sdim elf_group_name (unw) = name; 5743218822Sdim if (unwi) 5744218822Sdim { 5745218822Sdim elf_next_in_group (unw) = elf_next_in_group (unwi); 5746218822Sdim elf_next_in_group (unwi) = unw; 5747218822Sdim } 5748218822Sdim else 5749218822Sdim { 5750218822Sdim elf_next_in_group (unw) = sec; 5751218822Sdim elf_next_in_group (sec) = unw; 5752218822Sdim } 5753218822Sdim elf_sec_group (unw) = group; 5754218822Sdim } 5755218822Sdim 5756218822Sdim /* Fake SHT_GROUP section header. */ 5757218822Sdim elf_section_data (group)->this_hdr.bfd_section = group; 5758218822Sdim elf_section_data (group)->this_hdr.sh_type = SHT_GROUP; 5759218822Sdim } 5760218822Sdim } 5761218822Sdim return TRUE; 5762218822Sdim} 5763218822Sdim 5764218822Sdimstatic bfd_boolean 576589857SobrienelfNN_ia64_hpux_vec (const bfd_target *vec) 576689857Sobrien{ 576789857Sobrien extern const bfd_target bfd_elfNN_ia64_hpux_big_vec; 576889857Sobrien return (vec == & bfd_elfNN_ia64_hpux_big_vec); 576989857Sobrien} 577089857Sobrien 577189857Sobrienstatic void 577289857SobrienelfNN_hpux_post_process_headers (abfd, info) 577389857Sobrien bfd *abfd; 577489857Sobrien struct bfd_link_info *info ATTRIBUTE_UNUSED; 577589857Sobrien{ 577689857Sobrien Elf_Internal_Ehdr *i_ehdrp = elf_elfheader (abfd); 577789857Sobrien 5778218822Sdim i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi; 577989857Sobrien i_ehdrp->e_ident[EI_ABIVERSION] = 1; 578089857Sobrien} 578189857Sobrien 5782130561Sobrienbfd_boolean 578389857SobrienelfNN_hpux_backend_section_from_bfd_section (abfd, sec, retval) 578489857Sobrien bfd *abfd ATTRIBUTE_UNUSED; 578589857Sobrien asection *sec; 578689857Sobrien int *retval; 578789857Sobrien{ 578889857Sobrien if (bfd_is_com_section (sec)) 578989857Sobrien { 579089857Sobrien *retval = SHN_IA_64_ANSI_COMMON; 5791130561Sobrien return TRUE; 579289857Sobrien } 5793130561Sobrien return FALSE; 579489857Sobrien} 5795130561Sobrien 5796130561Sobrienstatic void 5797130561SobrienelfNN_hpux_backend_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, 5798130561Sobrien asymbol *asym) 5799130561Sobrien{ 5800218822Sdim elf_symbol_type *elfsym = (elf_symbol_type *) asym; 5801130561Sobrien 5802130561Sobrien switch (elfsym->internal_elf_sym.st_shndx) 5803130561Sobrien { 5804130561Sobrien case SHN_IA_64_ANSI_COMMON: 5805130561Sobrien asym->section = bfd_com_section_ptr; 5806130561Sobrien asym->value = elfsym->internal_elf_sym.st_size; 5807130561Sobrien asym->flags &= ~BSF_GLOBAL; 5808130561Sobrien break; 5809130561Sobrien } 5810130561Sobrien} 5811130561Sobrien 581284865Sobrien 581384865Sobrien#define TARGET_LITTLE_SYM bfd_elfNN_ia64_little_vec 581484865Sobrien#define TARGET_LITTLE_NAME "elfNN-ia64-little" 581584865Sobrien#define TARGET_BIG_SYM bfd_elfNN_ia64_big_vec 581684865Sobrien#define TARGET_BIG_NAME "elfNN-ia64-big" 581784865Sobrien#define ELF_ARCH bfd_arch_ia64 581884865Sobrien#define ELF_MACHINE_CODE EM_IA_64 581984865Sobrien#define ELF_MACHINE_ALT1 1999 /* EAS2.3 */ 582084865Sobrien#define ELF_MACHINE_ALT2 1998 /* EAS2.2 */ 582184865Sobrien#define ELF_MAXPAGESIZE 0x10000 /* 64KB */ 5822218822Sdim#define ELF_COMMONPAGESIZE 0x4000 /* 16KB */ 582384865Sobrien 582484865Sobrien#define elf_backend_section_from_shdr \ 582584865Sobrien elfNN_ia64_section_from_shdr 582684865Sobrien#define elf_backend_section_flags \ 582784865Sobrien elfNN_ia64_section_flags 582884865Sobrien#define elf_backend_fake_sections \ 582984865Sobrien elfNN_ia64_fake_sections 583084865Sobrien#define elf_backend_final_write_processing \ 583184865Sobrien elfNN_ia64_final_write_processing 583284865Sobrien#define elf_backend_add_symbol_hook \ 583384865Sobrien elfNN_ia64_add_symbol_hook 583484865Sobrien#define elf_backend_additional_program_headers \ 583584865Sobrien elfNN_ia64_additional_program_headers 583684865Sobrien#define elf_backend_modify_segment_map \ 583784865Sobrien elfNN_ia64_modify_segment_map 5838218822Sdim#define elf_backend_modify_program_headers \ 5839218822Sdim elfNN_ia64_modify_program_headers 584084865Sobrien#define elf_info_to_howto \ 584184865Sobrien elfNN_ia64_info_to_howto 584284865Sobrien 584384865Sobrien#define bfd_elfNN_bfd_reloc_type_lookup \ 584484865Sobrien elfNN_ia64_reloc_type_lookup 5845218822Sdim#define bfd_elfNN_bfd_reloc_name_lookup \ 5846218822Sdim elfNN_ia64_reloc_name_lookup 584784865Sobrien#define bfd_elfNN_bfd_is_local_label_name \ 584884865Sobrien elfNN_ia64_is_local_label_name 584984865Sobrien#define bfd_elfNN_bfd_relax_section \ 585084865Sobrien elfNN_ia64_relax_section 585184865Sobrien 5852218822Sdim#define elf_backend_object_p \ 5853218822Sdim elfNN_ia64_object_p 5854218822Sdim 585584865Sobrien/* Stuff for the BFD linker: */ 585684865Sobrien#define bfd_elfNN_bfd_link_hash_table_create \ 585784865Sobrien elfNN_ia64_hash_table_create 5858130561Sobrien#define bfd_elfNN_bfd_link_hash_table_free \ 5859130561Sobrien elfNN_ia64_hash_table_free 586084865Sobrien#define elf_backend_create_dynamic_sections \ 586184865Sobrien elfNN_ia64_create_dynamic_sections 586284865Sobrien#define elf_backend_check_relocs \ 586384865Sobrien elfNN_ia64_check_relocs 586484865Sobrien#define elf_backend_adjust_dynamic_symbol \ 586584865Sobrien elfNN_ia64_adjust_dynamic_symbol 586684865Sobrien#define elf_backend_size_dynamic_sections \ 586784865Sobrien elfNN_ia64_size_dynamic_sections 5868218822Sdim#define elf_backend_omit_section_dynsym \ 5869218822Sdim ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true) 587084865Sobrien#define elf_backend_relocate_section \ 587184865Sobrien elfNN_ia64_relocate_section 587284865Sobrien#define elf_backend_finish_dynamic_symbol \ 587384865Sobrien elfNN_ia64_finish_dynamic_symbol 587484865Sobrien#define elf_backend_finish_dynamic_sections \ 587584865Sobrien elfNN_ia64_finish_dynamic_sections 587684865Sobrien#define bfd_elfNN_bfd_final_link \ 587784865Sobrien elfNN_ia64_final_link 587884865Sobrien 587984865Sobrien#define bfd_elfNN_bfd_merge_private_bfd_data \ 588084865Sobrien elfNN_ia64_merge_private_bfd_data 588184865Sobrien#define bfd_elfNN_bfd_set_private_flags \ 588284865Sobrien elfNN_ia64_set_private_flags 588384865Sobrien#define bfd_elfNN_bfd_print_private_bfd_data \ 588484865Sobrien elfNN_ia64_print_private_bfd_data 588584865Sobrien 588684865Sobrien#define elf_backend_plt_readonly 1 588784865Sobrien#define elf_backend_want_plt_sym 0 588884865Sobrien#define elf_backend_plt_alignment 5 588984865Sobrien#define elf_backend_got_header_size 0 589084865Sobrien#define elf_backend_want_got_plt 1 589184865Sobrien#define elf_backend_may_use_rel_p 1 589284865Sobrien#define elf_backend_may_use_rela_p 1 589384865Sobrien#define elf_backend_default_use_rela_p 1 589484865Sobrien#define elf_backend_want_dynbss 0 589584865Sobrien#define elf_backend_copy_indirect_symbol elfNN_ia64_hash_copy_indirect 589684865Sobrien#define elf_backend_hide_symbol elfNN_ia64_hash_hide_symbol 5897218822Sdim#define elf_backend_fixup_symbol _bfd_elf_link_hash_fixup_symbol 589889857Sobrien#define elf_backend_reloc_type_class elfNN_ia64_reloc_type_class 589999461Sobrien#define elf_backend_rela_normal 1 5900130561Sobrien#define elf_backend_special_sections elfNN_ia64_special_sections 5901218822Sdim#define elf_backend_default_execstack 0 590284865Sobrien 5903218822Sdim/* FIXME: PR 290: The Intel C compiler generates SHT_IA_64_UNWIND with 5904218822Sdim SHF_LINK_ORDER. But it doesn't set the sh_link or sh_info fields. 5905218822Sdim We don't want to flood users with so many error messages. We turn 5906218822Sdim off the warning for now. It will be turned on later when the Intel 5907218822Sdim compiler is fixed. */ 5908218822Sdim#define elf_backend_link_order_error_handler NULL 5909218822Sdim 591084865Sobrien#include "elfNN-target.h" 591189857Sobrien 5912218822Sdim/* FreeBSD support. */ 5913218822Sdim 5914218822Sdim#undef TARGET_LITTLE_SYM 5915218822Sdim#define TARGET_LITTLE_SYM bfd_elfNN_ia64_freebsd_vec 5916218822Sdim#undef TARGET_LITTLE_NAME 5917218822Sdim#define TARGET_LITTLE_NAME "elfNN-ia64-freebsd" 5918218822Sdim#undef TARGET_BIG_SYM 5919218822Sdim#undef TARGET_BIG_NAME 5920218822Sdim 5921218822Sdim#undef ELF_OSABI 5922218822Sdim#define ELF_OSABI ELFOSABI_FREEBSD 5923218822Sdim 5924218822Sdim#undef elf_backend_post_process_headers 5925218822Sdim#define elf_backend_post_process_headers _bfd_elf_set_osabi 5926218822Sdim 5927218822Sdim#undef elfNN_bed 5928218822Sdim#define elfNN_bed elfNN_ia64_fbsd_bed 5929218822Sdim 5930218822Sdim#include "elfNN-target.h" 5931218822Sdim 593289857Sobrien/* HPUX-specific vectors. */ 593389857Sobrien 593489857Sobrien#undef TARGET_LITTLE_SYM 593589857Sobrien#undef TARGET_LITTLE_NAME 593689857Sobrien#undef TARGET_BIG_SYM 593789857Sobrien#define TARGET_BIG_SYM bfd_elfNN_ia64_hpux_big_vec 593889857Sobrien#undef TARGET_BIG_NAME 593989857Sobrien#define TARGET_BIG_NAME "elfNN-ia64-hpux-big" 594089857Sobrien 594189857Sobrien/* These are HP-UX specific functions. */ 594289857Sobrien 594389857Sobrien#undef elf_backend_post_process_headers 594489857Sobrien#define elf_backend_post_process_headers elfNN_hpux_post_process_headers 594589857Sobrien 594689857Sobrien#undef elf_backend_section_from_bfd_section 594789857Sobrien#define elf_backend_section_from_bfd_section elfNN_hpux_backend_section_from_bfd_section 594889857Sobrien 5949130561Sobrien#undef elf_backend_symbol_processing 5950130561Sobrien#define elf_backend_symbol_processing elfNN_hpux_backend_symbol_processing 5951130561Sobrien 5952104834Sobrien#undef elf_backend_want_p_paddr_set_to_zero 5953104834Sobrien#define elf_backend_want_p_paddr_set_to_zero 1 5954104834Sobrien 595589857Sobrien#undef ELF_MAXPAGESIZE 5956218822Sdim#define ELF_MAXPAGESIZE 0x1000 /* 4K */ 5957218822Sdim#undef ELF_COMMONPAGESIZE 5958218822Sdim#undef ELF_OSABI 5959218822Sdim#define ELF_OSABI ELFOSABI_HPUX 596089857Sobrien 596189857Sobrien#undef elfNN_bed 596289857Sobrien#define elfNN_bed elfNN_ia64_hpux_bed 596389857Sobrien 596489857Sobrien#include "elfNN-target.h" 5965104834Sobrien 5966104834Sobrien#undef elf_backend_want_p_paddr_set_to_zero 5967