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