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