133965Sjdp/* Alpha specific support for 64-bit ELF
2218822Sdim   Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
3218822Sdim   2006, 2007 Free Software Foundation, Inc.
433965Sjdp   Contributed by Richard Henderson <rth@tamu.edu>.
533965Sjdp
6130570Sobrien   This file is part of BFD, the Binary File Descriptor library.
733965Sjdp
8130570Sobrien   This program is free software; you can redistribute it and/or modify
9130570Sobrien   it under the terms of the GNU General Public License as published by
10130570Sobrien   the Free Software Foundation; either version 2 of the License, or
11130570Sobrien   (at your option) any later version.
1233965Sjdp
13130570Sobrien   This program is distributed in the hope that it will be useful,
14130570Sobrien   but WITHOUT ANY WARRANTY; without even the implied warranty of
15130570Sobrien   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16130570Sobrien   GNU General Public License for more details.
1733965Sjdp
18130570Sobrien   You should have received a copy of the GNU General Public License
19130570Sobrien   along with this program; if not, write to the Free Software
20218822Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
2133965Sjdp
2233965Sjdp/* We need a published ABI spec for this.  Until one comes out, don't
2333965Sjdp   assume this'll remain unchanged forever.  */
2433965Sjdp
25218822Sdim#include "sysdep.h"
2633965Sjdp#include "bfd.h"
2733965Sjdp#include "libbfd.h"
2833965Sjdp#include "elf-bfd.h"
2933965Sjdp
3033965Sjdp#include "elf/alpha.h"
3133965Sjdp
3233965Sjdp#define ALPHAECOFF
3333965Sjdp
3433965Sjdp#define NO_COFF_RELOCS
3533965Sjdp#define NO_COFF_SYMBOLS
3633965Sjdp#define NO_COFF_LINENOS
3733965Sjdp
3877303Sobrien/* Get the ECOFF swapping routines.  Needed for the debug information.  */
3933965Sjdp#include "coff/internal.h"
4033965Sjdp#include "coff/sym.h"
4133965Sjdp#include "coff/symconst.h"
4233965Sjdp#include "coff/ecoff.h"
4333965Sjdp#include "coff/alpha.h"
4433965Sjdp#include "aout/ar.h"
4533965Sjdp#include "libcoff.h"
4633965Sjdp#include "libecoff.h"
4733965Sjdp#define ECOFF_64
4833965Sjdp#include "ecoffswap.h"
4933965Sjdp
50218822Sdim
51218822Sdim/* Instruction data for plt generation and relaxation.  */
5233965Sjdp
53218822Sdim#define OP_LDA		0x08
54218822Sdim#define OP_LDAH		0x09
55218822Sdim#define OP_LDQ		0x29
56218822Sdim#define OP_BR		0x30
57218822Sdim#define OP_BSR		0x34
5833965Sjdp
59218822Sdim#define INSN_LDA	(OP_LDA << 26)
60218822Sdim#define INSN_LDAH	(OP_LDAH << 26)
61218822Sdim#define INSN_LDQ	(OP_LDQ << 26)
62218822Sdim#define INSN_BR		(OP_BR << 26)
6333965Sjdp
64218822Sdim#define INSN_ADDQ	0x40000400
65218822Sdim#define INSN_RDUNIQ	0x0000009e
66218822Sdim#define INSN_SUBQ	0x40000520
67218822Sdim#define INSN_S4SUBQ	0x40000560
68218822Sdim#define INSN_UNOP	0x2ffe0000
6933965Sjdp
70218822Sdim#define INSN_JSR	0x68004000
71218822Sdim#define INSN_JMP	0x68000000
72218822Sdim#define INSN_JSR_MASK	0xfc00c000
7333965Sjdp
74218822Sdim#define INSN_A(I,A)		(I | (A << 21))
75218822Sdim#define INSN_AB(I,A,B)		(I | (A << 21) | (B << 16))
76218822Sdim#define INSN_ABC(I,A,B,C)	(I | (A << 21) | (B << 16) | C)
77218822Sdim#define INSN_ABO(I,A,B,O)	(I | (A << 21) | (B << 16) | ((O) & 0xffff))
78218822Sdim#define INSN_AD(I,A,D)		(I | (A << 21) | (((D) >> 2) & 0x1fffff))
79218822Sdim
80218822Sdim/* PLT/GOT Stuff */
81218822Sdim
82218822Sdim/* Set by ld emulation.  Putting this into the link_info or hash structure
83218822Sdim   is simply working too hard.  */
84218822Sdim#ifdef USE_SECUREPLT
85218822Sdimbfd_boolean elf64_alpha_use_secureplt = TRUE;
86218822Sdim#else
87218822Sdimbfd_boolean elf64_alpha_use_secureplt = FALSE;
8833965Sjdp#endif
8933965Sjdp
90218822Sdim#define OLD_PLT_HEADER_SIZE	32
91218822Sdim#define OLD_PLT_ENTRY_SIZE	12
92218822Sdim#define NEW_PLT_HEADER_SIZE	36
93218822Sdim#define NEW_PLT_ENTRY_SIZE	4
9433965Sjdp
95218822Sdim#define PLT_HEADER_SIZE \
96218822Sdim  (elf64_alpha_use_secureplt ? NEW_PLT_HEADER_SIZE : OLD_PLT_HEADER_SIZE)
97218822Sdim#define PLT_ENTRY_SIZE \
98218822Sdim  (elf64_alpha_use_secureplt ? NEW_PLT_ENTRY_SIZE : OLD_PLT_ENTRY_SIZE)
99218822Sdim
100218822Sdim#define MAX_GOT_SIZE		(64*1024)
101218822Sdim
102218822Sdim#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so"
10333965Sjdp
10433965Sjdpstruct alpha_elf_link_hash_entry
10533965Sjdp{
10633965Sjdp  struct elf_link_hash_entry root;
10733965Sjdp
10833965Sjdp  /* External symbol information.  */
10933965Sjdp  EXTR esym;
11033965Sjdp
11133965Sjdp  /* Cumulative flags for all the .got entries.  */
11233965Sjdp  int flags;
11333965Sjdp
114104841Sobrien  /* Contexts in which a literal was referenced.  */
115218822Sdim#define ALPHA_ELF_LINK_HASH_LU_ADDR	 0x01
116218822Sdim#define ALPHA_ELF_LINK_HASH_LU_MEM	 0x02
117218822Sdim#define ALPHA_ELF_LINK_HASH_LU_BYTE	 0x04
118218822Sdim#define ALPHA_ELF_LINK_HASH_LU_JSR	 0x08
119218822Sdim#define ALPHA_ELF_LINK_HASH_LU_TLSGD	 0x10
120218822Sdim#define ALPHA_ELF_LINK_HASH_LU_TLSLDM	 0x20
121218822Sdim#define ALPHA_ELF_LINK_HASH_LU_JSRDIRECT 0x40
122218822Sdim#define ALPHA_ELF_LINK_HASH_LU_PLT	 0x38
123218822Sdim#define ALPHA_ELF_LINK_HASH_TLS_IE	 0x80
12433965Sjdp
12533965Sjdp  /* Used to implement multiple .got subsections.  */
12633965Sjdp  struct alpha_elf_got_entry
12733965Sjdp  {
12833965Sjdp    struct alpha_elf_got_entry *next;
12933965Sjdp
130130570Sobrien    /* Which .got subsection?  */
13133965Sjdp    bfd *gotobj;
13233965Sjdp
133130570Sobrien    /* The addend in effect for this entry.  */
13433965Sjdp    bfd_vma addend;
13533965Sjdp
136130570Sobrien    /* The .got offset for this entry.  */
13733965Sjdp    int got_offset;
13833965Sjdp
139218822Sdim    /* The .plt offset for this entry.  */
140218822Sdim    int plt_offset;
141218822Sdim
142104841Sobrien    /* How many references to this entry?  */
143104841Sobrien    int use_count;
14433965Sjdp
145104841Sobrien    /* The relocation type of this entry.  */
146104841Sobrien    unsigned char reloc_type;
14760510Sobrien
148104841Sobrien    /* How a LITERAL is used.  */
149104841Sobrien    unsigned char flags;
150104841Sobrien
151104841Sobrien    /* Have we initialized the dynamic relocation for this entry?  */
152104841Sobrien    unsigned char reloc_done;
153104841Sobrien
154104841Sobrien    /* Have we adjusted this entry for SEC_MERGE?  */
155104841Sobrien    unsigned char reloc_xlated;
15633965Sjdp  } *got_entries;
15733965Sjdp
158130570Sobrien  /* Used to count non-got, non-plt relocations for delayed sizing
15933965Sjdp     of relocation sections.  */
16033965Sjdp  struct alpha_elf_reloc_entry
16133965Sjdp  {
16233965Sjdp    struct alpha_elf_reloc_entry *next;
16333965Sjdp
164130570Sobrien    /* Which .reloc section? */
16533965Sjdp    asection *srel;
16633965Sjdp
167130570Sobrien    /* What kind of relocation? */
16889862Sobrien    unsigned int rtype;
16933965Sjdp
170130570Sobrien    /* Is this against read-only section? */
17189862Sobrien    unsigned int reltext : 1;
17289862Sobrien
173130570Sobrien    /* How many did we find?  */
17433965Sjdp    unsigned long count;
17533965Sjdp  } *reloc_entries;
17633965Sjdp};
17733965Sjdp
17833965Sjdp/* Alpha ELF linker hash table.  */
17933965Sjdp
18033965Sjdpstruct alpha_elf_link_hash_table
18133965Sjdp{
18233965Sjdp  struct elf_link_hash_table root;
18333965Sjdp
18433965Sjdp  /* The head of a list of .got subsections linked through
18533965Sjdp     alpha_elf_tdata(abfd)->got_link_next.  */
18633965Sjdp  bfd *got_list;
187218822Sdim
188218822Sdim  /* The most recent relax pass that we've seen.  The GOTs
189218822Sdim     should be regenerated if this doesn't match.  */
190218822Sdim  int relax_trip;
19133965Sjdp};
19233965Sjdp
19333965Sjdp/* Look up an entry in a Alpha ELF linker hash table.  */
19433965Sjdp
19533965Sjdp#define alpha_elf_link_hash_lookup(table, string, create, copy, follow)	\
19633965Sjdp  ((struct alpha_elf_link_hash_entry *)					\
19733965Sjdp   elf_link_hash_lookup (&(table)->root, (string), (create),		\
19833965Sjdp			 (copy), (follow)))
19933965Sjdp
20033965Sjdp/* Traverse a Alpha ELF linker hash table.  */
20133965Sjdp
20233965Sjdp#define alpha_elf_link_hash_traverse(table, func, info)			\
20333965Sjdp  (elf_link_hash_traverse						\
20433965Sjdp   (&(table)->root,							\
205218822Sdim    (bfd_boolean (*) (struct elf_link_hash_entry *, PTR)) (func),	\
20633965Sjdp    (info)))
20733965Sjdp
20833965Sjdp/* Get the Alpha ELF linker hash table from a link_info structure.  */
20933965Sjdp
21033965Sjdp#define alpha_elf_hash_table(p) \
21133965Sjdp  ((struct alpha_elf_link_hash_table *) ((p)->hash))
21233965Sjdp
21333965Sjdp/* Get the object's symbols as our own entry type.  */
21433965Sjdp
21533965Sjdp#define alpha_elf_sym_hashes(abfd) \
21633965Sjdp  ((struct alpha_elf_link_hash_entry **)elf_sym_hashes(abfd))
21733965Sjdp
218130570Sobrien/* Should we do dynamic things to this symbol?  This differs from the
219130570Sobrien   generic version in that we never need to consider function pointer
220130570Sobrien   equality wrt PLT entries -- we don't create a PLT entry if a symbol's
221130570Sobrien   address is ever taken.  */
22233965Sjdp
223130570Sobrienstatic inline bfd_boolean
224218822Sdimalpha_elf_dynamic_symbol_p (struct elf_link_hash_entry *h,
225218822Sdim			    struct bfd_link_info *info)
22677303Sobrien{
227130570Sobrien  return _bfd_elf_dynamic_symbol_p (h, info, 0);
22877303Sobrien}
22977303Sobrien
23033965Sjdp/* Create an entry in a Alpha ELF linker hash table.  */
23133965Sjdp
23233965Sjdpstatic struct bfd_hash_entry *
233218822Sdimelf64_alpha_link_hash_newfunc (struct bfd_hash_entry *entry,
234218822Sdim			       struct bfd_hash_table *table,
235218822Sdim			       const char *string)
23633965Sjdp{
23733965Sjdp  struct alpha_elf_link_hash_entry *ret =
23833965Sjdp    (struct alpha_elf_link_hash_entry *) entry;
23933965Sjdp
24033965Sjdp  /* Allocate the structure if it has not already been allocated by a
24133965Sjdp     subclass.  */
24233965Sjdp  if (ret == (struct alpha_elf_link_hash_entry *) NULL)
24333965Sjdp    ret = ((struct alpha_elf_link_hash_entry *)
24433965Sjdp	   bfd_hash_allocate (table,
24533965Sjdp			      sizeof (struct alpha_elf_link_hash_entry)));
24633965Sjdp  if (ret == (struct alpha_elf_link_hash_entry *) NULL)
24733965Sjdp    return (struct bfd_hash_entry *) ret;
24833965Sjdp
24933965Sjdp  /* Call the allocation method of the superclass.  */
25033965Sjdp  ret = ((struct alpha_elf_link_hash_entry *)
25133965Sjdp	 _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
25233965Sjdp				     table, string));
25333965Sjdp  if (ret != (struct alpha_elf_link_hash_entry *) NULL)
25433965Sjdp    {
25533965Sjdp      /* Set local fields.  */
25633965Sjdp      memset (&ret->esym, 0, sizeof (EXTR));
25733965Sjdp      /* We use -2 as a marker to indicate that the information has
25833965Sjdp	 not been set.  -1 means there is no associated ifd.  */
25933965Sjdp      ret->esym.ifd = -2;
26033965Sjdp      ret->flags = 0;
26133965Sjdp      ret->got_entries = NULL;
26233965Sjdp      ret->reloc_entries = NULL;
26333965Sjdp    }
26433965Sjdp
26533965Sjdp  return (struct bfd_hash_entry *) ret;
26633965Sjdp}
26733965Sjdp
26833965Sjdp/* Create a Alpha ELF linker hash table.  */
26933965Sjdp
27033965Sjdpstatic struct bfd_link_hash_table *
271218822Sdimelf64_alpha_bfd_link_hash_table_create (bfd *abfd)
27233965Sjdp{
27333965Sjdp  struct alpha_elf_link_hash_table *ret;
27489862Sobrien  bfd_size_type amt = sizeof (struct alpha_elf_link_hash_table);
27533965Sjdp
276104841Sobrien  ret = (struct alpha_elf_link_hash_table *) bfd_zmalloc (amt);
27733965Sjdp  if (ret == (struct alpha_elf_link_hash_table *) NULL)
27833965Sjdp    return NULL;
27933965Sjdp
280218822Sdim  if (!_bfd_elf_link_hash_table_init (&ret->root, abfd,
281218822Sdim				      elf64_alpha_link_hash_newfunc,
282218822Sdim				      sizeof (struct alpha_elf_link_hash_entry)))
28333965Sjdp    {
284104841Sobrien      free (ret);
28533965Sjdp      return NULL;
28633965Sjdp    }
28733965Sjdp
28833965Sjdp  return &ret->root.root;
28933965Sjdp}
29033965Sjdp
29133965Sjdp/* We have some private fields hanging off of the elf_tdata structure.  */
29233965Sjdp
29333965Sjdpstruct alpha_elf_obj_tdata
29433965Sjdp{
29533965Sjdp  struct elf_obj_tdata root;
29633965Sjdp
29733965Sjdp  /* For every input file, these are the got entries for that object's
29833965Sjdp     local symbols.  */
29933965Sjdp  struct alpha_elf_got_entry ** local_got_entries;
30033965Sjdp
30133965Sjdp  /* For every input file, this is the object that owns the got that
30233965Sjdp     this input file uses.  */
30333965Sjdp  bfd *gotobj;
30433965Sjdp
30533965Sjdp  /* For every got, this is a linked list through the objects using this got */
30633965Sjdp  bfd *in_got_link_next;
30733965Sjdp
30833965Sjdp  /* For every got, this is a link to the next got subsegment.  */
30933965Sjdp  bfd *got_link_next;
31033965Sjdp
31133965Sjdp  /* For every got, this is the section.  */
31233965Sjdp  asection *got;
31333965Sjdp
314104841Sobrien  /* For every got, this is it's total number of words.  */
315104841Sobrien  int total_got_size;
31633965Sjdp
317104841Sobrien  /* For every got, this is the sum of the number of words required
31833965Sjdp     to hold all of the member object's local got.  */
319104841Sobrien  int local_got_size;
32033965Sjdp};
32133965Sjdp
32233965Sjdp#define alpha_elf_tdata(abfd) \
32333965Sjdp  ((struct alpha_elf_obj_tdata *) (abfd)->tdata.any)
32433965Sjdp
325130570Sobrienstatic bfd_boolean
326218822Sdimelf64_alpha_mkobject (bfd *abfd)
32733965Sjdp{
32833965Sjdp  if (abfd->tdata.any == NULL)
329218822Sdim    {
330218822Sdim      bfd_size_type amt = sizeof (struct alpha_elf_obj_tdata);
331218822Sdim      abfd->tdata.any = bfd_zalloc (abfd, amt);
332218822Sdim      if (abfd->tdata.any == NULL)
333218822Sdim	return FALSE;
334218822Sdim    }
335218822Sdim  return bfd_elf_mkobject (abfd);
33633965Sjdp}
33733965Sjdp
338130570Sobrienstatic bfd_boolean
339218822Sdimelf64_alpha_object_p (bfd *abfd)
34033965Sjdp{
34133965Sjdp  /* Set the right machine number for an Alpha ELF file.  */
34233965Sjdp  return bfd_default_set_arch_mach (abfd, bfd_arch_alpha, 0);
34333965Sjdp}
34433965Sjdp
345218822Sdim/* A relocation function which doesn't do anything.  */
346218822Sdim
347218822Sdimstatic bfd_reloc_status_type
348218822Sdimelf64_alpha_reloc_nil (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc,
349218822Sdim		       asymbol *sym ATTRIBUTE_UNUSED,
350218822Sdim		       PTR data ATTRIBUTE_UNUSED, asection *sec,
351218822Sdim		       bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
352218822Sdim{
353218822Sdim  if (output_bfd)
354218822Sdim    reloc->address += sec->output_offset;
355218822Sdim  return bfd_reloc_ok;
356218822Sdim}
357218822Sdim
358218822Sdim/* A relocation function used for an unsupported reloc.  */
359218822Sdim
360218822Sdimstatic bfd_reloc_status_type
361218822Sdimelf64_alpha_reloc_bad (bfd *abfd ATTRIBUTE_UNUSED, arelent *reloc,
362218822Sdim		       asymbol *sym ATTRIBUTE_UNUSED,
363218822Sdim		       PTR data ATTRIBUTE_UNUSED, asection *sec,
364218822Sdim		       bfd *output_bfd, char **error_message ATTRIBUTE_UNUSED)
365218822Sdim{
366218822Sdim  if (output_bfd)
367218822Sdim    reloc->address += sec->output_offset;
368218822Sdim  return bfd_reloc_notsupported;
369218822Sdim}
370218822Sdim
371218822Sdim/* Do the work of the GPDISP relocation.  */
372218822Sdim
373218822Sdimstatic bfd_reloc_status_type
374218822Sdimelf64_alpha_do_reloc_gpdisp (bfd *abfd, bfd_vma gpdisp, bfd_byte *p_ldah,
375218822Sdim			     bfd_byte *p_lda)
376218822Sdim{
377218822Sdim  bfd_reloc_status_type ret = bfd_reloc_ok;
378218822Sdim  bfd_vma addend;
379218822Sdim  unsigned long i_ldah, i_lda;
380218822Sdim
381218822Sdim  i_ldah = bfd_get_32 (abfd, p_ldah);
382218822Sdim  i_lda = bfd_get_32 (abfd, p_lda);
383218822Sdim
384218822Sdim  /* Complain if the instructions are not correct.  */
385218822Sdim  if (((i_ldah >> 26) & 0x3f) != 0x09
386218822Sdim      || ((i_lda >> 26) & 0x3f) != 0x08)
387218822Sdim    ret = bfd_reloc_dangerous;
388218822Sdim
389218822Sdim  /* Extract the user-supplied offset, mirroring the sign extensions
390218822Sdim     that the instructions perform.  */
391218822Sdim  addend = ((i_ldah & 0xffff) << 16) | (i_lda & 0xffff);
392218822Sdim  addend = (addend ^ 0x80008000) - 0x80008000;
393218822Sdim
394218822Sdim  gpdisp += addend;
395218822Sdim
396218822Sdim  if ((bfd_signed_vma) gpdisp < -(bfd_signed_vma) 0x80000000
397218822Sdim      || (bfd_signed_vma) gpdisp >= (bfd_signed_vma) 0x7fff8000)
398218822Sdim    ret = bfd_reloc_overflow;
399218822Sdim
400218822Sdim  /* compensate for the sign extension again.  */
401218822Sdim  i_ldah = ((i_ldah & 0xffff0000)
402218822Sdim	    | (((gpdisp >> 16) + ((gpdisp >> 15) & 1)) & 0xffff));
403218822Sdim  i_lda = (i_lda & 0xffff0000) | (gpdisp & 0xffff);
404218822Sdim
405218822Sdim  bfd_put_32 (abfd, (bfd_vma) i_ldah, p_ldah);
406218822Sdim  bfd_put_32 (abfd, (bfd_vma) i_lda, p_lda);
407218822Sdim
408218822Sdim  return ret;
409218822Sdim}
410218822Sdim
411218822Sdim/* The special function for the GPDISP reloc.  */
412218822Sdim
413218822Sdimstatic bfd_reloc_status_type
414218822Sdimelf64_alpha_reloc_gpdisp (bfd *abfd, arelent *reloc_entry,
415218822Sdim			  asymbol *sym ATTRIBUTE_UNUSED, PTR data,
416218822Sdim			  asection *input_section, bfd *output_bfd,
417218822Sdim			  char **err_msg)
418218822Sdim{
419218822Sdim  bfd_reloc_status_type ret;
420218822Sdim  bfd_vma gp, relocation;
421218822Sdim  bfd_vma high_address;
422218822Sdim  bfd_byte *p_ldah, *p_lda;
423218822Sdim
424218822Sdim  /* Don't do anything if we're not doing a final link.  */
425218822Sdim  if (output_bfd)
426218822Sdim    {
427218822Sdim      reloc_entry->address += input_section->output_offset;
428218822Sdim      return bfd_reloc_ok;
429218822Sdim    }
430218822Sdim
431218822Sdim  high_address = bfd_get_section_limit (abfd, input_section);
432218822Sdim  if (reloc_entry->address > high_address
433218822Sdim      || reloc_entry->address + reloc_entry->addend > high_address)
434218822Sdim    return bfd_reloc_outofrange;
435218822Sdim
436218822Sdim  /* The gp used in the portion of the output object to which this
437218822Sdim     input object belongs is cached on the input bfd.  */
438218822Sdim  gp = _bfd_get_gp_value (abfd);
439218822Sdim
440218822Sdim  relocation = (input_section->output_section->vma
441218822Sdim		+ input_section->output_offset
442218822Sdim		+ reloc_entry->address);
443218822Sdim
444218822Sdim  p_ldah = (bfd_byte *) data + reloc_entry->address;
445218822Sdim  p_lda = p_ldah + reloc_entry->addend;
446218822Sdim
447218822Sdim  ret = elf64_alpha_do_reloc_gpdisp (abfd, gp - relocation, p_ldah, p_lda);
448218822Sdim
449218822Sdim  /* Complain if the instructions are not correct.  */
450218822Sdim  if (ret == bfd_reloc_dangerous)
451218822Sdim    *err_msg = _("GPDISP relocation did not find ldah and lda instructions");
452218822Sdim
453218822Sdim  return ret;
454218822Sdim}
455218822Sdim
45633965Sjdp/* In case we're on a 32-bit machine, construct a 64-bit "-1" value
45733965Sjdp   from smaller values.  Start with zero, widen, *then* decrement.  */
45833965Sjdp#define MINUS_ONE	(((bfd_vma)0) - 1)
45933965Sjdp
46089862Sobrien#define SKIP_HOWTO(N) \
46189862Sobrien  HOWTO(N, 0, 0, 0, 0, 0, 0, elf64_alpha_reloc_bad, 0, 0, 0, 0, 0)
46289862Sobrien
46333965Sjdpstatic reloc_howto_type elf64_alpha_howto_table[] =
46433965Sjdp{
46533965Sjdp  HOWTO (R_ALPHA_NONE,		/* type */
46633965Sjdp	 0,			/* rightshift */
46733965Sjdp	 0,			/* size (0 = byte, 1 = short, 2 = long) */
46833965Sjdp	 8,			/* bitsize */
469130570Sobrien	 TRUE,			/* pc_relative */
47033965Sjdp	 0,			/* bitpos */
47133965Sjdp	 complain_overflow_dont, /* complain_on_overflow */
47233965Sjdp	 elf64_alpha_reloc_nil,	/* special_function */
47333965Sjdp	 "NONE",		/* name */
474130570Sobrien	 FALSE,			/* partial_inplace */
47533965Sjdp	 0,			/* src_mask */
47633965Sjdp	 0,			/* dst_mask */
477130570Sobrien	 TRUE),			/* pcrel_offset */
47833965Sjdp
47933965Sjdp  /* A 32 bit reference to a symbol.  */
48033965Sjdp  HOWTO (R_ALPHA_REFLONG,	/* type */
48133965Sjdp	 0,			/* rightshift */
48233965Sjdp	 2,			/* size (0 = byte, 1 = short, 2 = long) */
48333965Sjdp	 32,			/* bitsize */
484130570Sobrien	 FALSE,			/* pc_relative */
48533965Sjdp	 0,			/* bitpos */
48633965Sjdp	 complain_overflow_bitfield, /* complain_on_overflow */
48733965Sjdp	 0,			/* special_function */
48833965Sjdp	 "REFLONG",		/* name */
489130570Sobrien	 FALSE,			/* partial_inplace */
49033965Sjdp	 0xffffffff,		/* src_mask */
49133965Sjdp	 0xffffffff,		/* dst_mask */
492130570Sobrien	 FALSE),		/* pcrel_offset */
49333965Sjdp
49433965Sjdp  /* A 64 bit reference to a symbol.  */
49533965Sjdp  HOWTO (R_ALPHA_REFQUAD,	/* type */
49633965Sjdp	 0,			/* rightshift */
49733965Sjdp	 4,			/* size (0 = byte, 1 = short, 2 = long) */
49833965Sjdp	 64,			/* bitsize */
499130570Sobrien	 FALSE,			/* pc_relative */
50033965Sjdp	 0,			/* bitpos */
50133965Sjdp	 complain_overflow_bitfield, /* complain_on_overflow */
50233965Sjdp	 0,			/* special_function */
50333965Sjdp	 "REFQUAD",		/* name */
504130570Sobrien	 FALSE,			/* partial_inplace */
50533965Sjdp	 MINUS_ONE,		/* src_mask */
50633965Sjdp	 MINUS_ONE,		/* dst_mask */
507130570Sobrien	 FALSE),		/* pcrel_offset */
50833965Sjdp
50933965Sjdp  /* A 32 bit GP relative offset.  This is just like REFLONG except
51033965Sjdp     that when the value is used the value of the gp register will be
51133965Sjdp     added in.  */
51233965Sjdp  HOWTO (R_ALPHA_GPREL32,	/* type */
51333965Sjdp	 0,			/* rightshift */
51433965Sjdp	 2,			/* size (0 = byte, 1 = short, 2 = long) */
51533965Sjdp	 32,			/* bitsize */
516130570Sobrien	 FALSE,			/* pc_relative */
51733965Sjdp	 0,			/* bitpos */
51833965Sjdp	 complain_overflow_bitfield, /* complain_on_overflow */
51933965Sjdp	 0,			/* special_function */
52033965Sjdp	 "GPREL32",		/* name */
521130570Sobrien	 FALSE,			/* partial_inplace */
52233965Sjdp	 0xffffffff,		/* src_mask */
52333965Sjdp	 0xffffffff,		/* dst_mask */
524130570Sobrien	 FALSE),		/* pcrel_offset */
52533965Sjdp
52633965Sjdp  /* Used for an instruction that refers to memory off the GP register.  */
52733965Sjdp  HOWTO (R_ALPHA_LITERAL,	/* type */
52833965Sjdp	 0,			/* rightshift */
52989862Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
53033965Sjdp	 16,			/* bitsize */
531130570Sobrien	 FALSE,			/* pc_relative */
53233965Sjdp	 0,			/* bitpos */
53333965Sjdp	 complain_overflow_signed, /* complain_on_overflow */
53433965Sjdp	 0,			/* special_function */
53533965Sjdp	 "ELF_LITERAL",		/* name */
536130570Sobrien	 FALSE,			/* partial_inplace */
53733965Sjdp	 0xffff,		/* src_mask */
53833965Sjdp	 0xffff,		/* dst_mask */
539130570Sobrien	 FALSE),		/* pcrel_offset */
54033965Sjdp
54133965Sjdp  /* This reloc only appears immediately following an ELF_LITERAL reloc.
54233965Sjdp     It identifies a use of the literal.  The symbol index is special:
54333965Sjdp     1 means the literal address is in the base register of a memory
54433965Sjdp     format instruction; 2 means the literal address is in the byte
54533965Sjdp     offset register of a byte-manipulation instruction; 3 means the
54633965Sjdp     literal address is in the target register of a jsr instruction.
54733965Sjdp     This does not actually do any relocation.  */
54833965Sjdp  HOWTO (R_ALPHA_LITUSE,	/* type */
54933965Sjdp	 0,			/* rightshift */
55089862Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
55133965Sjdp	 32,			/* bitsize */
552130570Sobrien	 FALSE,			/* pc_relative */
55333965Sjdp	 0,			/* bitpos */
55433965Sjdp	 complain_overflow_dont, /* complain_on_overflow */
55533965Sjdp	 elf64_alpha_reloc_nil,	/* special_function */
55633965Sjdp	 "LITUSE",		/* name */
557130570Sobrien	 FALSE,			/* partial_inplace */
55833965Sjdp	 0,			/* src_mask */
55933965Sjdp	 0,			/* dst_mask */
560130570Sobrien	 FALSE),		/* pcrel_offset */
56133965Sjdp
56233965Sjdp  /* Load the gp register.  This is always used for a ldah instruction
56333965Sjdp     which loads the upper 16 bits of the gp register.  The symbol
56433965Sjdp     index of the GPDISP instruction is an offset in bytes to the lda
56533965Sjdp     instruction that loads the lower 16 bits.  The value to use for
56633965Sjdp     the relocation is the difference between the GP value and the
56733965Sjdp     current location; the load will always be done against a register
56833965Sjdp     holding the current address.
56933965Sjdp
57033965Sjdp     NOTE: Unlike ECOFF, partial in-place relocation is not done.  If
57133965Sjdp     any offset is present in the instructions, it is an offset from
57233965Sjdp     the register to the ldah instruction.  This lets us avoid any
57333965Sjdp     stupid hackery like inventing a gp value to do partial relocation
57433965Sjdp     against.  Also unlike ECOFF, we do the whole relocation off of
57533965Sjdp     the GPDISP rather than a GPDISP_HI16/GPDISP_LO16 pair.  An odd,
57633965Sjdp     space consuming bit, that, since all the information was present
57733965Sjdp     in the GPDISP_HI16 reloc.  */
57833965Sjdp  HOWTO (R_ALPHA_GPDISP,	/* type */
57933965Sjdp	 16,			/* rightshift */
58033965Sjdp	 2,			/* size (0 = byte, 1 = short, 2 = long) */
58133965Sjdp	 16,			/* bitsize */
582130570Sobrien	 FALSE,			/* pc_relative */
58333965Sjdp	 0,			/* bitpos */
58433965Sjdp	 complain_overflow_dont, /* complain_on_overflow */
58533965Sjdp	 elf64_alpha_reloc_gpdisp, /* special_function */
58633965Sjdp	 "GPDISP",		/* name */
587130570Sobrien	 FALSE,			/* partial_inplace */
58833965Sjdp	 0xffff,		/* src_mask */
58933965Sjdp	 0xffff,		/* dst_mask */
590130570Sobrien	 TRUE),			/* pcrel_offset */
59133965Sjdp
59233965Sjdp  /* A 21 bit branch.  */
59333965Sjdp  HOWTO (R_ALPHA_BRADDR,	/* type */
59433965Sjdp	 2,			/* rightshift */
59533965Sjdp	 2,			/* size (0 = byte, 1 = short, 2 = long) */
59633965Sjdp	 21,			/* bitsize */
597130570Sobrien	 TRUE,			/* pc_relative */
59833965Sjdp	 0,			/* bitpos */
59933965Sjdp	 complain_overflow_signed, /* complain_on_overflow */
60033965Sjdp	 0,			/* special_function */
60133965Sjdp	 "BRADDR",		/* name */
602130570Sobrien	 FALSE,			/* partial_inplace */
60333965Sjdp	 0x1fffff,		/* src_mask */
60433965Sjdp	 0x1fffff,		/* dst_mask */
605130570Sobrien	 TRUE),			/* pcrel_offset */
60633965Sjdp
60733965Sjdp  /* A hint for a jump to a register.  */
60833965Sjdp  HOWTO (R_ALPHA_HINT,		/* type */
60933965Sjdp	 2,			/* rightshift */
61089862Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
61133965Sjdp	 14,			/* bitsize */
612130570Sobrien	 TRUE,			/* pc_relative */
61333965Sjdp	 0,			/* bitpos */
61433965Sjdp	 complain_overflow_dont, /* complain_on_overflow */
61533965Sjdp	 0,			/* special_function */
61633965Sjdp	 "HINT",		/* name */
617130570Sobrien	 FALSE,			/* partial_inplace */
61833965Sjdp	 0x3fff,		/* src_mask */
61933965Sjdp	 0x3fff,		/* dst_mask */
620130570Sobrien	 TRUE),			/* pcrel_offset */
62133965Sjdp
62233965Sjdp  /* 16 bit PC relative offset.  */
62333965Sjdp  HOWTO (R_ALPHA_SREL16,	/* type */
62433965Sjdp	 0,			/* rightshift */
62533965Sjdp	 1,			/* size (0 = byte, 1 = short, 2 = long) */
62633965Sjdp	 16,			/* bitsize */
627130570Sobrien	 TRUE,			/* pc_relative */
62833965Sjdp	 0,			/* bitpos */
62933965Sjdp	 complain_overflow_signed, /* complain_on_overflow */
63033965Sjdp	 0,			/* special_function */
63133965Sjdp	 "SREL16",		/* name */
632130570Sobrien	 FALSE,			/* partial_inplace */
63333965Sjdp	 0xffff,		/* src_mask */
63433965Sjdp	 0xffff,		/* dst_mask */
635130570Sobrien	 TRUE),			/* pcrel_offset */
63633965Sjdp
63733965Sjdp  /* 32 bit PC relative offset.  */
63833965Sjdp  HOWTO (R_ALPHA_SREL32,	/* type */
63933965Sjdp	 0,			/* rightshift */
64033965Sjdp	 2,			/* size (0 = byte, 1 = short, 2 = long) */
64133965Sjdp	 32,			/* bitsize */
642130570Sobrien	 TRUE,			/* pc_relative */
64333965Sjdp	 0,			/* bitpos */
64433965Sjdp	 complain_overflow_signed, /* complain_on_overflow */
64533965Sjdp	 0,			/* special_function */
64633965Sjdp	 "SREL32",		/* name */
647130570Sobrien	 FALSE,			/* partial_inplace */
64833965Sjdp	 0xffffffff,		/* src_mask */
64933965Sjdp	 0xffffffff,		/* dst_mask */
650130570Sobrien	 TRUE),			/* pcrel_offset */
65133965Sjdp
65233965Sjdp  /* A 64 bit PC relative offset.  */
65333965Sjdp  HOWTO (R_ALPHA_SREL64,	/* type */
65433965Sjdp	 0,			/* rightshift */
65533965Sjdp	 4,			/* size (0 = byte, 1 = short, 2 = long) */
65633965Sjdp	 64,			/* bitsize */
657130570Sobrien	 TRUE,			/* pc_relative */
65833965Sjdp	 0,			/* bitpos */
65933965Sjdp	 complain_overflow_signed, /* complain_on_overflow */
66033965Sjdp	 0,			/* special_function */
66133965Sjdp	 "SREL64",		/* name */
662130570Sobrien	 FALSE,			/* partial_inplace */
66333965Sjdp	 MINUS_ONE,		/* src_mask */
66433965Sjdp	 MINUS_ONE,		/* dst_mask */
665130570Sobrien	 TRUE),			/* pcrel_offset */
66633965Sjdp
66789862Sobrien  /* Skip 12 - 16; deprecated ECOFF relocs.  */
66889862Sobrien  SKIP_HOWTO (12),
66989862Sobrien  SKIP_HOWTO (13),
67089862Sobrien  SKIP_HOWTO (14),
67189862Sobrien  SKIP_HOWTO (15),
67289862Sobrien  SKIP_HOWTO (16),
67333965Sjdp
67438889Sjdp  /* The high 16 bits of the displacement from GP to the target.  */
67538889Sjdp  HOWTO (R_ALPHA_GPRELHIGH,
67638889Sjdp	 0,			/* rightshift */
67789862Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
67860510Sobrien	 16,			/* bitsize */
679130570Sobrien	 FALSE,			/* pc_relative */
68038889Sjdp	 0,			/* bitpos */
68160510Sobrien	 complain_overflow_signed, /* complain_on_overflow */
68289862Sobrien	 0,			/* special_function */
68338889Sjdp	 "GPRELHIGH",		/* name */
684130570Sobrien	 FALSE,			/* partial_inplace */
68560510Sobrien	 0xffff,		/* src_mask */
68660510Sobrien	 0xffff,		/* dst_mask */
687130570Sobrien	 FALSE),		/* pcrel_offset */
68838889Sjdp
68938889Sjdp  /* The low 16 bits of the displacement from GP to the target.  */
69038889Sjdp  HOWTO (R_ALPHA_GPRELLOW,
69138889Sjdp	 0,			/* rightshift */
69289862Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
69360510Sobrien	 16,			/* bitsize */
694130570Sobrien	 FALSE,			/* pc_relative */
69538889Sjdp	 0,			/* bitpos */
69638889Sjdp	 complain_overflow_dont, /* complain_on_overflow */
69789862Sobrien	 0,			/* special_function */
69838889Sjdp	 "GPRELLOW",		/* name */
699130570Sobrien	 FALSE,			/* partial_inplace */
70060510Sobrien	 0xffff,		/* src_mask */
70160510Sobrien	 0xffff,		/* dst_mask */
702130570Sobrien	 FALSE),		/* pcrel_offset */
70338889Sjdp
70438889Sjdp  /* A 16-bit displacement from the GP to the target.  */
70589862Sobrien  HOWTO (R_ALPHA_GPREL16,
70638889Sjdp	 0,			/* rightshift */
70789862Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
70860510Sobrien	 16,			/* bitsize */
709130570Sobrien	 FALSE,			/* pc_relative */
71038889Sjdp	 0,			/* bitpos */
71160510Sobrien	 complain_overflow_signed, /* complain_on_overflow */
71260510Sobrien	 0,			/* special_function */
71389862Sobrien	 "GPREL16",		/* name */
714130570Sobrien	 FALSE,			/* partial_inplace */
71560510Sobrien	 0xffff,		/* src_mask */
71660510Sobrien	 0xffff,		/* dst_mask */
717130570Sobrien	 FALSE),		/* pcrel_offset */
71838889Sjdp
71989862Sobrien  /* Skip 20 - 23; deprecated ECOFF relocs.  */
72089862Sobrien  SKIP_HOWTO (20),
72189862Sobrien  SKIP_HOWTO (21),
72289862Sobrien  SKIP_HOWTO (22),
72389862Sobrien  SKIP_HOWTO (23),
72438889Sjdp
72577303Sobrien  /* Misc ELF relocations.  */
72638889Sjdp
72738889Sjdp  /* A dynamic relocation to copy the target into our .dynbss section.  */
72838889Sjdp  /* Not generated, as all Alpha objects use PIC, so it is not needed.  It
72938889Sjdp     is present because every other ELF has one, but should not be used
73038889Sjdp     because .dynbss is an ugly thing.  */
73133965Sjdp  HOWTO (R_ALPHA_COPY,
73233965Sjdp	 0,
73333965Sjdp	 0,
73433965Sjdp	 0,
735130570Sobrien	 FALSE,
73633965Sjdp	 0,
73733965Sjdp	 complain_overflow_dont,
73833965Sjdp	 bfd_elf_generic_reloc,
73933965Sjdp	 "COPY",
740130570Sobrien	 FALSE,
74133965Sjdp	 0,
74233965Sjdp	 0,
743130570Sobrien	 TRUE),
74433965Sjdp
74538889Sjdp  /* A dynamic relocation for a .got entry.  */
74633965Sjdp  HOWTO (R_ALPHA_GLOB_DAT,
74733965Sjdp	 0,
74833965Sjdp	 0,
74933965Sjdp	 0,
750130570Sobrien	 FALSE,
75133965Sjdp	 0,
75233965Sjdp	 complain_overflow_dont,
75333965Sjdp	 bfd_elf_generic_reloc,
75433965Sjdp	 "GLOB_DAT",
755130570Sobrien	 FALSE,
75633965Sjdp	 0,
75733965Sjdp	 0,
758130570Sobrien	 TRUE),
75933965Sjdp
76038889Sjdp  /* A dynamic relocation for a .plt entry.  */
76133965Sjdp  HOWTO (R_ALPHA_JMP_SLOT,
76233965Sjdp	 0,
76333965Sjdp	 0,
76433965Sjdp	 0,
765130570Sobrien	 FALSE,
76633965Sjdp	 0,
76733965Sjdp	 complain_overflow_dont,
76833965Sjdp	 bfd_elf_generic_reloc,
76933965Sjdp	 "JMP_SLOT",
770130570Sobrien	 FALSE,
77133965Sjdp	 0,
77233965Sjdp	 0,
773130570Sobrien	 TRUE),
77433965Sjdp
77538889Sjdp  /* A dynamic relocation to add the base of the DSO to a 64-bit field.  */
77633965Sjdp  HOWTO (R_ALPHA_RELATIVE,
77733965Sjdp	 0,
77833965Sjdp	 0,
77933965Sjdp	 0,
780130570Sobrien	 FALSE,
78133965Sjdp	 0,
78233965Sjdp	 complain_overflow_dont,
78333965Sjdp	 bfd_elf_generic_reloc,
78433965Sjdp	 "RELATIVE",
785130570Sobrien	 FALSE,
78633965Sjdp	 0,
78733965Sjdp	 0,
788130570Sobrien	 TRUE),
78991049Sobrien
79091049Sobrien  /* A 21 bit branch that adjusts for gp loads.  */
79191049Sobrien  HOWTO (R_ALPHA_BRSGP,		/* type */
79291049Sobrien	 2,			/* rightshift */
79391049Sobrien	 2,			/* size (0 = byte, 1 = short, 2 = long) */
79491049Sobrien	 21,			/* bitsize */
795130570Sobrien	 TRUE,			/* pc_relative */
79691049Sobrien	 0,			/* bitpos */
79791049Sobrien	 complain_overflow_signed, /* complain_on_overflow */
79891049Sobrien	 0,			/* special_function */
79991049Sobrien	 "BRSGP",		/* name */
800130570Sobrien	 FALSE,			/* partial_inplace */
80191049Sobrien	 0x1fffff,		/* src_mask */
80291049Sobrien	 0x1fffff,		/* dst_mask */
803130570Sobrien	 TRUE),			/* pcrel_offset */
804104841Sobrien
805104841Sobrien  /* Creates a tls_index for the symbol in the got.  */
806104841Sobrien  HOWTO (R_ALPHA_TLSGD,		/* type */
807104841Sobrien	 0,			/* rightshift */
808104841Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
809104841Sobrien	 16,			/* bitsize */
810130570Sobrien	 FALSE,			/* pc_relative */
811104841Sobrien	 0,			/* bitpos */
812104841Sobrien	 complain_overflow_signed, /* complain_on_overflow */
813104841Sobrien	 0,			/* special_function */
814104841Sobrien	 "TLSGD",		/* name */
815130570Sobrien	 FALSE,			/* partial_inplace */
816104841Sobrien	 0xffff,		/* src_mask */
817104841Sobrien	 0xffff,		/* dst_mask */
818130570Sobrien	 FALSE),		/* pcrel_offset */
819104841Sobrien
820104841Sobrien  /* Creates a tls_index for the (current) module in the got.  */
821104841Sobrien  HOWTO (R_ALPHA_TLSLDM,	/* type */
822104841Sobrien	 0,			/* rightshift */
823104841Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
824104841Sobrien	 16,			/* bitsize */
825130570Sobrien	 FALSE,			/* pc_relative */
826104841Sobrien	 0,			/* bitpos */
827104841Sobrien	 complain_overflow_signed, /* complain_on_overflow */
828104841Sobrien	 0,			/* special_function */
829104841Sobrien	 "TLSLDM",		/* name */
830130570Sobrien	 FALSE,			/* partial_inplace */
831104841Sobrien	 0xffff,		/* src_mask */
832104841Sobrien	 0xffff,		/* dst_mask */
833130570Sobrien	 FALSE),		/* pcrel_offset */
834104841Sobrien
835104841Sobrien  /* A dynamic relocation for a DTP module entry.  */
836104841Sobrien  HOWTO (R_ALPHA_DTPMOD64,	/* type */
837104841Sobrien	 0,			/* rightshift */
838104841Sobrien	 4,			/* size (0 = byte, 1 = short, 2 = long) */
839104841Sobrien	 64,			/* bitsize */
840130570Sobrien	 FALSE,			/* pc_relative */
841104841Sobrien	 0,			/* bitpos */
842104841Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
843104841Sobrien	 0,			/* special_function */
844104841Sobrien	 "DTPMOD64",		/* name */
845130570Sobrien	 FALSE,			/* partial_inplace */
846104841Sobrien	 MINUS_ONE,		/* src_mask */
847104841Sobrien	 MINUS_ONE,		/* dst_mask */
848130570Sobrien	 FALSE),		/* pcrel_offset */
849104841Sobrien
850104841Sobrien  /* Creates a 64-bit offset in the got for the displacement
851104841Sobrien     from DTP to the target.  */
852104841Sobrien  HOWTO (R_ALPHA_GOTDTPREL,	/* type */
853104841Sobrien	 0,			/* rightshift */
854104841Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
855104841Sobrien	 16,			/* bitsize */
856130570Sobrien	 FALSE,			/* pc_relative */
857104841Sobrien	 0,			/* bitpos */
858104841Sobrien	 complain_overflow_signed, /* complain_on_overflow */
859104841Sobrien	 0,			/* special_function */
860104841Sobrien	 "GOTDTPREL",		/* name */
861130570Sobrien	 FALSE,			/* partial_inplace */
862104841Sobrien	 0xffff,		/* src_mask */
863104841Sobrien	 0xffff,		/* dst_mask */
864130570Sobrien	 FALSE),		/* pcrel_offset */
865104841Sobrien
866104841Sobrien  /* A dynamic relocation for a displacement from DTP to the target.  */
867104841Sobrien  HOWTO (R_ALPHA_DTPREL64,	/* type */
868104841Sobrien	 0,			/* rightshift */
869104841Sobrien	 4,			/* size (0 = byte, 1 = short, 2 = long) */
870104841Sobrien	 64,			/* bitsize */
871130570Sobrien	 FALSE,			/* pc_relative */
872104841Sobrien	 0,			/* bitpos */
873104841Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
874104841Sobrien	 0,			/* special_function */
875104841Sobrien	 "DTPREL64",		/* name */
876130570Sobrien	 FALSE,			/* partial_inplace */
877104841Sobrien	 MINUS_ONE,		/* src_mask */
878104841Sobrien	 MINUS_ONE,		/* dst_mask */
879130570Sobrien	 FALSE),		/* pcrel_offset */
880104841Sobrien
881104841Sobrien  /* The high 16 bits of the displacement from DTP to the target.  */
882104841Sobrien  HOWTO (R_ALPHA_DTPRELHI,	/* type */
883104841Sobrien	 0,			/* rightshift */
884104841Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
885104841Sobrien	 16,			/* bitsize */
886130570Sobrien	 FALSE,			/* pc_relative */
887104841Sobrien	 0,			/* bitpos */
888104841Sobrien	 complain_overflow_signed, /* complain_on_overflow */
889104841Sobrien	 0,			/* special_function */
890104841Sobrien	 "DTPRELHI",		/* name */
891130570Sobrien	 FALSE,			/* partial_inplace */
892104841Sobrien	 0xffff,		/* src_mask */
893104841Sobrien	 0xffff,		/* dst_mask */
894130570Sobrien	 FALSE),		/* pcrel_offset */
895104841Sobrien
896104841Sobrien  /* The low 16 bits of the displacement from DTP to the target.  */
897104841Sobrien  HOWTO (R_ALPHA_DTPRELLO,	/* type */
898104841Sobrien	 0,			/* rightshift */
899104841Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
900104841Sobrien	 16,			/* bitsize */
901130570Sobrien	 FALSE,			/* pc_relative */
902104841Sobrien	 0,			/* bitpos */
903104841Sobrien	 complain_overflow_dont, /* complain_on_overflow */
904104841Sobrien	 0,			/* special_function */
905104841Sobrien	 "DTPRELLO",		/* name */
906130570Sobrien	 FALSE,			/* partial_inplace */
907104841Sobrien	 0xffff,		/* src_mask */
908104841Sobrien	 0xffff,		/* dst_mask */
909130570Sobrien	 FALSE),		/* pcrel_offset */
910104841Sobrien
911104841Sobrien  /* A 16-bit displacement from DTP to the target.  */
912104841Sobrien  HOWTO (R_ALPHA_DTPREL16,	/* type */
913104841Sobrien	 0,			/* rightshift */
914104841Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
915104841Sobrien	 16,			/* bitsize */
916130570Sobrien	 FALSE,			/* pc_relative */
917104841Sobrien	 0,			/* bitpos */
918104841Sobrien	 complain_overflow_signed, /* complain_on_overflow */
919104841Sobrien	 0,			/* special_function */
920104841Sobrien	 "DTPREL16",		/* name */
921130570Sobrien	 FALSE,			/* partial_inplace */
922104841Sobrien	 0xffff,		/* src_mask */
923104841Sobrien	 0xffff,		/* dst_mask */
924130570Sobrien	 FALSE),		/* pcrel_offset */
925104841Sobrien
926104841Sobrien  /* Creates a 64-bit offset in the got for the displacement
927104841Sobrien     from TP to the target.  */
928104841Sobrien  HOWTO (R_ALPHA_GOTTPREL,	/* type */
929104841Sobrien	 0,			/* rightshift */
930104841Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
931104841Sobrien	 16,			/* bitsize */
932130570Sobrien	 FALSE,			/* pc_relative */
933104841Sobrien	 0,			/* bitpos */
934104841Sobrien	 complain_overflow_signed, /* complain_on_overflow */
935104841Sobrien	 0,			/* special_function */
936104841Sobrien	 "GOTTPREL",		/* name */
937130570Sobrien	 FALSE,			/* partial_inplace */
938104841Sobrien	 0xffff,		/* src_mask */
939104841Sobrien	 0xffff,		/* dst_mask */
940130570Sobrien	 FALSE),		/* pcrel_offset */
941104841Sobrien
942104841Sobrien  /* A dynamic relocation for a displacement from TP to the target.  */
943104841Sobrien  HOWTO (R_ALPHA_TPREL64,	/* type */
944104841Sobrien	 0,			/* rightshift */
945104841Sobrien	 4,			/* size (0 = byte, 1 = short, 2 = long) */
946104841Sobrien	 64,			/* bitsize */
947130570Sobrien	 FALSE,			/* pc_relative */
948104841Sobrien	 0,			/* bitpos */
949104841Sobrien	 complain_overflow_bitfield, /* complain_on_overflow */
950104841Sobrien	 0,			/* special_function */
951104841Sobrien	 "TPREL64",		/* name */
952130570Sobrien	 FALSE,			/* partial_inplace */
953104841Sobrien	 MINUS_ONE,		/* src_mask */
954104841Sobrien	 MINUS_ONE,		/* dst_mask */
955130570Sobrien	 FALSE),		/* pcrel_offset */
956104841Sobrien
957104841Sobrien  /* The high 16 bits of the displacement from TP to the target.  */
958104841Sobrien  HOWTO (R_ALPHA_TPRELHI,	/* type */
959104841Sobrien	 0,			/* rightshift */
960104841Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
961104841Sobrien	 16,			/* bitsize */
962130570Sobrien	 FALSE,			/* pc_relative */
963104841Sobrien	 0,			/* bitpos */
964104841Sobrien	 complain_overflow_signed, /* complain_on_overflow */
965104841Sobrien	 0,			/* special_function */
966104841Sobrien	 "TPRELHI",		/* name */
967130570Sobrien	 FALSE,			/* partial_inplace */
968104841Sobrien	 0xffff,		/* src_mask */
969104841Sobrien	 0xffff,		/* dst_mask */
970130570Sobrien	 FALSE),		/* pcrel_offset */
971104841Sobrien
972104841Sobrien  /* The low 16 bits of the displacement from TP to the target.  */
973104841Sobrien  HOWTO (R_ALPHA_TPRELLO,	/* type */
974104841Sobrien	 0,			/* rightshift */
975104841Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
976104841Sobrien	 16,			/* bitsize */
977130570Sobrien	 FALSE,			/* pc_relative */
978104841Sobrien	 0,			/* bitpos */
979104841Sobrien	 complain_overflow_dont, /* complain_on_overflow */
980104841Sobrien	 0,			/* special_function */
981104841Sobrien	 "TPRELLO",		/* name */
982130570Sobrien	 FALSE,			/* partial_inplace */
983104841Sobrien	 0xffff,		/* src_mask */
984104841Sobrien	 0xffff,		/* dst_mask */
985130570Sobrien	 FALSE),		/* pcrel_offset */
986104841Sobrien
987104841Sobrien  /* A 16-bit displacement from TP to the target.  */
988104841Sobrien  HOWTO (R_ALPHA_TPREL16,	/* type */
989104841Sobrien	 0,			/* rightshift */
990104841Sobrien	 1,			/* size (0 = byte, 1 = short, 2 = long) */
991104841Sobrien	 16,			/* bitsize */
992130570Sobrien	 FALSE,			/* pc_relative */
993104841Sobrien	 0,			/* bitpos */
994104841Sobrien	 complain_overflow_signed, /* complain_on_overflow */
995104841Sobrien	 0,			/* special_function */
996104841Sobrien	 "TPREL16",		/* name */
997130570Sobrien	 FALSE,			/* partial_inplace */
998104841Sobrien	 0xffff,		/* src_mask */
999104841Sobrien	 0xffff,		/* dst_mask */
1000130570Sobrien	 FALSE),		/* pcrel_offset */
100133965Sjdp};
100233965Sjdp
100333965Sjdp/* A mapping from BFD reloc types to Alpha ELF reloc types.  */
100433965Sjdp
100533965Sjdpstruct elf_reloc_map
100633965Sjdp{
100733965Sjdp  bfd_reloc_code_real_type bfd_reloc_val;
100833965Sjdp  int elf_reloc_val;
100933965Sjdp};
101033965Sjdp
101133965Sjdpstatic const struct elf_reloc_map elf64_alpha_reloc_map[] =
101233965Sjdp{
101389862Sobrien  {BFD_RELOC_NONE,			R_ALPHA_NONE},
101489862Sobrien  {BFD_RELOC_32,			R_ALPHA_REFLONG},
101589862Sobrien  {BFD_RELOC_64,			R_ALPHA_REFQUAD},
101689862Sobrien  {BFD_RELOC_CTOR,			R_ALPHA_REFQUAD},
101789862Sobrien  {BFD_RELOC_GPREL32,			R_ALPHA_GPREL32},
101889862Sobrien  {BFD_RELOC_ALPHA_ELF_LITERAL,		R_ALPHA_LITERAL},
101989862Sobrien  {BFD_RELOC_ALPHA_LITUSE,		R_ALPHA_LITUSE},
102089862Sobrien  {BFD_RELOC_ALPHA_GPDISP,		R_ALPHA_GPDISP},
102189862Sobrien  {BFD_RELOC_23_PCREL_S2,		R_ALPHA_BRADDR},
102289862Sobrien  {BFD_RELOC_ALPHA_HINT,		R_ALPHA_HINT},
102389862Sobrien  {BFD_RELOC_16_PCREL,			R_ALPHA_SREL16},
102489862Sobrien  {BFD_RELOC_32_PCREL,			R_ALPHA_SREL32},
102589862Sobrien  {BFD_RELOC_64_PCREL,			R_ALPHA_SREL64},
102689862Sobrien  {BFD_RELOC_ALPHA_GPREL_HI16,		R_ALPHA_GPRELHIGH},
102789862Sobrien  {BFD_RELOC_ALPHA_GPREL_LO16,		R_ALPHA_GPRELLOW},
102889862Sobrien  {BFD_RELOC_GPREL16,			R_ALPHA_GPREL16},
102991049Sobrien  {BFD_RELOC_ALPHA_BRSGP,		R_ALPHA_BRSGP},
1030104841Sobrien  {BFD_RELOC_ALPHA_TLSGD,		R_ALPHA_TLSGD},
1031104841Sobrien  {BFD_RELOC_ALPHA_TLSLDM,		R_ALPHA_TLSLDM},
1032104841Sobrien  {BFD_RELOC_ALPHA_DTPMOD64,		R_ALPHA_DTPMOD64},
1033104841Sobrien  {BFD_RELOC_ALPHA_GOTDTPREL16,		R_ALPHA_GOTDTPREL},
1034104841Sobrien  {BFD_RELOC_ALPHA_DTPREL64,		R_ALPHA_DTPREL64},
1035104841Sobrien  {BFD_RELOC_ALPHA_DTPREL_HI16,		R_ALPHA_DTPRELHI},
1036104841Sobrien  {BFD_RELOC_ALPHA_DTPREL_LO16,		R_ALPHA_DTPRELLO},
1037104841Sobrien  {BFD_RELOC_ALPHA_DTPREL16,		R_ALPHA_DTPREL16},
1038104841Sobrien  {BFD_RELOC_ALPHA_GOTTPREL16,		R_ALPHA_GOTTPREL},
1039104841Sobrien  {BFD_RELOC_ALPHA_TPREL64,		R_ALPHA_TPREL64},
1040104841Sobrien  {BFD_RELOC_ALPHA_TPREL_HI16,		R_ALPHA_TPRELHI},
1041104841Sobrien  {BFD_RELOC_ALPHA_TPREL_LO16,		R_ALPHA_TPRELLO},
1042104841Sobrien  {BFD_RELOC_ALPHA_TPREL16,		R_ALPHA_TPREL16},
104333965Sjdp};
104433965Sjdp
104533965Sjdp/* Given a BFD reloc type, return a HOWTO structure.  */
104633965Sjdp
104733965Sjdpstatic reloc_howto_type *
1048218822Sdimelf64_alpha_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
1049218822Sdim				   bfd_reloc_code_real_type code)
105033965Sjdp{
105133965Sjdp  const struct elf_reloc_map *i, *e;
105233965Sjdp  i = e = elf64_alpha_reloc_map;
105333965Sjdp  e += sizeof (elf64_alpha_reloc_map) / sizeof (struct elf_reloc_map);
105433965Sjdp  for (; i != e; ++i)
105533965Sjdp    {
105633965Sjdp      if (i->bfd_reloc_val == code)
105733965Sjdp	return &elf64_alpha_howto_table[i->elf_reloc_val];
105833965Sjdp    }
105933965Sjdp  return 0;
106033965Sjdp}
106133965Sjdp
1062218822Sdimstatic reloc_howto_type *
1063218822Sdimelf64_alpha_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
1064218822Sdim				   const char *r_name)
1065218822Sdim{
1066218822Sdim  unsigned int i;
1067218822Sdim
1068218822Sdim  for (i = 0;
1069218822Sdim       i < (sizeof (elf64_alpha_howto_table)
1070218822Sdim	    / sizeof (elf64_alpha_howto_table[0]));
1071218822Sdim       i++)
1072218822Sdim    if (elf64_alpha_howto_table[i].name != NULL
1073218822Sdim	&& strcasecmp (elf64_alpha_howto_table[i].name, r_name) == 0)
1074218822Sdim      return &elf64_alpha_howto_table[i];
1075218822Sdim
1076218822Sdim  return NULL;
1077218822Sdim}
1078218822Sdim
107933965Sjdp/* Given an Alpha ELF reloc type, fill in an arelent structure.  */
108033965Sjdp
108133965Sjdpstatic void
1082218822Sdimelf64_alpha_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr,
1083218822Sdim			   Elf_Internal_Rela *dst)
108433965Sjdp{
1085218822Sdim  unsigned r_type = ELF64_R_TYPE(dst->r_info);
108633965Sjdp  BFD_ASSERT (r_type < (unsigned int) R_ALPHA_max);
108733965Sjdp  cache_ptr->howto = &elf64_alpha_howto_table[r_type];
108833965Sjdp}
1089104841Sobrien
1090104841Sobrien/* These two relocations create a two-word entry in the got.  */
1091104841Sobrien#define alpha_got_entry_size(r_type) \
1092104841Sobrien  (r_type == R_ALPHA_TLSGD || r_type == R_ALPHA_TLSLDM ? 16 : 8)
1093104841Sobrien
1094104841Sobrien/* This is PT_TLS segment p_vaddr.  */
1095130570Sobrien#define alpha_get_dtprel_base(info) \
1096130570Sobrien  (elf_hash_table (info)->tls_sec->vma)
1097104841Sobrien
1098104841Sobrien/* Main program TLS (whose template starts at PT_TLS p_vaddr)
1099104841Sobrien   is assigned offset round(16, PT_TLS p_align).  */
1100130570Sobrien#define alpha_get_tprel_base(info) \
1101130570Sobrien  (elf_hash_table (info)->tls_sec->vma					\
1102130570Sobrien   - align_power ((bfd_vma) 16,						\
1103130570Sobrien		  elf_hash_table (info)->tls_sec->alignment_power))
110433965Sjdp
110533965Sjdp/* Handle an Alpha specific section when reading an object file.  This
1106218822Sdim   is called when bfd_section_from_shdr finds a section with an unknown
1107218822Sdim   type.
110860510Sobrien   FIXME: We need to handle the SHF_ALPHA_GPREL flag, but I'm not sure
110933965Sjdp   how to.  */
111033965Sjdp
1111130570Sobrienstatic bfd_boolean
1112218822Sdimelf64_alpha_section_from_shdr (bfd *abfd,
1113218822Sdim			       Elf_Internal_Shdr *hdr,
1114218822Sdim			       const char *name,
1115218822Sdim			       int shindex)
111633965Sjdp{
111733965Sjdp  asection *newsect;
111833965Sjdp
111933965Sjdp  /* There ought to be a place to keep ELF backend specific flags, but
112033965Sjdp     at the moment there isn't one.  We just keep track of the
112133965Sjdp     sections by their name, instead.  Fortunately, the ABI gives
112233965Sjdp     suggested names for all the MIPS specific sections, so we will
112333965Sjdp     probably get away with this.  */
112433965Sjdp  switch (hdr->sh_type)
112533965Sjdp    {
112633965Sjdp    case SHT_ALPHA_DEBUG:
112733965Sjdp      if (strcmp (name, ".mdebug") != 0)
1128130570Sobrien	return FALSE;
112933965Sjdp      break;
113033965Sjdp    default:
1131130570Sobrien      return FALSE;
113233965Sjdp    }
113333965Sjdp
1134218822Sdim  if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
1135130570Sobrien    return FALSE;
113633965Sjdp  newsect = hdr->bfd_section;
113733965Sjdp
113833965Sjdp  if (hdr->sh_type == SHT_ALPHA_DEBUG)
113933965Sjdp    {
114033965Sjdp      if (! bfd_set_section_flags (abfd, newsect,
114133965Sjdp				   (bfd_get_section_flags (abfd, newsect)
114233965Sjdp				    | SEC_DEBUGGING)))
1143130570Sobrien	return FALSE;
114433965Sjdp    }
114533965Sjdp
1146130570Sobrien  return TRUE;
114789862Sobrien}
114833965Sjdp
114989862Sobrien/* Convert Alpha specific section flags to bfd internal section flags.  */
115033965Sjdp
1151130570Sobrienstatic bfd_boolean
1152218822Sdimelf64_alpha_section_flags (flagword *flags, const Elf_Internal_Shdr *hdr)
115389862Sobrien{
115489862Sobrien  if (hdr->sh_flags & SHF_ALPHA_GPREL)
115589862Sobrien    *flags |= SEC_SMALL_DATA;
115689862Sobrien
1157130570Sobrien  return TRUE;
115833965Sjdp}
115933965Sjdp
116033965Sjdp/* Set the correct type for an Alpha ELF section.  We do this by the
116133965Sjdp   section name, which is a hack, but ought to work.  */
116233965Sjdp
1163130570Sobrienstatic bfd_boolean
1164218822Sdimelf64_alpha_fake_sections (bfd *abfd, Elf_Internal_Shdr *hdr, asection *sec)
116533965Sjdp{
116633965Sjdp  register const char *name;
116733965Sjdp
116833965Sjdp  name = bfd_get_section_name (abfd, sec);
116933965Sjdp
117033965Sjdp  if (strcmp (name, ".mdebug") == 0)
117133965Sjdp    {
117233965Sjdp      hdr->sh_type = SHT_ALPHA_DEBUG;
117333965Sjdp      /* In a shared object on Irix 5.3, the .mdebug section has an
117433965Sjdp         entsize of 0.  FIXME: Does this matter?  */
117533965Sjdp      if ((abfd->flags & DYNAMIC) != 0 )
117633965Sjdp	hdr->sh_entsize = 0;
117733965Sjdp      else
117833965Sjdp	hdr->sh_entsize = 1;
117933965Sjdp    }
118089862Sobrien  else if ((sec->flags & SEC_SMALL_DATA)
118189862Sobrien	   || strcmp (name, ".sdata") == 0
118233965Sjdp	   || strcmp (name, ".sbss") == 0
118333965Sjdp	   || strcmp (name, ".lit4") == 0
118433965Sjdp	   || strcmp (name, ".lit8") == 0)
118533965Sjdp    hdr->sh_flags |= SHF_ALPHA_GPREL;
118633965Sjdp
1187130570Sobrien  return TRUE;
118833965Sjdp}
118933965Sjdp
119060510Sobrien/* Hook called by the linker routine which adds symbols from an object
119160510Sobrien   file.  We use it to put .comm items in .sbss, and not .bss.  */
119233965Sjdp
1193130570Sobrienstatic bfd_boolean
1194218822Sdimelf64_alpha_add_symbol_hook (bfd *abfd, struct bfd_link_info *info,
1195218822Sdim			     Elf_Internal_Sym *sym,
1196218822Sdim			     const char **namep ATTRIBUTE_UNUSED,
1197218822Sdim			     flagword *flagsp ATTRIBUTE_UNUSED,
1198218822Sdim			     asection **secp, bfd_vma *valp)
119933965Sjdp{
120060510Sobrien  if (sym->st_shndx == SHN_COMMON
1201130570Sobrien      && !info->relocatable
120289862Sobrien      && sym->st_size <= elf_gp_size (abfd))
120360510Sobrien    {
120460510Sobrien      /* Common symbols less than or equal to -G nn bytes are
120560510Sobrien	 automatically put into .sbss.  */
120633965Sjdp
120760510Sobrien      asection *scomm = bfd_get_section_by_name (abfd, ".scommon");
120833965Sjdp
120960510Sobrien      if (scomm == NULL)
121060510Sobrien	{
1211218822Sdim	  scomm = bfd_make_section_with_flags (abfd, ".scommon",
1212218822Sdim					       (SEC_ALLOC
1213218822Sdim						| SEC_IS_COMMON
1214218822Sdim						| SEC_LINKER_CREATED));
1215218822Sdim	  if (scomm == NULL)
1216130570Sobrien	    return FALSE;
121760510Sobrien	}
121833965Sjdp
121960510Sobrien      *secp = scomm;
122060510Sobrien      *valp = sym->st_size;
122133965Sjdp    }
122233965Sjdp
1223130570Sobrien  return TRUE;
122433965Sjdp}
122533965Sjdp
122633965Sjdp/* Create the .got section.  */
122733965Sjdp
1228130570Sobrienstatic bfd_boolean
1229218822Sdimelf64_alpha_create_got_section (bfd *abfd,
1230218822Sdim				struct bfd_link_info *info ATTRIBUTE_UNUSED)
123133965Sjdp{
1232218822Sdim  flagword flags;
123333965Sjdp  asection *s;
123433965Sjdp
1235218822Sdim  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
1236218822Sdim	   | SEC_LINKER_CREATED);
1237218822Sdim  s = bfd_make_section_anyway_with_flags (abfd, ".got", flags);
123833965Sjdp  if (s == NULL
123933965Sjdp      || !bfd_set_section_alignment (abfd, s, 3))
1240130570Sobrien    return FALSE;
124133965Sjdp
124233965Sjdp  alpha_elf_tdata (abfd)->got = s;
124333965Sjdp
1244218822Sdim  /* Make sure the object's gotobj is set to itself so that we default
1245218822Sdim     to every object with its own .got.  We'll merge .gots later once
1246218822Sdim     we've collected each object's info.  */
1247218822Sdim  alpha_elf_tdata (abfd)->gotobj = abfd;
1248218822Sdim
1249130570Sobrien  return TRUE;
125033965Sjdp}
125133965Sjdp
125233965Sjdp/* Create all the dynamic sections.  */
125333965Sjdp
1254130570Sobrienstatic bfd_boolean
1255218822Sdimelf64_alpha_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info)
125633965Sjdp{
125733965Sjdp  asection *s;
1258218822Sdim  flagword flags;
125933965Sjdp  struct elf_link_hash_entry *h;
126033965Sjdp
126133965Sjdp  /* We need to create .plt, .rela.plt, .got, and .rela.got sections.  */
126233965Sjdp
1263218822Sdim  flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS | SEC_IN_MEMORY
1264218822Sdim	   | SEC_LINKER_CREATED
1265218822Sdim	   | (elf64_alpha_use_secureplt ? SEC_READONLY : 0));
1266218822Sdim  s = bfd_make_section_anyway_with_flags (abfd, ".plt", flags);
1267218822Sdim  if (s == NULL || ! bfd_set_section_alignment (abfd, s, 4))
1268130570Sobrien    return FALSE;
126933965Sjdp
127033965Sjdp  /* Define the symbol _PROCEDURE_LINKAGE_TABLE_ at the start of the
127133965Sjdp     .plt section.  */
1272218822Sdim  h = _bfd_elf_define_linkage_sym (abfd, info, s,
1273218822Sdim				   "_PROCEDURE_LINKAGE_TABLE_");
1274218822Sdim  elf_hash_table (info)->hplt = h;
1275218822Sdim  if (h == NULL)
1276130570Sobrien    return FALSE;
127733965Sjdp
1278218822Sdim  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
1279218822Sdim	   | SEC_LINKER_CREATED | SEC_READONLY);
1280218822Sdim  s = bfd_make_section_anyway_with_flags (abfd, ".rela.plt", flags);
1281218822Sdim  if (s == NULL || ! bfd_set_section_alignment (abfd, s, 3))
1282130570Sobrien    return FALSE;
128333965Sjdp
1284218822Sdim  if (elf64_alpha_use_secureplt)
1285218822Sdim    {
1286218822Sdim      flags = SEC_ALLOC | SEC_LINKER_CREATED;
1287218822Sdim      s = bfd_make_section_anyway_with_flags (abfd, ".got.plt", flags);
1288218822Sdim      if (s == NULL || ! bfd_set_section_alignment (abfd, s, 3))
1289218822Sdim	return FALSE;
1290218822Sdim    }
129133965Sjdp
129233965Sjdp  /* We may or may not have created a .got section for this object, but
129333965Sjdp     we definitely havn't done the rest of the work.  */
129433965Sjdp
1295218822Sdim  if (alpha_elf_tdata(abfd)->gotobj == NULL)
1296218822Sdim    {
1297218822Sdim      if (!elf64_alpha_create_got_section (abfd, info))
1298218822Sdim	return FALSE;
1299218822Sdim    }
130033965Sjdp
1301218822Sdim  flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
1302218822Sdim	   | SEC_LINKER_CREATED | SEC_READONLY);
1303218822Sdim  s = bfd_make_section_anyway_with_flags (abfd, ".rela.got", flags);
130433965Sjdp  if (s == NULL
130533965Sjdp      || !bfd_set_section_alignment (abfd, s, 3))
1306130570Sobrien    return FALSE;
130733965Sjdp
130833965Sjdp  /* Define the symbol _GLOBAL_OFFSET_TABLE_ at the start of the
130933965Sjdp     dynobj's .got section.  We don't do this in the linker script
131033965Sjdp     because we don't want to define the symbol if we are not creating
131133965Sjdp     a global offset table.  */
1312218822Sdim  h = _bfd_elf_define_linkage_sym (abfd, info, alpha_elf_tdata(abfd)->got,
1313218822Sdim				   "_GLOBAL_OFFSET_TABLE_");
1314218822Sdim  elf_hash_table (info)->hgot = h;
1315218822Sdim  if (h == NULL)
1316130570Sobrien    return FALSE;
131733965Sjdp
1318130570Sobrien  return TRUE;
131933965Sjdp}
132033965Sjdp
132133965Sjdp/* Read ECOFF debugging information from a .mdebug section into a
132233965Sjdp   ecoff_debug_info structure.  */
132333965Sjdp
1324130570Sobrienstatic bfd_boolean
1325218822Sdimelf64_alpha_read_ecoff_info (bfd *abfd, asection *section,
1326218822Sdim			     struct ecoff_debug_info *debug)
132733965Sjdp{
132833965Sjdp  HDRR *symhdr;
132933965Sjdp  const struct ecoff_debug_swap *swap;
133033965Sjdp  char *ext_hdr = NULL;
133133965Sjdp
133233965Sjdp  swap = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
133377303Sobrien  memset (debug, 0, sizeof (*debug));
133433965Sjdp
133589862Sobrien  ext_hdr = (char *) bfd_malloc (swap->external_hdr_size);
133633965Sjdp  if (ext_hdr == NULL && swap->external_hdr_size != 0)
133733965Sjdp    goto error_return;
133833965Sjdp
1339104841Sobrien  if (! bfd_get_section_contents (abfd, section, ext_hdr, (file_ptr) 0,
1340104841Sobrien				  swap->external_hdr_size))
134133965Sjdp    goto error_return;
134233965Sjdp
134333965Sjdp  symhdr = &debug->symbolic_header;
134433965Sjdp  (*swap->swap_hdr_in) (abfd, ext_hdr, symhdr);
134533965Sjdp
134633965Sjdp  /* The symbolic header contains absolute file offsets and sizes to
134733965Sjdp     read.  */
134833965Sjdp#define READ(ptr, offset, count, size, type)				\
134933965Sjdp  if (symhdr->count == 0)						\
135033965Sjdp    debug->ptr = NULL;							\
135133965Sjdp  else									\
135233965Sjdp    {									\
135389862Sobrien      bfd_size_type amt = (bfd_size_type) size * symhdr->count;		\
135489862Sobrien      debug->ptr = (type) bfd_malloc (amt);				\
135533965Sjdp      if (debug->ptr == NULL)						\
135633965Sjdp	goto error_return;						\
135733965Sjdp      if (bfd_seek (abfd, (file_ptr) symhdr->offset, SEEK_SET) != 0	\
135889862Sobrien	  || bfd_bread (debug->ptr, amt, abfd) != amt)			\
135933965Sjdp	goto error_return;						\
136033965Sjdp    }
136133965Sjdp
136233965Sjdp  READ (line, cbLineOffset, cbLine, sizeof (unsigned char), unsigned char *);
136333965Sjdp  READ (external_dnr, cbDnOffset, idnMax, swap->external_dnr_size, PTR);
136433965Sjdp  READ (external_pdr, cbPdOffset, ipdMax, swap->external_pdr_size, PTR);
136533965Sjdp  READ (external_sym, cbSymOffset, isymMax, swap->external_sym_size, PTR);
136633965Sjdp  READ (external_opt, cbOptOffset, ioptMax, swap->external_opt_size, PTR);
136733965Sjdp  READ (external_aux, cbAuxOffset, iauxMax, sizeof (union aux_ext),
136833965Sjdp	union aux_ext *);
136933965Sjdp  READ (ss, cbSsOffset, issMax, sizeof (char), char *);
137033965Sjdp  READ (ssext, cbSsExtOffset, issExtMax, sizeof (char), char *);
137133965Sjdp  READ (external_fdr, cbFdOffset, ifdMax, swap->external_fdr_size, PTR);
137233965Sjdp  READ (external_rfd, cbRfdOffset, crfd, swap->external_rfd_size, PTR);
137333965Sjdp  READ (external_ext, cbExtOffset, iextMax, swap->external_ext_size, PTR);
137433965Sjdp#undef READ
137533965Sjdp
137633965Sjdp  debug->fdr = NULL;
137733965Sjdp
1378130570Sobrien  return TRUE;
137933965Sjdp
138033965Sjdp error_return:
138133965Sjdp  if (ext_hdr != NULL)
138233965Sjdp    free (ext_hdr);
138333965Sjdp  if (debug->line != NULL)
138433965Sjdp    free (debug->line);
138533965Sjdp  if (debug->external_dnr != NULL)
138633965Sjdp    free (debug->external_dnr);
138733965Sjdp  if (debug->external_pdr != NULL)
138833965Sjdp    free (debug->external_pdr);
138933965Sjdp  if (debug->external_sym != NULL)
139033965Sjdp    free (debug->external_sym);
139133965Sjdp  if (debug->external_opt != NULL)
139233965Sjdp    free (debug->external_opt);
139333965Sjdp  if (debug->external_aux != NULL)
139433965Sjdp    free (debug->external_aux);
139533965Sjdp  if (debug->ss != NULL)
139633965Sjdp    free (debug->ss);
139733965Sjdp  if (debug->ssext != NULL)
139833965Sjdp    free (debug->ssext);
139933965Sjdp  if (debug->external_fdr != NULL)
140033965Sjdp    free (debug->external_fdr);
140133965Sjdp  if (debug->external_rfd != NULL)
140233965Sjdp    free (debug->external_rfd);
140333965Sjdp  if (debug->external_ext != NULL)
140433965Sjdp    free (debug->external_ext);
1405130570Sobrien  return FALSE;
140633965Sjdp}
140733965Sjdp
140833965Sjdp/* Alpha ELF local labels start with '$'.  */
140933965Sjdp
1410130570Sobrienstatic bfd_boolean
1411218822Sdimelf64_alpha_is_local_label_name (bfd *abfd ATTRIBUTE_UNUSED, const char *name)
141233965Sjdp{
141333965Sjdp  return name[0] == '$';
141433965Sjdp}
141533965Sjdp
141633965Sjdp/* Alpha ELF follows MIPS ELF in using a special find_nearest_line
141733965Sjdp   routine in order to handle the ECOFF debugging information.  We
141833965Sjdp   still call this mips_elf_find_line because of the slot
141933965Sjdp   find_line_info in elf_obj_tdata is declared that way.  */
142033965Sjdp
142133965Sjdpstruct mips_elf_find_line
142233965Sjdp{
142333965Sjdp  struct ecoff_debug_info d;
142433965Sjdp  struct ecoff_find_line i;
142533965Sjdp};
142633965Sjdp
1427130570Sobrienstatic bfd_boolean
1428218822Sdimelf64_alpha_find_nearest_line (bfd *abfd, asection *section, asymbol **symbols,
1429218822Sdim			       bfd_vma offset, const char **filename_ptr,
1430218822Sdim			       const char **functionname_ptr,
1431218822Sdim			       unsigned int *line_ptr)
143233965Sjdp{
143333965Sjdp  asection *msec;
143433965Sjdp
143577303Sobrien  if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
143677303Sobrien				     filename_ptr, functionname_ptr,
143777303Sobrien				     line_ptr, 0,
143877303Sobrien				     &elf_tdata (abfd)->dwarf2_find_line_info))
1439130570Sobrien    return TRUE;
144077303Sobrien
144133965Sjdp  msec = bfd_get_section_by_name (abfd, ".mdebug");
144233965Sjdp  if (msec != NULL)
144333965Sjdp    {
144433965Sjdp      flagword origflags;
144533965Sjdp      struct mips_elf_find_line *fi;
144633965Sjdp      const struct ecoff_debug_swap * const swap =
144733965Sjdp	get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
144833965Sjdp
144933965Sjdp      /* If we are called during a link, alpha_elf_final_link may have
145033965Sjdp	 cleared the SEC_HAS_CONTENTS field.  We force it back on here
145133965Sjdp	 if appropriate (which it normally will be).  */
145233965Sjdp      origflags = msec->flags;
145333965Sjdp      if (elf_section_data (msec)->this_hdr.sh_type != SHT_NOBITS)
145433965Sjdp	msec->flags |= SEC_HAS_CONTENTS;
145533965Sjdp
145633965Sjdp      fi = elf_tdata (abfd)->find_line_info;
145733965Sjdp      if (fi == NULL)
145833965Sjdp	{
145933965Sjdp	  bfd_size_type external_fdr_size;
146033965Sjdp	  char *fraw_src;
146133965Sjdp	  char *fraw_end;
146233965Sjdp	  struct fdr *fdr_ptr;
146389862Sobrien	  bfd_size_type amt = sizeof (struct mips_elf_find_line);
146433965Sjdp
146589862Sobrien	  fi = (struct mips_elf_find_line *) bfd_zalloc (abfd, amt);
146633965Sjdp	  if (fi == NULL)
146733965Sjdp	    {
146833965Sjdp	      msec->flags = origflags;
1469130570Sobrien	      return FALSE;
147033965Sjdp	    }
147133965Sjdp
147233965Sjdp	  if (!elf64_alpha_read_ecoff_info (abfd, msec, &fi->d))
147333965Sjdp	    {
147433965Sjdp	      msec->flags = origflags;
1475130570Sobrien	      return FALSE;
147633965Sjdp	    }
147733965Sjdp
147833965Sjdp	  /* Swap in the FDR information.  */
147989862Sobrien	  amt = fi->d.symbolic_header.ifdMax * sizeof (struct fdr);
148089862Sobrien	  fi->d.fdr = (struct fdr *) bfd_alloc (abfd, amt);
148133965Sjdp	  if (fi->d.fdr == NULL)
148233965Sjdp	    {
148333965Sjdp	      msec->flags = origflags;
1484130570Sobrien	      return FALSE;
148533965Sjdp	    }
148633965Sjdp	  external_fdr_size = swap->external_fdr_size;
148733965Sjdp	  fdr_ptr = fi->d.fdr;
148833965Sjdp	  fraw_src = (char *) fi->d.external_fdr;
148933965Sjdp	  fraw_end = (fraw_src
149033965Sjdp		      + fi->d.symbolic_header.ifdMax * external_fdr_size);
149133965Sjdp	  for (; fraw_src < fraw_end; fraw_src += external_fdr_size, fdr_ptr++)
149233965Sjdp	    (*swap->swap_fdr_in) (abfd, (PTR) fraw_src, fdr_ptr);
149333965Sjdp
149433965Sjdp	  elf_tdata (abfd)->find_line_info = fi;
149533965Sjdp
149633965Sjdp	  /* Note that we don't bother to ever free this information.
149733965Sjdp             find_nearest_line is either called all the time, as in
149833965Sjdp             objdump -l, so the information should be saved, or it is
149933965Sjdp             rarely called, as in ld error messages, so the memory
150033965Sjdp             wasted is unimportant.  Still, it would probably be a
150133965Sjdp             good idea for free_cached_info to throw it away.  */
150233965Sjdp	}
150333965Sjdp
150433965Sjdp      if (_bfd_ecoff_locate_line (abfd, section, offset, &fi->d, swap,
150533965Sjdp				  &fi->i, filename_ptr, functionname_ptr,
150633965Sjdp				  line_ptr))
150733965Sjdp	{
150833965Sjdp	  msec->flags = origflags;
1509130570Sobrien	  return TRUE;
151033965Sjdp	}
151133965Sjdp
151233965Sjdp      msec->flags = origflags;
151333965Sjdp    }
151433965Sjdp
151533965Sjdp  /* Fall back on the generic ELF find_nearest_line routine.  */
151633965Sjdp
151733965Sjdp  return _bfd_elf_find_nearest_line (abfd, section, symbols, offset,
151833965Sjdp				     filename_ptr, functionname_ptr,
151933965Sjdp				     line_ptr);
152033965Sjdp}
152133965Sjdp
152233965Sjdp/* Structure used to pass information to alpha_elf_output_extsym.  */
152333965Sjdp
152433965Sjdpstruct extsym_info
152533965Sjdp{
152633965Sjdp  bfd *abfd;
152733965Sjdp  struct bfd_link_info *info;
152833965Sjdp  struct ecoff_debug_info *debug;
152933965Sjdp  const struct ecoff_debug_swap *swap;
1530130570Sobrien  bfd_boolean failed;
153133965Sjdp};
153233965Sjdp
1533130570Sobrienstatic bfd_boolean
1534218822Sdimelf64_alpha_output_extsym (struct alpha_elf_link_hash_entry *h, PTR data)
153533965Sjdp{
153633965Sjdp  struct extsym_info *einfo = (struct extsym_info *) data;
1537130570Sobrien  bfd_boolean strip;
153833965Sjdp  asection *sec, *output_section;
153933965Sjdp
154094544Sobrien  if (h->root.root.type == bfd_link_hash_warning)
154194544Sobrien    h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
154294544Sobrien
154333965Sjdp  if (h->root.indx == -2)
1544130570Sobrien    strip = FALSE;
1545218822Sdim  else if ((h->root.def_dynamic
1546218822Sdim	    || h->root.ref_dynamic
1547218822Sdim	    || h->root.root.type == bfd_link_hash_new)
1548218822Sdim	   && !h->root.def_regular
1549218822Sdim	   && !h->root.ref_regular)
1550130570Sobrien    strip = TRUE;
155133965Sjdp  else if (einfo->info->strip == strip_all
155294544Sobrien	   || (einfo->info->strip == strip_some
155394544Sobrien	       && bfd_hash_lookup (einfo->info->keep_hash,
155494544Sobrien				   h->root.root.root.string,
1555130570Sobrien				   FALSE, FALSE) == NULL))
1556130570Sobrien    strip = TRUE;
155733965Sjdp  else
1558130570Sobrien    strip = FALSE;
155933965Sjdp
156033965Sjdp  if (strip)
1561130570Sobrien    return TRUE;
156233965Sjdp
156333965Sjdp  if (h->esym.ifd == -2)
156433965Sjdp    {
156533965Sjdp      h->esym.jmptbl = 0;
156633965Sjdp      h->esym.cobol_main = 0;
156733965Sjdp      h->esym.weakext = 0;
156833965Sjdp      h->esym.reserved = 0;
156933965Sjdp      h->esym.ifd = ifdNil;
157033965Sjdp      h->esym.asym.value = 0;
157133965Sjdp      h->esym.asym.st = stGlobal;
157233965Sjdp
157333965Sjdp      if (h->root.root.type != bfd_link_hash_defined
157494544Sobrien	  && h->root.root.type != bfd_link_hash_defweak)
157594544Sobrien	h->esym.asym.sc = scAbs;
157633965Sjdp      else
157794544Sobrien	{
157894544Sobrien	  const char *name;
157933965Sjdp
158094544Sobrien	  sec = h->root.root.u.def.section;
158194544Sobrien	  output_section = sec->output_section;
158233965Sjdp
158394544Sobrien	  /* When making a shared library and symbol h is the one from
158494544Sobrien	     the another shared library, OUTPUT_SECTION may be null.  */
158594544Sobrien	  if (output_section == NULL)
158694544Sobrien	    h->esym.asym.sc = scUndefined;
158794544Sobrien	  else
158894544Sobrien	    {
158994544Sobrien	      name = bfd_section_name (output_section->owner, output_section);
159033965Sjdp
159194544Sobrien	      if (strcmp (name, ".text") == 0)
159294544Sobrien		h->esym.asym.sc = scText;
159394544Sobrien	      else if (strcmp (name, ".data") == 0)
159494544Sobrien		h->esym.asym.sc = scData;
159594544Sobrien	      else if (strcmp (name, ".sdata") == 0)
159694544Sobrien		h->esym.asym.sc = scSData;
159794544Sobrien	      else if (strcmp (name, ".rodata") == 0
159894544Sobrien		       || strcmp (name, ".rdata") == 0)
159994544Sobrien		h->esym.asym.sc = scRData;
160094544Sobrien	      else if (strcmp (name, ".bss") == 0)
160194544Sobrien		h->esym.asym.sc = scBss;
160294544Sobrien	      else if (strcmp (name, ".sbss") == 0)
160394544Sobrien		h->esym.asym.sc = scSBss;
160494544Sobrien	      else if (strcmp (name, ".init") == 0)
160594544Sobrien		h->esym.asym.sc = scInit;
160694544Sobrien	      else if (strcmp (name, ".fini") == 0)
160794544Sobrien		h->esym.asym.sc = scFini;
160894544Sobrien	      else
160994544Sobrien		h->esym.asym.sc = scAbs;
161094544Sobrien	    }
161194544Sobrien	}
161233965Sjdp
161333965Sjdp      h->esym.asym.reserved = 0;
161433965Sjdp      h->esym.asym.index = indexNil;
161533965Sjdp    }
161633965Sjdp
161733965Sjdp  if (h->root.root.type == bfd_link_hash_common)
161833965Sjdp    h->esym.asym.value = h->root.root.u.c.size;
161933965Sjdp  else if (h->root.root.type == bfd_link_hash_defined
162033965Sjdp	   || h->root.root.type == bfd_link_hash_defweak)
162133965Sjdp    {
162233965Sjdp      if (h->esym.asym.sc == scCommon)
162394544Sobrien	h->esym.asym.sc = scBss;
162433965Sjdp      else if (h->esym.asym.sc == scSCommon)
162594544Sobrien	h->esym.asym.sc = scSBss;
162633965Sjdp
162733965Sjdp      sec = h->root.root.u.def.section;
162833965Sjdp      output_section = sec->output_section;
162933965Sjdp      if (output_section != NULL)
163094544Sobrien	h->esym.asym.value = (h->root.root.u.def.value
163194544Sobrien			      + sec->output_offset
163294544Sobrien			      + output_section->vma);
163333965Sjdp      else
163494544Sobrien	h->esym.asym.value = 0;
163533965Sjdp    }
163633965Sjdp
163733965Sjdp  if (! bfd_ecoff_debug_one_external (einfo->abfd, einfo->debug, einfo->swap,
163894544Sobrien				      h->root.root.root.string,
163994544Sobrien				      &h->esym))
164033965Sjdp    {
1641130570Sobrien      einfo->failed = TRUE;
1642130570Sobrien      return FALSE;
164333965Sjdp    }
164433965Sjdp
1645130570Sobrien  return TRUE;
164633965Sjdp}
1647104841Sobrien
1648104841Sobrien/* Search for and possibly create a got entry.  */
164933965Sjdp
1650104841Sobrienstatic struct alpha_elf_got_entry *
1651218822Sdimget_got_entry (bfd *abfd, struct alpha_elf_link_hash_entry *h,
1652218822Sdim	       unsigned long r_type, unsigned long r_symndx,
1653218822Sdim	       bfd_vma r_addend)
1654104841Sobrien{
1655104841Sobrien  struct alpha_elf_got_entry *gotent;
1656104841Sobrien  struct alpha_elf_got_entry **slot;
165733965Sjdp
1658104841Sobrien  if (h)
1659104841Sobrien    slot = &h->got_entries;
1660104841Sobrien  else
1661104841Sobrien    {
1662104841Sobrien      /* This is a local .got entry -- record for merge.  */
1663104841Sobrien
1664104841Sobrien      struct alpha_elf_got_entry **local_got_entries;
1665104841Sobrien
1666104841Sobrien      local_got_entries = alpha_elf_tdata(abfd)->local_got_entries;
1667104841Sobrien      if (!local_got_entries)
1668104841Sobrien	{
1669104841Sobrien	  bfd_size_type size;
1670104841Sobrien	  Elf_Internal_Shdr *symtab_hdr;
1671104841Sobrien
1672104841Sobrien	  symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
1673104841Sobrien	  size = symtab_hdr->sh_info;
1674104841Sobrien	  size *= sizeof (struct alpha_elf_got_entry *);
1675104841Sobrien
1676104841Sobrien	  local_got_entries
1677104841Sobrien	    = (struct alpha_elf_got_entry **) bfd_zalloc (abfd, size);
1678104841Sobrien	  if (!local_got_entries)
1679104841Sobrien	    return NULL;
1680104841Sobrien
1681104841Sobrien	  alpha_elf_tdata (abfd)->local_got_entries = local_got_entries;
1682104841Sobrien	}
1683104841Sobrien
1684104841Sobrien      slot = &local_got_entries[r_symndx];
1685104841Sobrien    }
1686104841Sobrien
1687104841Sobrien  for (gotent = *slot; gotent ; gotent = gotent->next)
1688104841Sobrien    if (gotent->gotobj == abfd
1689104841Sobrien	&& gotent->reloc_type == r_type
1690104841Sobrien	&& gotent->addend == r_addend)
1691104841Sobrien      break;
1692104841Sobrien
1693104841Sobrien  if (!gotent)
1694104841Sobrien    {
1695104841Sobrien      int entry_size;
1696104841Sobrien      bfd_size_type amt;
1697104841Sobrien
1698104841Sobrien      amt = sizeof (struct alpha_elf_got_entry);
1699104841Sobrien      gotent = (struct alpha_elf_got_entry *) bfd_alloc (abfd, amt);
1700104841Sobrien      if (!gotent)
1701104841Sobrien	return NULL;
1702104841Sobrien
1703104841Sobrien      gotent->gotobj = abfd;
1704104841Sobrien      gotent->addend = r_addend;
1705104841Sobrien      gotent->got_offset = -1;
1706218822Sdim      gotent->plt_offset = -1;
1707104841Sobrien      gotent->use_count = 1;
1708104841Sobrien      gotent->reloc_type = r_type;
1709104841Sobrien      gotent->reloc_done = 0;
1710104841Sobrien      gotent->reloc_xlated = 0;
1711104841Sobrien
1712104841Sobrien      gotent->next = *slot;
1713104841Sobrien      *slot = gotent;
1714104841Sobrien
1715104841Sobrien      entry_size = alpha_got_entry_size (r_type);
1716104841Sobrien      alpha_elf_tdata (abfd)->total_got_size += entry_size;
1717104841Sobrien      if (!h)
1718104841Sobrien	alpha_elf_tdata(abfd)->local_got_size += entry_size;
1719104841Sobrien    }
1720104841Sobrien  else
1721104841Sobrien    gotent->use_count += 1;
1722104841Sobrien
1723104841Sobrien  return gotent;
1724104841Sobrien}
1725104841Sobrien
1726218822Sdimstatic bfd_boolean
1727218822Sdimelf64_alpha_want_plt (struct alpha_elf_link_hash_entry *ah)
1728218822Sdim{
1729218822Sdim  return ((ah->root.type == STT_FUNC
1730218822Sdim	  || ah->root.root.type == bfd_link_hash_undefweak
1731218822Sdim	  || ah->root.root.type == bfd_link_hash_undefined)
1732218822Sdim	  && (ah->flags & ALPHA_ELF_LINK_HASH_LU_PLT) != 0
1733218822Sdim	  && (ah->flags & ~ALPHA_ELF_LINK_HASH_LU_PLT) == 0);
1734218822Sdim}
1735218822Sdim
173633965Sjdp/* Handle dynamic relocations when doing an Alpha ELF link.  */
173733965Sjdp
1738130570Sobrienstatic bfd_boolean
1739218822Sdimelf64_alpha_check_relocs (bfd *abfd, struct bfd_link_info *info,
1740218822Sdim			  asection *sec, const Elf_Internal_Rela *relocs)
174133965Sjdp{
174233965Sjdp  bfd *dynobj;
174333965Sjdp  asection *sreloc;
174433965Sjdp  const char *rel_sec_name;
174533965Sjdp  Elf_Internal_Shdr *symtab_hdr;
174633965Sjdp  struct alpha_elf_link_hash_entry **sym_hashes;
174733965Sjdp  const Elf_Internal_Rela *rel, *relend;
174889862Sobrien  bfd_size_type amt;
174933965Sjdp
1750130570Sobrien  if (info->relocatable)
1751130570Sobrien    return TRUE;
175233965Sjdp
1753218822Sdim  /* Don't do anything special with non-loaded, non-alloced sections.
1754218822Sdim     In particular, any relocs in such sections should not affect GOT
1755218822Sdim     and PLT reference counting (ie. we don't allow them to create GOT
1756218822Sdim     or PLT entries), there's no possibility or desire to optimize TLS
1757218822Sdim     relocs, and there's not much point in propagating relocs to shared
1758218822Sdim     libs that the dynamic linker won't relocate.  */
1759218822Sdim  if ((sec->flags & SEC_ALLOC) == 0)
1760218822Sdim    return TRUE;
1761218822Sdim
176233965Sjdp  dynobj = elf_hash_table(info)->dynobj;
176333965Sjdp  if (dynobj == NULL)
176433965Sjdp    elf_hash_table(info)->dynobj = dynobj = abfd;
176533965Sjdp
176633965Sjdp  sreloc = NULL;
176733965Sjdp  rel_sec_name = NULL;
176833965Sjdp  symtab_hdr = &elf_tdata(abfd)->symtab_hdr;
176933965Sjdp  sym_hashes = alpha_elf_sym_hashes(abfd);
177033965Sjdp
177133965Sjdp  relend = relocs + sec->reloc_count;
177233965Sjdp  for (rel = relocs; rel < relend; ++rel)
177333965Sjdp    {
1774104841Sobrien      enum {
1775104841Sobrien	NEED_GOT = 1,
1776104841Sobrien	NEED_GOT_ENTRY = 2,
1777104841Sobrien	NEED_DYNREL = 4
1778104841Sobrien      };
1779104841Sobrien
178033965Sjdp      unsigned long r_symndx, r_type;
178133965Sjdp      struct alpha_elf_link_hash_entry *h;
1782104841Sobrien      unsigned int gotent_flags;
1783130570Sobrien      bfd_boolean maybe_dynamic;
1784104841Sobrien      unsigned int need;
1785104841Sobrien      bfd_vma addend;
178633965Sjdp
178733965Sjdp      r_symndx = ELF64_R_SYM (rel->r_info);
178833965Sjdp      if (r_symndx < symtab_hdr->sh_info)
178933965Sjdp	h = NULL;
179033965Sjdp      else
179133965Sjdp	{
179233965Sjdp	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
179338889Sjdp
179438889Sjdp	  while (h->root.root.type == bfd_link_hash_indirect
179538889Sjdp		 || h->root.root.type == bfd_link_hash_warning)
179638889Sjdp	    h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
179738889Sjdp
1798218822Sdim	  h->root.ref_regular = 1;
179933965Sjdp	}
1800104841Sobrien
1801104841Sobrien      /* We can only get preliminary data on whether a symbol is
1802104841Sobrien         locally or externally defined, as not all of the input files
1803104841Sobrien         have yet been processed.  Do something with what we know, as
1804104841Sobrien         this may help reduce memory usage and processing time later.  */
1805130570Sobrien      maybe_dynamic = FALSE;
1806104841Sobrien      if (h && ((info->shared
1807218822Sdim		 && (!info->symbolic
1808218822Sdim		     || info->unresolved_syms_in_shared_libs == RM_IGNORE))
1809218822Sdim		|| !h->root.def_regular
1810104841Sobrien		|| h->root.root.type == bfd_link_hash_defweak))
1811130570Sobrien        maybe_dynamic = TRUE;
1812104841Sobrien
1813104841Sobrien      need = 0;
1814104841Sobrien      gotent_flags = 0;
181533965Sjdp      r_type = ELF64_R_TYPE (rel->r_info);
1816104841Sobrien      addend = rel->r_addend;
181733965Sjdp
181833965Sjdp      switch (r_type)
181933965Sjdp	{
182033965Sjdp	case R_ALPHA_LITERAL:
1821104841Sobrien	  need = NEED_GOT | NEED_GOT_ENTRY;
182233965Sjdp
1823104841Sobrien	  /* Remember how this literal is used from its LITUSEs.
1824104841Sobrien	     This will be important when it comes to decide if we can
1825104841Sobrien	     create a .plt entry for a function symbol.  */
1826104841Sobrien	  while (++rel < relend && ELF64_R_TYPE (rel->r_info) == R_ALPHA_LITUSE)
1827218822Sdim	    if (rel->r_addend >= 1 && rel->r_addend <= 6)
1828104841Sobrien	      gotent_flags |= 1 << rel->r_addend;
1829104841Sobrien	  --rel;
183033965Sjdp
1831104841Sobrien	  /* No LITUSEs -- presumably the address is used somehow.  */
1832104841Sobrien	  if (gotent_flags == 0)
1833104841Sobrien	    gotent_flags = ALPHA_ELF_LINK_HASH_LU_ADDR;
1834104841Sobrien	  break;
183533965Sjdp
183633965Sjdp	case R_ALPHA_GPDISP:
183789862Sobrien	case R_ALPHA_GPREL16:
183833965Sjdp	case R_ALPHA_GPREL32:
183960510Sobrien	case R_ALPHA_GPRELHIGH:
184060510Sobrien	case R_ALPHA_GPRELLOW:
184191049Sobrien	case R_ALPHA_BRSGP:
1842104841Sobrien	  need = NEED_GOT;
1843104841Sobrien	  break;
1844104841Sobrien
1845104841Sobrien	case R_ALPHA_REFLONG:
1846104841Sobrien	case R_ALPHA_REFQUAD:
1847218822Sdim	  if (info->shared || maybe_dynamic)
1848104841Sobrien	    need = NEED_DYNREL;
1849104841Sobrien	  break;
1850104841Sobrien
1851130570Sobrien	case R_ALPHA_TLSLDM:
1852130570Sobrien	  /* The symbol for a TLSLDM reloc is ignored.  Collapse the
1853130570Sobrien	     reloc to the 0 symbol so that they all match.  */
1854130570Sobrien	  r_symndx = 0;
1855130570Sobrien	  h = 0;
1856130570Sobrien	  maybe_dynamic = FALSE;
1857130570Sobrien	  /* FALLTHRU */
1858130570Sobrien
1859104841Sobrien	case R_ALPHA_TLSGD:
1860104841Sobrien	case R_ALPHA_GOTDTPREL:
1861104841Sobrien	  need = NEED_GOT | NEED_GOT_ENTRY;
1862104841Sobrien	  break;
1863104841Sobrien
1864104841Sobrien	case R_ALPHA_GOTTPREL:
1865104841Sobrien	  need = NEED_GOT | NEED_GOT_ENTRY;
1866104841Sobrien	  gotent_flags = ALPHA_ELF_LINK_HASH_TLS_IE;
1867104841Sobrien	  if (info->shared)
1868104841Sobrien	    info->flags |= DF_STATIC_TLS;
1869104841Sobrien	  break;
1870104841Sobrien
1871104841Sobrien	case R_ALPHA_TPREL64:
1872104841Sobrien	  if (info->shared || maybe_dynamic)
1873104841Sobrien	    need = NEED_DYNREL;
1874104841Sobrien	  if (info->shared)
1875104841Sobrien	    info->flags |= DF_STATIC_TLS;
1876104841Sobrien	  break;
1877104841Sobrien	}
1878104841Sobrien
1879104841Sobrien      if (need & NEED_GOT)
1880104841Sobrien	{
1881218822Sdim	  if (alpha_elf_tdata(abfd)->gotobj == NULL)
188233965Sjdp	    {
188333965Sjdp	      if (!elf64_alpha_create_got_section (abfd, info))
1884130570Sobrien		return FALSE;
188533965Sjdp	    }
1886104841Sobrien	}
188733965Sjdp
1888104841Sobrien      if (need & NEED_GOT_ENTRY)
1889104841Sobrien	{
1890104841Sobrien	  struct alpha_elf_got_entry *gotent;
189133965Sjdp
1892104841Sobrien	  gotent = get_got_entry (abfd, h, r_type, r_symndx, addend);
1893104841Sobrien	  if (!gotent)
1894130570Sobrien	    return FALSE;
1895104841Sobrien
1896104841Sobrien	  if (gotent_flags)
1897104841Sobrien	    {
1898104841Sobrien	      gotent->flags |= gotent_flags;
1899104841Sobrien	      if (h)
1900104841Sobrien		{
1901104841Sobrien		  gotent_flags |= h->flags;
1902104841Sobrien		  h->flags = gotent_flags;
1903104841Sobrien
1904104841Sobrien		  /* Make a guess as to whether a .plt entry is needed.  */
1905218822Sdim		  /* ??? It appears that we won't make it into
1906218822Sdim		     adjust_dynamic_symbol for symbols that remain
1907218822Sdim		     totally undefined.  Copying this check here means
1908218822Sdim		     we can create a plt entry for them too.  */
1909218822Sdim		  h->root.needs_plt
1910218822Sdim		    = (maybe_dynamic && elf64_alpha_want_plt (h));
1911218822Sdim		}
1912104841Sobrien	    }
1913104841Sobrien	}
1914104841Sobrien
1915104841Sobrien      if (need & NEED_DYNREL)
1916104841Sobrien	{
191733965Sjdp	  if (rel_sec_name == NULL)
191833965Sjdp	    {
191933965Sjdp	      rel_sec_name = (bfd_elf_string_from_elf_section
192033965Sjdp			      (abfd, elf_elfheader(abfd)->e_shstrndx,
192133965Sjdp			       elf_section_data(sec)->rel_hdr.sh_name));
192233965Sjdp	      if (rel_sec_name == NULL)
1923130570Sobrien		return FALSE;
192433965Sjdp
1925218822Sdim	      BFD_ASSERT (CONST_STRNEQ (rel_sec_name, ".rela")
192633965Sjdp			  && strcmp (bfd_get_section_name (abfd, sec),
192733965Sjdp				     rel_sec_name+5) == 0);
192833965Sjdp	    }
192933965Sjdp
193033965Sjdp	  /* We need to create the section here now whether we eventually
193133965Sjdp	     use it or not so that it gets mapped to an output section by
193233965Sjdp	     the linker.  If not used, we'll kill it in
193333965Sjdp	     size_dynamic_sections.  */
193433965Sjdp	  if (sreloc == NULL)
193533965Sjdp	    {
193633965Sjdp	      sreloc = bfd_get_section_by_name (dynobj, rel_sec_name);
193733965Sjdp	      if (sreloc == NULL)
193833965Sjdp		{
193989862Sobrien		  flagword flags;
194089862Sobrien
194189862Sobrien		  flags = (SEC_HAS_CONTENTS | SEC_IN_MEMORY
194289862Sobrien			   | SEC_LINKER_CREATED | SEC_READONLY);
194389862Sobrien		  if (sec->flags & SEC_ALLOC)
194489862Sobrien		    flags |= SEC_ALLOC | SEC_LOAD;
1945218822Sdim		  sreloc = bfd_make_section_with_flags (dynobj,
1946218822Sdim							rel_sec_name,
1947218822Sdim							flags);
194833965Sjdp		  if (sreloc == NULL
194933965Sjdp		      || !bfd_set_section_alignment (dynobj, sreloc, 3))
1950130570Sobrien		    return FALSE;
195133965Sjdp		}
195233965Sjdp	    }
195333965Sjdp
195433965Sjdp	  if (h)
195533965Sjdp	    {
195633965Sjdp	      /* Since we havn't seen all of the input symbols yet, we
195733965Sjdp		 don't know whether we'll actually need a dynamic relocation
195833965Sjdp		 entry for this reloc.  So make a record of it.  Once we
195933965Sjdp		 find out if this thing needs dynamic relocation we'll
196077303Sobrien		 expand the relocation sections by the appropriate amount.  */
196133965Sjdp
196233965Sjdp	      struct alpha_elf_reloc_entry *rent;
196333965Sjdp
196433965Sjdp	      for (rent = h->reloc_entries; rent; rent = rent->next)
196533965Sjdp		if (rent->rtype == r_type && rent->srel == sreloc)
196633965Sjdp		  break;
196733965Sjdp
196833965Sjdp	      if (!rent)
196933965Sjdp		{
197089862Sobrien		  amt = sizeof (struct alpha_elf_reloc_entry);
197189862Sobrien		  rent = (struct alpha_elf_reloc_entry *) bfd_alloc (abfd, amt);
197233965Sjdp		  if (!rent)
1973130570Sobrien		    return FALSE;
197433965Sjdp
197533965Sjdp		  rent->srel = sreloc;
197633965Sjdp		  rent->rtype = r_type;
197733965Sjdp		  rent->count = 1;
1978218822Sdim		  rent->reltext = (sec->flags & SEC_READONLY) != 0;
197933965Sjdp
198033965Sjdp		  rent->next = h->reloc_entries;
198133965Sjdp		  h->reloc_entries = rent;
198233965Sjdp		}
198333965Sjdp	      else
198433965Sjdp		rent->count++;
198533965Sjdp	    }
1986104841Sobrien	  else if (info->shared)
198733965Sjdp	    {
198860510Sobrien	      /* If this is a shared library, and the section is to be
198960510Sobrien		 loaded into memory, we need a RELATIVE reloc.  */
1990218822Sdim	      sreloc->size += sizeof (Elf64_External_Rela);
1991218822Sdim	      if (sec->flags & SEC_READONLY)
199289862Sobrien		info->flags |= DF_TEXTREL;
199333965Sjdp	    }
199433965Sjdp	}
199533965Sjdp    }
199633965Sjdp
1997130570Sobrien  return TRUE;
199833965Sjdp}
199933965Sjdp
200033965Sjdp/* Adjust a symbol defined by a dynamic object and referenced by a
200133965Sjdp   regular object.  The current definition is in some section of the
200233965Sjdp   dynamic object, but we're not including those sections.  We have to
200333965Sjdp   change the definition to something the rest of the link can
200433965Sjdp   understand.  */
200533965Sjdp
2006130570Sobrienstatic bfd_boolean
2007218822Sdimelf64_alpha_adjust_dynamic_symbol (struct bfd_link_info *info,
2008218822Sdim				   struct elf_link_hash_entry *h)
200933965Sjdp{
201033965Sjdp  bfd *dynobj;
201133965Sjdp  asection *s;
201233965Sjdp  struct alpha_elf_link_hash_entry *ah;
201333965Sjdp
201433965Sjdp  dynobj = elf_hash_table(info)->dynobj;
201533965Sjdp  ah = (struct alpha_elf_link_hash_entry *)h;
201633965Sjdp
201733965Sjdp  /* Now that we've seen all of the input symbols, finalize our decision
2018218822Sdim     about whether this symbol should get a .plt entry.  Irritatingly, it
2019218822Sdim     is common for folk to leave undefined symbols in shared libraries,
2020218822Sdim     and they still expect lazy binding; accept undefined symbols in lieu
2021218822Sdim     of STT_FUNC.  */
2022218822Sdim  if (alpha_elf_dynamic_symbol_p (h, info) && elf64_alpha_want_plt (ah))
202333965Sjdp    {
2024218822Sdim      h->needs_plt = TRUE;
202533965Sjdp
202633965Sjdp      s = bfd_get_section_by_name(dynobj, ".plt");
202733965Sjdp      if (!s && !elf64_alpha_create_dynamic_sections (dynobj, info))
2028130570Sobrien	return FALSE;
202933965Sjdp
2030218822Sdim      /* We need one plt entry per got subsection.  Delay allocation of
2031218822Sdim	 the actual plt entries until size_plt_section, called from
2032218822Sdim	 size_dynamic_sections or during relaxation.  */
203333965Sjdp
2034130570Sobrien      return TRUE;
203533965Sjdp    }
203633965Sjdp  else
2037218822Sdim    h->needs_plt = FALSE;
203833965Sjdp
203933965Sjdp  /* If this is a weak symbol, and there is a real definition, the
204033965Sjdp     processor independent code will have arranged for us to see the
204133965Sjdp     real definition first, and we can just use the same value.  */
2042218822Sdim  if (h->u.weakdef != NULL)
204333965Sjdp    {
2044218822Sdim      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
2045218822Sdim		  || h->u.weakdef->root.type == bfd_link_hash_defweak);
2046218822Sdim      h->root.u.def.section = h->u.weakdef->root.u.def.section;
2047218822Sdim      h->root.u.def.value = h->u.weakdef->root.u.def.value;
2048130570Sobrien      return TRUE;
204933965Sjdp    }
205033965Sjdp
205133965Sjdp  /* This is a reference to a symbol defined by a dynamic object which
205233965Sjdp     is not a function.  The Alpha, since it uses .got entries for all
205333965Sjdp     symbols even in regular objects, does not need the hackery of a
205433965Sjdp     .dynbss section and COPY dynamic relocations.  */
205533965Sjdp
2056130570Sobrien  return TRUE;
205733965Sjdp}
205833965Sjdp
2059218822Sdim/* Record STO_ALPHA_NOPV and STO_ALPHA_STD_GPLOAD.  */
2060218822Sdim
2061218822Sdimstatic void
2062218822Sdimelf64_alpha_merge_symbol_attribute (struct elf_link_hash_entry *h,
2063218822Sdim				    const Elf_Internal_Sym *isym,
2064218822Sdim				    bfd_boolean definition,
2065218822Sdim				    bfd_boolean dynamic)
2066218822Sdim{
2067218822Sdim  if (!dynamic && definition)
2068218822Sdim    h->other = ((h->other & ELF_ST_VISIBILITY (-1))
2069218822Sdim		| (isym->st_other & ~ELF_ST_VISIBILITY (-1)));
2070218822Sdim}
2071218822Sdim
207238889Sjdp/* Symbol versioning can create new symbols, and make our old symbols
207338889Sjdp   indirect to the new ones.  Consolidate the got and reloc information
207438889Sjdp   in these situations.  */
207538889Sjdp
2076130570Sobrienstatic bfd_boolean
2077218822Sdimelf64_alpha_merge_ind_symbols (struct alpha_elf_link_hash_entry *hi,
2078218822Sdim			       PTR dummy ATTRIBUTE_UNUSED)
207938889Sjdp{
208038889Sjdp  struct alpha_elf_link_hash_entry *hs;
208138889Sjdp
208238889Sjdp  if (hi->root.root.type != bfd_link_hash_indirect)
2083130570Sobrien    return TRUE;
208438889Sjdp  hs = hi;
208538889Sjdp  do {
208638889Sjdp    hs = (struct alpha_elf_link_hash_entry *)hs->root.root.u.i.link;
208738889Sjdp  } while (hs->root.root.type == bfd_link_hash_indirect);
208838889Sjdp
208938889Sjdp  /* Merge the flags.  Whee.  */
209038889Sjdp
209138889Sjdp  hs->flags |= hi->flags;
209238889Sjdp
209338889Sjdp  /* Merge the .got entries.  Cannibalize the old symbol's list in
209438889Sjdp     doing so, since we don't need it anymore.  */
209538889Sjdp
209638889Sjdp  if (hs->got_entries == NULL)
209738889Sjdp    hs->got_entries = hi->got_entries;
209838889Sjdp  else
209938889Sjdp    {
210038889Sjdp      struct alpha_elf_got_entry *gi, *gs, *gin, *gsh;
210138889Sjdp
210238889Sjdp      gsh = hs->got_entries;
210338889Sjdp      for (gi = hi->got_entries; gi ; gi = gin)
210438889Sjdp	{
210538889Sjdp	  gin = gi->next;
210638889Sjdp	  for (gs = gsh; gs ; gs = gs->next)
2107104841Sobrien	    if (gi->gotobj == gs->gotobj
2108104841Sobrien		&& gi->reloc_type == gs->reloc_type
2109104841Sobrien		&& gi->addend == gs->addend)
2110104841Sobrien	      {
2111104841Sobrien		gi->use_count += gs->use_count;
2112104841Sobrien	        goto got_found;
2113104841Sobrien	      }
211438889Sjdp	  gi->next = hs->got_entries;
211538889Sjdp	  hs->got_entries = gi;
211638889Sjdp	got_found:;
211738889Sjdp	}
211838889Sjdp    }
211938889Sjdp  hi->got_entries = NULL;
212038889Sjdp
212138889Sjdp  /* And similar for the reloc entries.  */
212238889Sjdp
212338889Sjdp  if (hs->reloc_entries == NULL)
212438889Sjdp    hs->reloc_entries = hi->reloc_entries;
212538889Sjdp  else
212638889Sjdp    {
212738889Sjdp      struct alpha_elf_reloc_entry *ri, *rs, *rin, *rsh;
212838889Sjdp
212938889Sjdp      rsh = hs->reloc_entries;
213038889Sjdp      for (ri = hi->reloc_entries; ri ; ri = rin)
213138889Sjdp	{
213238889Sjdp	  rin = ri->next;
213338889Sjdp	  for (rs = rsh; rs ; rs = rs->next)
2134104841Sobrien	    if (ri->rtype == rs->rtype && ri->srel == rs->srel)
213538889Sjdp	      {
213638889Sjdp		rs->count += ri->count;
213738889Sjdp		goto found_reloc;
213838889Sjdp	      }
213938889Sjdp	  ri->next = hs->reloc_entries;
214038889Sjdp	  hs->reloc_entries = ri;
214138889Sjdp	found_reloc:;
214238889Sjdp	}
214338889Sjdp    }
214438889Sjdp  hi->reloc_entries = NULL;
214538889Sjdp
2146130570Sobrien  return TRUE;
214738889Sjdp}
214838889Sjdp
214933965Sjdp/* Is it possible to merge two object file's .got tables?  */
215033965Sjdp
2151130570Sobrienstatic bfd_boolean
2152218822Sdimelf64_alpha_can_merge_gots (bfd *a, bfd *b)
215333965Sjdp{
2154104841Sobrien  int total = alpha_elf_tdata (a)->total_got_size;
215560510Sobrien  bfd *bsub;
215633965Sjdp
215733965Sjdp  /* Trivial quick fallout test.  */
2158104841Sobrien  if (total + alpha_elf_tdata (b)->total_got_size <= MAX_GOT_SIZE)
2159130570Sobrien    return TRUE;
216033965Sjdp
216133965Sjdp  /* By their nature, local .got entries cannot be merged.  */
2162104841Sobrien  if ((total += alpha_elf_tdata (b)->local_got_size) > MAX_GOT_SIZE)
2163130570Sobrien    return FALSE;
216433965Sjdp
216533965Sjdp  /* Failing the common trivial comparison, we must effectively
216633965Sjdp     perform the merge.  Not actually performing the merge means that
216733965Sjdp     we don't have to store undo information in case we fail.  */
216860510Sobrien  for (bsub = b; bsub ; bsub = alpha_elf_tdata (bsub)->in_got_link_next)
216960510Sobrien    {
217060510Sobrien      struct alpha_elf_link_hash_entry **hashes = alpha_elf_sym_hashes (bsub);
217160510Sobrien      Elf_Internal_Shdr *symtab_hdr = &elf_tdata (bsub)->symtab_hdr;
217260510Sobrien      int i, n;
217333965Sjdp
217478833Sobrien      n = NUM_SHDR_ENTRIES (symtab_hdr) - symtab_hdr->sh_info;
217560510Sobrien      for (i = 0; i < n; ++i)
217660510Sobrien	{
217760510Sobrien	  struct alpha_elf_got_entry *ae, *be;
217860510Sobrien	  struct alpha_elf_link_hash_entry *h;
217938889Sjdp
218060510Sobrien	  h = hashes[i];
218160510Sobrien	  while (h->root.root.type == bfd_link_hash_indirect
218260510Sobrien	         || h->root.root.type == bfd_link_hash_warning)
218360510Sobrien	    h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
218438889Sjdp
218560510Sobrien	  for (be = h->got_entries; be ; be = be->next)
218660510Sobrien	    {
218760510Sobrien	      if (be->use_count == 0)
218860510Sobrien	        continue;
218960510Sobrien	      if (be->gotobj != b)
219060510Sobrien	        continue;
219133965Sjdp
219260510Sobrien	      for (ae = h->got_entries; ae ; ae = ae->next)
2193104841Sobrien	        if (ae->gotobj == a
2194104841Sobrien		    && ae->reloc_type == be->reloc_type
2195104841Sobrien		    && ae->addend == be->addend)
219660510Sobrien		  goto global_found;
219733965Sjdp
2198104841Sobrien	      total += alpha_got_entry_size (be->reloc_type);
2199104841Sobrien	      if (total > MAX_GOT_SIZE)
2200130570Sobrien	        return FALSE;
220160510Sobrien	    global_found:;
220260510Sobrien	    }
220360510Sobrien	}
220460510Sobrien    }
220533965Sjdp
2206130570Sobrien  return TRUE;
220733965Sjdp}
220833965Sjdp
220933965Sjdp/* Actually merge two .got tables.  */
221033965Sjdp
221133965Sjdpstatic void
2212218822Sdimelf64_alpha_merge_gots (bfd *a, bfd *b)
221333965Sjdp{
2214104841Sobrien  int total = alpha_elf_tdata (a)->total_got_size;
221560510Sobrien  bfd *bsub;
221633965Sjdp
221733965Sjdp  /* Remember local expansion.  */
221833965Sjdp  {
2219104841Sobrien    int e = alpha_elf_tdata (b)->local_got_size;
222033965Sjdp    total += e;
2221104841Sobrien    alpha_elf_tdata (a)->local_got_size += e;
222233965Sjdp  }
222333965Sjdp
222460510Sobrien  for (bsub = b; bsub ; bsub = alpha_elf_tdata (bsub)->in_got_link_next)
222560510Sobrien    {
222660510Sobrien      struct alpha_elf_got_entry **local_got_entries;
222760510Sobrien      struct alpha_elf_link_hash_entry **hashes;
222860510Sobrien      Elf_Internal_Shdr *symtab_hdr;
222960510Sobrien      int i, n;
223033965Sjdp
223160510Sobrien      /* Let the local .got entries know they are part of a new subsegment.  */
223260510Sobrien      local_got_entries = alpha_elf_tdata (bsub)->local_got_entries;
223360510Sobrien      if (local_got_entries)
223460510Sobrien        {
223560510Sobrien	  n = elf_tdata (bsub)->symtab_hdr.sh_info;
223660510Sobrien	  for (i = 0; i < n; ++i)
223760510Sobrien	    {
223860510Sobrien	      struct alpha_elf_got_entry *ent;
223960510Sobrien	      for (ent = local_got_entries[i]; ent; ent = ent->next)
224060510Sobrien	        ent->gotobj = a;
224160510Sobrien	    }
224260510Sobrien        }
224333965Sjdp
224460510Sobrien      /* Merge the global .got entries.  */
224560510Sobrien      hashes = alpha_elf_sym_hashes (bsub);
224660510Sobrien      symtab_hdr = &elf_tdata (bsub)->symtab_hdr;
224733965Sjdp
224878833Sobrien      n = NUM_SHDR_ENTRIES (symtab_hdr) - symtab_hdr->sh_info;
224960510Sobrien      for (i = 0; i < n; ++i)
225060510Sobrien        {
225160510Sobrien	  struct alpha_elf_got_entry *ae, *be, **pbe, **start;
225260510Sobrien	  struct alpha_elf_link_hash_entry *h;
225338889Sjdp
225460510Sobrien	  h = hashes[i];
225560510Sobrien	  while (h->root.root.type == bfd_link_hash_indirect
225660510Sobrien	         || h->root.root.type == bfd_link_hash_warning)
225760510Sobrien	    h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
225838889Sjdp
2259218822Sdim	  pbe = start = &h->got_entries;
2260218822Sdim	  while ((be = *pbe) != NULL)
226160510Sobrien	    {
226260510Sobrien	      if (be->use_count == 0)
226360510Sobrien	        {
226433965Sjdp		  *pbe = be->next;
2265218822Sdim		  memset (be, 0xa5, sizeof (*be));
2266218822Sdim		  goto kill;
226760510Sobrien	        }
226860510Sobrien	      if (be->gotobj != b)
2269218822Sdim	        goto next;
227033965Sjdp
227160510Sobrien	      for (ae = *start; ae ; ae = ae->next)
2272104841Sobrien	        if (ae->gotobj == a
2273104841Sobrien		    && ae->reloc_type == be->reloc_type
2274104841Sobrien		    && ae->addend == be->addend)
227560510Sobrien		  {
227660510Sobrien		    ae->flags |= be->flags;
227760510Sobrien		    ae->use_count += be->use_count;
227860510Sobrien		    *pbe = be->next;
2279218822Sdim		    memset (be, 0xa5, sizeof (*be));
2280218822Sdim		    goto kill;
228160510Sobrien		  }
228260510Sobrien	      be->gotobj = a;
2283104841Sobrien	      total += alpha_got_entry_size (be->reloc_type);
228460510Sobrien
2285218822Sdim	    next:;
2286218822Sdim	      pbe = &be->next;
2287218822Sdim	    kill:;
228860510Sobrien	    }
228960510Sobrien        }
229060510Sobrien
229160510Sobrien      alpha_elf_tdata (bsub)->gotobj = a;
229260510Sobrien    }
2293104841Sobrien  alpha_elf_tdata (a)->total_got_size = total;
229460510Sobrien
229560510Sobrien  /* Merge the two in_got chains.  */
229660510Sobrien  {
229760510Sobrien    bfd *next;
229860510Sobrien
229960510Sobrien    bsub = a;
230060510Sobrien    while ((next = alpha_elf_tdata (bsub)->in_got_link_next) != NULL)
230160510Sobrien      bsub = next;
230260510Sobrien
230360510Sobrien    alpha_elf_tdata (bsub)->in_got_link_next = b;
230433965Sjdp  }
230533965Sjdp}
230633965Sjdp
230733965Sjdp/* Calculate the offsets for the got entries.  */
230833965Sjdp
2309130570Sobrienstatic bfd_boolean
2310218822Sdimelf64_alpha_calc_got_offsets_for_symbol (struct alpha_elf_link_hash_entry *h,
2311218822Sdim					 PTR arg ATTRIBUTE_UNUSED)
231233965Sjdp{
231333965Sjdp  struct alpha_elf_got_entry *gotent;
231433965Sjdp
231594544Sobrien  if (h->root.root.type == bfd_link_hash_warning)
231694544Sobrien    h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
231794544Sobrien
231833965Sjdp  for (gotent = h->got_entries; gotent; gotent = gotent->next)
231960510Sobrien    if (gotent->use_count > 0)
232060510Sobrien      {
2321130570Sobrien	struct alpha_elf_obj_tdata *td;
2322130570Sobrien	bfd_size_type *plge;
232333965Sjdp
2324130570Sobrien	td = alpha_elf_tdata (gotent->gotobj);
2325218822Sdim	plge = &td->got->size;
232660510Sobrien	gotent->got_offset = *plge;
2327104841Sobrien	*plge += alpha_got_entry_size (gotent->reloc_type);
232860510Sobrien      }
232960510Sobrien
2330218822Sdim  return TRUE;
233133965Sjdp}
233233965Sjdp
233333965Sjdpstatic void
2334218822Sdimelf64_alpha_calc_got_offsets (struct bfd_link_info *info)
233533965Sjdp{
233633965Sjdp  bfd *i, *got_list = alpha_elf_hash_table(info)->got_list;
233733965Sjdp
233833965Sjdp  /* First, zero out the .got sizes, as we may be recalculating the
233933965Sjdp     .got after optimizing it.  */
234033965Sjdp  for (i = got_list; i ; i = alpha_elf_tdata(i)->got_link_next)
2341218822Sdim    alpha_elf_tdata(i)->got->size = 0;
234233965Sjdp
234333965Sjdp  /* Next, fill in the offsets for all the global entries.  */
234433965Sjdp  alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
234533965Sjdp				elf64_alpha_calc_got_offsets_for_symbol,
234633965Sjdp				NULL);
234733965Sjdp
234833965Sjdp  /* Finally, fill in the offsets for the local entries.  */
234933965Sjdp  for (i = got_list; i ; i = alpha_elf_tdata(i)->got_link_next)
235033965Sjdp    {
2351218822Sdim      bfd_size_type got_offset = alpha_elf_tdata(i)->got->size;
235233965Sjdp      bfd *j;
235333965Sjdp
235433965Sjdp      for (j = i; j ; j = alpha_elf_tdata(j)->in_got_link_next)
235533965Sjdp	{
235633965Sjdp	  struct alpha_elf_got_entry **local_got_entries, *gotent;
235733965Sjdp	  int k, n;
235833965Sjdp
235933965Sjdp	  local_got_entries = alpha_elf_tdata(j)->local_got_entries;
236033965Sjdp	  if (!local_got_entries)
236133965Sjdp	    continue;
236233965Sjdp
236333965Sjdp	  for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k)
236433965Sjdp	    for (gotent = local_got_entries[k]; gotent; gotent = gotent->next)
236560510Sobrien	      if (gotent->use_count > 0)
236660510Sobrien	        {
236760510Sobrien		  gotent->got_offset = got_offset;
2368104841Sobrien		  got_offset += alpha_got_entry_size (gotent->reloc_type);
236960510Sobrien	        }
237033965Sjdp	}
237133965Sjdp
2372218822Sdim      alpha_elf_tdata(i)->got->size = got_offset;
237333965Sjdp    }
237433965Sjdp}
237533965Sjdp
237633965Sjdp/* Constructs the gots.  */
237733965Sjdp
2378130570Sobrienstatic bfd_boolean
2379218822Sdimelf64_alpha_size_got_sections (struct bfd_link_info *info)
238033965Sjdp{
238189862Sobrien  bfd *i, *got_list, *cur_got_obj = NULL;
238233965Sjdp
238360510Sobrien  got_list = alpha_elf_hash_table (info)->got_list;
238433965Sjdp
238560510Sobrien  /* On the first time through, pretend we have an existing got list
238660510Sobrien     consisting of all of the input files.  */
238760510Sobrien  if (got_list == NULL)
238833965Sjdp    {
238960510Sobrien      for (i = info->input_bfds; i ; i = i->link_next)
239060510Sobrien	{
239160510Sobrien	  bfd *this_got = alpha_elf_tdata (i)->gotobj;
239260510Sobrien	  if (this_got == NULL)
239360510Sobrien	    continue;
239433965Sjdp
2395130570Sobrien	  /* We are assuming no merging has yet occurred.  */
239660510Sobrien	  BFD_ASSERT (this_got == i);
239733965Sjdp
2398104841Sobrien          if (alpha_elf_tdata (this_got)->total_got_size > MAX_GOT_SIZE)
239933965Sjdp	    {
240060510Sobrien	      /* Yikes! A single object file has too many entries.  */
240160510Sobrien	      (*_bfd_error_handler)
2402218822Sdim	        (_("%B: .got subsegment exceeds 64K (size %d)"),
2403218822Sdim	         i, alpha_elf_tdata (this_got)->total_got_size);
2404130570Sobrien	      return FALSE;
240533965Sjdp	    }
240660510Sobrien
240760510Sobrien	  if (got_list == NULL)
240860510Sobrien	    got_list = this_got;
240933965Sjdp	  else
241060510Sobrien	    alpha_elf_tdata(cur_got_obj)->got_link_next = this_got;
241160510Sobrien	  cur_got_obj = this_got;
241233965Sjdp	}
241360510Sobrien
241460510Sobrien      /* Strange degenerate case of no got references.  */
241560510Sobrien      if (got_list == NULL)
2416130570Sobrien	return TRUE;
241760510Sobrien
241860510Sobrien      alpha_elf_hash_table (info)->got_list = got_list;
241960510Sobrien    }
242060510Sobrien
242160510Sobrien  cur_got_obj = got_list;
242260510Sobrien  i = alpha_elf_tdata(cur_got_obj)->got_link_next;
242360510Sobrien  while (i != NULL)
242460510Sobrien    {
242560510Sobrien      if (elf64_alpha_can_merge_gots (cur_got_obj, i))
242660510Sobrien	{
242760510Sobrien	  elf64_alpha_merge_gots (cur_got_obj, i);
2428218822Sdim
2429218822Sdim	  alpha_elf_tdata(i)->got->size = 0;
243060510Sobrien	  i = alpha_elf_tdata(i)->got_link_next;
243160510Sobrien	  alpha_elf_tdata(cur_got_obj)->got_link_next = i;
243260510Sobrien	}
243333965Sjdp      else
243433965Sjdp	{
243533965Sjdp	  cur_got_obj = i;
243660510Sobrien	  i = alpha_elf_tdata(i)->got_link_next;
243733965Sjdp	}
243833965Sjdp    }
243933965Sjdp
244060510Sobrien  /* Once the gots have been merged, fill in the got offsets for
244160510Sobrien     everything therein.  */
2442218822Sdim  elf64_alpha_calc_got_offsets (info);
244333965Sjdp
2444130570Sobrien  return TRUE;
244560510Sobrien}
244633965Sjdp
2447130570Sobrienstatic bfd_boolean
2448218822Sdimelf64_alpha_size_plt_section_1 (struct alpha_elf_link_hash_entry *h, PTR data)
2449104841Sobrien{
2450218822Sdim  asection *splt = (asection *) data;
2451218822Sdim  struct alpha_elf_got_entry *gotent;
2452218822Sdim  bfd_boolean saw_one = FALSE;
2453218822Sdim
2454218822Sdim  /* If we didn't need an entry before, we still don't.  */
2455218822Sdim  if (!h->root.needs_plt)
2456218822Sdim    return TRUE;
2457218822Sdim
2458218822Sdim  /* For each LITERAL got entry still in use, allocate a plt entry.  */
2459218822Sdim  for (gotent = h->got_entries; gotent ; gotent = gotent->next)
2460218822Sdim    if (gotent->reloc_type == R_ALPHA_LITERAL
2461218822Sdim	&& gotent->use_count > 0)
2462218822Sdim      {
2463218822Sdim	if (splt->size == 0)
2464218822Sdim	  splt->size = PLT_HEADER_SIZE;
2465218822Sdim	gotent->plt_offset = splt->size;
2466218822Sdim	splt->size += PLT_ENTRY_SIZE;
2467218822Sdim	saw_one = TRUE;
2468218822Sdim      }
2469218822Sdim
2470218822Sdim  /* If there weren't any, there's no longer a need for the PLT entry.  */
2471218822Sdim  if (!saw_one)
2472218822Sdim    h->root.needs_plt = FALSE;
2473218822Sdim
2474218822Sdim  return TRUE;
2475218822Sdim}
2476218822Sdim
2477218822Sdim/* Called from relax_section to rebuild the PLT in light of potential changes
2478218822Sdim   in the function's status.  */
2479218822Sdim
2480218822Sdimstatic void
2481218822Sdimelf64_alpha_size_plt_section (struct bfd_link_info *info)
2482218822Sdim{
2483218822Sdim  asection *splt, *spltrel, *sgotplt;
2484104841Sobrien  unsigned long entries;
2485104841Sobrien  bfd *dynobj;
2486104841Sobrien
2487104841Sobrien  dynobj = elf_hash_table(info)->dynobj;
2488218822Sdim  splt = bfd_get_section_by_name (dynobj, ".plt");
2489104841Sobrien  if (splt == NULL)
2490218822Sdim    return;
2491104841Sobrien
2492218822Sdim  splt->size = 0;
2493104841Sobrien
2494104841Sobrien  alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
2495104841Sobrien				elf64_alpha_size_plt_section_1, splt);
2496104841Sobrien
2497104841Sobrien  /* Every plt entry requires a JMP_SLOT relocation.  */
2498104841Sobrien  spltrel = bfd_get_section_by_name (dynobj, ".rela.plt");
2499218822Sdim  entries = 0;
2500218822Sdim  if (splt->size)
2501104841Sobrien    {
2502218822Sdim      if (elf64_alpha_use_secureplt)
2503218822Sdim	entries = (splt->size - NEW_PLT_HEADER_SIZE) / NEW_PLT_ENTRY_SIZE;
2504218822Sdim      else
2505218822Sdim	entries = (splt->size - OLD_PLT_HEADER_SIZE) / OLD_PLT_ENTRY_SIZE;
2506104841Sobrien    }
2507218822Sdim  spltrel->size = entries * sizeof (Elf64_External_Rela);
2508218822Sdim
2509218822Sdim  /* When using the secureplt, we need two words somewhere in the data
2510218822Sdim     segment for the dynamic linker to tell us where to go.  This is the
2511218822Sdim     entire contents of the .got.plt section.  */
2512218822Sdim  if (elf64_alpha_use_secureplt)
2513104841Sobrien    {
2514218822Sdim      sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
2515218822Sdim      sgotplt->size = entries ? 16 : 0;
2516104841Sobrien    }
2517104841Sobrien}
2518104841Sobrien
2519130570Sobrienstatic bfd_boolean
2520218822Sdimelf64_alpha_always_size_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
2521218822Sdim				  struct bfd_link_info *info)
252260510Sobrien{
252360510Sobrien  bfd *i;
252460510Sobrien
2525130570Sobrien  if (info->relocatable)
2526130570Sobrien    return TRUE;
252760510Sobrien
252860510Sobrien  /* First, take care of the indirect symbols created by versioning.  */
252960510Sobrien  alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
253060510Sobrien				elf64_alpha_merge_ind_symbols,
253160510Sobrien				NULL);
253260510Sobrien
2533104841Sobrien  if (!elf64_alpha_size_got_sections (info))
2534130570Sobrien    return FALSE;
253560510Sobrien
253633965Sjdp  /* Allocate space for all of the .got subsections.  */
253760510Sobrien  i = alpha_elf_hash_table (info)->got_list;
253860510Sobrien  for ( ; i ; i = alpha_elf_tdata(i)->got_link_next)
253933965Sjdp    {
254033965Sjdp      asection *s = alpha_elf_tdata(i)->got;
2541218822Sdim      if (s->size > 0)
254233965Sjdp	{
2543218822Sdim	  s->contents = (bfd_byte *) bfd_zalloc (i, s->size);
254433965Sjdp	  if (s->contents == NULL)
2545130570Sobrien	    return FALSE;
254633965Sjdp	}
254733965Sjdp    }
254833965Sjdp
2549130570Sobrien  return TRUE;
255033965Sjdp}
255133965Sjdp
2552104841Sobrien/* The number of dynamic relocations required by a static relocation.  */
2553104841Sobrien
2554104841Sobrienstatic int
2555218822Sdimalpha_dynamic_entries_for_reloc (int r_type, int dynamic, int shared)
2556104841Sobrien{
2557104841Sobrien  switch (r_type)
2558104841Sobrien    {
2559104841Sobrien    /* May appear in GOT entries.  */
2560104841Sobrien    case R_ALPHA_TLSGD:
2561104841Sobrien      return (dynamic ? 2 : shared ? 1 : 0);
2562104841Sobrien    case R_ALPHA_TLSLDM:
2563104841Sobrien      return shared;
2564104841Sobrien    case R_ALPHA_LITERAL:
2565130570Sobrien    case R_ALPHA_GOTTPREL:
2566104841Sobrien      return dynamic || shared;
2567104841Sobrien    case R_ALPHA_GOTDTPREL:
2568104841Sobrien      return dynamic;
2569104841Sobrien
2570104841Sobrien    /* May appear in data sections.  */
2571104841Sobrien    case R_ALPHA_REFLONG:
2572104841Sobrien    case R_ALPHA_REFQUAD:
2573130570Sobrien    case R_ALPHA_TPREL64:
2574104841Sobrien      return dynamic || shared;
2575104841Sobrien
2576104841Sobrien    /* Everything else is illegal.  We'll issue an error during
2577104841Sobrien       relocate_section.  */
2578104841Sobrien    default:
2579104841Sobrien      return 0;
2580104841Sobrien    }
2581104841Sobrien}
2582104841Sobrien
258333965Sjdp/* Work out the sizes of the dynamic relocation entries.  */
258433965Sjdp
2585130570Sobrienstatic bfd_boolean
2586218822Sdimelf64_alpha_calc_dynrel_sizes (struct alpha_elf_link_hash_entry *h,
2587218822Sdim			       struct bfd_link_info *info)
258833965Sjdp{
2589130570Sobrien  bfd_boolean dynamic;
2590104841Sobrien  struct alpha_elf_reloc_entry *relent;
2591104841Sobrien  unsigned long entries;
2592104841Sobrien
259394544Sobrien  if (h->root.root.type == bfd_link_hash_warning)
259494544Sobrien    h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
259594544Sobrien
259633965Sjdp  /* If the symbol was defined as a common symbol in a regular object
259733965Sjdp     file, and there was no definition in any dynamic object, then the
259833965Sjdp     linker will have allocated space for the symbol in a common
259933965Sjdp     section but the ELF_LINK_HASH_DEF_REGULAR flag will not have been
260033965Sjdp     set.  This is done for dynamic symbols in
260133965Sjdp     elf_adjust_dynamic_symbol but this is not done for non-dynamic
260233965Sjdp     symbols, somehow.  */
2603218822Sdim  if (!h->root.def_regular
2604218822Sdim      && h->root.ref_regular
2605218822Sdim      && !h->root.def_dynamic
260633965Sjdp      && (h->root.root.type == bfd_link_hash_defined
260733965Sjdp	  || h->root.root.type == bfd_link_hash_defweak)
260833965Sjdp      && !(h->root.root.u.def.section->owner->flags & DYNAMIC))
2609218822Sdim    h->root.def_regular = 1;
261033965Sjdp
261133965Sjdp  /* If the symbol is dynamic, we'll need all the relocations in their
261260510Sobrien     natural form.  If this is a shared object, and it has been forced
261360510Sobrien     local, we'll need the same number of RELATIVE relocations.  */
2614104841Sobrien  dynamic = alpha_elf_dynamic_symbol_p (&h->root, info);
2615104841Sobrien
2616218822Sdim  /* If the symbol is a hidden undefined weak, then we never have any
2617218822Sdim     relocations.  Avoid the loop which may want to add RELATIVE relocs
2618218822Sdim     based on info->shared.  */
2619218822Sdim  if (h->root.root.type == bfd_link_hash_undefweak && !dynamic)
2620218822Sdim    return TRUE;
2621218822Sdim
2622104841Sobrien  for (relent = h->reloc_entries; relent; relent = relent->next)
262333965Sjdp    {
2624104841Sobrien      entries = alpha_dynamic_entries_for_reloc (relent->rtype, dynamic,
2625104841Sobrien						 info->shared);
2626104841Sobrien      if (entries)
2627104841Sobrien	{
2628218822Sdim	  relent->srel->size +=
2629104841Sobrien	    entries * sizeof (Elf64_External_Rela) * relent->count;
2630104841Sobrien	  if (relent->reltext)
2631104841Sobrien	    info->flags |= DT_TEXTREL;
2632104841Sobrien	}
2633104841Sobrien    }
263433965Sjdp
2635130570Sobrien  return TRUE;
2636104841Sobrien}
263733965Sjdp
2638218822Sdim/* Subroutine of elf64_alpha_size_rela_got_section for doing the
2639218822Sdim   global symbols.  */
264048850Sdfr
2641130570Sobrienstatic bfd_boolean
2642218822Sdimelf64_alpha_size_rela_got_1 (struct alpha_elf_link_hash_entry *h,
2643218822Sdim			     struct bfd_link_info *info)
2644104841Sobrien{
2645218822Sdim  bfd_boolean dynamic;
2646218822Sdim  struct alpha_elf_got_entry *gotent;
2647104841Sobrien  unsigned long entries;
2648218822Sdim
2649218822Sdim  if (h->root.root.type == bfd_link_hash_warning)
2650218822Sdim    h = (struct alpha_elf_link_hash_entry *) h->root.root.u.i.link;
2651218822Sdim
2652218822Sdim  /* If we're using a plt for this symbol, then all of its relocations
2653218822Sdim     for its got entries go into .rela.plt.  */
2654218822Sdim  if (h->root.needs_plt)
2655218822Sdim    return TRUE;
2656218822Sdim
2657218822Sdim  /* If the symbol is dynamic, we'll need all the relocations in their
2658218822Sdim     natural form.  If this is a shared object, and it has been forced
2659218822Sdim     local, we'll need the same number of RELATIVE relocations.  */
2660218822Sdim  dynamic = alpha_elf_dynamic_symbol_p (&h->root, info);
2661218822Sdim
2662218822Sdim  /* If the symbol is a hidden undefined weak, then we never have any
2663218822Sdim     relocations.  Avoid the loop which may want to add RELATIVE relocs
2664218822Sdim     based on info->shared.  */
2665218822Sdim  if (h->root.root.type == bfd_link_hash_undefweak && !dynamic)
2666218822Sdim    return TRUE;
2667218822Sdim
2668218822Sdim  entries = 0;
2669218822Sdim  for (gotent = h->got_entries; gotent ; gotent = gotent->next)
2670218822Sdim    if (gotent->use_count > 0)
2671218822Sdim      entries += alpha_dynamic_entries_for_reloc (gotent->reloc_type,
2672218822Sdim						  dynamic, info->shared);
2673218822Sdim
2674218822Sdim  if (entries > 0)
2675218822Sdim    {
2676218822Sdim      bfd *dynobj = elf_hash_table(info)->dynobj;
2677218822Sdim      asection *srel = bfd_get_section_by_name (dynobj, ".rela.got");
2678218822Sdim      BFD_ASSERT (srel != NULL);
2679218822Sdim      srel->size += sizeof (Elf64_External_Rela) * entries;
2680218822Sdim    }
2681218822Sdim
2682218822Sdim  return TRUE;
2683218822Sdim}
2684218822Sdim
2685218822Sdim/* Set the sizes of the dynamic relocation sections.  */
2686218822Sdim
2687218822Sdimstatic void
2688218822Sdimelf64_alpha_size_rela_got_section (struct bfd_link_info *info)
2689218822Sdim{
2690218822Sdim  unsigned long entries;
2691104841Sobrien  bfd *i, *dynobj;
2692104841Sobrien  asection *srel;
269348850Sdfr
2694104841Sobrien  /* Shared libraries often require RELATIVE relocs, and some relocs
2695104841Sobrien     require attention for the main application as well.  */
269648850Sdfr
2697104841Sobrien  entries = 0;
2698104841Sobrien  for (i = alpha_elf_hash_table(info)->got_list;
2699104841Sobrien       i ; i = alpha_elf_tdata(i)->got_link_next)
2700104841Sobrien    {
2701104841Sobrien      bfd *j;
2702104841Sobrien
2703104841Sobrien      for (j = i; j ; j = alpha_elf_tdata(j)->in_got_link_next)
270433965Sjdp	{
2705104841Sobrien	  struct alpha_elf_got_entry **local_got_entries, *gotent;
2706104841Sobrien	  int k, n;
2707104841Sobrien
2708104841Sobrien	  local_got_entries = alpha_elf_tdata(j)->local_got_entries;
2709104841Sobrien	  if (!local_got_entries)
2710104841Sobrien	    continue;
2711104841Sobrien
2712104841Sobrien	  for (k = 0, n = elf_tdata(j)->symtab_hdr.sh_info; k < n; ++k)
2713104841Sobrien	    for (gotent = local_got_entries[k];
2714104841Sobrien		 gotent ; gotent = gotent->next)
2715104841Sobrien	      if (gotent->use_count > 0)
2716104841Sobrien		entries += (alpha_dynamic_entries_for_reloc
2717104841Sobrien			    (gotent->reloc_type, 0, info->shared));
271833965Sjdp	}
271933965Sjdp    }
272048850Sdfr
2721104841Sobrien  dynobj = elf_hash_table(info)->dynobj;
2722104841Sobrien  srel = bfd_get_section_by_name (dynobj, ".rela.got");
2723104841Sobrien  if (!srel)
2724104841Sobrien    {
2725104841Sobrien      BFD_ASSERT (entries == 0);
2726218822Sdim      return;
2727104841Sobrien    }
2728218822Sdim  srel->size = sizeof (Elf64_External_Rela) * entries;
2729104841Sobrien
2730104841Sobrien  /* Now do the non-local symbols.  */
2731104841Sobrien  alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
2732104841Sobrien				elf64_alpha_size_rela_got_1, info);
273333965Sjdp}
273433965Sjdp
273533965Sjdp/* Set the sizes of the dynamic sections.  */
273633965Sjdp
2737130570Sobrienstatic bfd_boolean
2738218822Sdimelf64_alpha_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED,
2739218822Sdim				   struct bfd_link_info *info)
274033965Sjdp{
274133965Sjdp  bfd *dynobj;
274233965Sjdp  asection *s;
2743130570Sobrien  bfd_boolean relplt;
274433965Sjdp
274533965Sjdp  dynobj = elf_hash_table(info)->dynobj;
274633965Sjdp  BFD_ASSERT(dynobj != NULL);
274733965Sjdp
274833965Sjdp  if (elf_hash_table (info)->dynamic_sections_created)
274933965Sjdp    {
275033965Sjdp      /* Set the contents of the .interp section to the interpreter.  */
2751130570Sobrien      if (info->executable)
275233965Sjdp	{
275333965Sjdp	  s = bfd_get_section_by_name (dynobj, ".interp");
275433965Sjdp	  BFD_ASSERT (s != NULL);
2755218822Sdim	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
275633965Sjdp	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
275733965Sjdp	}
275833965Sjdp
275933965Sjdp      /* Now that we've seen all of the input files, we can decide which
276033965Sjdp	 symbols need dynamic relocation entries and which don't.  We've
276133965Sjdp	 collected information in check_relocs that we can now apply to
276233965Sjdp	 size the dynamic relocation sections.  */
276333965Sjdp      alpha_elf_link_hash_traverse (alpha_elf_hash_table (info),
2764104841Sobrien				    elf64_alpha_calc_dynrel_sizes, info);
276533965Sjdp
2766104841Sobrien      elf64_alpha_size_rela_got_section (info);
2767218822Sdim      elf64_alpha_size_plt_section (info);
276833965Sjdp    }
276933965Sjdp  /* else we're not dynamic and by definition we don't need such things.  */
277033965Sjdp
277133965Sjdp  /* The check_relocs and adjust_dynamic_symbol entry points have
277233965Sjdp     determined the sizes of the various dynamic sections.  Allocate
277333965Sjdp     memory for them.  */
2774130570Sobrien  relplt = FALSE;
277533965Sjdp  for (s = dynobj->sections; s != NULL; s = s->next)
277633965Sjdp    {
277733965Sjdp      const char *name;
277833965Sjdp
277933965Sjdp      if (!(s->flags & SEC_LINKER_CREATED))
278033965Sjdp	continue;
278133965Sjdp
278233965Sjdp      /* It's OK to base decisions on the section name, because none
278333965Sjdp	 of the dynobj section names depend upon the input files.  */
278433965Sjdp      name = bfd_get_section_name (dynobj, s);
278533965Sjdp
2786218822Sdim      if (CONST_STRNEQ (name, ".rela"))
278733965Sjdp	{
2788218822Sdim	  if (s->size != 0)
278933965Sjdp	    {
2790218822Sdim	      if (strcmp (name, ".rela.plt") == 0)
2791130570Sobrien		relplt = TRUE;
279233965Sjdp
279333965Sjdp	      /* We use the reloc_count field as a counter if we need
279433965Sjdp		 to copy relocs into the output file.  */
279533965Sjdp	      s->reloc_count = 0;
279633965Sjdp	    }
279733965Sjdp	}
2798218822Sdim      else if (! CONST_STRNEQ (name, ".got")
2799218822Sdim	       && strcmp (name, ".plt") != 0
2800218822Sdim	       && strcmp (name, ".dynbss") != 0)
280133965Sjdp	{
280233965Sjdp	  /* It's not one of our dynamic sections, so don't allocate space.  */
280333965Sjdp	  continue;
280433965Sjdp	}
280533965Sjdp
2806218822Sdim      if (s->size == 0)
280733965Sjdp	{
2808218822Sdim	  /* If we don't need this section, strip it from the output file.
2809218822Sdim	     This is to handle .rela.bss and .rela.plt.  We must create it
2810218822Sdim	     in create_dynamic_sections, because it must be created before
2811218822Sdim	     the linker maps input sections to output sections.  The
2812218822Sdim	     linker does that before adjust_dynamic_symbol is called, and
2813218822Sdim	     it is that function which decides whether anything needs to
2814218822Sdim	     go into these sections.  */
2815218822Sdim	  s->flags |= SEC_EXCLUDE;
2816218822Sdim	}
2817218822Sdim      else if ((s->flags & SEC_HAS_CONTENTS) != 0)
2818218822Sdim	{
281933965Sjdp	  /* Allocate memory for the section contents.  */
2820218822Sdim	  s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
2821218822Sdim	  if (s->contents == NULL)
2822130570Sobrien	    return FALSE;
282333965Sjdp	}
282433965Sjdp    }
282533965Sjdp
282633965Sjdp  if (elf_hash_table (info)->dynamic_sections_created)
282733965Sjdp    {
282833965Sjdp      /* Add some entries to the .dynamic section.  We fill in the
282933965Sjdp	 values later, in elf64_alpha_finish_dynamic_sections, but we
283033965Sjdp	 must add the entries now so that we get the correct size for
283133965Sjdp	 the .dynamic section.  The DT_DEBUG entry is filled in by the
283233965Sjdp	 dynamic linker and used by the debugger.  */
283389862Sobrien#define add_dynamic_entry(TAG, VAL) \
2834130570Sobrien  _bfd_elf_add_dynamic_entry (info, TAG, VAL)
283589862Sobrien
2836130570Sobrien      if (info->executable)
283733965Sjdp	{
283889862Sobrien	  if (!add_dynamic_entry (DT_DEBUG, 0))
2839130570Sobrien	    return FALSE;
284033965Sjdp	}
284133965Sjdp
284233965Sjdp      if (relplt)
284333965Sjdp	{
2844102735Sobrien	  if (!add_dynamic_entry (DT_PLTGOT, 0)
2845102735Sobrien	      || !add_dynamic_entry (DT_PLTRELSZ, 0)
284689862Sobrien	      || !add_dynamic_entry (DT_PLTREL, DT_RELA)
284789862Sobrien	      || !add_dynamic_entry (DT_JMPREL, 0))
2848130570Sobrien	    return FALSE;
2849218822Sdim
2850218822Sdim	  if (elf64_alpha_use_secureplt
2851218822Sdim	      && !add_dynamic_entry (DT_ALPHA_PLTRO, 1))
2852218822Sdim	    return FALSE;
285333965Sjdp	}
285433965Sjdp
285589862Sobrien      if (!add_dynamic_entry (DT_RELA, 0)
285689862Sobrien	  || !add_dynamic_entry (DT_RELASZ, 0)
285789862Sobrien	  || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela)))
2858130570Sobrien	return FALSE;
285933965Sjdp
286089862Sobrien      if (info->flags & DF_TEXTREL)
286133965Sjdp	{
286289862Sobrien	  if (!add_dynamic_entry (DT_TEXTREL, 0))
2863130570Sobrien	    return FALSE;
286433965Sjdp	}
286533965Sjdp    }
286689862Sobrien#undef add_dynamic_entry
286733965Sjdp
2868130570Sobrien  return TRUE;
286933965Sjdp}
2870218822Sdim
2871218822Sdim/* These functions do relaxation for Alpha ELF.
287233965Sjdp
2873218822Sdim   Currently I'm only handling what I can do with existing compiler
2874218822Sdim   and assembler support, which means no instructions are removed,
2875218822Sdim   though some may be nopped.  At this time GCC does not emit enough
2876218822Sdim   information to do all of the relaxing that is possible.  It will
2877218822Sdim   take some not small amount of work for that to happen.
2878218822Sdim
2879218822Sdim   There are a couple of interesting papers that I once read on this
2880218822Sdim   subject, that I cannot find references to at the moment, that
2881218822Sdim   related to Alpha in particular.  They are by David Wall, then of
2882218822Sdim   DEC WRL.  */
2883218822Sdim
2884218822Sdimstruct alpha_relax_info
2885218822Sdim{
2886218822Sdim  bfd *abfd;
2887218822Sdim  asection *sec;
2888218822Sdim  bfd_byte *contents;
2889218822Sdim  Elf_Internal_Shdr *symtab_hdr;
2890218822Sdim  Elf_Internal_Rela *relocs, *relend;
2891218822Sdim  struct bfd_link_info *link_info;
2892218822Sdim  bfd_vma gp;
2893218822Sdim  bfd *gotobj;
2894218822Sdim  asection *tsec;
2895218822Sdim  struct alpha_elf_link_hash_entry *h;
2896218822Sdim  struct alpha_elf_got_entry **first_gotent;
2897218822Sdim  struct alpha_elf_got_entry *gotent;
2898218822Sdim  bfd_boolean changed_contents;
2899218822Sdim  bfd_boolean changed_relocs;
2900218822Sdim  unsigned char other;
2901218822Sdim};
2902218822Sdim
2903218822Sdimstatic Elf_Internal_Rela *
2904218822Sdimelf64_alpha_find_reloc_at_ofs (Elf_Internal_Rela *rel,
2905218822Sdim			       Elf_Internal_Rela *relend,
2906218822Sdim			       bfd_vma offset, int type)
2907218822Sdim{
2908218822Sdim  while (rel < relend)
2909218822Sdim    {
2910218822Sdim      if (rel->r_offset == offset
2911218822Sdim	  && ELF64_R_TYPE (rel->r_info) == (unsigned int) type)
2912218822Sdim	return rel;
2913218822Sdim      ++rel;
2914218822Sdim    }
2915218822Sdim  return NULL;
2916218822Sdim}
2917218822Sdim
2918218822Sdimstatic bfd_boolean
2919218822Sdimelf64_alpha_relax_got_load (struct alpha_relax_info *info, bfd_vma symval,
2920218822Sdim			    Elf_Internal_Rela *irel, unsigned long r_type)
2921218822Sdim{
2922218822Sdim  unsigned int insn;
2923218822Sdim  bfd_signed_vma disp;
2924218822Sdim
2925218822Sdim  /* Get the instruction.  */
2926218822Sdim  insn = bfd_get_32 (info->abfd, info->contents + irel->r_offset);
2927218822Sdim
2928218822Sdim  if (insn >> 26 != OP_LDQ)
2929218822Sdim    {
2930218822Sdim      reloc_howto_type *howto = elf64_alpha_howto_table + r_type;
2931218822Sdim      ((*_bfd_error_handler)
2932218822Sdim       ("%B: %A+0x%lx: warning: %s relocation against unexpected insn",
2933218822Sdim	info->abfd, info->sec,
2934218822Sdim	(unsigned long) irel->r_offset, howto->name));
2935218822Sdim      return TRUE;
2936218822Sdim    }
2937218822Sdim
2938218822Sdim  /* Can't relax dynamic symbols.  */
2939218822Sdim  if (alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info))
2940218822Sdim    return TRUE;
2941218822Sdim
2942218822Sdim  /* Can't use local-exec relocations in shared libraries.  */
2943218822Sdim  if (r_type == R_ALPHA_GOTTPREL && info->link_info->shared)
2944218822Sdim    return TRUE;
2945218822Sdim
2946218822Sdim  if (r_type == R_ALPHA_LITERAL)
2947218822Sdim    {
2948218822Sdim      /* Look for nice constant addresses.  This includes the not-uncommon
2949218822Sdim	 special case of 0 for undefweak symbols.  */
2950218822Sdim      if ((info->h && info->h->root.root.type == bfd_link_hash_undefweak)
2951218822Sdim	  || (!info->link_info->shared
2952218822Sdim	      && (symval >= (bfd_vma)-0x8000 || symval < 0x8000)))
2953218822Sdim	{
2954218822Sdim	  disp = 0;
2955218822Sdim	  insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16);
2956218822Sdim	  insn |= (symval & 0xffff);
2957218822Sdim	  r_type = R_ALPHA_NONE;
2958218822Sdim	}
2959218822Sdim      else
2960218822Sdim	{
2961218822Sdim	  disp = symval - info->gp;
2962218822Sdim	  insn = (OP_LDA << 26) | (insn & 0x03ff0000);
2963218822Sdim	  r_type = R_ALPHA_GPREL16;
2964218822Sdim	}
2965218822Sdim    }
2966218822Sdim  else
2967218822Sdim    {
2968218822Sdim      bfd_vma dtp_base, tp_base;
2969218822Sdim
2970218822Sdim      BFD_ASSERT (elf_hash_table (info->link_info)->tls_sec != NULL);
2971218822Sdim      dtp_base = alpha_get_dtprel_base (info->link_info);
2972218822Sdim      tp_base = alpha_get_tprel_base (info->link_info);
2973218822Sdim      disp = symval - (r_type == R_ALPHA_GOTDTPREL ? dtp_base : tp_base);
2974218822Sdim
2975218822Sdim      insn = (OP_LDA << 26) | (insn & (31 << 21)) | (31 << 16);
2976218822Sdim
2977218822Sdim      switch (r_type)
2978218822Sdim	{
2979218822Sdim	case R_ALPHA_GOTDTPREL:
2980218822Sdim	  r_type = R_ALPHA_DTPREL16;
2981218822Sdim	  break;
2982218822Sdim	case R_ALPHA_GOTTPREL:
2983218822Sdim	  r_type = R_ALPHA_TPREL16;
2984218822Sdim	  break;
2985218822Sdim	default:
2986218822Sdim	  BFD_ASSERT (0);
2987218822Sdim	  return FALSE;
2988218822Sdim	}
2989218822Sdim    }
2990218822Sdim
2991218822Sdim  if (disp < -0x8000 || disp >= 0x8000)
2992218822Sdim    return TRUE;
2993218822Sdim
2994218822Sdim  bfd_put_32 (info->abfd, (bfd_vma) insn, info->contents + irel->r_offset);
2995218822Sdim  info->changed_contents = TRUE;
2996218822Sdim
2997218822Sdim  /* Reduce the use count on this got entry by one, possibly
2998218822Sdim     eliminating it.  */
2999218822Sdim  if (--info->gotent->use_count == 0)
3000218822Sdim    {
3001218822Sdim      int sz = alpha_got_entry_size (r_type);
3002218822Sdim      alpha_elf_tdata (info->gotobj)->total_got_size -= sz;
3003218822Sdim      if (!info->h)
3004218822Sdim	alpha_elf_tdata (info->gotobj)->local_got_size -= sz;
3005218822Sdim    }
3006218822Sdim
3007218822Sdim  /* Smash the existing GOT relocation for its 16-bit immediate pair.  */
3008218822Sdim  irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info), r_type);
3009218822Sdim  info->changed_relocs = TRUE;
3010218822Sdim
3011218822Sdim  /* ??? Search forward through this basic block looking for insns
3012218822Sdim     that use the target register.  Stop after an insn modifying the
3013218822Sdim     register is seen, or after a branch or call.
3014218822Sdim
3015218822Sdim     Any such memory load insn may be substituted by a load directly
3016218822Sdim     off the GP.  This allows the memory load insn to be issued before
3017218822Sdim     the calculated GP register would otherwise be ready.
3018218822Sdim
3019218822Sdim     Any such jsr insn can be replaced by a bsr if it is in range.
3020218822Sdim
3021218822Sdim     This would mean that we'd have to _add_ relocations, the pain of
3022218822Sdim     which gives one pause.  */
3023218822Sdim
3024218822Sdim  return TRUE;
3025218822Sdim}
3026218822Sdim
3027218822Sdimstatic bfd_vma
3028218822Sdimelf64_alpha_relax_opt_call (struct alpha_relax_info *info, bfd_vma symval)
3029218822Sdim{
3030218822Sdim  /* If the function has the same gp, and we can identify that the
3031218822Sdim     function does not use its function pointer, we can eliminate the
3032218822Sdim     address load.  */
3033218822Sdim
3034218822Sdim  /* If the symbol is marked NOPV, we are being told the function never
3035218822Sdim     needs its procedure value.  */
3036218822Sdim  if ((info->other & STO_ALPHA_STD_GPLOAD) == STO_ALPHA_NOPV)
3037218822Sdim    return symval;
3038218822Sdim
3039218822Sdim  /* If the symbol is marked STD_GP, we are being told the function does
3040218822Sdim     a normal ldgp in the first two words.  */
3041218822Sdim  else if ((info->other & STO_ALPHA_STD_GPLOAD) == STO_ALPHA_STD_GPLOAD)
3042218822Sdim    ;
3043218822Sdim
3044218822Sdim  /* Otherwise, we may be able to identify a GP load in the first two
3045218822Sdim     words, which we can then skip.  */
3046218822Sdim  else
3047218822Sdim    {
3048218822Sdim      Elf_Internal_Rela *tsec_relocs, *tsec_relend, *tsec_free, *gpdisp;
3049218822Sdim      bfd_vma ofs;
3050218822Sdim
3051218822Sdim      /* Load the relocations from the section that the target symbol is in.  */
3052218822Sdim      if (info->sec == info->tsec)
3053218822Sdim	{
3054218822Sdim	  tsec_relocs = info->relocs;
3055218822Sdim	  tsec_relend = info->relend;
3056218822Sdim	  tsec_free = NULL;
3057218822Sdim	}
3058218822Sdim      else
3059218822Sdim	{
3060218822Sdim	  tsec_relocs = (_bfd_elf_link_read_relocs
3061218822Sdim		         (info->abfd, info->tsec, (PTR) NULL,
3062218822Sdim			 (Elf_Internal_Rela *) NULL,
3063218822Sdim			 info->link_info->keep_memory));
3064218822Sdim	  if (tsec_relocs == NULL)
3065218822Sdim	    return 0;
3066218822Sdim	  tsec_relend = tsec_relocs + info->tsec->reloc_count;
3067218822Sdim	  tsec_free = (info->link_info->keep_memory ? NULL : tsec_relocs);
3068218822Sdim	}
3069218822Sdim
3070218822Sdim      /* Recover the symbol's offset within the section.  */
3071218822Sdim      ofs = (symval - info->tsec->output_section->vma
3072218822Sdim	     - info->tsec->output_offset);
3073218822Sdim
3074218822Sdim      /* Look for a GPDISP reloc.  */
3075218822Sdim      gpdisp = (elf64_alpha_find_reloc_at_ofs
3076218822Sdim		(tsec_relocs, tsec_relend, ofs, R_ALPHA_GPDISP));
3077218822Sdim
3078218822Sdim      if (!gpdisp || gpdisp->r_addend != 4)
3079218822Sdim	{
3080218822Sdim	  if (tsec_free)
3081218822Sdim	    free (tsec_free);
3082218822Sdim	  return 0;
3083218822Sdim	}
3084218822Sdim      if (tsec_free)
3085218822Sdim        free (tsec_free);
3086218822Sdim    }
3087218822Sdim
3088218822Sdim  /* We've now determined that we can skip an initial gp load.  Verify
3089218822Sdim     that the call and the target use the same gp.   */
3090218822Sdim  if (info->link_info->hash->creator != info->tsec->owner->xvec
3091218822Sdim      || info->gotobj != alpha_elf_tdata (info->tsec->owner)->gotobj)
3092218822Sdim    return 0;
3093218822Sdim
3094218822Sdim  return symval + 8;
3095218822Sdim}
3096218822Sdim
3097218822Sdimstatic bfd_boolean
3098218822Sdimelf64_alpha_relax_with_lituse (struct alpha_relax_info *info,
3099218822Sdim			       bfd_vma symval, Elf_Internal_Rela *irel)
3100218822Sdim{
3101218822Sdim  Elf_Internal_Rela *urel, *irelend = info->relend;
3102218822Sdim  int flags, count, i;
3103218822Sdim  bfd_signed_vma disp;
3104218822Sdim  bfd_boolean fits16;
3105218822Sdim  bfd_boolean fits32;
3106218822Sdim  bfd_boolean lit_reused = FALSE;
3107218822Sdim  bfd_boolean all_optimized = TRUE;
3108218822Sdim  unsigned int lit_insn;
3109218822Sdim
3110218822Sdim  lit_insn = bfd_get_32 (info->abfd, info->contents + irel->r_offset);
3111218822Sdim  if (lit_insn >> 26 != OP_LDQ)
3112218822Sdim    {
3113218822Sdim      ((*_bfd_error_handler)
3114218822Sdim       ("%B: %A+0x%lx: warning: LITERAL relocation against unexpected insn",
3115218822Sdim	info->abfd, info->sec,
3116218822Sdim	(unsigned long) irel->r_offset));
3117218822Sdim      return TRUE;
3118218822Sdim    }
3119218822Sdim
3120218822Sdim  /* Can't relax dynamic symbols.  */
3121218822Sdim  if (alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info))
3122218822Sdim    return TRUE;
3123218822Sdim
3124218822Sdim  /* Summarize how this particular LITERAL is used.  */
3125218822Sdim  for (urel = irel+1, flags = count = 0; urel < irelend; ++urel, ++count)
3126218822Sdim    {
3127218822Sdim      if (ELF64_R_TYPE (urel->r_info) != R_ALPHA_LITUSE)
3128218822Sdim	break;
3129218822Sdim      if (urel->r_addend <= 6)
3130218822Sdim	flags |= 1 << urel->r_addend;
3131218822Sdim    }
3132218822Sdim
3133218822Sdim  /* A little preparation for the loop...  */
3134218822Sdim  disp = symval - info->gp;
3135218822Sdim
3136218822Sdim  for (urel = irel+1, i = 0; i < count; ++i, ++urel)
3137218822Sdim    {
3138218822Sdim      unsigned int insn;
3139218822Sdim      int insn_disp;
3140218822Sdim      bfd_signed_vma xdisp;
3141218822Sdim
3142218822Sdim      insn = bfd_get_32 (info->abfd, info->contents + urel->r_offset);
3143218822Sdim
3144218822Sdim      switch (urel->r_addend)
3145218822Sdim	{
3146218822Sdim	case LITUSE_ALPHA_ADDR:
3147218822Sdim	default:
3148218822Sdim	  /* This type is really just a placeholder to note that all
3149218822Sdim	     uses cannot be optimized, but to still allow some.  */
3150218822Sdim	  all_optimized = FALSE;
3151218822Sdim	  break;
3152218822Sdim
3153218822Sdim	case LITUSE_ALPHA_BASE:
3154218822Sdim	  /* We can always optimize 16-bit displacements.  */
3155218822Sdim
3156218822Sdim	  /* Extract the displacement from the instruction, sign-extending
3157218822Sdim	     it if necessary, then test whether it is within 16 or 32 bits
3158218822Sdim	     displacement from GP.  */
3159218822Sdim	  insn_disp = ((insn & 0xffff) ^ 0x8000) - 0x8000;
3160218822Sdim
3161218822Sdim	  xdisp = disp + insn_disp;
3162218822Sdim	  fits16 = (xdisp >= - (bfd_signed_vma) 0x8000 && xdisp < 0x8000);
3163218822Sdim	  fits32 = (xdisp >= - (bfd_signed_vma) 0x80000000
3164218822Sdim		    && xdisp < 0x7fff8000);
3165218822Sdim
3166218822Sdim	  if (fits16)
3167218822Sdim	    {
3168218822Sdim	      /* Take the op code and dest from this insn, take the base
3169218822Sdim		 register from the literal insn.  Leave the offset alone.  */
3170218822Sdim	      insn = (insn & 0xffe0ffff) | (lit_insn & 0x001f0000);
3171218822Sdim	      urel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
3172218822Sdim					   R_ALPHA_GPREL16);
3173218822Sdim	      urel->r_addend = irel->r_addend;
3174218822Sdim	      info->changed_relocs = TRUE;
3175218822Sdim
3176218822Sdim	      bfd_put_32 (info->abfd, (bfd_vma) insn,
3177218822Sdim			  info->contents + urel->r_offset);
3178218822Sdim	      info->changed_contents = TRUE;
3179218822Sdim	    }
3180218822Sdim
3181218822Sdim	  /* If all mem+byte, we can optimize 32-bit mem displacements.  */
3182218822Sdim	  else if (fits32 && !(flags & ~6))
3183218822Sdim	    {
3184218822Sdim	      /* FIXME: sanity check that lit insn Ra is mem insn Rb.  */
3185218822Sdim
3186218822Sdim	      irel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
3187218822Sdim					   R_ALPHA_GPRELHIGH);
3188218822Sdim	      lit_insn = (OP_LDAH << 26) | (lit_insn & 0x03ff0000);
3189218822Sdim	      bfd_put_32 (info->abfd, (bfd_vma) lit_insn,
3190218822Sdim			  info->contents + irel->r_offset);
3191218822Sdim	      lit_reused = TRUE;
3192218822Sdim	      info->changed_contents = TRUE;
3193218822Sdim
3194218822Sdim	      urel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
3195218822Sdim					   R_ALPHA_GPRELLOW);
3196218822Sdim	      urel->r_addend = irel->r_addend;
3197218822Sdim	      info->changed_relocs = TRUE;
3198218822Sdim	    }
3199218822Sdim	  else
3200218822Sdim	    all_optimized = FALSE;
3201218822Sdim	  break;
3202218822Sdim
3203218822Sdim	case LITUSE_ALPHA_BYTOFF:
3204218822Sdim	  /* We can always optimize byte instructions.  */
3205218822Sdim
3206218822Sdim	  /* FIXME: sanity check the insn for byte op.  Check that the
3207218822Sdim	     literal dest reg is indeed Rb in the byte insn.  */
3208218822Sdim
3209218822Sdim	  insn &= ~ (unsigned) 0x001ff000;
3210218822Sdim	  insn |= ((symval & 7) << 13) | 0x1000;
3211218822Sdim
3212218822Sdim	  urel->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
3213218822Sdim	  urel->r_addend = 0;
3214218822Sdim	  info->changed_relocs = TRUE;
3215218822Sdim
3216218822Sdim	  bfd_put_32 (info->abfd, (bfd_vma) insn,
3217218822Sdim		      info->contents + urel->r_offset);
3218218822Sdim	  info->changed_contents = TRUE;
3219218822Sdim	  break;
3220218822Sdim
3221218822Sdim	case LITUSE_ALPHA_JSR:
3222218822Sdim	case LITUSE_ALPHA_TLSGD:
3223218822Sdim	case LITUSE_ALPHA_TLSLDM:
3224218822Sdim	case LITUSE_ALPHA_JSRDIRECT:
3225218822Sdim	  {
3226218822Sdim	    bfd_vma optdest, org;
3227218822Sdim	    bfd_signed_vma odisp;
3228218822Sdim
3229218822Sdim	    /* For undefined weak symbols, we're mostly interested in getting
3230218822Sdim	       rid of the got entry whenever possible, so optimize this to a
3231218822Sdim	       use of the zero register.  */
3232218822Sdim	    if (info->h && info->h->root.root.type == bfd_link_hash_undefweak)
3233218822Sdim	      {
3234218822Sdim		insn |= 31 << 16;
3235218822Sdim		bfd_put_32 (info->abfd, (bfd_vma) insn,
3236218822Sdim			    info->contents + urel->r_offset);
3237218822Sdim
3238218822Sdim		info->changed_contents = TRUE;
3239218822Sdim		break;
3240218822Sdim	      }
3241218822Sdim
3242218822Sdim	    /* If not zero, place to jump without needing pv.  */
3243218822Sdim	    optdest = elf64_alpha_relax_opt_call (info, symval);
3244218822Sdim	    org = (info->sec->output_section->vma
3245218822Sdim		   + info->sec->output_offset
3246218822Sdim		   + urel->r_offset + 4);
3247218822Sdim	    odisp = (optdest ? optdest : symval) - org;
3248218822Sdim
3249218822Sdim	    if (odisp >= -0x400000 && odisp < 0x400000)
3250218822Sdim	      {
3251218822Sdim		Elf_Internal_Rela *xrel;
3252218822Sdim
3253218822Sdim		/* Preserve branch prediction call stack when possible.  */
3254218822Sdim		if ((insn & INSN_JSR_MASK) == INSN_JSR)
3255218822Sdim		  insn = (OP_BSR << 26) | (insn & 0x03e00000);
3256218822Sdim		else
3257218822Sdim		  insn = (OP_BR << 26) | (insn & 0x03e00000);
3258218822Sdim
3259218822Sdim		urel->r_info = ELF64_R_INFO (ELF64_R_SYM (irel->r_info),
3260218822Sdim					     R_ALPHA_BRADDR);
3261218822Sdim		urel->r_addend = irel->r_addend;
3262218822Sdim
3263218822Sdim		if (optdest)
3264218822Sdim		  urel->r_addend += optdest - symval;
3265218822Sdim		else
3266218822Sdim		  all_optimized = FALSE;
3267218822Sdim
3268218822Sdim		bfd_put_32 (info->abfd, (bfd_vma) insn,
3269218822Sdim			    info->contents + urel->r_offset);
3270218822Sdim
3271218822Sdim		/* Kill any HINT reloc that might exist for this insn.  */
3272218822Sdim		xrel = (elf64_alpha_find_reloc_at_ofs
3273218822Sdim			(info->relocs, info->relend, urel->r_offset,
3274218822Sdim			 R_ALPHA_HINT));
3275218822Sdim		if (xrel)
3276218822Sdim		  xrel->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
3277218822Sdim
3278218822Sdim		info->changed_contents = TRUE;
3279218822Sdim		info->changed_relocs = TRUE;
3280218822Sdim	      }
3281218822Sdim	    else
3282218822Sdim	      all_optimized = FALSE;
3283218822Sdim
3284218822Sdim	    /* Even if the target is not in range for a direct branch,
3285218822Sdim	       if we share a GP, we can eliminate the gp reload.  */
3286218822Sdim	    if (optdest)
3287218822Sdim	      {
3288218822Sdim		Elf_Internal_Rela *gpdisp
3289218822Sdim		  = (elf64_alpha_find_reloc_at_ofs
3290218822Sdim		     (info->relocs, irelend, urel->r_offset + 4,
3291218822Sdim		      R_ALPHA_GPDISP));
3292218822Sdim		if (gpdisp)
3293218822Sdim		  {
3294218822Sdim		    bfd_byte *p_ldah = info->contents + gpdisp->r_offset;
3295218822Sdim		    bfd_byte *p_lda = p_ldah + gpdisp->r_addend;
3296218822Sdim		    unsigned int ldah = bfd_get_32 (info->abfd, p_ldah);
3297218822Sdim		    unsigned int lda = bfd_get_32 (info->abfd, p_lda);
3298218822Sdim
3299218822Sdim		    /* Verify that the instruction is "ldah $29,0($26)".
3300218822Sdim		       Consider a function that ends in a noreturn call,
3301218822Sdim		       and that the next function begins with an ldgp,
3302218822Sdim		       and that by accident there is no padding between.
3303218822Sdim		       In that case the insn would use $27 as the base.  */
3304218822Sdim		    if (ldah == 0x27ba0000 && lda == 0x23bd0000)
3305218822Sdim		      {
3306218822Sdim			bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, p_ldah);
3307218822Sdim			bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, p_lda);
3308218822Sdim
3309218822Sdim			gpdisp->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
3310218822Sdim			info->changed_contents = TRUE;
3311218822Sdim			info->changed_relocs = TRUE;
3312218822Sdim		      }
3313218822Sdim		  }
3314218822Sdim	      }
3315218822Sdim	  }
3316218822Sdim	  break;
3317218822Sdim	}
3318218822Sdim    }
3319218822Sdim
3320218822Sdim  /* If all cases were optimized, we can reduce the use count on this
3321218822Sdim     got entry by one, possibly eliminating it.  */
3322218822Sdim  if (all_optimized)
3323218822Sdim    {
3324218822Sdim      if (--info->gotent->use_count == 0)
3325218822Sdim	{
3326218822Sdim	  int sz = alpha_got_entry_size (R_ALPHA_LITERAL);
3327218822Sdim	  alpha_elf_tdata (info->gotobj)->total_got_size -= sz;
3328218822Sdim	  if (!info->h)
3329218822Sdim	    alpha_elf_tdata (info->gotobj)->local_got_size -= sz;
3330218822Sdim	}
3331218822Sdim
3332218822Sdim      /* If the literal instruction is no longer needed (it may have been
3333218822Sdim	 reused.  We can eliminate it.  */
3334218822Sdim      /* ??? For now, I don't want to deal with compacting the section,
3335218822Sdim	 so just nop it out.  */
3336218822Sdim      if (!lit_reused)
3337218822Sdim	{
3338218822Sdim	  irel->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
3339218822Sdim	  info->changed_relocs = TRUE;
3340218822Sdim
3341218822Sdim	  bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP,
3342218822Sdim		      info->contents + irel->r_offset);
3343218822Sdim	  info->changed_contents = TRUE;
3344218822Sdim	}
3345218822Sdim
3346218822Sdim      return TRUE;
3347218822Sdim    }
3348218822Sdim  else
3349218822Sdim    return elf64_alpha_relax_got_load (info, symval, irel, R_ALPHA_LITERAL);
3350218822Sdim}
3351218822Sdim
3352218822Sdimstatic bfd_boolean
3353218822Sdimelf64_alpha_relax_tls_get_addr (struct alpha_relax_info *info, bfd_vma symval,
3354218822Sdim				Elf_Internal_Rela *irel, bfd_boolean is_gd)
3355218822Sdim{
3356218822Sdim  bfd_byte *pos[5];
3357218822Sdim  unsigned int insn;
3358218822Sdim  Elf_Internal_Rela *gpdisp, *hint;
3359218822Sdim  bfd_boolean dynamic, use_gottprel, pos1_unusable;
3360218822Sdim  unsigned long new_symndx;
3361218822Sdim
3362218822Sdim  dynamic = alpha_elf_dynamic_symbol_p (&info->h->root, info->link_info);
3363218822Sdim
3364218822Sdim  /* If a TLS symbol is accessed using IE at least once, there is no point
3365218822Sdim     to use dynamic model for it.  */
3366218822Sdim  if (is_gd && info->h && (info->h->flags & ALPHA_ELF_LINK_HASH_TLS_IE))
3367218822Sdim    ;
3368218822Sdim
3369218822Sdim  /* If the symbol is local, and we've already committed to DF_STATIC_TLS,
3370218822Sdim     then we might as well relax to IE.  */
3371218822Sdim  else if (info->link_info->shared && !dynamic
3372218822Sdim	   && (info->link_info->flags & DF_STATIC_TLS))
3373218822Sdim    ;
3374218822Sdim
3375218822Sdim  /* Otherwise we must be building an executable to do anything.  */
3376218822Sdim  else if (info->link_info->shared)
3377218822Sdim    return TRUE;
3378218822Sdim
3379218822Sdim  /* The TLSGD/TLSLDM relocation must be followed by a LITERAL and
3380218822Sdim     the matching LITUSE_TLS relocations.  */
3381218822Sdim  if (irel + 2 >= info->relend)
3382218822Sdim    return TRUE;
3383218822Sdim  if (ELF64_R_TYPE (irel[1].r_info) != R_ALPHA_LITERAL
3384218822Sdim      || ELF64_R_TYPE (irel[2].r_info) != R_ALPHA_LITUSE
3385218822Sdim      || irel[2].r_addend != (is_gd ? LITUSE_ALPHA_TLSGD : LITUSE_ALPHA_TLSLDM))
3386218822Sdim    return TRUE;
3387218822Sdim
3388218822Sdim  /* There must be a GPDISP relocation positioned immediately after the
3389218822Sdim     LITUSE relocation.  */
3390218822Sdim  gpdisp = elf64_alpha_find_reloc_at_ofs (info->relocs, info->relend,
3391218822Sdim					  irel[2].r_offset + 4, R_ALPHA_GPDISP);
3392218822Sdim  if (!gpdisp)
3393218822Sdim    return TRUE;
3394218822Sdim
3395218822Sdim  pos[0] = info->contents + irel[0].r_offset;
3396218822Sdim  pos[1] = info->contents + irel[1].r_offset;
3397218822Sdim  pos[2] = info->contents + irel[2].r_offset;
3398218822Sdim  pos[3] = info->contents + gpdisp->r_offset;
3399218822Sdim  pos[4] = pos[3] + gpdisp->r_addend;
3400218822Sdim  pos1_unusable = FALSE;
3401218822Sdim
3402218822Sdim  /* Generally, the positions are not allowed to be out of order, lest the
3403218822Sdim     modified insn sequence have different register lifetimes.  We can make
3404218822Sdim     an exception when pos 1 is adjacent to pos 0.  */
3405218822Sdim  if (pos[1] + 4 == pos[0])
3406218822Sdim    {
3407218822Sdim      bfd_byte *tmp = pos[0];
3408218822Sdim      pos[0] = pos[1];
3409218822Sdim      pos[1] = tmp;
3410218822Sdim    }
3411218822Sdim  else if (pos[1] < pos[0])
3412218822Sdim    pos1_unusable = TRUE;
3413218822Sdim  if (pos[1] >= pos[2] || pos[2] >= pos[3])
3414218822Sdim    return TRUE;
3415218822Sdim
3416218822Sdim  /* Reduce the use count on the LITERAL relocation.  Do this before we
3417218822Sdim     smash the symndx when we adjust the relocations below.  */
3418218822Sdim  {
3419218822Sdim    struct alpha_elf_got_entry *lit_gotent;
3420218822Sdim    struct alpha_elf_link_hash_entry *lit_h;
3421218822Sdim    unsigned long indx;
3422218822Sdim
3423218822Sdim    BFD_ASSERT (ELF64_R_SYM (irel[1].r_info) >= info->symtab_hdr->sh_info);
3424218822Sdim    indx = ELF64_R_SYM (irel[1].r_info) - info->symtab_hdr->sh_info;
3425218822Sdim    lit_h = alpha_elf_sym_hashes (info->abfd)[indx];
3426218822Sdim
3427218822Sdim    while (lit_h->root.root.type == bfd_link_hash_indirect
3428218822Sdim	   || lit_h->root.root.type == bfd_link_hash_warning)
3429218822Sdim      lit_h = (struct alpha_elf_link_hash_entry *) lit_h->root.root.u.i.link;
3430218822Sdim
3431218822Sdim    for (lit_gotent = lit_h->got_entries; lit_gotent ;
3432218822Sdim	 lit_gotent = lit_gotent->next)
3433218822Sdim      if (lit_gotent->gotobj == info->gotobj
3434218822Sdim	  && lit_gotent->reloc_type == R_ALPHA_LITERAL
3435218822Sdim	  && lit_gotent->addend == irel[1].r_addend)
3436218822Sdim	break;
3437218822Sdim    BFD_ASSERT (lit_gotent);
3438218822Sdim
3439218822Sdim    if (--lit_gotent->use_count == 0)
3440218822Sdim      {
3441218822Sdim	int sz = alpha_got_entry_size (R_ALPHA_LITERAL);
3442218822Sdim	alpha_elf_tdata (info->gotobj)->total_got_size -= sz;
3443218822Sdim      }
3444218822Sdim  }
3445218822Sdim
3446218822Sdim  /* Change
3447218822Sdim
3448218822Sdim	lda	$16,x($gp)			!tlsgd!1
3449218822Sdim	ldq	$27,__tls_get_addr($gp)		!literal!1
3450218822Sdim	jsr	$26,($27),__tls_get_addr	!lituse_tlsgd!1
3451218822Sdim	ldah	$29,0($26)			!gpdisp!2
3452218822Sdim	lda	$29,0($29)			!gpdisp!2
3453218822Sdim     to
3454218822Sdim	ldq	$16,x($gp)			!gottprel
3455218822Sdim	unop
3456218822Sdim	call_pal rduniq
3457218822Sdim	addq	$16,$0,$0
3458218822Sdim	unop
3459218822Sdim     or the first pair to
3460218822Sdim	lda	$16,x($gp)			!tprel
3461218822Sdim	unop
3462218822Sdim     or
3463218822Sdim	ldah	$16,x($gp)			!tprelhi
3464218822Sdim	lda	$16,x($16)			!tprello
3465218822Sdim
3466218822Sdim     as appropriate.  */
3467218822Sdim
3468218822Sdim  use_gottprel = FALSE;
3469218822Sdim  new_symndx = is_gd ? ELF64_R_SYM (irel->r_info) : 0;
3470218822Sdim  switch (!dynamic && !info->link_info->shared)
3471218822Sdim    {
3472218822Sdim    case 1:
3473218822Sdim      {
3474218822Sdim	bfd_vma tp_base;
3475218822Sdim	bfd_signed_vma disp;
3476218822Sdim
3477218822Sdim	BFD_ASSERT (elf_hash_table (info->link_info)->tls_sec != NULL);
3478218822Sdim	tp_base = alpha_get_tprel_base (info->link_info);
3479218822Sdim	disp = symval - tp_base;
3480218822Sdim
3481218822Sdim	if (disp >= -0x8000 && disp < 0x8000)
3482218822Sdim	  {
3483218822Sdim	    insn = (OP_LDA << 26) | (16 << 21) | (31 << 16);
3484218822Sdim	    bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
3485218822Sdim	    bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
3486218822Sdim
3487218822Sdim	    irel[0].r_offset = pos[0] - info->contents;
3488218822Sdim	    irel[0].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_TPREL16);
3489218822Sdim	    irel[1].r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
3490218822Sdim	    break;
3491218822Sdim	  }
3492218822Sdim	else if (disp >= -(bfd_signed_vma) 0x80000000
3493218822Sdim		 && disp < (bfd_signed_vma) 0x7fff8000
3494218822Sdim		 && !pos1_unusable)
3495218822Sdim	  {
3496218822Sdim	    insn = (OP_LDAH << 26) | (16 << 21) | (31 << 16);
3497218822Sdim	    bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
3498218822Sdim	    insn = (OP_LDA << 26) | (16 << 21) | (16 << 16);
3499218822Sdim	    bfd_put_32 (info->abfd, (bfd_vma) insn, pos[1]);
3500218822Sdim
3501218822Sdim	    irel[0].r_offset = pos[0] - info->contents;
3502218822Sdim	    irel[0].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_TPRELHI);
3503218822Sdim	    irel[1].r_offset = pos[1] - info->contents;
3504218822Sdim	    irel[1].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_TPRELLO);
3505218822Sdim	    break;
3506218822Sdim	  }
3507218822Sdim      }
3508218822Sdim      /* FALLTHRU */
3509218822Sdim
3510218822Sdim    default:
3511218822Sdim      use_gottprel = TRUE;
3512218822Sdim
3513218822Sdim      insn = (OP_LDQ << 26) | (16 << 21) | (29 << 16);
3514218822Sdim      bfd_put_32 (info->abfd, (bfd_vma) insn, pos[0]);
3515218822Sdim      bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[1]);
3516218822Sdim
3517218822Sdim      irel[0].r_offset = pos[0] - info->contents;
3518218822Sdim      irel[0].r_info = ELF64_R_INFO (new_symndx, R_ALPHA_GOTTPREL);
3519218822Sdim      irel[1].r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
3520218822Sdim      break;
3521218822Sdim    }
3522218822Sdim
3523218822Sdim  bfd_put_32 (info->abfd, (bfd_vma) INSN_RDUNIQ, pos[2]);
3524218822Sdim
3525218822Sdim  insn = INSN_ADDQ | (16 << 21) | (0 << 16) | (0 << 0);
3526218822Sdim  bfd_put_32 (info->abfd, (bfd_vma) insn, pos[3]);
3527218822Sdim
3528218822Sdim  bfd_put_32 (info->abfd, (bfd_vma) INSN_UNOP, pos[4]);
3529218822Sdim
3530218822Sdim  irel[2].r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
3531218822Sdim  gpdisp->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
3532218822Sdim
3533218822Sdim  hint = elf64_alpha_find_reloc_at_ofs (info->relocs, info->relend,
3534218822Sdim					irel[2].r_offset, R_ALPHA_HINT);
3535218822Sdim  if (hint)
3536218822Sdim    hint->r_info = ELF64_R_INFO (0, R_ALPHA_NONE);
3537218822Sdim
3538218822Sdim  info->changed_contents = TRUE;
3539218822Sdim  info->changed_relocs = TRUE;
3540218822Sdim
3541218822Sdim  /* Reduce the use count on the TLSGD/TLSLDM relocation.  */
3542218822Sdim  if (--info->gotent->use_count == 0)
3543218822Sdim    {
3544218822Sdim      int sz = alpha_got_entry_size (info->gotent->reloc_type);
3545218822Sdim      alpha_elf_tdata (info->gotobj)->total_got_size -= sz;
3546218822Sdim      if (!info->h)
3547218822Sdim	alpha_elf_tdata (info->gotobj)->local_got_size -= sz;
3548218822Sdim    }
3549218822Sdim
3550218822Sdim  /* If we've switched to a GOTTPREL relocation, increment the reference
3551218822Sdim     count on that got entry.  */
3552218822Sdim  if (use_gottprel)
3553218822Sdim    {
3554218822Sdim      struct alpha_elf_got_entry *tprel_gotent;
3555218822Sdim
3556218822Sdim      for (tprel_gotent = *info->first_gotent; tprel_gotent ;
3557218822Sdim	   tprel_gotent = tprel_gotent->next)
3558218822Sdim	if (tprel_gotent->gotobj == info->gotobj
3559218822Sdim	    && tprel_gotent->reloc_type == R_ALPHA_GOTTPREL
3560218822Sdim	    && tprel_gotent->addend == irel->r_addend)
3561218822Sdim	  break;
3562218822Sdim      if (tprel_gotent)
3563218822Sdim	tprel_gotent->use_count++;
3564218822Sdim      else
3565218822Sdim	{
3566218822Sdim	  if (info->gotent->use_count == 0)
3567218822Sdim	    tprel_gotent = info->gotent;
3568218822Sdim	  else
3569218822Sdim	    {
3570218822Sdim	      tprel_gotent = (struct alpha_elf_got_entry *)
3571218822Sdim		bfd_alloc (info->abfd, sizeof (struct alpha_elf_got_entry));
3572218822Sdim	      if (!tprel_gotent)
3573218822Sdim		return FALSE;
3574218822Sdim
3575218822Sdim	      tprel_gotent->next = *info->first_gotent;
3576218822Sdim	      *info->first_gotent = tprel_gotent;
3577218822Sdim
3578218822Sdim	      tprel_gotent->gotobj = info->gotobj;
3579218822Sdim	      tprel_gotent->addend = irel->r_addend;
3580218822Sdim	      tprel_gotent->got_offset = -1;
3581218822Sdim	      tprel_gotent->reloc_done = 0;
3582218822Sdim	      tprel_gotent->reloc_xlated = 0;
3583218822Sdim	    }
3584218822Sdim
3585218822Sdim	  tprel_gotent->use_count = 1;
3586218822Sdim	  tprel_gotent->reloc_type = R_ALPHA_GOTTPREL;
3587218822Sdim	}
3588218822Sdim    }
3589218822Sdim
3590218822Sdim  return TRUE;
3591218822Sdim}
3592218822Sdim
3593218822Sdimstatic bfd_boolean
3594218822Sdimelf64_alpha_relax_section (bfd *abfd, asection *sec,
3595218822Sdim			   struct bfd_link_info *link_info, bfd_boolean *again)
3596218822Sdim{
3597218822Sdim  Elf_Internal_Shdr *symtab_hdr;
3598218822Sdim  Elf_Internal_Rela *internal_relocs;
3599218822Sdim  Elf_Internal_Rela *irel, *irelend;
3600218822Sdim  Elf_Internal_Sym *isymbuf = NULL;
3601218822Sdim  struct alpha_elf_got_entry **local_got_entries;
3602218822Sdim  struct alpha_relax_info info;
3603218822Sdim
3604218822Sdim  /* There's nothing to change, yet.  */
3605218822Sdim  *again = FALSE;
3606218822Sdim
3607218822Sdim  if (link_info->relocatable
3608218822Sdim      || ((sec->flags & (SEC_CODE | SEC_RELOC | SEC_ALLOC))
3609218822Sdim	  != (SEC_CODE | SEC_RELOC | SEC_ALLOC))
3610218822Sdim      || sec->reloc_count == 0)
3611218822Sdim    return TRUE;
3612218822Sdim
3613218822Sdim  /* Make sure our GOT and PLT tables are up-to-date.  */
3614218822Sdim  if (alpha_elf_hash_table(link_info)->relax_trip != link_info->relax_trip)
3615218822Sdim    {
3616218822Sdim      alpha_elf_hash_table(link_info)->relax_trip = link_info->relax_trip;
3617218822Sdim
3618218822Sdim      /* This should never fail after the initial round, since the only
3619218822Sdim	 error is GOT overflow, and relaxation only shrinks the table.  */
3620218822Sdim      if (!elf64_alpha_size_got_sections (link_info))
3621218822Sdim	abort ();
3622218822Sdim      if (elf_hash_table (link_info)->dynamic_sections_created)
3623218822Sdim	{
3624218822Sdim	  elf64_alpha_size_plt_section (link_info);
3625218822Sdim	  elf64_alpha_size_rela_got_section (link_info);
3626218822Sdim	}
3627218822Sdim    }
3628218822Sdim
3629218822Sdim  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
3630218822Sdim  local_got_entries = alpha_elf_tdata(abfd)->local_got_entries;
3631218822Sdim
3632218822Sdim  /* Load the relocations for this section.  */
3633218822Sdim  internal_relocs = (_bfd_elf_link_read_relocs
3634218822Sdim		     (abfd, sec, (PTR) NULL, (Elf_Internal_Rela *) NULL,
3635218822Sdim		      link_info->keep_memory));
3636218822Sdim  if (internal_relocs == NULL)
3637218822Sdim    return FALSE;
3638218822Sdim
3639218822Sdim  memset(&info, 0, sizeof (info));
3640218822Sdim  info.abfd = abfd;
3641218822Sdim  info.sec = sec;
3642218822Sdim  info.link_info = link_info;
3643218822Sdim  info.symtab_hdr = symtab_hdr;
3644218822Sdim  info.relocs = internal_relocs;
3645218822Sdim  info.relend = irelend = internal_relocs + sec->reloc_count;
3646218822Sdim
3647218822Sdim  /* Find the GP for this object.  Do not store the result back via
3648218822Sdim     _bfd_set_gp_value, since this could change again before final.  */
3649218822Sdim  info.gotobj = alpha_elf_tdata (abfd)->gotobj;
3650218822Sdim  if (info.gotobj)
3651218822Sdim    {
3652218822Sdim      asection *sgot = alpha_elf_tdata (info.gotobj)->got;
3653218822Sdim      info.gp = (sgot->output_section->vma
3654218822Sdim		 + sgot->output_offset
3655218822Sdim		 + 0x8000);
3656218822Sdim    }
3657218822Sdim
3658218822Sdim  /* Get the section contents.  */
3659218822Sdim  if (elf_section_data (sec)->this_hdr.contents != NULL)
3660218822Sdim    info.contents = elf_section_data (sec)->this_hdr.contents;
3661218822Sdim  else
3662218822Sdim    {
3663218822Sdim      if (!bfd_malloc_and_get_section (abfd, sec, &info.contents))
3664218822Sdim	goto error_return;
3665218822Sdim    }
3666218822Sdim
3667218822Sdim  for (irel = internal_relocs; irel < irelend; irel++)
3668218822Sdim    {
3669218822Sdim      bfd_vma symval;
3670218822Sdim      struct alpha_elf_got_entry *gotent;
3671218822Sdim      unsigned long r_type = ELF64_R_TYPE (irel->r_info);
3672218822Sdim      unsigned long r_symndx = ELF64_R_SYM (irel->r_info);
3673218822Sdim
3674218822Sdim      /* Early exit for unhandled or unrelaxable relocations.  */
3675218822Sdim      switch (r_type)
3676218822Sdim	{
3677218822Sdim	case R_ALPHA_LITERAL:
3678218822Sdim	case R_ALPHA_GPRELHIGH:
3679218822Sdim	case R_ALPHA_GPRELLOW:
3680218822Sdim	case R_ALPHA_GOTDTPREL:
3681218822Sdim	case R_ALPHA_GOTTPREL:
3682218822Sdim	case R_ALPHA_TLSGD:
3683218822Sdim	  break;
3684218822Sdim
3685218822Sdim	case R_ALPHA_TLSLDM:
3686218822Sdim	  /* The symbol for a TLSLDM reloc is ignored.  Collapse the
3687218822Sdim             reloc to the 0 symbol so that they all match.  */
3688218822Sdim	  r_symndx = 0;
3689218822Sdim	  break;
3690218822Sdim
3691218822Sdim	default:
3692218822Sdim	  continue;
3693218822Sdim	}
3694218822Sdim
3695218822Sdim      /* Get the value of the symbol referred to by the reloc.  */
3696218822Sdim      if (r_symndx < symtab_hdr->sh_info)
3697218822Sdim	{
3698218822Sdim	  /* A local symbol.  */
3699218822Sdim	  Elf_Internal_Sym *isym;
3700218822Sdim
3701218822Sdim	  /* Read this BFD's local symbols.  */
3702218822Sdim	  if (isymbuf == NULL)
3703218822Sdim	    {
3704218822Sdim	      isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents;
3705218822Sdim	      if (isymbuf == NULL)
3706218822Sdim		isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr,
3707218822Sdim						symtab_hdr->sh_info, 0,
3708218822Sdim						NULL, NULL, NULL);
3709218822Sdim	      if (isymbuf == NULL)
3710218822Sdim		goto error_return;
3711218822Sdim	    }
3712218822Sdim
3713218822Sdim	  isym = isymbuf + r_symndx;
3714218822Sdim
3715218822Sdim	  /* Given the symbol for a TLSLDM reloc is ignored, this also
3716218822Sdim	     means forcing the symbol value to the tp base.  */
3717218822Sdim	  if (r_type == R_ALPHA_TLSLDM)
3718218822Sdim	    {
3719218822Sdim	      info.tsec = bfd_abs_section_ptr;
3720218822Sdim	      symval = alpha_get_tprel_base (info.link_info);
3721218822Sdim	    }
3722218822Sdim	  else
3723218822Sdim	    {
3724218822Sdim	      symval = isym->st_value;
3725218822Sdim	      if (isym->st_shndx == SHN_UNDEF)
3726218822Sdim	        continue;
3727218822Sdim	      else if (isym->st_shndx == SHN_ABS)
3728218822Sdim	        info.tsec = bfd_abs_section_ptr;
3729218822Sdim	      else if (isym->st_shndx == SHN_COMMON)
3730218822Sdim	        info.tsec = bfd_com_section_ptr;
3731218822Sdim	      else
3732218822Sdim	        info.tsec = bfd_section_from_elf_index (abfd, isym->st_shndx);
3733218822Sdim	    }
3734218822Sdim
3735218822Sdim	  info.h = NULL;
3736218822Sdim	  info.other = isym->st_other;
3737218822Sdim	  if (local_got_entries)
3738218822Sdim	    info.first_gotent = &local_got_entries[r_symndx];
3739218822Sdim	  else
3740218822Sdim	    {
3741218822Sdim	      info.first_gotent = &info.gotent;
3742218822Sdim	      info.gotent = NULL;
3743218822Sdim	    }
3744218822Sdim	}
3745218822Sdim      else
3746218822Sdim	{
3747218822Sdim	  unsigned long indx;
3748218822Sdim	  struct alpha_elf_link_hash_entry *h;
3749218822Sdim
3750218822Sdim	  indx = r_symndx - symtab_hdr->sh_info;
3751218822Sdim	  h = alpha_elf_sym_hashes (abfd)[indx];
3752218822Sdim	  BFD_ASSERT (h != NULL);
3753218822Sdim
3754218822Sdim	  while (h->root.root.type == bfd_link_hash_indirect
3755218822Sdim		 || h->root.root.type == bfd_link_hash_warning)
3756218822Sdim	    h = (struct alpha_elf_link_hash_entry *)h->root.root.u.i.link;
3757218822Sdim
3758218822Sdim	  /* If the symbol is undefined, we can't do anything with it.  */
3759218822Sdim	  if (h->root.root.type == bfd_link_hash_undefined)
3760218822Sdim	    continue;
3761218822Sdim
3762218822Sdim	  /* If the symbol isn't defined in the current module,
3763218822Sdim	     again we can't do anything.  */
3764218822Sdim	  if (h->root.root.type == bfd_link_hash_undefweak)
3765218822Sdim	    {
3766218822Sdim	      info.tsec = bfd_abs_section_ptr;
3767218822Sdim	      symval = 0;
3768218822Sdim	    }
3769218822Sdim	  else if (!h->root.def_regular)
3770218822Sdim	    {
3771218822Sdim	      /* Except for TLSGD relocs, which can sometimes be
3772218822Sdim		 relaxed to GOTTPREL relocs.  */
3773218822Sdim	      if (r_type != R_ALPHA_TLSGD)
3774218822Sdim		continue;
3775218822Sdim	      info.tsec = bfd_abs_section_ptr;
3776218822Sdim	      symval = 0;
3777218822Sdim	    }
3778218822Sdim	  else
3779218822Sdim	    {
3780218822Sdim	      info.tsec = h->root.root.u.def.section;
3781218822Sdim	      symval = h->root.root.u.def.value;
3782218822Sdim	    }
3783218822Sdim
3784218822Sdim	  info.h = h;
3785218822Sdim	  info.other = h->root.other;
3786218822Sdim	  info.first_gotent = &h->got_entries;
3787218822Sdim	}
3788218822Sdim
3789218822Sdim      /* Search for the got entry to be used by this relocation.  */
3790218822Sdim      for (gotent = *info.first_gotent; gotent ; gotent = gotent->next)
3791218822Sdim	if (gotent->gotobj == info.gotobj
3792218822Sdim	    && gotent->reloc_type == r_type
3793218822Sdim	    && gotent->addend == irel->r_addend)
3794218822Sdim	  break;
3795218822Sdim      info.gotent = gotent;
3796218822Sdim
3797218822Sdim      symval += info.tsec->output_section->vma + info.tsec->output_offset;
3798218822Sdim      symval += irel->r_addend;
3799218822Sdim
3800218822Sdim      switch (r_type)
3801218822Sdim	{
3802218822Sdim	case R_ALPHA_LITERAL:
3803218822Sdim	  BFD_ASSERT(info.gotent != NULL);
3804218822Sdim
3805218822Sdim	  /* If there exist LITUSE relocations immediately following, this
3806218822Sdim	     opens up all sorts of interesting optimizations, because we
3807218822Sdim	     now know every location that this address load is used.  */
3808218822Sdim	  if (irel+1 < irelend
3809218822Sdim	      && ELF64_R_TYPE (irel[1].r_info) == R_ALPHA_LITUSE)
3810218822Sdim	    {
3811218822Sdim	      if (!elf64_alpha_relax_with_lituse (&info, symval, irel))
3812218822Sdim		goto error_return;
3813218822Sdim	    }
3814218822Sdim	  else
3815218822Sdim	    {
3816218822Sdim	      if (!elf64_alpha_relax_got_load (&info, symval, irel, r_type))
3817218822Sdim		goto error_return;
3818218822Sdim	    }
3819218822Sdim	  break;
3820218822Sdim
3821218822Sdim	case R_ALPHA_GOTDTPREL:
3822218822Sdim	case R_ALPHA_GOTTPREL:
3823218822Sdim	  BFD_ASSERT(info.gotent != NULL);
3824218822Sdim	  if (!elf64_alpha_relax_got_load (&info, symval, irel, r_type))
3825218822Sdim	    goto error_return;
3826218822Sdim	  break;
3827218822Sdim
3828218822Sdim	case R_ALPHA_TLSGD:
3829218822Sdim	case R_ALPHA_TLSLDM:
3830218822Sdim	  BFD_ASSERT(info.gotent != NULL);
3831218822Sdim	  if (!elf64_alpha_relax_tls_get_addr (&info, symval, irel,
3832218822Sdim					       r_type == R_ALPHA_TLSGD))
3833218822Sdim	    goto error_return;
3834218822Sdim	  break;
3835218822Sdim	}
3836218822Sdim    }
3837218822Sdim
3838218822Sdim  if (isymbuf != NULL
3839218822Sdim      && symtab_hdr->contents != (unsigned char *) isymbuf)
3840218822Sdim    {
3841218822Sdim      if (!link_info->keep_memory)
3842218822Sdim	free (isymbuf);
3843218822Sdim      else
3844218822Sdim	{
3845218822Sdim	  /* Cache the symbols for elf_link_input_bfd.  */
3846218822Sdim	  symtab_hdr->contents = (unsigned char *) isymbuf;
3847218822Sdim	}
3848218822Sdim    }
3849218822Sdim
3850218822Sdim  if (info.contents != NULL
3851218822Sdim      && elf_section_data (sec)->this_hdr.contents != info.contents)
3852218822Sdim    {
3853218822Sdim      if (!info.changed_contents && !link_info->keep_memory)
3854218822Sdim	free (info.contents);
3855218822Sdim      else
3856218822Sdim	{
3857218822Sdim	  /* Cache the section contents for elf_link_input_bfd.  */
3858218822Sdim	  elf_section_data (sec)->this_hdr.contents = info.contents;
3859218822Sdim	}
3860218822Sdim    }
3861218822Sdim
3862218822Sdim  if (elf_section_data (sec)->relocs != internal_relocs)
3863218822Sdim    {
3864218822Sdim      if (!info.changed_relocs)
3865218822Sdim	free (internal_relocs);
3866218822Sdim      else
3867218822Sdim	elf_section_data (sec)->relocs = internal_relocs;
3868218822Sdim    }
3869218822Sdim
3870218822Sdim  *again = info.changed_contents || info.changed_relocs;
3871218822Sdim
3872218822Sdim  return TRUE;
3873218822Sdim
3874218822Sdim error_return:
3875218822Sdim  if (isymbuf != NULL
3876218822Sdim      && symtab_hdr->contents != (unsigned char *) isymbuf)
3877218822Sdim    free (isymbuf);
3878218822Sdim  if (info.contents != NULL
3879218822Sdim      && elf_section_data (sec)->this_hdr.contents != info.contents)
3880218822Sdim    free (info.contents);
3881218822Sdim  if (internal_relocs != NULL
3882218822Sdim      && elf_section_data (sec)->relocs != internal_relocs)
3883218822Sdim    free (internal_relocs);
3884218822Sdim  return FALSE;
3885218822Sdim}
3886218822Sdim
3887130570Sobrien/* Emit a dynamic relocation for (DYNINDX, RTYPE, ADDEND) at (SEC, OFFSET)
3888130570Sobrien   into the next available slot in SREL.  */
3889130570Sobrien
3890130570Sobrienstatic void
3891218822Sdimelf64_alpha_emit_dynrel (bfd *abfd, struct bfd_link_info *info,
3892218822Sdim			 asection *sec, asection *srel, bfd_vma offset,
3893218822Sdim			 long dynindx, long rtype, bfd_vma addend)
3894130570Sobrien{
3895130570Sobrien  Elf_Internal_Rela outrel;
3896130570Sobrien  bfd_byte *loc;
3897130570Sobrien
3898130570Sobrien  BFD_ASSERT (srel != NULL);
3899130570Sobrien
3900130570Sobrien  outrel.r_info = ELF64_R_INFO (dynindx, rtype);
3901130570Sobrien  outrel.r_addend = addend;
3902130570Sobrien
3903130570Sobrien  offset = _bfd_elf_section_offset (abfd, info, sec, offset);
3904130570Sobrien  if ((offset | 1) != (bfd_vma) -1)
3905130570Sobrien    outrel.r_offset = sec->output_section->vma + sec->output_offset + offset;
3906130570Sobrien  else
3907130570Sobrien    memset (&outrel, 0, sizeof (outrel));
3908130570Sobrien
3909130570Sobrien  loc = srel->contents;
3910130570Sobrien  loc += srel->reloc_count++ * sizeof (Elf64_External_Rela);
3911130570Sobrien  bfd_elf64_swap_reloca_out (abfd, &outrel, loc);
3912218822Sdim  BFD_ASSERT (sizeof (Elf64_External_Rela) * srel->reloc_count <= srel->size);
3913130570Sobrien}
3914130570Sobrien
3915104841Sobrien/* Relocate an Alpha ELF section for a relocatable link.
3916104841Sobrien
3917104841Sobrien   We don't have to change anything unless the reloc is against a section
3918104841Sobrien   symbol, in which case we have to adjust according to where the section
3919104841Sobrien   symbol winds up in the output section.  */
3920104841Sobrien
3921130570Sobrienstatic bfd_boolean
3922218822Sdimelf64_alpha_relocate_section_r (bfd *output_bfd ATTRIBUTE_UNUSED,
3923218822Sdim				struct bfd_link_info *info ATTRIBUTE_UNUSED,
3924218822Sdim				bfd *input_bfd, asection *input_section,
3925218822Sdim				bfd_byte *contents ATTRIBUTE_UNUSED,
3926218822Sdim				Elf_Internal_Rela *relocs,
3927218822Sdim				Elf_Internal_Sym *local_syms,
3928218822Sdim				asection **local_sections)
3929104841Sobrien{
3930104841Sobrien  unsigned long symtab_hdr_sh_info;
3931104841Sobrien  Elf_Internal_Rela *rel;
3932104841Sobrien  Elf_Internal_Rela *relend;
3933218822Sdim  struct elf_link_hash_entry **sym_hashes;
3934130570Sobrien  bfd_boolean ret_val = TRUE;
3935104841Sobrien
3936104841Sobrien  symtab_hdr_sh_info = elf_tdata (input_bfd)->symtab_hdr.sh_info;
3937218822Sdim  sym_hashes = elf_sym_hashes (input_bfd);
3938104841Sobrien
3939104841Sobrien  relend = relocs + input_section->reloc_count;
3940104841Sobrien  for (rel = relocs; rel < relend; rel++)
3941104841Sobrien    {
3942104841Sobrien      unsigned long r_symndx;
3943104841Sobrien      Elf_Internal_Sym *sym;
3944104841Sobrien      asection *sec;
3945104841Sobrien      unsigned long r_type;
3946104841Sobrien
3947218822Sdim      r_type = ELF64_R_TYPE (rel->r_info);
3948104841Sobrien      if (r_type >= R_ALPHA_max)
3949104841Sobrien	{
3950104841Sobrien	  (*_bfd_error_handler)
3951218822Sdim	    (_("%B: unknown relocation type %d"),
3952218822Sdim	     input_bfd, (int) r_type);
3953104841Sobrien	  bfd_set_error (bfd_error_bad_value);
3954130570Sobrien	  ret_val = FALSE;
3955104841Sobrien	  continue;
3956104841Sobrien	}
3957104841Sobrien
3958104841Sobrien      /* The symbol associated with GPDISP and LITUSE is
3959104841Sobrien	 immaterial.  Only the addend is significant.  */
3960104841Sobrien      if (r_type == R_ALPHA_GPDISP || r_type == R_ALPHA_LITUSE)
3961104841Sobrien	continue;
3962104841Sobrien
3963218822Sdim      r_symndx = ELF64_R_SYM (rel->r_info);
3964104841Sobrien      if (r_symndx < symtab_hdr_sh_info)
3965104841Sobrien	{
3966104841Sobrien	  sym = local_syms + r_symndx;
3967218822Sdim	  sec = local_sections[r_symndx];
3968104841Sobrien	}
3969218822Sdim      else
3970218822Sdim	{
3971218822Sdim	  struct elf_link_hash_entry *h;
3972218822Sdim
3973218822Sdim	  h = sym_hashes[r_symndx - symtab_hdr_sh_info];
3974218822Sdim
3975218822Sdim	  while (h->root.type == bfd_link_hash_indirect
3976218822Sdim		 || h->root.type == bfd_link_hash_warning)
3977218822Sdim	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
3978218822Sdim
3979218822Sdim	  if (h->root.type != bfd_link_hash_defined
3980218822Sdim	      && h->root.type != bfd_link_hash_defweak)
3981218822Sdim	    continue;
3982218822Sdim
3983218822Sdim	  sym = NULL;
3984218822Sdim	  sec = h->root.u.def.section;
3985218822Sdim	}
3986218822Sdim
3987218822Sdim      if (sec != NULL && elf_discarded_section (sec))
3988218822Sdim	{
3989218822Sdim	  /* For relocs against symbols from removed linkonce sections,
3990218822Sdim	     or sections discarded by a linker script, we just want the
3991218822Sdim	     section contents zeroed.  */
3992218822Sdim	  _bfd_clear_contents (elf64_alpha_howto_table + r_type,
3993218822Sdim			       input_bfd, contents + rel->r_offset);
3994218822Sdim	  rel->r_info = 0;
3995218822Sdim	  rel->r_addend = 0;
3996218822Sdim	  continue;
3997218822Sdim	}
3998218822Sdim
3999218822Sdim      if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
4000218822Sdim	rel->r_addend += sec->output_offset;
4001104841Sobrien    }
4002104841Sobrien
4003104841Sobrien  return ret_val;
4004104841Sobrien}
4005104841Sobrien
400633965Sjdp/* Relocate an Alpha ELF section.  */
400733965Sjdp
4008130570Sobrienstatic bfd_boolean
4009218822Sdimelf64_alpha_relocate_section (bfd *output_bfd, struct bfd_link_info *info,
4010218822Sdim			      bfd *input_bfd, asection *input_section,
4011218822Sdim			      bfd_byte *contents, Elf_Internal_Rela *relocs,
4012218822Sdim			      Elf_Internal_Sym *local_syms,
4013218822Sdim			      asection **local_sections)
401433965Sjdp{
401533965Sjdp  Elf_Internal_Shdr *symtab_hdr;
401633965Sjdp  Elf_Internal_Rela *rel;
401733965Sjdp  Elf_Internal_Rela *relend;
4018104841Sobrien  asection *sgot, *srel, *srelgot;
401933965Sjdp  bfd *dynobj, *gotobj;
4020104841Sobrien  bfd_vma gp, tp_base, dtp_base;
4021104841Sobrien  struct alpha_elf_got_entry **local_got_entries;
4022130570Sobrien  bfd_boolean ret_val;
402333965Sjdp
4024104841Sobrien  /* Handle relocatable links with a smaller loop.  */
4025130570Sobrien  if (info->relocatable)
4026104841Sobrien    return elf64_alpha_relocate_section_r (output_bfd, info, input_bfd,
4027104841Sobrien					   input_section, contents, relocs,
4028104841Sobrien					   local_syms, local_sections);
4029104841Sobrien
4030104841Sobrien  /* This is a final link.  */
4031104841Sobrien
4032130570Sobrien  ret_val = TRUE;
4033104841Sobrien
403433965Sjdp  symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr;
4035104841Sobrien
403633965Sjdp  dynobj = elf_hash_table (info)->dynobj;
403733965Sjdp  if (dynobj)
4038104841Sobrien    srelgot = bfd_get_section_by_name (dynobj, ".rela.got");
4039104841Sobrien  else
4040104841Sobrien    srelgot = NULL;
404133965Sjdp
4042218822Sdim  if (input_section->flags & SEC_ALLOC)
4043218822Sdim    {
4044218822Sdim      const char *section_name;
4045218822Sdim      section_name = (bfd_elf_string_from_elf_section
4046218822Sdim		      (input_bfd, elf_elfheader(input_bfd)->e_shstrndx,
4047218822Sdim		       elf_section_data(input_section)->rel_hdr.sh_name));
4048218822Sdim      BFD_ASSERT(section_name != NULL);
4049218822Sdim      srel = bfd_get_section_by_name (dynobj, section_name);
4050218822Sdim    }
4051218822Sdim  else
4052218822Sdim    srel = NULL;
4053104841Sobrien
405433965Sjdp  /* Find the gp value for this input bfd.  */
405533965Sjdp  gotobj = alpha_elf_tdata (input_bfd)->gotobj;
405633965Sjdp  if (gotobj)
405733965Sjdp    {
405833965Sjdp      sgot = alpha_elf_tdata (gotobj)->got;
405933965Sjdp      gp = _bfd_get_gp_value (gotobj);
406033965Sjdp      if (gp == 0)
406133965Sjdp	{
406233965Sjdp	  gp = (sgot->output_section->vma
406333965Sjdp		+ sgot->output_offset
406433965Sjdp		+ 0x8000);
406533965Sjdp	  _bfd_set_gp_value (gotobj, gp);
406633965Sjdp	}
406733965Sjdp    }
4068104841Sobrien  else
4069104841Sobrien    {
4070104841Sobrien      sgot = NULL;
4071104841Sobrien      gp = 0;
4072104841Sobrien    }
407333965Sjdp
4074104841Sobrien  local_got_entries = alpha_elf_tdata(input_bfd)->local_got_entries;
4075104841Sobrien
4076130570Sobrien  if (elf_hash_table (info)->tls_sec != NULL)
4077104841Sobrien    {
4078130570Sobrien      dtp_base = alpha_get_dtprel_base (info);
4079130570Sobrien      tp_base = alpha_get_tprel_base (info);
4080104841Sobrien    }
4081104841Sobrien  else
4082104841Sobrien    dtp_base = tp_base = 0;
4083104841Sobrien
408433965Sjdp  relend = relocs + input_section->reloc_count;
4085104841Sobrien  for (rel = relocs; rel < relend; rel++)
408633965Sjdp    {
4087104841Sobrien      struct alpha_elf_link_hash_entry *h = NULL;
4088104841Sobrien      struct alpha_elf_got_entry *gotent;
4089104841Sobrien      bfd_reloc_status_type r;
409033965Sjdp      reloc_howto_type *howto;
409133965Sjdp      unsigned long r_symndx;
4092104841Sobrien      Elf_Internal_Sym *sym = NULL;
4093104841Sobrien      asection *sec = NULL;
4094104841Sobrien      bfd_vma value;
409533965Sjdp      bfd_vma addend;
4096130570Sobrien      bfd_boolean dynamic_symbol_p;
4097130570Sobrien      bfd_boolean undef_weak_ref = FALSE;
4098104841Sobrien      unsigned long r_type;
409933965Sjdp
410033965Sjdp      r_type = ELF64_R_TYPE(rel->r_info);
4101104841Sobrien      if (r_type >= R_ALPHA_max)
410233965Sjdp	{
4103104841Sobrien	  (*_bfd_error_handler)
4104218822Sdim	    (_("%B: unknown relocation type %d"),
4105218822Sdim	     input_bfd, (int) r_type);
410633965Sjdp	  bfd_set_error (bfd_error_bad_value);
4107130570Sobrien	  ret_val = FALSE;
4108104841Sobrien	  continue;
410933965Sjdp	}
4110104841Sobrien
411133965Sjdp      howto = elf64_alpha_howto_table + r_type;
411233965Sjdp      r_symndx = ELF64_R_SYM(rel->r_info);
411333965Sjdp
4114130570Sobrien      /* The symbol for a TLSLDM reloc is ignored.  Collapse the
4115130570Sobrien	 reloc to the 0 symbol so that they all match.  */
4116130570Sobrien      if (r_type == R_ALPHA_TLSLDM)
4117130570Sobrien	r_symndx = 0;
4118130570Sobrien
4119104841Sobrien      if (r_symndx < symtab_hdr->sh_info)
412033965Sjdp	{
4121130570Sobrien	  asection *msec;
4122104841Sobrien	  sym = local_syms + r_symndx;
4123104841Sobrien	  sec = local_sections[r_symndx];
4124130570Sobrien	  msec = sec;
4125130570Sobrien	  value = _bfd_elf_rela_local_sym (output_bfd, sym, &msec, rel);
412660510Sobrien
4127130570Sobrien	  /* If this is a tp-relative relocation against sym 0,
4128130570Sobrien	     this is hackery from relax_section.  Force the value to
4129218822Sdim	     be the tls module base.  */
4130130570Sobrien	  if (r_symndx == 0
4131130570Sobrien	      && (r_type == R_ALPHA_TLSLDM
4132130570Sobrien		  || r_type == R_ALPHA_GOTTPREL
4133130570Sobrien		  || r_type == R_ALPHA_TPREL64
4134130570Sobrien		  || r_type == R_ALPHA_TPRELHI
4135130570Sobrien		  || r_type == R_ALPHA_TPRELLO
4136130570Sobrien		  || r_type == R_ALPHA_TPREL16))
4137218822Sdim	    value = dtp_base;
4138130570Sobrien
4139104841Sobrien	  if (local_got_entries)
4140104841Sobrien	    gotent = local_got_entries[r_symndx];
4141104841Sobrien	  else
4142104841Sobrien	    gotent = NULL;
414360510Sobrien
4144104841Sobrien	  /* Need to adjust local GOT entries' addends for SEC_MERGE
4145104841Sobrien	     unless it has been done already.  */
4146104841Sobrien	  if ((sec->flags & SEC_MERGE)
4147104841Sobrien	      && ELF_ST_TYPE (sym->st_info) == STT_SECTION
4148130570Sobrien	      && sec->sec_info_type == ELF_INFO_TYPE_MERGE
4149104841Sobrien	      && gotent
4150104841Sobrien	      && !gotent->reloc_xlated)
415133965Sjdp	    {
4152104841Sobrien	      struct alpha_elf_got_entry *ent;
4153104841Sobrien
4154104841Sobrien	      for (ent = gotent; ent; ent = ent->next)
415533965Sjdp		{
4156104841Sobrien		  ent->reloc_xlated = 1;
4157104841Sobrien		  if (ent->use_count == 0)
4158104841Sobrien		    continue;
4159104841Sobrien		  msec = sec;
4160104841Sobrien		  ent->addend =
4161104841Sobrien		    _bfd_merged_section_offset (output_bfd, &msec,
4162104841Sobrien						elf_section_data (sec)->
4163104841Sobrien						  sec_info,
4164218822Sdim						sym->st_value + ent->addend);
4165104841Sobrien		  ent->addend -= sym->st_value;
4166104841Sobrien		  ent->addend += msec->output_section->vma
4167104841Sobrien				 + msec->output_offset
4168104841Sobrien				 - sec->output_section->vma
4169104841Sobrien				 - sec->output_offset;
417033965Sjdp		}
417133965Sjdp	    }
417233965Sjdp
4173130570Sobrien	  dynamic_symbol_p = FALSE;
417433965Sjdp	}
417533965Sjdp      else
417633965Sjdp	{
4177130570Sobrien	  bfd_boolean warned;
4178130570Sobrien	  bfd_boolean unresolved_reloc;
4179130570Sobrien	  struct elf_link_hash_entry *hh;
4180130570Sobrien	  struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (input_bfd);
418133965Sjdp
4182130570Sobrien	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
4183130570Sobrien				   r_symndx, symtab_hdr, sym_hashes,
4184130570Sobrien				   hh, sec, value,
4185130570Sobrien				   unresolved_reloc, warned);
418633965Sjdp
4187130570Sobrien	  if (warned)
4188130570Sobrien	    continue;
418933965Sjdp
4190130570Sobrien	  if (value == 0
4191130570Sobrien	      && ! unresolved_reloc
4192130570Sobrien	      && hh->root.type == bfd_link_hash_undefweak)
4193130570Sobrien	    undef_weak_ref = TRUE;
4194104841Sobrien
4195130570Sobrien	  h = (struct alpha_elf_link_hash_entry *) hh;
4196104841Sobrien          dynamic_symbol_p = alpha_elf_dynamic_symbol_p (&h->root, info);
4197104841Sobrien	  gotent = h->got_entries;
419833965Sjdp	}
4199104841Sobrien
4200218822Sdim      if (sec != NULL && elf_discarded_section (sec))
4201218822Sdim	{
4202218822Sdim	  /* For relocs against symbols from removed linkonce sections,
4203218822Sdim	     or sections discarded by a linker script, we just want the
4204218822Sdim	     section contents zeroed.  Avoid any special processing.  */
4205218822Sdim	  _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
4206218822Sdim	  rel->r_info = 0;
4207218822Sdim	  rel->r_addend = 0;
4208218822Sdim	  continue;
4209218822Sdim	}
4210218822Sdim
421133965Sjdp      addend = rel->r_addend;
4212104841Sobrien      value += addend;
421333965Sjdp
4214104841Sobrien      /* Search for the proper got entry.  */
4215104841Sobrien      for (; gotent ; gotent = gotent->next)
4216104841Sobrien	if (gotent->gotobj == gotobj
4217104841Sobrien	    && gotent->reloc_type == r_type
4218104841Sobrien	    && gotent->addend == addend)
4219104841Sobrien	  break;
4220104841Sobrien
422133965Sjdp      switch (r_type)
422233965Sjdp	{
422333965Sjdp	case R_ALPHA_GPDISP:
422433965Sjdp	  {
422533965Sjdp	    bfd_byte *p_ldah, *p_lda;
422633965Sjdp
422733965Sjdp	    BFD_ASSERT(gp != 0);
422833965Sjdp
4229104841Sobrien	    value = (input_section->output_section->vma
4230104841Sobrien		     + input_section->output_offset
4231104841Sobrien		     + rel->r_offset);
423233965Sjdp
4233104841Sobrien	    p_ldah = contents + rel->r_offset;
423433965Sjdp	    p_lda = p_ldah + rel->r_addend;
423533965Sjdp
4236104841Sobrien	    r = elf64_alpha_do_reloc_gpdisp (input_bfd, gp - value,
423733965Sjdp					     p_ldah, p_lda);
423833965Sjdp	  }
423933965Sjdp	  break;
424033965Sjdp
424133965Sjdp	case R_ALPHA_LITERAL:
4242104841Sobrien	  BFD_ASSERT(sgot != NULL);
4243104841Sobrien	  BFD_ASSERT(gp != 0);
4244104841Sobrien	  BFD_ASSERT(gotent != NULL);
4245104841Sobrien	  BFD_ASSERT(gotent->use_count >= 1);
424633965Sjdp
4247104841Sobrien	  if (!gotent->reloc_done)
4248104841Sobrien	    {
4249104841Sobrien	      gotent->reloc_done = 1;
425033965Sjdp
4251104841Sobrien	      bfd_put_64 (output_bfd, value,
4252104841Sobrien			  sgot->contents + gotent->got_offset);
425389862Sobrien
4254104841Sobrien	      /* If the symbol has been forced local, output a
4255104841Sobrien		 RELATIVE reloc, otherwise it will be handled in
4256104841Sobrien		 finish_dynamic_symbol.  */
4257218822Sdim	      if (info->shared && !dynamic_symbol_p && !undef_weak_ref)
4258130570Sobrien		elf64_alpha_emit_dynrel (output_bfd, info, sgot, srelgot,
4259130570Sobrien					 gotent->got_offset, 0,
4260130570Sobrien					 R_ALPHA_RELATIVE, value);
4261104841Sobrien	    }
426233965Sjdp
4263104841Sobrien	  value = (sgot->output_section->vma
4264104841Sobrien		   + sgot->output_offset
4265104841Sobrien		   + gotent->got_offset);
4266104841Sobrien	  value -= gp;
426733965Sjdp	  goto default_reloc;
426833965Sjdp
4269115361Sobrien	case R_ALPHA_GPREL32:
427089862Sobrien	case R_ALPHA_GPREL16:
427160510Sobrien	case R_ALPHA_GPRELLOW:
4272104841Sobrien	  if (dynamic_symbol_p)
427389862Sobrien            {
427489862Sobrien              (*_bfd_error_handler)
4275218822Sdim                (_("%B: gp-relative relocation against dynamic symbol %s"),
4276218822Sdim                 input_bfd, h->root.root.root.string);
4277130570Sobrien              ret_val = FALSE;
427889862Sobrien            }
427933965Sjdp	  BFD_ASSERT(gp != 0);
4280104841Sobrien	  value -= gp;
428133965Sjdp	  goto default_reloc;
428233965Sjdp
428360510Sobrien	case R_ALPHA_GPRELHIGH:
4284104841Sobrien	  if (dynamic_symbol_p)
428589862Sobrien            {
428689862Sobrien              (*_bfd_error_handler)
4287218822Sdim                (_("%B: gp-relative relocation against dynamic symbol %s"),
4288218822Sdim                 input_bfd, h->root.root.root.string);
4289130570Sobrien              ret_val = FALSE;
429089862Sobrien            }
429160510Sobrien	  BFD_ASSERT(gp != 0);
4292104841Sobrien	  value -= gp;
4293104841Sobrien	  value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1);
429460510Sobrien	  goto default_reloc;
429560510Sobrien
429689862Sobrien	case R_ALPHA_HINT:
429789862Sobrien	  /* A call to a dynamic symbol is definitely out of range of
429889862Sobrien	     the 16-bit displacement.  Don't bother writing anything.  */
4299104841Sobrien	  if (dynamic_symbol_p)
430089862Sobrien	    {
430189862Sobrien	      r = bfd_reloc_ok;
430289862Sobrien	      break;
430389862Sobrien	    }
4304104841Sobrien	  /* The regular PC-relative stuff measures from the start of
4305104841Sobrien	     the instruction rather than the end.  */
4306104841Sobrien	  value -= 4;
4307104841Sobrien	  goto default_reloc;
430889862Sobrien
430933965Sjdp	case R_ALPHA_BRADDR:
4310104841Sobrien	  if (dynamic_symbol_p)
4311104841Sobrien            {
4312104841Sobrien              (*_bfd_error_handler)
4313218822Sdim                (_("%B: pc-relative relocation against dynamic symbol %s"),
4314218822Sdim                 input_bfd, h->root.root.root.string);
4315130570Sobrien              ret_val = FALSE;
4316104841Sobrien            }
431733965Sjdp	  /* The regular PC-relative stuff measures from the start of
431833965Sjdp	     the instruction rather than the end.  */
4319104841Sobrien	  value -= 4;
432033965Sjdp	  goto default_reloc;
432133965Sjdp
432291049Sobrien	case R_ALPHA_BRSGP:
432391049Sobrien	  {
432491049Sobrien	    int other;
432591049Sobrien	    const char *name;
432691049Sobrien
432791049Sobrien	    /* The regular PC-relative stuff measures from the start of
432891049Sobrien	       the instruction rather than the end.  */
4329104841Sobrien	    value -= 4;
433091049Sobrien
433191049Sobrien	    /* The source and destination gp must be the same.  Note that
433291049Sobrien	       the source will always have an assigned gp, since we forced
433391049Sobrien	       one in check_relocs, but that the destination may not, as
4334104841Sobrien	       it might not have had any relocations at all.  Also take
433591049Sobrien	       care not to crash if H is an undefined symbol.  */
433691049Sobrien	    if (h != NULL && sec != NULL
433791049Sobrien		&& alpha_elf_tdata (sec->owner)->gotobj
433891049Sobrien		&& gotobj != alpha_elf_tdata (sec->owner)->gotobj)
433991049Sobrien	      {
434091049Sobrien		(*_bfd_error_handler)
4341218822Sdim		  (_("%B: change in gp: BRSGP %s"),
4342218822Sdim		   input_bfd, h->root.root.root.string);
4343130570Sobrien		ret_val = FALSE;
434491049Sobrien	      }
434591049Sobrien
434691049Sobrien	    /* The symbol should be marked either NOPV or STD_GPLOAD.  */
434791049Sobrien	    if (h != NULL)
434891049Sobrien	      other = h->root.other;
434991049Sobrien	    else
435091049Sobrien	      other = sym->st_other;
435191049Sobrien	    switch (other & STO_ALPHA_STD_GPLOAD)
435291049Sobrien	      {
435391049Sobrien	      case STO_ALPHA_NOPV:
435491049Sobrien	        break;
435591049Sobrien	      case STO_ALPHA_STD_GPLOAD:
4356107497Sobrien		value += 8;
435791049Sobrien		break;
435891049Sobrien	      default:
435991049Sobrien		if (h != NULL)
436091049Sobrien		  name = h->root.root.root.string;
436191049Sobrien		else
436291049Sobrien		  {
436391049Sobrien		    name = (bfd_elf_string_from_elf_section
436491049Sobrien			    (input_bfd, symtab_hdr->sh_link, sym->st_name));
436591049Sobrien		    if (name == NULL)
436691049Sobrien		      name = _("<unknown>");
436791049Sobrien		    else if (name[0] == 0)
436891049Sobrien		      name = bfd_section_name (input_bfd, sec);
436991049Sobrien		  }
437091049Sobrien		(*_bfd_error_handler)
4371218822Sdim		  (_("%B: !samegp reloc against symbol without .prologue: %s"),
4372218822Sdim		   input_bfd, name);
4373130570Sobrien		ret_val = FALSE;
437491049Sobrien		break;
437591049Sobrien	      }
437691049Sobrien
437791049Sobrien	    goto default_reloc;
437891049Sobrien	  }
437991049Sobrien
438033965Sjdp	case R_ALPHA_REFLONG:
438133965Sjdp	case R_ALPHA_REFQUAD:
4382104841Sobrien	case R_ALPHA_DTPREL64:
4383104841Sobrien	case R_ALPHA_TPREL64:
438433965Sjdp	  {
4385130570Sobrien	    long dynindx, dyntype = r_type;
4386130570Sobrien	    bfd_vma dynaddend;
438733965Sjdp
438833965Sjdp	    /* Careful here to remember RELATIVE relocations for global
438933965Sjdp	       variables for symbolic shared objects.  */
439033965Sjdp
4391104841Sobrien	    if (dynamic_symbol_p)
439233965Sjdp	      {
439333965Sjdp		BFD_ASSERT(h->root.dynindx != -1);
4394130570Sobrien		dynindx = h->root.dynindx;
4395130570Sobrien		dynaddend = addend;
4396104841Sobrien		addend = 0, value = 0;
439733965Sjdp	      }
4398104841Sobrien	    else if (r_type == R_ALPHA_DTPREL64)
4399104841Sobrien	      {
4400130570Sobrien		BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
4401104841Sobrien		value -= dtp_base;
4402104841Sobrien		goto default_reloc;
4403104841Sobrien	      }
4404104841Sobrien	    else if (r_type == R_ALPHA_TPREL64)
4405104841Sobrien	      {
4406130570Sobrien		BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
4407130570Sobrien		if (!info->shared)
4408130570Sobrien		  {
4409130570Sobrien		    value -= tp_base;
4410130570Sobrien		    goto default_reloc;
4411130570Sobrien		  }
4412130570Sobrien		dynindx = 0;
4413130570Sobrien		dynaddend = value - dtp_base;
4414104841Sobrien	      }
441589862Sobrien	    else if (info->shared
441689862Sobrien		     && r_symndx != 0
4417218822Sdim		     && (input_section->flags & SEC_ALLOC)
4418218822Sdim		     && !undef_weak_ref)
441933965Sjdp	      {
4420104841Sobrien		if (r_type == R_ALPHA_REFLONG)
4421104841Sobrien		  {
4422104841Sobrien		    (*_bfd_error_handler)
4423218822Sdim		      (_("%B: unhandled dynamic relocation against %s"),
4424218822Sdim		       input_bfd,
4425104841Sobrien		       h->root.root.root.string);
4426130570Sobrien		    ret_val = FALSE;
4427104841Sobrien		  }
4428130570Sobrien		dynindx = 0;
4429130570Sobrien		dyntype = R_ALPHA_RELATIVE;
4430130570Sobrien		dynaddend = value;
443133965Sjdp	      }
443233965Sjdp	    else
443333965Sjdp	      goto default_reloc;
443433965Sjdp
4435218822Sdim	    if (input_section->flags & SEC_ALLOC)
4436218822Sdim	      elf64_alpha_emit_dynrel (output_bfd, info, input_section,
4437218822Sdim				       srel, rel->r_offset, dynindx,
4438218822Sdim				       dyntype, dynaddend);
443933965Sjdp	  }
444033965Sjdp	  goto default_reloc;
444133965Sjdp
4442104841Sobrien	case R_ALPHA_SREL16:
444399465Sobrien	case R_ALPHA_SREL32:
444499465Sobrien	case R_ALPHA_SREL64:
4445104841Sobrien	  if (dynamic_symbol_p)
4446104841Sobrien            {
4447104841Sobrien              (*_bfd_error_handler)
4448218822Sdim                (_("%B: pc-relative relocation against dynamic symbol %s"),
4449218822Sdim                 input_bfd, h->root.root.root.string);
4450130570Sobrien              ret_val = FALSE;
4451104841Sobrien            }
4452218822Sdim	  else if ((info->shared || info->pie) && undef_weak_ref)
4453218822Sdim            {
4454218822Sdim              (*_bfd_error_handler)
4455218822Sdim                (_("%B: pc-relative relocation against undefined weak symbol %s"),
4456218822Sdim                 input_bfd, h->root.root.root.string);
4457218822Sdim              ret_val = FALSE;
4458218822Sdim            }
4459104841Sobrien
4460218822Sdim
446199465Sobrien	  /* ??? .eh_frame references to discarded sections will be smashed
446299465Sobrien	     to relocations against SHN_UNDEF.  The .eh_frame format allows
446399465Sobrien	     NULL to be encoded as 0 in any format, so this works here.  */
446499465Sobrien	  if (r_symndx == 0)
446599465Sobrien	    howto = (elf64_alpha_howto_table
446699465Sobrien		     + (r_type - R_ALPHA_SREL32 + R_ALPHA_REFLONG));
446799465Sobrien	  goto default_reloc;
446899465Sobrien
4469104841Sobrien	case R_ALPHA_TLSLDM:
4470104841Sobrien	  /* Ignore the symbol for the relocation.  The result is always
4471104841Sobrien	     the current module.  */
4472104841Sobrien	  dynamic_symbol_p = 0;
4473104841Sobrien	  /* FALLTHRU */
4474104841Sobrien
4475104841Sobrien	case R_ALPHA_TLSGD:
4476104841Sobrien	  if (!gotent->reloc_done)
4477104841Sobrien	    {
4478104841Sobrien	      gotent->reloc_done = 1;
4479104841Sobrien
4480104841Sobrien	      /* Note that the module index for the main program is 1.  */
4481104841Sobrien	      bfd_put_64 (output_bfd, !info->shared && !dynamic_symbol_p,
4482104841Sobrien			  sgot->contents + gotent->got_offset);
4483104841Sobrien
4484104841Sobrien	      /* If the symbol has been forced local, output a
4485104841Sobrien		 DTPMOD64 reloc, otherwise it will be handled in
4486104841Sobrien		 finish_dynamic_symbol.  */
4487104841Sobrien	      if (info->shared && !dynamic_symbol_p)
4488130570Sobrien		elf64_alpha_emit_dynrel (output_bfd, info, sgot, srelgot,
4489130570Sobrien					 gotent->got_offset, 0,
4490130570Sobrien					 R_ALPHA_DTPMOD64, 0);
4491104841Sobrien
4492104841Sobrien	      if (dynamic_symbol_p || r_type == R_ALPHA_TLSLDM)
4493104841Sobrien		value = 0;
4494104841Sobrien	      else
4495104841Sobrien		{
4496130570Sobrien		  BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
4497104841Sobrien	          value -= dtp_base;
4498104841Sobrien		}
4499104841Sobrien	      bfd_put_64 (output_bfd, value,
4500104841Sobrien			  sgot->contents + gotent->got_offset + 8);
4501104841Sobrien	    }
4502104841Sobrien
4503104841Sobrien	  value = (sgot->output_section->vma
4504104841Sobrien		   + sgot->output_offset
4505104841Sobrien		   + gotent->got_offset);
4506104841Sobrien	  value -= gp;
4507104841Sobrien	  goto default_reloc;
4508104841Sobrien
4509104841Sobrien	case R_ALPHA_DTPRELHI:
4510104841Sobrien	case R_ALPHA_DTPRELLO:
4511104841Sobrien	case R_ALPHA_DTPREL16:
4512104841Sobrien	  if (dynamic_symbol_p)
4513104841Sobrien            {
4514104841Sobrien              (*_bfd_error_handler)
4515218822Sdim                (_("%B: dtp-relative relocation against dynamic symbol %s"),
4516218822Sdim                 input_bfd, h->root.root.root.string);
4517130570Sobrien              ret_val = FALSE;
4518104841Sobrien            }
4519130570Sobrien	  BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
4520104841Sobrien	  value -= dtp_base;
4521104841Sobrien	  if (r_type == R_ALPHA_DTPRELHI)
4522104841Sobrien	    value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1);
4523104841Sobrien	  goto default_reloc;
4524104841Sobrien
4525104841Sobrien	case R_ALPHA_TPRELHI:
4526104841Sobrien	case R_ALPHA_TPRELLO:
4527104841Sobrien	case R_ALPHA_TPREL16:
4528104841Sobrien	  if (info->shared)
4529104841Sobrien	    {
4530104841Sobrien	      (*_bfd_error_handler)
4531218822Sdim		(_("%B: TLS local exec code cannot be linked into shared objects"),
4532218822Sdim		input_bfd);
4533130570Sobrien              ret_val = FALSE;
4534104841Sobrien	    }
4535104841Sobrien	  else if (dynamic_symbol_p)
4536104841Sobrien            {
4537104841Sobrien              (*_bfd_error_handler)
4538218822Sdim                (_("%B: tp-relative relocation against dynamic symbol %s"),
4539218822Sdim                 input_bfd, h->root.root.root.string);
4540130570Sobrien              ret_val = FALSE;
4541104841Sobrien            }
4542130570Sobrien	  BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
4543104841Sobrien	  value -= tp_base;
4544104841Sobrien	  if (r_type == R_ALPHA_TPRELHI)
4545104841Sobrien	    value = ((bfd_signed_vma) value >> 16) + ((value >> 15) & 1);
4546104841Sobrien	  goto default_reloc;
4547104841Sobrien
4548104841Sobrien	case R_ALPHA_GOTDTPREL:
4549104841Sobrien	case R_ALPHA_GOTTPREL:
4550104841Sobrien	  BFD_ASSERT(sgot != NULL);
4551104841Sobrien	  BFD_ASSERT(gp != 0);
4552104841Sobrien	  BFD_ASSERT(gotent != NULL);
4553104841Sobrien	  BFD_ASSERT(gotent->use_count >= 1);
4554104841Sobrien
4555104841Sobrien	  if (!gotent->reloc_done)
4556104841Sobrien	    {
4557104841Sobrien	      gotent->reloc_done = 1;
4558104841Sobrien
4559104841Sobrien	      if (dynamic_symbol_p)
4560104841Sobrien		value = 0;
4561104841Sobrien	      else
4562104841Sobrien		{
4563130570Sobrien		  BFD_ASSERT (elf_hash_table (info)->tls_sec != NULL);
4564130570Sobrien		  if (r_type == R_ALPHA_GOTDTPREL)
4565130570Sobrien		    value -= dtp_base;
4566130570Sobrien		  else if (!info->shared)
4567130570Sobrien		    value -= tp_base;
4568130570Sobrien		  else
4569130570Sobrien		    {
4570130570Sobrien		      elf64_alpha_emit_dynrel (output_bfd, info, sgot, srelgot,
4571130570Sobrien					       gotent->got_offset, 0,
4572130570Sobrien					       R_ALPHA_TPREL64,
4573130570Sobrien					       value - dtp_base);
4574130570Sobrien		      value = 0;
4575130570Sobrien		    }
4576104841Sobrien		}
4577104841Sobrien	      bfd_put_64 (output_bfd, value,
4578104841Sobrien			  sgot->contents + gotent->got_offset);
4579104841Sobrien	    }
4580104841Sobrien
4581104841Sobrien	  value = (sgot->output_section->vma
4582104841Sobrien		   + sgot->output_offset
4583104841Sobrien		   + gotent->got_offset);
4584104841Sobrien	  value -= gp;
4585104841Sobrien	  goto default_reloc;
4586104841Sobrien
458733965Sjdp	default:
458833965Sjdp	default_reloc:
458933965Sjdp	  r = _bfd_final_link_relocate (howto, input_bfd, input_section,
4590104841Sobrien					contents, rel->r_offset, value, 0);
459133965Sjdp	  break;
459233965Sjdp	}
459333965Sjdp
459433965Sjdp      switch (r)
459533965Sjdp	{
459633965Sjdp	case bfd_reloc_ok:
459733965Sjdp	  break;
459833965Sjdp
459933965Sjdp	case bfd_reloc_overflow:
460033965Sjdp	  {
460133965Sjdp	    const char *name;
460233965Sjdp
460389862Sobrien	    /* Don't warn if the overflow is due to pc relative reloc
460489862Sobrien	       against discarded section.  Section optimization code should
460589862Sobrien	       handle it.  */
460689862Sobrien
460789862Sobrien	    if (r_symndx < symtab_hdr->sh_info
460889862Sobrien		&& sec != NULL && howto->pc_relative
460989862Sobrien		&& elf_discarded_section (sec))
461089862Sobrien	      break;
461189862Sobrien
461233965Sjdp	    if (h != NULL)
4613218822Sdim	      name = NULL;
461433965Sjdp	    else
461533965Sjdp	      {
461633965Sjdp		name = (bfd_elf_string_from_elf_section
461733965Sjdp			(input_bfd, symtab_hdr->sh_link, sym->st_name));
461833965Sjdp		if (name == NULL)
4619130570Sobrien		  return FALSE;
462033965Sjdp		if (*name == '\0')
462133965Sjdp		  name = bfd_section_name (input_bfd, sec);
462233965Sjdp	      }
462333965Sjdp	    if (! ((*info->callbacks->reloc_overflow)
4624218822Sdim		   (info, (h ? &h->root.root : NULL), name, howto->name,
4625218822Sdim		    (bfd_vma) 0, input_bfd, input_section,
4626218822Sdim		    rel->r_offset)))
4627130570Sobrien	      ret_val = FALSE;
462833965Sjdp	  }
462933965Sjdp	  break;
463033965Sjdp
463133965Sjdp	default:
463233965Sjdp	case bfd_reloc_outofrange:
463333965Sjdp	  abort ();
463433965Sjdp	}
463533965Sjdp    }
463633965Sjdp
463789862Sobrien  return ret_val;
463833965Sjdp}
463933965Sjdp
464033965Sjdp/* Finish up dynamic symbol handling.  We set the contents of various
464133965Sjdp   dynamic sections here.  */
464233965Sjdp
4643130570Sobrienstatic bfd_boolean
4644218822Sdimelf64_alpha_finish_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info,
4645218822Sdim				   struct elf_link_hash_entry *h,
4646218822Sdim				   Elf_Internal_Sym *sym)
464733965Sjdp{
4648218822Sdim  struct alpha_elf_link_hash_entry *ah = (struct alpha_elf_link_hash_entry *)h;
464933965Sjdp  bfd *dynobj = elf_hash_table(info)->dynobj;
465033965Sjdp
4651218822Sdim  if (h->needs_plt)
465233965Sjdp    {
465333965Sjdp      /* Fill in the .plt entry for this symbol.  */
465433965Sjdp      asection *splt, *sgot, *srel;
465533965Sjdp      Elf_Internal_Rela outrel;
4656130570Sobrien      bfd_byte *loc;
465733965Sjdp      bfd_vma got_addr, plt_addr;
465833965Sjdp      bfd_vma plt_index;
465933965Sjdp      struct alpha_elf_got_entry *gotent;
466033965Sjdp
466133965Sjdp      BFD_ASSERT (h->dynindx != -1);
466233965Sjdp
466333965Sjdp      splt = bfd_get_section_by_name (dynobj, ".plt");
466433965Sjdp      BFD_ASSERT (splt != NULL);
466533965Sjdp      srel = bfd_get_section_by_name (dynobj, ".rela.plt");
466633965Sjdp      BFD_ASSERT (srel != NULL);
466733965Sjdp
4668218822Sdim      for (gotent = ah->got_entries; gotent ; gotent = gotent->next)
4669218822Sdim	if (gotent->reloc_type == R_ALPHA_LITERAL
4670218822Sdim	    && gotent->use_count > 0)
4671218822Sdim	  {
4672218822Sdim	    unsigned int insn;
4673218822Sdim	    int disp;
467433965Sjdp
4675218822Sdim	    sgot = alpha_elf_tdata (gotent->gotobj)->got;
4676218822Sdim	    BFD_ASSERT (sgot != NULL);
467733965Sjdp
4678218822Sdim	    BFD_ASSERT (gotent->got_offset != -1);
4679218822Sdim	    BFD_ASSERT (gotent->plt_offset != -1);
468033965Sjdp
4681218822Sdim	    got_addr = (sgot->output_section->vma
4682218822Sdim			+ sgot->output_offset
4683218822Sdim			+ gotent->got_offset);
4684218822Sdim	    plt_addr = (splt->output_section->vma
4685218822Sdim			+ splt->output_offset
4686218822Sdim			+ gotent->plt_offset);
468733965Sjdp
4688218822Sdim	    plt_index = (gotent->plt_offset-PLT_HEADER_SIZE) / PLT_ENTRY_SIZE;
468933965Sjdp
4690218822Sdim	    /* Fill in the entry in the procedure linkage table.  */
4691218822Sdim	    if (elf64_alpha_use_secureplt)
4692218822Sdim	      {
4693218822Sdim		disp = (PLT_HEADER_SIZE - 4) - (gotent->plt_offset + 4);
4694218822Sdim		insn = INSN_AD (INSN_BR, 31, disp);
4695218822Sdim		bfd_put_32 (output_bfd, insn,
4696218822Sdim			    splt->contents + gotent->plt_offset);
469733965Sjdp
4698218822Sdim		plt_index = ((gotent->plt_offset - NEW_PLT_HEADER_SIZE)
4699218822Sdim			     / NEW_PLT_ENTRY_SIZE);
4700218822Sdim	      }
4701218822Sdim	    else
4702218822Sdim	      {
4703218822Sdim		disp = -(gotent->plt_offset + 4);
4704218822Sdim		insn = INSN_AD (INSN_BR, 28, disp);
4705218822Sdim		bfd_put_32 (output_bfd, insn,
4706218822Sdim			    splt->contents + gotent->plt_offset);
4707218822Sdim		bfd_put_32 (output_bfd, INSN_UNOP,
4708218822Sdim			    splt->contents + gotent->plt_offset + 4);
4709218822Sdim		bfd_put_32 (output_bfd, INSN_UNOP,
4710218822Sdim			    splt->contents + gotent->plt_offset + 8);
471133965Sjdp
4712218822Sdim		plt_index = ((gotent->plt_offset - OLD_PLT_HEADER_SIZE)
4713218822Sdim			     / OLD_PLT_ENTRY_SIZE);
4714218822Sdim	      }
471533965Sjdp
4716218822Sdim	    /* Fill in the entry in the .rela.plt section.  */
4717218822Sdim	    outrel.r_offset = got_addr;
4718218822Sdim	    outrel.r_info = ELF64_R_INFO(h->dynindx, R_ALPHA_JMP_SLOT);
4719218822Sdim	    outrel.r_addend = 0;
472033965Sjdp
4721218822Sdim	    loc = srel->contents + plt_index * sizeof (Elf64_External_Rela);
4722218822Sdim	    bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc);
472333965Sjdp
4724218822Sdim	    /* Fill in the entry in the .got.  */
4725218822Sdim	    bfd_put_64 (output_bfd, plt_addr,
4726218822Sdim			sgot->contents + gotent->got_offset);
4727218822Sdim	  }
472833965Sjdp    }
472933965Sjdp  else if (alpha_elf_dynamic_symbol_p (h, info))
473033965Sjdp    {
473133965Sjdp      /* Fill in the dynamic relocations for this symbol's .got entries.  */
473233965Sjdp      asection *srel;
473333965Sjdp      struct alpha_elf_got_entry *gotent;
473433965Sjdp
473533965Sjdp      srel = bfd_get_section_by_name (dynobj, ".rela.got");
473633965Sjdp      BFD_ASSERT (srel != NULL);
473733965Sjdp
473833965Sjdp      for (gotent = ((struct alpha_elf_link_hash_entry *) h)->got_entries;
473933965Sjdp	   gotent != NULL;
474033965Sjdp	   gotent = gotent->next)
474133965Sjdp	{
4742104841Sobrien	  asection *sgot;
4743130570Sobrien	  long r_type;
4744104841Sobrien
4745104841Sobrien	  if (gotent->use_count == 0)
4746104841Sobrien	    continue;
4747104841Sobrien
4748104841Sobrien	  sgot = alpha_elf_tdata (gotent->gotobj)->got;
4749104841Sobrien
4750104841Sobrien	  r_type = gotent->reloc_type;
4751104841Sobrien	  switch (r_type)
4752104841Sobrien	    {
4753104841Sobrien	    case R_ALPHA_LITERAL:
4754104841Sobrien	      r_type = R_ALPHA_GLOB_DAT;
4755104841Sobrien	      break;
4756104841Sobrien	    case R_ALPHA_TLSGD:
4757104841Sobrien	      r_type = R_ALPHA_DTPMOD64;
4758104841Sobrien	      break;
4759104841Sobrien	    case R_ALPHA_GOTDTPREL:
4760104841Sobrien	      r_type = R_ALPHA_DTPREL64;
4761104841Sobrien	      break;
4762104841Sobrien	    case R_ALPHA_GOTTPREL:
4763104841Sobrien	      r_type = R_ALPHA_TPREL64;
4764104841Sobrien	      break;
4765104841Sobrien	    case R_ALPHA_TLSLDM:
4766104841Sobrien	    default:
4767104841Sobrien	      abort ();
4768104841Sobrien	    }
4769104841Sobrien
4770130570Sobrien	  elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel,
4771130570Sobrien				   gotent->got_offset, h->dynindx,
4772130570Sobrien				   r_type, gotent->addend);
477333965Sjdp
4774104841Sobrien	  if (gotent->reloc_type == R_ALPHA_TLSGD)
4775130570Sobrien	    elf64_alpha_emit_dynrel (output_bfd, info, sgot, srel,
4776130570Sobrien				     gotent->got_offset + 8, h->dynindx,
4777130570Sobrien				     R_ALPHA_DTPREL64, gotent->addend);
477833965Sjdp	}
477933965Sjdp    }
478033965Sjdp
478133965Sjdp  /* Mark some specially defined symbols as absolute.  */
478233965Sjdp  if (strcmp (h->root.root.string, "_DYNAMIC") == 0
4783218822Sdim      || h == elf_hash_table (info)->hgot
4784218822Sdim      || h == elf_hash_table (info)->hplt)
478533965Sjdp    sym->st_shndx = SHN_ABS;
478633965Sjdp
4787130570Sobrien  return TRUE;
478833965Sjdp}
478933965Sjdp
479033965Sjdp/* Finish up the dynamic sections.  */
479133965Sjdp
4792130570Sobrienstatic bfd_boolean
4793218822Sdimelf64_alpha_finish_dynamic_sections (bfd *output_bfd,
4794218822Sdim				     struct bfd_link_info *info)
479533965Sjdp{
479633965Sjdp  bfd *dynobj;
479733965Sjdp  asection *sdyn;
479833965Sjdp
479933965Sjdp  dynobj = elf_hash_table (info)->dynobj;
480033965Sjdp  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
480133965Sjdp
480233965Sjdp  if (elf_hash_table (info)->dynamic_sections_created)
480333965Sjdp    {
4804218822Sdim      asection *splt, *sgotplt, *srelaplt;
480533965Sjdp      Elf64_External_Dyn *dyncon, *dynconend;
4806218822Sdim      bfd_vma plt_vma, gotplt_vma;
480733965Sjdp
480833965Sjdp      splt = bfd_get_section_by_name (dynobj, ".plt");
4809218822Sdim      srelaplt = bfd_get_section_by_name (output_bfd, ".rela.plt");
481033965Sjdp      BFD_ASSERT (splt != NULL && sdyn != NULL);
481133965Sjdp
4812218822Sdim      plt_vma = splt->output_section->vma + splt->output_offset;
4813218822Sdim
4814218822Sdim      gotplt_vma = 0;
4815218822Sdim      if (elf64_alpha_use_secureplt)
4816218822Sdim	{
4817218822Sdim	  sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
4818218822Sdim	  BFD_ASSERT (sgotplt != NULL);
4819218822Sdim	  if (sgotplt->size > 0)
4820218822Sdim	    gotplt_vma = sgotplt->output_section->vma + sgotplt->output_offset;
4821218822Sdim	}
4822218822Sdim
482333965Sjdp      dyncon = (Elf64_External_Dyn *) sdyn->contents;
4824218822Sdim      dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size);
482533965Sjdp      for (; dyncon < dynconend; dyncon++)
482633965Sjdp	{
482733965Sjdp	  Elf_Internal_Dyn dyn;
482833965Sjdp
482933965Sjdp	  bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn);
483033965Sjdp
483133965Sjdp	  switch (dyn.d_tag)
483233965Sjdp	    {
483333965Sjdp	    case DT_PLTGOT:
4834218822Sdim	      dyn.d_un.d_ptr
4835218822Sdim		= elf64_alpha_use_secureplt ? gotplt_vma : plt_vma;
4836218822Sdim	      break;
483733965Sjdp	    case DT_PLTRELSZ:
4838218822Sdim	      dyn.d_un.d_val = srelaplt ? srelaplt->size : 0;
4839218822Sdim	      break;
484033965Sjdp	    case DT_JMPREL:
4841218822Sdim	      dyn.d_un.d_ptr = srelaplt ? srelaplt->vma : 0;
4842218822Sdim	      break;
484333965Sjdp
484433965Sjdp	    case DT_RELASZ:
484533965Sjdp	      /* My interpretation of the TIS v1.1 ELF document indicates
484633965Sjdp		 that RELASZ should not include JMPREL.  This is not what
484733965Sjdp		 the rest of the BFD does.  It is, however, what the
484833965Sjdp		 glibc ld.so wants.  Do this fixup here until we found
484933965Sjdp		 out who is right.  */
4850218822Sdim	      if (srelaplt)
4851218822Sdim		dyn.d_un.d_val -= srelaplt->size;
485233965Sjdp	      break;
485333965Sjdp	    }
485433965Sjdp
485533965Sjdp	  bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon);
485633965Sjdp	}
485733965Sjdp
4858218822Sdim      /* Initialize the plt header.  */
4859218822Sdim      if (splt->size > 0)
486033965Sjdp	{
4861218822Sdim	  unsigned int insn;
4862218822Sdim	  int ofs;
486333965Sjdp
4864218822Sdim	  if (elf64_alpha_use_secureplt)
4865218822Sdim	    {
4866218822Sdim	      ofs = gotplt_vma - (plt_vma + PLT_HEADER_SIZE);
486733965Sjdp
4868218822Sdim	      insn = INSN_ABC (INSN_SUBQ, 27, 28, 25);
4869218822Sdim	      bfd_put_32 (output_bfd, insn, splt->contents);
4870218822Sdim
4871218822Sdim	      insn = INSN_ABO (INSN_LDAH, 28, 28, (ofs + 0x8000) >> 16);
4872218822Sdim	      bfd_put_32 (output_bfd, insn, splt->contents + 4);
4873218822Sdim
4874218822Sdim	      insn = INSN_ABC (INSN_S4SUBQ, 25, 25, 25);
4875218822Sdim	      bfd_put_32 (output_bfd, insn, splt->contents + 8);
4876218822Sdim
4877218822Sdim	      insn = INSN_ABO (INSN_LDA, 28, 28, ofs);
4878218822Sdim	      bfd_put_32 (output_bfd, insn, splt->contents + 12);
4879218822Sdim
4880218822Sdim	      insn = INSN_ABO (INSN_LDQ, 27, 28, 0);
4881218822Sdim	      bfd_put_32 (output_bfd, insn, splt->contents + 16);
4882218822Sdim
4883218822Sdim	      insn = INSN_ABC (INSN_ADDQ, 25, 25, 25);
4884218822Sdim	      bfd_put_32 (output_bfd, insn, splt->contents + 20);
4885218822Sdim
4886218822Sdim	      insn = INSN_ABO (INSN_LDQ, 28, 28, 8);
4887218822Sdim	      bfd_put_32 (output_bfd, insn, splt->contents + 24);
4888218822Sdim
4889218822Sdim	      insn = INSN_AB (INSN_JMP, 31, 27);
4890218822Sdim	      bfd_put_32 (output_bfd, insn, splt->contents + 28);
4891218822Sdim
4892218822Sdim	      insn = INSN_AD (INSN_BR, 28, -PLT_HEADER_SIZE);
4893218822Sdim	      bfd_put_32 (output_bfd, insn, splt->contents + 32);
4894218822Sdim	    }
4895218822Sdim	  else
4896218822Sdim	    {
4897218822Sdim	      insn = INSN_AD (INSN_BR, 27, 0);	/* br $27, .+4 */
4898218822Sdim	      bfd_put_32 (output_bfd, insn, splt->contents);
4899218822Sdim
4900218822Sdim	      insn = INSN_ABO (INSN_LDQ, 27, 27, 12);
4901218822Sdim	      bfd_put_32 (output_bfd, insn, splt->contents + 4);
4902218822Sdim
4903218822Sdim	      insn = INSN_UNOP;
4904218822Sdim	      bfd_put_32 (output_bfd, insn, splt->contents + 8);
4905218822Sdim
4906218822Sdim	      insn = INSN_AB (INSN_JMP, 27, 27);
4907218822Sdim	      bfd_put_32 (output_bfd, insn, splt->contents + 12);
4908218822Sdim
4909218822Sdim	      /* The next two words will be filled in by ld.so.  */
4910218822Sdim	      bfd_put_64 (output_bfd, 0, splt->contents + 16);
4911218822Sdim	      bfd_put_64 (output_bfd, 0, splt->contents + 24);
4912218822Sdim	    }
4913218822Sdim
4914130570Sobrien	  elf_section_data (splt->output_section)->this_hdr.sh_entsize = 0;
491533965Sjdp	}
491633965Sjdp    }
491733965Sjdp
4918130570Sobrien  return TRUE;
491933965Sjdp}
492033965Sjdp
492189862Sobrien/* We need to use a special link routine to handle the .mdebug section.
492289862Sobrien   We need to merge all instances of these sections together, not write
492389862Sobrien   them all out sequentially.  */
492433965Sjdp
4925130570Sobrienstatic bfd_boolean
4926218822Sdimelf64_alpha_final_link (bfd *abfd, struct bfd_link_info *info)
492733965Sjdp{
492833965Sjdp  asection *o;
492933965Sjdp  struct bfd_link_order *p;
493089862Sobrien  asection *mdebug_sec;
493133965Sjdp  struct ecoff_debug_info debug;
493233965Sjdp  const struct ecoff_debug_swap *swap
493333965Sjdp    = get_elf_backend_data (abfd)->elf_backend_ecoff_debug_swap;
493433965Sjdp  HDRR *symhdr = &debug.symbolic_header;
493533965Sjdp  PTR mdebug_handle = NULL;
493633965Sjdp
493789862Sobrien  /* Go through the sections and collect the mdebug information.  */
493833965Sjdp  mdebug_sec = NULL;
493933965Sjdp  for (o = abfd->sections; o != (asection *) NULL; o = o->next)
494033965Sjdp    {
494133965Sjdp      if (strcmp (o->name, ".mdebug") == 0)
494233965Sjdp	{
494333965Sjdp	  struct extsym_info einfo;
494433965Sjdp
494533965Sjdp	  /* We have found the .mdebug section in the output file.
494633965Sjdp	     Look through all the link_orders comprising it and merge
494733965Sjdp	     the information together.  */
494833965Sjdp	  symhdr->magic = swap->sym_magic;
494933965Sjdp	  /* FIXME: What should the version stamp be?  */
495033965Sjdp	  symhdr->vstamp = 0;
495133965Sjdp	  symhdr->ilineMax = 0;
495233965Sjdp	  symhdr->cbLine = 0;
495333965Sjdp	  symhdr->idnMax = 0;
495433965Sjdp	  symhdr->ipdMax = 0;
495533965Sjdp	  symhdr->isymMax = 0;
495633965Sjdp	  symhdr->ioptMax = 0;
495733965Sjdp	  symhdr->iauxMax = 0;
495833965Sjdp	  symhdr->issMax = 0;
495933965Sjdp	  symhdr->issExtMax = 0;
496033965Sjdp	  symhdr->ifdMax = 0;
496133965Sjdp	  symhdr->crfd = 0;
496233965Sjdp	  symhdr->iextMax = 0;
496333965Sjdp
496433965Sjdp	  /* We accumulate the debugging information itself in the
496533965Sjdp	     debug_info structure.  */
496633965Sjdp	  debug.line = NULL;
496733965Sjdp	  debug.external_dnr = NULL;
496833965Sjdp	  debug.external_pdr = NULL;
496933965Sjdp	  debug.external_sym = NULL;
497033965Sjdp	  debug.external_opt = NULL;
497133965Sjdp	  debug.external_aux = NULL;
497233965Sjdp	  debug.ss = NULL;
497333965Sjdp	  debug.ssext = debug.ssext_end = NULL;
497433965Sjdp	  debug.external_fdr = NULL;
497533965Sjdp	  debug.external_rfd = NULL;
497633965Sjdp	  debug.external_ext = debug.external_ext_end = NULL;
497733965Sjdp
497833965Sjdp	  mdebug_handle = bfd_ecoff_debug_init (abfd, &debug, swap, info);
497933965Sjdp	  if (mdebug_handle == (PTR) NULL)
4980130570Sobrien	    return FALSE;
498133965Sjdp
498233965Sjdp	  if (1)
498333965Sjdp	    {
498433965Sjdp	      asection *s;
498533965Sjdp	      EXTR esym;
498689862Sobrien	      bfd_vma last = 0;
498733965Sjdp	      unsigned int i;
498833965Sjdp	      static const char * const name[] =
498933965Sjdp		{
499033965Sjdp		  ".text", ".init", ".fini", ".data",
499133965Sjdp		  ".rodata", ".sdata", ".sbss", ".bss"
499233965Sjdp		};
499333965Sjdp	      static const int sc[] = { scText, scInit, scFini, scData,
499433965Sjdp					  scRData, scSData, scSBss, scBss };
499533965Sjdp
499633965Sjdp	      esym.jmptbl = 0;
499733965Sjdp	      esym.cobol_main = 0;
499833965Sjdp	      esym.weakext = 0;
499933965Sjdp	      esym.reserved = 0;
500033965Sjdp	      esym.ifd = ifdNil;
500133965Sjdp	      esym.asym.iss = issNil;
500233965Sjdp	      esym.asym.st = stLocal;
500333965Sjdp	      esym.asym.reserved = 0;
500433965Sjdp	      esym.asym.index = indexNil;
500533965Sjdp	      for (i = 0; i < 8; i++)
500633965Sjdp		{
500733965Sjdp		  esym.asym.sc = sc[i];
500833965Sjdp		  s = bfd_get_section_by_name (abfd, name[i]);
500933965Sjdp		  if (s != NULL)
501033965Sjdp		    {
501133965Sjdp		      esym.asym.value = s->vma;
5012218822Sdim		      last = s->vma + s->size;
501333965Sjdp		    }
501433965Sjdp		  else
501533965Sjdp		    esym.asym.value = last;
501633965Sjdp
501733965Sjdp		  if (! bfd_ecoff_debug_one_external (abfd, &debug, swap,
501833965Sjdp						      name[i], &esym))
5019130570Sobrien		    return FALSE;
502033965Sjdp		}
502133965Sjdp	    }
502233965Sjdp
5023218822Sdim	  for (p = o->map_head.link_order;
502433965Sjdp	       p != (struct bfd_link_order *) NULL;
502533965Sjdp	       p = p->next)
502633965Sjdp	    {
502733965Sjdp	      asection *input_section;
502833965Sjdp	      bfd *input_bfd;
502933965Sjdp	      const struct ecoff_debug_swap *input_swap;
503033965Sjdp	      struct ecoff_debug_info input_debug;
503133965Sjdp	      char *eraw_src;
503233965Sjdp	      char *eraw_end;
503333965Sjdp
503433965Sjdp	      if (p->type != bfd_indirect_link_order)
503533965Sjdp		{
5036104841Sobrien		  if (p->type == bfd_data_link_order)
503733965Sjdp		    continue;
503833965Sjdp		  abort ();
503933965Sjdp		}
504033965Sjdp
504133965Sjdp	      input_section = p->u.indirect.section;
504233965Sjdp	      input_bfd = input_section->owner;
504333965Sjdp
504433965Sjdp	      if (bfd_get_flavour (input_bfd) != bfd_target_elf_flavour
504533965Sjdp		  || (get_elf_backend_data (input_bfd)
504633965Sjdp		      ->elf_backend_ecoff_debug_swap) == NULL)
504733965Sjdp		{
504833965Sjdp		  /* I don't know what a non ALPHA ELF bfd would be
504933965Sjdp		     doing with a .mdebug section, but I don't really
505033965Sjdp		     want to deal with it.  */
505133965Sjdp		  continue;
505233965Sjdp		}
505333965Sjdp
505433965Sjdp	      input_swap = (get_elf_backend_data (input_bfd)
505533965Sjdp			    ->elf_backend_ecoff_debug_swap);
505633965Sjdp
5057218822Sdim	      BFD_ASSERT (p->size == input_section->size);
505833965Sjdp
505933965Sjdp	      /* The ECOFF linking code expects that we have already
506033965Sjdp		 read in the debugging information and set up an
506133965Sjdp		 ecoff_debug_info structure, so we do that now.  */
506233965Sjdp	      if (!elf64_alpha_read_ecoff_info (input_bfd, input_section,
506333965Sjdp						&input_debug))
5064130570Sobrien		return FALSE;
506533965Sjdp
506633965Sjdp	      if (! (bfd_ecoff_debug_accumulate
506733965Sjdp		     (mdebug_handle, abfd, &debug, swap, input_bfd,
506833965Sjdp		      &input_debug, input_swap, info)))
5069130570Sobrien		return FALSE;
507033965Sjdp
507133965Sjdp	      /* Loop through the external symbols.  For each one with
507233965Sjdp		 interesting information, try to find the symbol in
507333965Sjdp		 the linker global hash table and save the information
507433965Sjdp		 for the output external symbols.  */
507533965Sjdp	      eraw_src = input_debug.external_ext;
507633965Sjdp	      eraw_end = (eraw_src
507733965Sjdp			  + (input_debug.symbolic_header.iextMax
507833965Sjdp			     * input_swap->external_ext_size));
507933965Sjdp	      for (;
508033965Sjdp		   eraw_src < eraw_end;
508133965Sjdp		   eraw_src += input_swap->external_ext_size)
508233965Sjdp		{
508333965Sjdp		  EXTR ext;
508433965Sjdp		  const char *name;
508533965Sjdp		  struct alpha_elf_link_hash_entry *h;
508633965Sjdp
508733965Sjdp		  (*input_swap->swap_ext_in) (input_bfd, (PTR) eraw_src, &ext);
508833965Sjdp		  if (ext.asym.sc == scNil
508933965Sjdp		      || ext.asym.sc == scUndefined
509033965Sjdp		      || ext.asym.sc == scSUndefined)
509133965Sjdp		    continue;
509233965Sjdp
509333965Sjdp		  name = input_debug.ssext + ext.asym.iss;
509433965Sjdp		  h = alpha_elf_link_hash_lookup (alpha_elf_hash_table (info),
5095130570Sobrien						  name, FALSE, FALSE, TRUE);
509633965Sjdp		  if (h == NULL || h->esym.ifd != -2)
509733965Sjdp		    continue;
509833965Sjdp
509933965Sjdp		  if (ext.ifd != -1)
510033965Sjdp		    {
510133965Sjdp		      BFD_ASSERT (ext.ifd
510233965Sjdp				  < input_debug.symbolic_header.ifdMax);
510333965Sjdp		      ext.ifd = input_debug.ifdmap[ext.ifd];
510433965Sjdp		    }
510533965Sjdp
510633965Sjdp		  h->esym = ext;
510733965Sjdp		}
510833965Sjdp
510933965Sjdp	      /* Free up the information we just read.  */
511033965Sjdp	      free (input_debug.line);
511133965Sjdp	      free (input_debug.external_dnr);
511233965Sjdp	      free (input_debug.external_pdr);
511333965Sjdp	      free (input_debug.external_sym);
511433965Sjdp	      free (input_debug.external_opt);
511533965Sjdp	      free (input_debug.external_aux);
511633965Sjdp	      free (input_debug.ss);
511733965Sjdp	      free (input_debug.ssext);
511833965Sjdp	      free (input_debug.external_fdr);
511933965Sjdp	      free (input_debug.external_rfd);
512033965Sjdp	      free (input_debug.external_ext);
512133965Sjdp
512233965Sjdp	      /* Hack: reset the SEC_HAS_CONTENTS flag so that
512333965Sjdp		 elf_link_input_bfd ignores this section.  */
512433965Sjdp	      input_section->flags &=~ SEC_HAS_CONTENTS;
512533965Sjdp	    }
512633965Sjdp
512733965Sjdp	  /* Build the external symbol information.  */
512833965Sjdp	  einfo.abfd = abfd;
512933965Sjdp	  einfo.info = info;
513033965Sjdp	  einfo.debug = &debug;
513133965Sjdp	  einfo.swap = swap;
5132130570Sobrien	  einfo.failed = FALSE;
513333965Sjdp	  elf_link_hash_traverse (elf_hash_table (info),
513433965Sjdp				  elf64_alpha_output_extsym,
513533965Sjdp				  (PTR) &einfo);
513633965Sjdp	  if (einfo.failed)
5137130570Sobrien	    return FALSE;
513833965Sjdp
513933965Sjdp	  /* Set the size of the .mdebug section.  */
5140218822Sdim	  o->size = bfd_ecoff_debug_size (abfd, &debug, swap);
514133965Sjdp
514233965Sjdp	  /* Skip this section later on (I don't think this currently
514333965Sjdp	     matters, but someday it might).  */
5144218822Sdim	  o->map_head.link_order = (struct bfd_link_order *) NULL;
514533965Sjdp
514633965Sjdp	  mdebug_sec = o;
514733965Sjdp	}
514833965Sjdp    }
514933965Sjdp
515033965Sjdp  /* Invoke the regular ELF backend linker to do all the work.  */
5151130570Sobrien  if (! bfd_elf_final_link (abfd, info))
5152130570Sobrien    return FALSE;
515333965Sjdp
515433965Sjdp  /* Now write out the computed sections.  */
515533965Sjdp
515633965Sjdp  /* The .got subsections...  */
515733965Sjdp  {
515833965Sjdp    bfd *i, *dynobj = elf_hash_table(info)->dynobj;
515933965Sjdp    for (i = alpha_elf_hash_table(info)->got_list;
516033965Sjdp	 i != NULL;
516133965Sjdp	 i = alpha_elf_tdata(i)->got_link_next)
516233965Sjdp      {
516333965Sjdp	asection *sgot;
516433965Sjdp
516533965Sjdp	/* elf_bfd_final_link already did everything in dynobj.  */
516633965Sjdp	if (i == dynobj)
516733965Sjdp	  continue;
516833965Sjdp
516933965Sjdp	sgot = alpha_elf_tdata(i)->got;
517033965Sjdp	if (! bfd_set_section_contents (abfd, sgot->output_section,
517189862Sobrien					sgot->contents,
517289862Sobrien					(file_ptr) sgot->output_offset,
5173218822Sdim					sgot->size))
5174130570Sobrien	  return FALSE;
517533965Sjdp      }
517633965Sjdp  }
517733965Sjdp
517833965Sjdp  if (mdebug_sec != (asection *) NULL)
517933965Sjdp    {
518033965Sjdp      BFD_ASSERT (abfd->output_has_begun);
518133965Sjdp      if (! bfd_ecoff_write_accumulated_debug (mdebug_handle, abfd, &debug,
518233965Sjdp					       swap, info,
518333965Sjdp					       mdebug_sec->filepos))
5184130570Sobrien	return FALSE;
518533965Sjdp
518633965Sjdp      bfd_ecoff_debug_free (mdebug_handle, abfd, &debug, swap, info);
518733965Sjdp    }
518833965Sjdp
5189130570Sobrien  return TRUE;
519089862Sobrien}
519133965Sjdp
519289862Sobrienstatic enum elf_reloc_type_class
5193218822Sdimelf64_alpha_reloc_type_class (const Elf_Internal_Rela *rela)
519489862Sobrien{
519589862Sobrien  switch ((int) ELF64_R_TYPE (rela->r_info))
519633965Sjdp    {
519789862Sobrien    case R_ALPHA_RELATIVE:
519889862Sobrien      return reloc_class_relative;
519989862Sobrien    case R_ALPHA_JMP_SLOT:
520089862Sobrien      return reloc_class_plt;
520189862Sobrien    case R_ALPHA_COPY:
520289862Sobrien      return reloc_class_copy;
520389862Sobrien    default:
520489862Sobrien      return reloc_class_normal;
520533965Sjdp    }
520633965Sjdp}
520733965Sjdp
5208218822Sdimstatic const struct bfd_elf_special_section elf64_alpha_special_sections[] =
5209130570Sobrien{
5210218822Sdim  { STRING_COMMA_LEN (".sbss"),  -2, SHT_NOBITS,   SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL },
5211218822Sdim  { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_ALPHA_GPREL },
5212218822Sdim  { NULL,                     0,  0, 0,            0 }
5213130570Sobrien};
5214130570Sobrien
521533965Sjdp/* ECOFF swapping routines.  These are used when dealing with the
521633965Sjdp   .mdebug section, which is in the ECOFF debugging format.  Copied
521777303Sobrien   from elf32-mips.c.  */
521833965Sjdpstatic const struct ecoff_debug_swap
521933965Sjdpelf64_alpha_ecoff_debug_swap =
522033965Sjdp{
522133965Sjdp  /* Symbol table magic number.  */
522233965Sjdp  magicSym2,
522333965Sjdp  /* Alignment of debugging information.  E.g., 4.  */
522433965Sjdp  8,
522533965Sjdp  /* Sizes of external symbolic information.  */
522633965Sjdp  sizeof (struct hdr_ext),
522733965Sjdp  sizeof (struct dnr_ext),
522833965Sjdp  sizeof (struct pdr_ext),
522933965Sjdp  sizeof (struct sym_ext),
523033965Sjdp  sizeof (struct opt_ext),
523133965Sjdp  sizeof (struct fdr_ext),
523233965Sjdp  sizeof (struct rfd_ext),
523333965Sjdp  sizeof (struct ext_ext),
523433965Sjdp  /* Functions to swap in external symbolic data.  */
523533965Sjdp  ecoff_swap_hdr_in,
523633965Sjdp  ecoff_swap_dnr_in,
523733965Sjdp  ecoff_swap_pdr_in,
523833965Sjdp  ecoff_swap_sym_in,
523933965Sjdp  ecoff_swap_opt_in,
524033965Sjdp  ecoff_swap_fdr_in,
524133965Sjdp  ecoff_swap_rfd_in,
524233965Sjdp  ecoff_swap_ext_in,
524333965Sjdp  _bfd_ecoff_swap_tir_in,
524433965Sjdp  _bfd_ecoff_swap_rndx_in,
524533965Sjdp  /* Functions to swap out external symbolic data.  */
524633965Sjdp  ecoff_swap_hdr_out,
524733965Sjdp  ecoff_swap_dnr_out,
524833965Sjdp  ecoff_swap_pdr_out,
524933965Sjdp  ecoff_swap_sym_out,
525033965Sjdp  ecoff_swap_opt_out,
525133965Sjdp  ecoff_swap_fdr_out,
525233965Sjdp  ecoff_swap_rfd_out,
525333965Sjdp  ecoff_swap_ext_out,
525433965Sjdp  _bfd_ecoff_swap_tir_out,
525533965Sjdp  _bfd_ecoff_swap_rndx_out,
525633965Sjdp  /* Function to read in symbolic data.  */
525733965Sjdp  elf64_alpha_read_ecoff_info
525833965Sjdp};
525933965Sjdp
526077303Sobrien/* Use a non-standard hash bucket size of 8.  */
526177303Sobrien
5262104841Sobrienstatic const struct elf_size_info alpha_elf_size_info =
526377303Sobrien{
526477303Sobrien  sizeof (Elf64_External_Ehdr),
526577303Sobrien  sizeof (Elf64_External_Phdr),
526677303Sobrien  sizeof (Elf64_External_Shdr),
526777303Sobrien  sizeof (Elf64_External_Rel),
526877303Sobrien  sizeof (Elf64_External_Rela),
526977303Sobrien  sizeof (Elf64_External_Sym),
527077303Sobrien  sizeof (Elf64_External_Dyn),
527177303Sobrien  sizeof (Elf_External_Note),
527277303Sobrien  8,
527377303Sobrien  1,
5274130570Sobrien  64, 3,
527577303Sobrien  ELFCLASS64, EV_CURRENT,
527677303Sobrien  bfd_elf64_write_out_phdrs,
527777303Sobrien  bfd_elf64_write_shdrs_and_ehdr,
527877303Sobrien  bfd_elf64_write_relocs,
5279104841Sobrien  bfd_elf64_swap_symbol_in,
528077303Sobrien  bfd_elf64_swap_symbol_out,
528177303Sobrien  bfd_elf64_slurp_reloc_table,
528277303Sobrien  bfd_elf64_slurp_symbol_table,
528377303Sobrien  bfd_elf64_swap_dyn_in,
528477303Sobrien  bfd_elf64_swap_dyn_out,
5285130570Sobrien  bfd_elf64_swap_reloc_in,
5286130570Sobrien  bfd_elf64_swap_reloc_out,
5287130570Sobrien  bfd_elf64_swap_reloca_in,
5288130570Sobrien  bfd_elf64_swap_reloca_out
528977303Sobrien};
529077303Sobrien
529133965Sjdp#define TARGET_LITTLE_SYM	bfd_elf64_alpha_vec
529233965Sjdp#define TARGET_LITTLE_NAME	"elf64-alpha"
529333965Sjdp#define ELF_ARCH		bfd_arch_alpha
529478833Sobrien#define ELF_MACHINE_CODE	EM_ALPHA
529578833Sobrien#define ELF_MAXPAGESIZE	0x10000
5296218822Sdim#define ELF_COMMONPAGESIZE	0x2000
529733965Sjdp
529833965Sjdp#define bfd_elf64_bfd_link_hash_table_create \
529933965Sjdp  elf64_alpha_bfd_link_hash_table_create
530033965Sjdp
530133965Sjdp#define bfd_elf64_bfd_reloc_type_lookup \
530233965Sjdp  elf64_alpha_bfd_reloc_type_lookup
5303218822Sdim#define bfd_elf64_bfd_reloc_name_lookup \
5304218822Sdim  elf64_alpha_bfd_reloc_name_lookup
530533965Sjdp#define elf_info_to_howto \
530633965Sjdp  elf64_alpha_info_to_howto
530733965Sjdp
530833965Sjdp#define bfd_elf64_mkobject \
530933965Sjdp  elf64_alpha_mkobject
531033965Sjdp#define elf_backend_object_p \
531133965Sjdp  elf64_alpha_object_p
531233965Sjdp
531333965Sjdp#define elf_backend_section_from_shdr \
531433965Sjdp  elf64_alpha_section_from_shdr
531589862Sobrien#define elf_backend_section_flags \
531689862Sobrien  elf64_alpha_section_flags
531733965Sjdp#define elf_backend_fake_sections \
531833965Sjdp  elf64_alpha_fake_sections
531933965Sjdp
532033965Sjdp#define bfd_elf64_bfd_is_local_label_name \
532133965Sjdp  elf64_alpha_is_local_label_name
532233965Sjdp#define bfd_elf64_find_nearest_line \
532333965Sjdp  elf64_alpha_find_nearest_line
532460510Sobrien#define bfd_elf64_bfd_relax_section \
532560510Sobrien  elf64_alpha_relax_section
532633965Sjdp
532760510Sobrien#define elf_backend_add_symbol_hook \
532860510Sobrien  elf64_alpha_add_symbol_hook
5329218822Sdim#define elf_backend_relocs_compatible \
5330218822Sdim  _bfd_elf_relocs_compatible
533133965Sjdp#define elf_backend_check_relocs \
533233965Sjdp  elf64_alpha_check_relocs
533333965Sjdp#define elf_backend_create_dynamic_sections \
533433965Sjdp  elf64_alpha_create_dynamic_sections
533533965Sjdp#define elf_backend_adjust_dynamic_symbol \
533633965Sjdp  elf64_alpha_adjust_dynamic_symbol
5337218822Sdim#define elf_backend_merge_symbol_attribute \
5338218822Sdim  elf64_alpha_merge_symbol_attribute
533933965Sjdp#define elf_backend_always_size_sections \
534033965Sjdp  elf64_alpha_always_size_sections
534133965Sjdp#define elf_backend_size_dynamic_sections \
534233965Sjdp  elf64_alpha_size_dynamic_sections
5343218822Sdim#define elf_backend_omit_section_dynsym \
5344218822Sdim  ((bfd_boolean (*) (bfd *, struct bfd_link_info *, asection *)) bfd_true)
534533965Sjdp#define elf_backend_relocate_section \
534633965Sjdp  elf64_alpha_relocate_section
534733965Sjdp#define elf_backend_finish_dynamic_symbol \
534833965Sjdp  elf64_alpha_finish_dynamic_symbol
534933965Sjdp#define elf_backend_finish_dynamic_sections \
535033965Sjdp  elf64_alpha_finish_dynamic_sections
535133965Sjdp#define bfd_elf64_bfd_final_link \
535233965Sjdp  elf64_alpha_final_link
535389862Sobrien#define elf_backend_reloc_type_class \
535489862Sobrien  elf64_alpha_reloc_type_class
535533965Sjdp
535633965Sjdp#define elf_backend_ecoff_debug_swap \
535733965Sjdp  &elf64_alpha_ecoff_debug_swap
535833965Sjdp
535977303Sobrien#define elf_backend_size_info \
536077303Sobrien  alpha_elf_size_info
536177303Sobrien
5362130570Sobrien#define elf_backend_special_sections \
5363130570Sobrien  elf64_alpha_special_sections
5364130570Sobrien
536577303Sobrien/* A few constants that determine how the .plt section is set up.  */
536633965Sjdp#define elf_backend_want_got_plt 0
536733965Sjdp#define elf_backend_plt_readonly 0
536833965Sjdp#define elf_backend_want_plt_sym 1
536960510Sobrien#define elf_backend_got_header_size 0
537033965Sjdp
537133965Sjdp#include "elf64-target.h"
5372130570Sobrien
5373130570Sobrien/* FreeBSD support.  */
5374130570Sobrien
5375130570Sobrien#undef TARGET_LITTLE_SYM
5376130570Sobrien#define TARGET_LITTLE_SYM	bfd_elf64_alpha_freebsd_vec
5377130570Sobrien#undef TARGET_LITTLE_NAME
5378130570Sobrien#define TARGET_LITTLE_NAME	"elf64-alpha-freebsd"
5379218822Sdim#undef	ELF_OSABI
5380218822Sdim#define	ELF_OSABI		ELFOSABI_FREEBSD
5381130570Sobrien
5382130570Sobrien/* The kernel recognizes executables as valid only if they carry a
5383130570Sobrien   "FreeBSD" label in the ELF header.  So we put this label on all
5384130570Sobrien   executables and (for simplicity) also all other object files.  */
5385130570Sobrien
5386130570Sobrienstatic void
5387218822Sdimelf64_alpha_fbsd_post_process_headers (bfd * abfd,
5388218822Sdim	struct bfd_link_info * link_info ATTRIBUTE_UNUSED)
5389130570Sobrien{
5390130570Sobrien  Elf_Internal_Ehdr * i_ehdrp;	/* ELF file header, internal form.  */
5391130570Sobrien
5392130570Sobrien  i_ehdrp = elf_elfheader (abfd);
5393130570Sobrien
5394130570Sobrien  /* Put an ABI label supported by FreeBSD >= 4.1.  */
5395218822Sdim  i_ehdrp->e_ident[EI_OSABI] = get_elf_backend_data (abfd)->elf_osabi;
5396130570Sobrien#ifdef OLD_FREEBSD_ABI_LABEL
5397130570Sobrien  /* The ABI label supported by FreeBSD <= 4.0 is quite nonstandard.  */
5398130570Sobrien  memcpy (&i_ehdrp->e_ident[EI_ABIVERSION], "FreeBSD", 8);
5399130570Sobrien#endif
5400130570Sobrien}
5401130570Sobrien
5402130570Sobrien#undef elf_backend_post_process_headers
5403130570Sobrien#define elf_backend_post_process_headers \
5404130570Sobrien  elf64_alpha_fbsd_post_process_headers
5405130570Sobrien
5406130570Sobrien#undef  elf64_bed
5407130570Sobrien#define elf64_bed elf64_alpha_fbsd_bed
5408130570Sobrien
5409130570Sobrien#include "elf64-target.h"
5410