185815Sobrien/* X86-64 specific support for 64-bit ELF 2218822Sdim Copyright 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 3218822Sdim Free Software Foundation, Inc. 485815Sobrien Contributed by Jan Hubicka <jh@suse.cz>. 585815Sobrien 6130561Sobrien This file is part of BFD, the Binary File Descriptor library. 785815Sobrien 8130561Sobrien This program is free software; you can redistribute it and/or modify 9130561Sobrien it under the terms of the GNU General Public License as published by 10130561Sobrien the Free Software Foundation; either version 2 of the License, or 11130561Sobrien (at your option) any later version. 1285815Sobrien 13130561Sobrien This program is distributed in the hope that it will be useful, 14130561Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 15130561Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16130561Sobrien GNU General Public License for more details. 1785815Sobrien 18130561Sobrien You should have received a copy of the GNU General Public License 19130561Sobrien along with this program; if not, write to the Free Software 20218822Sdim Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2185815Sobrien 22218822Sdim#include "sysdep.h" 2385815Sobrien#include "bfd.h" 2499461Sobrien#include "bfdlink.h" 2585815Sobrien#include "libbfd.h" 2685815Sobrien#include "elf-bfd.h" 2785815Sobrien 2885815Sobrien#include "elf/x86-64.h" 2985815Sobrien 3085815Sobrien/* In case we're on a 32-bit machine, construct a 64-bit "-1" value. */ 3185815Sobrien#define MINUS_ONE (~ (bfd_vma) 0) 3285815Sobrien 3385815Sobrien/* The relocation "howto" table. Order of fields: 34218822Sdim type, rightshift, size, bitsize, pc_relative, bitpos, complain_on_overflow, 35218822Sdim special_function, name, partial_inplace, src_mask, dst_mask, pcrel_offset. */ 3685815Sobrienstatic reloc_howto_type x86_64_elf_howto_table[] = 3785815Sobrien{ 38130561Sobrien HOWTO(R_X86_64_NONE, 0, 0, 0, FALSE, 0, complain_overflow_dont, 39130561Sobrien bfd_elf_generic_reloc, "R_X86_64_NONE", FALSE, 0x00000000, 0x00000000, 40130561Sobrien FALSE), 41130561Sobrien HOWTO(R_X86_64_64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, 42130561Sobrien bfd_elf_generic_reloc, "R_X86_64_64", FALSE, MINUS_ONE, MINUS_ONE, 43130561Sobrien FALSE), 44130561Sobrien HOWTO(R_X86_64_PC32, 0, 2, 32, TRUE, 0, complain_overflow_signed, 45130561Sobrien bfd_elf_generic_reloc, "R_X86_64_PC32", FALSE, 0xffffffff, 0xffffffff, 46130561Sobrien TRUE), 47130561Sobrien HOWTO(R_X86_64_GOT32, 0, 2, 32, FALSE, 0, complain_overflow_signed, 48130561Sobrien bfd_elf_generic_reloc, "R_X86_64_GOT32", FALSE, 0xffffffff, 0xffffffff, 49130561Sobrien FALSE), 50130561Sobrien HOWTO(R_X86_64_PLT32, 0, 2, 32, TRUE, 0, complain_overflow_signed, 51130561Sobrien bfd_elf_generic_reloc, "R_X86_64_PLT32", FALSE, 0xffffffff, 0xffffffff, 52130561Sobrien TRUE), 53130561Sobrien HOWTO(R_X86_64_COPY, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 54130561Sobrien bfd_elf_generic_reloc, "R_X86_64_COPY", FALSE, 0xffffffff, 0xffffffff, 55130561Sobrien FALSE), 56130561Sobrien HOWTO(R_X86_64_GLOB_DAT, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, 57130561Sobrien bfd_elf_generic_reloc, "R_X86_64_GLOB_DAT", FALSE, MINUS_ONE, 58130561Sobrien MINUS_ONE, FALSE), 59130561Sobrien HOWTO(R_X86_64_JUMP_SLOT, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, 60130561Sobrien bfd_elf_generic_reloc, "R_X86_64_JUMP_SLOT", FALSE, MINUS_ONE, 61130561Sobrien MINUS_ONE, FALSE), 62130561Sobrien HOWTO(R_X86_64_RELATIVE, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, 63130561Sobrien bfd_elf_generic_reloc, "R_X86_64_RELATIVE", FALSE, MINUS_ONE, 64130561Sobrien MINUS_ONE, FALSE), 65130561Sobrien HOWTO(R_X86_64_GOTPCREL, 0, 2, 32, TRUE, 0, complain_overflow_signed, 66130561Sobrien bfd_elf_generic_reloc, "R_X86_64_GOTPCREL", FALSE, 0xffffffff, 67130561Sobrien 0xffffffff, TRUE), 68130561Sobrien HOWTO(R_X86_64_32, 0, 2, 32, FALSE, 0, complain_overflow_unsigned, 69130561Sobrien bfd_elf_generic_reloc, "R_X86_64_32", FALSE, 0xffffffff, 0xffffffff, 70130561Sobrien FALSE), 71130561Sobrien HOWTO(R_X86_64_32S, 0, 2, 32, FALSE, 0, complain_overflow_signed, 72130561Sobrien bfd_elf_generic_reloc, "R_X86_64_32S", FALSE, 0xffffffff, 0xffffffff, 73130561Sobrien FALSE), 74130561Sobrien HOWTO(R_X86_64_16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 75130561Sobrien bfd_elf_generic_reloc, "R_X86_64_16", FALSE, 0xffff, 0xffff, FALSE), 76130561Sobrien HOWTO(R_X86_64_PC16,0, 1, 16, TRUE, 0, complain_overflow_bitfield, 77130561Sobrien bfd_elf_generic_reloc, "R_X86_64_PC16", FALSE, 0xffff, 0xffff, TRUE), 78218822Sdim HOWTO(R_X86_64_8, 0, 0, 8, FALSE, 0, complain_overflow_bitfield, 79130561Sobrien bfd_elf_generic_reloc, "R_X86_64_8", FALSE, 0xff, 0xff, FALSE), 80130561Sobrien HOWTO(R_X86_64_PC8, 0, 0, 8, TRUE, 0, complain_overflow_signed, 81130561Sobrien bfd_elf_generic_reloc, "R_X86_64_PC8", FALSE, 0xff, 0xff, TRUE), 82130561Sobrien HOWTO(R_X86_64_DTPMOD64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, 83130561Sobrien bfd_elf_generic_reloc, "R_X86_64_DTPMOD64", FALSE, MINUS_ONE, 84130561Sobrien MINUS_ONE, FALSE), 85130561Sobrien HOWTO(R_X86_64_DTPOFF64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, 86130561Sobrien bfd_elf_generic_reloc, "R_X86_64_DTPOFF64", FALSE, MINUS_ONE, 87130561Sobrien MINUS_ONE, FALSE), 88130561Sobrien HOWTO(R_X86_64_TPOFF64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, 89130561Sobrien bfd_elf_generic_reloc, "R_X86_64_TPOFF64", FALSE, MINUS_ONE, 90130561Sobrien MINUS_ONE, FALSE), 91130561Sobrien HOWTO(R_X86_64_TLSGD, 0, 2, 32, TRUE, 0, complain_overflow_signed, 92130561Sobrien bfd_elf_generic_reloc, "R_X86_64_TLSGD", FALSE, 0xffffffff, 93130561Sobrien 0xffffffff, TRUE), 94130561Sobrien HOWTO(R_X86_64_TLSLD, 0, 2, 32, TRUE, 0, complain_overflow_signed, 95130561Sobrien bfd_elf_generic_reloc, "R_X86_64_TLSLD", FALSE, 0xffffffff, 96130561Sobrien 0xffffffff, TRUE), 97218822Sdim HOWTO(R_X86_64_DTPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_signed, 98130561Sobrien bfd_elf_generic_reloc, "R_X86_64_DTPOFF32", FALSE, 0xffffffff, 99130561Sobrien 0xffffffff, FALSE), 100130561Sobrien HOWTO(R_X86_64_GOTTPOFF, 0, 2, 32, TRUE, 0, complain_overflow_signed, 101130561Sobrien bfd_elf_generic_reloc, "R_X86_64_GOTTPOFF", FALSE, 0xffffffff, 102130561Sobrien 0xffffffff, TRUE), 103130561Sobrien HOWTO(R_X86_64_TPOFF32, 0, 2, 32, FALSE, 0, complain_overflow_signed, 104130561Sobrien bfd_elf_generic_reloc, "R_X86_64_TPOFF32", FALSE, 0xffffffff, 105130561Sobrien 0xffffffff, FALSE), 106218822Sdim HOWTO(R_X86_64_PC64, 0, 4, 64, TRUE, 0, complain_overflow_bitfield, 107218822Sdim bfd_elf_generic_reloc, "R_X86_64_PC64", FALSE, MINUS_ONE, MINUS_ONE, 108218822Sdim TRUE), 109218822Sdim HOWTO(R_X86_64_GOTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_bitfield, 110218822Sdim bfd_elf_generic_reloc, "R_X86_64_GOTOFF64", 111218822Sdim FALSE, MINUS_ONE, MINUS_ONE, FALSE), 112218822Sdim HOWTO(R_X86_64_GOTPC32, 0, 2, 32, TRUE, 0, complain_overflow_signed, 113218822Sdim bfd_elf_generic_reloc, "R_X86_64_GOTPC32", 114218822Sdim FALSE, 0xffffffff, 0xffffffff, TRUE), 115218822Sdim HOWTO(R_X86_64_GOT64, 0, 4, 64, FALSE, 0, complain_overflow_signed, 116218822Sdim bfd_elf_generic_reloc, "R_X86_64_GOT64", FALSE, MINUS_ONE, MINUS_ONE, 117218822Sdim FALSE), 118218822Sdim HOWTO(R_X86_64_GOTPCREL64, 0, 4, 64, TRUE, 0, complain_overflow_signed, 119218822Sdim bfd_elf_generic_reloc, "R_X86_64_GOTPCREL64", FALSE, MINUS_ONE, 120218822Sdim MINUS_ONE, TRUE), 121218822Sdim HOWTO(R_X86_64_GOTPC64, 0, 4, 64, TRUE, 0, complain_overflow_signed, 122218822Sdim bfd_elf_generic_reloc, "R_X86_64_GOTPC64", 123218822Sdim FALSE, MINUS_ONE, MINUS_ONE, TRUE), 124218822Sdim HOWTO(R_X86_64_GOTPLT64, 0, 4, 64, FALSE, 0, complain_overflow_signed, 125218822Sdim bfd_elf_generic_reloc, "R_X86_64_GOTPLT64", FALSE, MINUS_ONE, 126218822Sdim MINUS_ONE, FALSE), 127218822Sdim HOWTO(R_X86_64_PLTOFF64, 0, 4, 64, FALSE, 0, complain_overflow_signed, 128218822Sdim bfd_elf_generic_reloc, "R_X86_64_PLTOFF64", FALSE, MINUS_ONE, 129218822Sdim MINUS_ONE, FALSE), 130218822Sdim EMPTY_HOWTO (32), 131218822Sdim EMPTY_HOWTO (33), 132218822Sdim HOWTO(R_X86_64_GOTPC32_TLSDESC, 0, 2, 32, TRUE, 0, 133218822Sdim complain_overflow_bitfield, bfd_elf_generic_reloc, 134218822Sdim "R_X86_64_GOTPC32_TLSDESC", 135218822Sdim FALSE, 0xffffffff, 0xffffffff, TRUE), 136218822Sdim HOWTO(R_X86_64_TLSDESC_CALL, 0, 0, 0, FALSE, 0, 137218822Sdim complain_overflow_dont, bfd_elf_generic_reloc, 138218822Sdim "R_X86_64_TLSDESC_CALL", 139218822Sdim FALSE, 0, 0, FALSE), 140218822Sdim HOWTO(R_X86_64_TLSDESC, 0, 4, 64, FALSE, 0, 141218822Sdim complain_overflow_bitfield, bfd_elf_generic_reloc, 142218822Sdim "R_X86_64_TLSDESC", 143218822Sdim FALSE, MINUS_ONE, MINUS_ONE, FALSE), 14489857Sobrien 145218822Sdim /* We have a gap in the reloc numbers here. 146218822Sdim R_X86_64_standard counts the number up to this point, and 147218822Sdim R_X86_64_vt_offset is the value to subtract from a reloc type of 148218822Sdim R_X86_64_GNU_VT* to form an index into this table. */ 149218822Sdim#define R_X86_64_standard (R_X86_64_TLSDESC + 1) 150218822Sdim#define R_X86_64_vt_offset (R_X86_64_GNU_VTINHERIT - R_X86_64_standard) 151218822Sdim 15289857Sobrien/* GNU extension to record C++ vtable hierarchy. */ 153130561Sobrien HOWTO (R_X86_64_GNU_VTINHERIT, 0, 4, 0, FALSE, 0, complain_overflow_dont, 154130561Sobrien NULL, "R_X86_64_GNU_VTINHERIT", FALSE, 0, 0, FALSE), 15589857Sobrien 15689857Sobrien/* GNU extension to record C++ vtable member usage. */ 157130561Sobrien HOWTO (R_X86_64_GNU_VTENTRY, 0, 4, 0, FALSE, 0, complain_overflow_dont, 158130561Sobrien _bfd_elf_rel_vtable_reloc_fn, "R_X86_64_GNU_VTENTRY", FALSE, 0, 0, 159130561Sobrien FALSE) 16085815Sobrien}; 16185815Sobrien 16285815Sobrien/* Map BFD relocs to the x86_64 elf relocs. */ 16385815Sobrienstruct elf_reloc_map 16485815Sobrien{ 16585815Sobrien bfd_reloc_code_real_type bfd_reloc_val; 16685815Sobrien unsigned char elf_reloc_val; 16785815Sobrien}; 16885815Sobrien 16989857Sobrienstatic const struct elf_reloc_map x86_64_reloc_map[] = 17085815Sobrien{ 17185815Sobrien { BFD_RELOC_NONE, R_X86_64_NONE, }, 17285815Sobrien { BFD_RELOC_64, R_X86_64_64, }, 17385815Sobrien { BFD_RELOC_32_PCREL, R_X86_64_PC32, }, 17485815Sobrien { BFD_RELOC_X86_64_GOT32, R_X86_64_GOT32,}, 17585815Sobrien { BFD_RELOC_X86_64_PLT32, R_X86_64_PLT32,}, 17685815Sobrien { BFD_RELOC_X86_64_COPY, R_X86_64_COPY, }, 17785815Sobrien { BFD_RELOC_X86_64_GLOB_DAT, R_X86_64_GLOB_DAT, }, 17885815Sobrien { BFD_RELOC_X86_64_JUMP_SLOT, R_X86_64_JUMP_SLOT, }, 17985815Sobrien { BFD_RELOC_X86_64_RELATIVE, R_X86_64_RELATIVE, }, 18085815Sobrien { BFD_RELOC_X86_64_GOTPCREL, R_X86_64_GOTPCREL, }, 18185815Sobrien { BFD_RELOC_32, R_X86_64_32, }, 18285815Sobrien { BFD_RELOC_X86_64_32S, R_X86_64_32S, }, 18385815Sobrien { BFD_RELOC_16, R_X86_64_16, }, 18485815Sobrien { BFD_RELOC_16_PCREL, R_X86_64_PC16, }, 18585815Sobrien { BFD_RELOC_8, R_X86_64_8, }, 18685815Sobrien { BFD_RELOC_8_PCREL, R_X86_64_PC8, }, 187130561Sobrien { BFD_RELOC_X86_64_DTPMOD64, R_X86_64_DTPMOD64, }, 188130561Sobrien { BFD_RELOC_X86_64_DTPOFF64, R_X86_64_DTPOFF64, }, 189130561Sobrien { BFD_RELOC_X86_64_TPOFF64, R_X86_64_TPOFF64, }, 190130561Sobrien { BFD_RELOC_X86_64_TLSGD, R_X86_64_TLSGD, }, 191130561Sobrien { BFD_RELOC_X86_64_TLSLD, R_X86_64_TLSLD, }, 192130561Sobrien { BFD_RELOC_X86_64_DTPOFF32, R_X86_64_DTPOFF32, }, 193130561Sobrien { BFD_RELOC_X86_64_GOTTPOFF, R_X86_64_GOTTPOFF, }, 194130561Sobrien { BFD_RELOC_X86_64_TPOFF32, R_X86_64_TPOFF32, }, 195218822Sdim { BFD_RELOC_64_PCREL, R_X86_64_PC64, }, 196218822Sdim { BFD_RELOC_X86_64_GOTOFF64, R_X86_64_GOTOFF64, }, 197218822Sdim { BFD_RELOC_X86_64_GOTPC32, R_X86_64_GOTPC32, }, 198218822Sdim { BFD_RELOC_X86_64_GOT64, R_X86_64_GOT64, }, 199218822Sdim { BFD_RELOC_X86_64_GOTPCREL64,R_X86_64_GOTPCREL64, }, 200218822Sdim { BFD_RELOC_X86_64_GOTPC64, R_X86_64_GOTPC64, }, 201218822Sdim { BFD_RELOC_X86_64_GOTPLT64, R_X86_64_GOTPLT64, }, 202218822Sdim { BFD_RELOC_X86_64_PLTOFF64, R_X86_64_PLTOFF64, }, 203218822Sdim { BFD_RELOC_X86_64_GOTPC32_TLSDESC, R_X86_64_GOTPC32_TLSDESC, }, 204218822Sdim { BFD_RELOC_X86_64_TLSDESC_CALL, R_X86_64_TLSDESC_CALL, }, 205218822Sdim { BFD_RELOC_X86_64_TLSDESC, R_X86_64_TLSDESC, }, 20689857Sobrien { BFD_RELOC_VTABLE_INHERIT, R_X86_64_GNU_VTINHERIT, }, 20789857Sobrien { BFD_RELOC_VTABLE_ENTRY, R_X86_64_GNU_VTENTRY, }, 20885815Sobrien}; 20985815Sobrien 210218822Sdimstatic reloc_howto_type * 211218822Sdimelf64_x86_64_rtype_to_howto (bfd *abfd, unsigned r_type) 212218822Sdim{ 213218822Sdim unsigned i; 21485815Sobrien 215218822Sdim if (r_type < (unsigned int) R_X86_64_GNU_VTINHERIT 216218822Sdim || r_type >= (unsigned int) R_X86_64_max) 217218822Sdim { 218218822Sdim if (r_type >= (unsigned int) R_X86_64_standard) 219218822Sdim { 220218822Sdim (*_bfd_error_handler) (_("%B: invalid relocation type %d"), 221218822Sdim abfd, (int) r_type); 222218822Sdim r_type = R_X86_64_NONE; 223218822Sdim } 224218822Sdim i = r_type; 225218822Sdim } 226218822Sdim else 227218822Sdim i = r_type - (unsigned int) R_X86_64_vt_offset; 228218822Sdim BFD_ASSERT (x86_64_elf_howto_table[i].type == r_type); 229218822Sdim return &x86_64_elf_howto_table[i]; 230218822Sdim} 231218822Sdim 23285815Sobrien/* Given a BFD reloc type, return a HOWTO structure. */ 23385815Sobrienstatic reloc_howto_type * 234218822Sdimelf64_x86_64_reloc_type_lookup (bfd *abfd, 235130561Sobrien bfd_reloc_code_real_type code) 23685815Sobrien{ 23785815Sobrien unsigned int i; 238130561Sobrien 23985815Sobrien for (i = 0; i < sizeof (x86_64_reloc_map) / sizeof (struct elf_reloc_map); 24085815Sobrien i++) 24185815Sobrien { 24285815Sobrien if (x86_64_reloc_map[i].bfd_reloc_val == code) 243218822Sdim return elf64_x86_64_rtype_to_howto (abfd, 244218822Sdim x86_64_reloc_map[i].elf_reloc_val); 24585815Sobrien } 24685815Sobrien return 0; 24785815Sobrien} 24885815Sobrien 249218822Sdimstatic reloc_howto_type * 250218822Sdimelf64_x86_64_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 251218822Sdim const char *r_name) 252218822Sdim{ 253218822Sdim unsigned int i; 254218822Sdim 255218822Sdim for (i = 0; 256218822Sdim i < (sizeof (x86_64_elf_howto_table) 257218822Sdim / sizeof (x86_64_elf_howto_table[0])); 258218822Sdim i++) 259218822Sdim if (x86_64_elf_howto_table[i].name != NULL 260218822Sdim && strcasecmp (x86_64_elf_howto_table[i].name, r_name) == 0) 261218822Sdim return &x86_64_elf_howto_table[i]; 262218822Sdim 263218822Sdim return NULL; 264218822Sdim} 265218822Sdim 26685815Sobrien/* Given an x86_64 ELF reloc type, fill in an arelent structure. */ 26785815Sobrien 26885815Sobrienstatic void 269130561Sobrienelf64_x86_64_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, 270130561Sobrien Elf_Internal_Rela *dst) 27185815Sobrien{ 272218822Sdim unsigned r_type; 27385815Sobrien 27485815Sobrien r_type = ELF64_R_TYPE (dst->r_info); 275218822Sdim cache_ptr->howto = elf64_x86_64_rtype_to_howto (abfd, r_type); 27685815Sobrien BFD_ASSERT (r_type == cache_ptr->howto->type); 27785815Sobrien} 27885815Sobrien 279104834Sobrien/* Support for core dump NOTE sections. */ 280130561Sobrienstatic bfd_boolean 281130561Sobrienelf64_x86_64_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) 282104834Sobrien{ 283104834Sobrien int offset; 284218822Sdim size_t size; 285104834Sobrien 286104834Sobrien switch (note->descsz) 287104834Sobrien { 288104834Sobrien default: 289130561Sobrien return FALSE; 290104834Sobrien 291104834Sobrien case 336: /* sizeof(istruct elf_prstatus) on Linux/x86_64 */ 292104834Sobrien /* pr_cursig */ 293104834Sobrien elf_tdata (abfd)->core_signal 294104834Sobrien = bfd_get_16 (abfd, note->descdata + 12); 295104834Sobrien 296104834Sobrien /* pr_pid */ 297104834Sobrien elf_tdata (abfd)->core_pid 298104834Sobrien = bfd_get_32 (abfd, note->descdata + 32); 299104834Sobrien 300104834Sobrien /* pr_reg */ 301104834Sobrien offset = 112; 302218822Sdim size = 216; 303104834Sobrien 304104834Sobrien break; 305104834Sobrien } 306104834Sobrien 307104834Sobrien /* Make a ".reg/999" section. */ 308104834Sobrien return _bfd_elfcore_make_pseudosection (abfd, ".reg", 309218822Sdim size, note->descpos + offset); 310104834Sobrien} 311104834Sobrien 312130561Sobrienstatic bfd_boolean 313130561Sobrienelf64_x86_64_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) 314104834Sobrien{ 315104834Sobrien switch (note->descsz) 316104834Sobrien { 317104834Sobrien default: 318130561Sobrien return FALSE; 319104834Sobrien 320104834Sobrien case 136: /* sizeof(struct elf_prpsinfo) on Linux/x86_64 */ 321104834Sobrien elf_tdata (abfd)->core_program 322104834Sobrien = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16); 323104834Sobrien elf_tdata (abfd)->core_command 324104834Sobrien = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80); 325104834Sobrien } 326104834Sobrien 327104834Sobrien /* Note that for some reason, a spurious space is tacked 328104834Sobrien onto the end of the args in some (at least one anyway) 329104834Sobrien implementations, so strip it off if it exists. */ 330104834Sobrien 331104834Sobrien { 332104834Sobrien char *command = elf_tdata (abfd)->core_command; 333104834Sobrien int n = strlen (command); 334104834Sobrien 335104834Sobrien if (0 < n && command[n - 1] == ' ') 336104834Sobrien command[n - 1] = '\0'; 337104834Sobrien } 338104834Sobrien 339130561Sobrien return TRUE; 340104834Sobrien} 341104834Sobrien 34285815Sobrien/* Functions for the x86-64 ELF linker. */ 34385815Sobrien 34485815Sobrien/* The name of the dynamic interpreter. This is put in the .interp 34585815Sobrien section. */ 34685815Sobrien 34785815Sobrien#define ELF_DYNAMIC_INTERPRETER "/lib/ld64.so.1" 34885815Sobrien 349130561Sobrien/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid 350130561Sobrien copying dynamic variables from a shared lib into an app's dynbss 351130561Sobrien section, and instead use a dynamic relocation to point into the 352130561Sobrien shared lib. */ 353130561Sobrien#define ELIMINATE_COPY_RELOCS 1 354130561Sobrien 35585815Sobrien/* The size in bytes of an entry in the global offset table. */ 35685815Sobrien 35785815Sobrien#define GOT_ENTRY_SIZE 8 35885815Sobrien 35985815Sobrien/* The size in bytes of an entry in the procedure linkage table. */ 36085815Sobrien 36185815Sobrien#define PLT_ENTRY_SIZE 16 36285815Sobrien 36385815Sobrien/* The first entry in a procedure linkage table looks like this. See the 36485815Sobrien SVR4 ABI i386 supplement and the x86-64 ABI to see how this works. */ 36585815Sobrien 36685815Sobrienstatic const bfd_byte elf64_x86_64_plt0_entry[PLT_ENTRY_SIZE] = 36785815Sobrien{ 36885815Sobrien 0xff, 0x35, 8, 0, 0, 0, /* pushq GOT+8(%rip) */ 36985815Sobrien 0xff, 0x25, 16, 0, 0, 0, /* jmpq *GOT+16(%rip) */ 370218822Sdim 0x0f, 0x1f, 0x40, 0x00 /* nopl 0(%rax) */ 37185815Sobrien}; 37285815Sobrien 37385815Sobrien/* Subsequent entries in a procedure linkage table look like this. */ 37485815Sobrien 37585815Sobrienstatic const bfd_byte elf64_x86_64_plt_entry[PLT_ENTRY_SIZE] = 37685815Sobrien{ 37785815Sobrien 0xff, 0x25, /* jmpq *name@GOTPC(%rip) */ 37885815Sobrien 0, 0, 0, 0, /* replaced with offset to this symbol in .got. */ 37985815Sobrien 0x68, /* pushq immediate */ 38085815Sobrien 0, 0, 0, 0, /* replaced with index into relocation table. */ 38185815Sobrien 0xe9, /* jmp relative */ 38285815Sobrien 0, 0, 0, 0 /* replaced with offset to start of .plt0. */ 38385815Sobrien}; 38485815Sobrien 38585815Sobrien/* The x86-64 linker needs to keep track of the number of relocs that 38699461Sobrien it decides to copy as dynamic relocs in check_relocs for each symbol. 38799461Sobrien This is so that it can later discard them if they are found to be 38899461Sobrien unnecessary. We store the information in a field extending the 38999461Sobrien regular ELF linker hash table. */ 39085815Sobrien 39199461Sobrienstruct elf64_x86_64_dyn_relocs 39285815Sobrien{ 39385815Sobrien /* Next section. */ 39499461Sobrien struct elf64_x86_64_dyn_relocs *next; 39599461Sobrien 39699461Sobrien /* The input section of the reloc. */ 39799461Sobrien asection *sec; 39899461Sobrien 39999461Sobrien /* Total number of relocs copied for the input section. */ 40085815Sobrien bfd_size_type count; 40199461Sobrien 40299461Sobrien /* Number of pc-relative relocs copied for the input section. */ 40399461Sobrien bfd_size_type pc_count; 40485815Sobrien}; 40585815Sobrien 40685815Sobrien/* x86-64 ELF linker hash entry. */ 40785815Sobrien 40885815Sobrienstruct elf64_x86_64_link_hash_entry 40985815Sobrien{ 41099461Sobrien struct elf_link_hash_entry elf; 41185815Sobrien 41299461Sobrien /* Track dynamic relocs copied for this symbol. */ 41399461Sobrien struct elf64_x86_64_dyn_relocs *dyn_relocs; 414130561Sobrien 415130561Sobrien#define GOT_UNKNOWN 0 416130561Sobrien#define GOT_NORMAL 1 417130561Sobrien#define GOT_TLS_GD 2 418130561Sobrien#define GOT_TLS_IE 3 419218822Sdim#define GOT_TLS_GDESC 4 420218822Sdim#define GOT_TLS_GD_BOTH_P(type) \ 421218822Sdim ((type) == (GOT_TLS_GD | GOT_TLS_GDESC)) 422218822Sdim#define GOT_TLS_GD_P(type) \ 423218822Sdim ((type) == GOT_TLS_GD || GOT_TLS_GD_BOTH_P (type)) 424218822Sdim#define GOT_TLS_GDESC_P(type) \ 425218822Sdim ((type) == GOT_TLS_GDESC || GOT_TLS_GD_BOTH_P (type)) 426218822Sdim#define GOT_TLS_GD_ANY_P(type) \ 427218822Sdim (GOT_TLS_GD_P (type) || GOT_TLS_GDESC_P (type)) 428130561Sobrien unsigned char tls_type; 429218822Sdim 430218822Sdim /* Offset of the GOTPLT entry reserved for the TLS descriptor, 431218822Sdim starting at the end of the jump table. */ 432218822Sdim bfd_vma tlsdesc_got; 43385815Sobrien}; 43485815Sobrien 435130561Sobrien#define elf64_x86_64_hash_entry(ent) \ 436130561Sobrien ((struct elf64_x86_64_link_hash_entry *)(ent)) 437130561Sobrien 438130561Sobrienstruct elf64_x86_64_obj_tdata 439130561Sobrien{ 440130561Sobrien struct elf_obj_tdata root; 441130561Sobrien 442130561Sobrien /* tls_type for each local got entry. */ 443130561Sobrien char *local_got_tls_type; 444218822Sdim 445218822Sdim /* GOTPLT entries for TLS descriptors. */ 446218822Sdim bfd_vma *local_tlsdesc_gotent; 447130561Sobrien}; 448130561Sobrien 449130561Sobrien#define elf64_x86_64_tdata(abfd) \ 450130561Sobrien ((struct elf64_x86_64_obj_tdata *) (abfd)->tdata.any) 451130561Sobrien 452130561Sobrien#define elf64_x86_64_local_got_tls_type(abfd) \ 453130561Sobrien (elf64_x86_64_tdata (abfd)->local_got_tls_type) 454130561Sobrien 455218822Sdim#define elf64_x86_64_local_tlsdesc_gotent(abfd) \ 456218822Sdim (elf64_x86_64_tdata (abfd)->local_tlsdesc_gotent) 457130561Sobrien 45899461Sobrien/* x86-64 ELF linker hash table. */ 45985815Sobrien 46085815Sobrienstruct elf64_x86_64_link_hash_table 46185815Sobrien{ 46299461Sobrien struct elf_link_hash_table elf; 46385815Sobrien 46499461Sobrien /* Short-cuts to get to dynamic linker sections. */ 46599461Sobrien asection *sgot; 46699461Sobrien asection *sgotplt; 46799461Sobrien asection *srelgot; 46899461Sobrien asection *splt; 46999461Sobrien asection *srelplt; 47099461Sobrien asection *sdynbss; 47199461Sobrien asection *srelbss; 47285815Sobrien 473218822Sdim /* The offset into splt of the PLT entry for the TLS descriptor 474218822Sdim resolver. Special values are 0, if not necessary (or not found 475218822Sdim to be necessary yet), and -1 if needed but not determined 476218822Sdim yet. */ 477218822Sdim bfd_vma tlsdesc_plt; 478218822Sdim /* The offset into sgot of the GOT entry used by the PLT entry 479218822Sdim above. */ 480218822Sdim bfd_vma tlsdesc_got; 481218822Sdim 482130561Sobrien union { 483130561Sobrien bfd_signed_vma refcount; 484130561Sobrien bfd_vma offset; 485130561Sobrien } tls_ld_got; 486130561Sobrien 487218822Sdim /* The amount of space used by the jump slots in the GOT. */ 488218822Sdim bfd_vma sgotplt_jump_table_size; 489218822Sdim 49099461Sobrien /* Small local sym to section mapping cache. */ 49199461Sobrien struct sym_sec_cache sym_sec; 49299461Sobrien}; 49385815Sobrien 49485815Sobrien/* Get the x86-64 ELF linker hash table from a link_info structure. */ 49585815Sobrien 49685815Sobrien#define elf64_x86_64_hash_table(p) \ 49785815Sobrien ((struct elf64_x86_64_link_hash_table *) ((p)->hash)) 49885815Sobrien 499218822Sdim#define elf64_x86_64_compute_jump_table_size(htab) \ 500218822Sdim ((htab)->srelplt->reloc_count * GOT_ENTRY_SIZE) 501218822Sdim 50285815Sobrien/* Create an entry in an x86-64 ELF linker hash table. */ 50385815Sobrien 50485815Sobrienstatic struct bfd_hash_entry * 505130561Sobrienlink_hash_newfunc (struct bfd_hash_entry *entry, struct bfd_hash_table *table, 506130561Sobrien const char *string) 50785815Sobrien{ 50885815Sobrien /* Allocate the structure if it has not already been allocated by a 50999461Sobrien subclass. */ 51099461Sobrien if (entry == NULL) 51199461Sobrien { 51299461Sobrien entry = bfd_hash_allocate (table, 51399461Sobrien sizeof (struct elf64_x86_64_link_hash_entry)); 51499461Sobrien if (entry == NULL) 51599461Sobrien return entry; 51699461Sobrien } 51785815Sobrien 51885815Sobrien /* Call the allocation method of the superclass. */ 51999461Sobrien entry = _bfd_elf_link_hash_newfunc (entry, table, string); 52099461Sobrien if (entry != NULL) 52185815Sobrien { 52299461Sobrien struct elf64_x86_64_link_hash_entry *eh; 52399461Sobrien 52499461Sobrien eh = (struct elf64_x86_64_link_hash_entry *) entry; 52599461Sobrien eh->dyn_relocs = NULL; 526130561Sobrien eh->tls_type = GOT_UNKNOWN; 527218822Sdim eh->tlsdesc_got = (bfd_vma) -1; 52885815Sobrien } 52985815Sobrien 53099461Sobrien return entry; 53185815Sobrien} 53285815Sobrien 53385815Sobrien/* Create an X86-64 ELF linker hash table. */ 53485815Sobrien 53585815Sobrienstatic struct bfd_link_hash_table * 536130561Sobrienelf64_x86_64_link_hash_table_create (bfd *abfd) 53785815Sobrien{ 53885815Sobrien struct elf64_x86_64_link_hash_table *ret; 53989857Sobrien bfd_size_type amt = sizeof (struct elf64_x86_64_link_hash_table); 54085815Sobrien 541104834Sobrien ret = (struct elf64_x86_64_link_hash_table *) bfd_malloc (amt); 54299461Sobrien if (ret == NULL) 54385815Sobrien return NULL; 54485815Sobrien 545218822Sdim if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, link_hash_newfunc, 546218822Sdim sizeof (struct elf64_x86_64_link_hash_entry))) 54785815Sobrien { 548104834Sobrien free (ret); 54985815Sobrien return NULL; 55085815Sobrien } 55185815Sobrien 55299461Sobrien ret->sgot = NULL; 55399461Sobrien ret->sgotplt = NULL; 55499461Sobrien ret->srelgot = NULL; 55599461Sobrien ret->splt = NULL; 55699461Sobrien ret->srelplt = NULL; 55799461Sobrien ret->sdynbss = NULL; 55899461Sobrien ret->srelbss = NULL; 55999461Sobrien ret->sym_sec.abfd = NULL; 560218822Sdim ret->tlsdesc_plt = 0; 561218822Sdim ret->tlsdesc_got = 0; 562130561Sobrien ret->tls_ld_got.refcount = 0; 563218822Sdim ret->sgotplt_jump_table_size = 0; 56499461Sobrien 56599461Sobrien return &ret->elf.root; 56685815Sobrien} 56785815Sobrien 56899461Sobrien/* Create .got, .gotplt, and .rela.got sections in DYNOBJ, and set up 56999461Sobrien shortcuts to them in our hash table. */ 57099461Sobrien 571130561Sobrienstatic bfd_boolean 572130561Sobriencreate_got_section (bfd *dynobj, struct bfd_link_info *info) 57399461Sobrien{ 57499461Sobrien struct elf64_x86_64_link_hash_table *htab; 57599461Sobrien 57699461Sobrien if (! _bfd_elf_create_got_section (dynobj, info)) 577130561Sobrien return FALSE; 57899461Sobrien 57999461Sobrien htab = elf64_x86_64_hash_table (info); 58099461Sobrien htab->sgot = bfd_get_section_by_name (dynobj, ".got"); 58199461Sobrien htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt"); 58299461Sobrien if (!htab->sgot || !htab->sgotplt) 58399461Sobrien abort (); 58499461Sobrien 585218822Sdim htab->srelgot = bfd_make_section_with_flags (dynobj, ".rela.got", 586218822Sdim (SEC_ALLOC | SEC_LOAD 587218822Sdim | SEC_HAS_CONTENTS 588218822Sdim | SEC_IN_MEMORY 589218822Sdim | SEC_LINKER_CREATED 590218822Sdim | SEC_READONLY)); 59199461Sobrien if (htab->srelgot == NULL 59299461Sobrien || ! bfd_set_section_alignment (dynobj, htab->srelgot, 3)) 593130561Sobrien return FALSE; 594130561Sobrien return TRUE; 59599461Sobrien} 59699461Sobrien 59799461Sobrien/* Create .plt, .rela.plt, .got, .got.plt, .rela.got, .dynbss, and 59899461Sobrien .rela.bss sections in DYNOBJ, and set up shortcuts to them in our 59999461Sobrien hash table. */ 60099461Sobrien 601130561Sobrienstatic bfd_boolean 602130561Sobrienelf64_x86_64_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) 60399461Sobrien{ 60499461Sobrien struct elf64_x86_64_link_hash_table *htab; 60599461Sobrien 60699461Sobrien htab = elf64_x86_64_hash_table (info); 60799461Sobrien if (!htab->sgot && !create_got_section (dynobj, info)) 608130561Sobrien return FALSE; 60999461Sobrien 61099461Sobrien if (!_bfd_elf_create_dynamic_sections (dynobj, info)) 611130561Sobrien return FALSE; 61299461Sobrien 61399461Sobrien htab->splt = bfd_get_section_by_name (dynobj, ".plt"); 61499461Sobrien htab->srelplt = bfd_get_section_by_name (dynobj, ".rela.plt"); 61599461Sobrien htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss"); 61699461Sobrien if (!info->shared) 61799461Sobrien htab->srelbss = bfd_get_section_by_name (dynobj, ".rela.bss"); 61899461Sobrien 61999461Sobrien if (!htab->splt || !htab->srelplt || !htab->sdynbss 62099461Sobrien || (!info->shared && !htab->srelbss)) 62199461Sobrien abort (); 62299461Sobrien 623130561Sobrien return TRUE; 62499461Sobrien} 62599461Sobrien 62699461Sobrien/* Copy the extra info we tack onto an elf_link_hash_entry. */ 62799461Sobrien 62899461Sobrienstatic void 629218822Sdimelf64_x86_64_copy_indirect_symbol (struct bfd_link_info *info, 630130561Sobrien struct elf_link_hash_entry *dir, 631130561Sobrien struct elf_link_hash_entry *ind) 63299461Sobrien{ 63399461Sobrien struct elf64_x86_64_link_hash_entry *edir, *eind; 63499461Sobrien 63599461Sobrien edir = (struct elf64_x86_64_link_hash_entry *) dir; 63699461Sobrien eind = (struct elf64_x86_64_link_hash_entry *) ind; 63799461Sobrien 63899461Sobrien if (eind->dyn_relocs != NULL) 63999461Sobrien { 64099461Sobrien if (edir->dyn_relocs != NULL) 64199461Sobrien { 64299461Sobrien struct elf64_x86_64_dyn_relocs **pp; 64399461Sobrien struct elf64_x86_64_dyn_relocs *p; 64499461Sobrien 645218822Sdim /* Add reloc counts against the indirect sym to the direct sym 64699461Sobrien list. Merge any entries against the same section. */ 64799461Sobrien for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) 64899461Sobrien { 64999461Sobrien struct elf64_x86_64_dyn_relocs *q; 65099461Sobrien 65199461Sobrien for (q = edir->dyn_relocs; q != NULL; q = q->next) 65299461Sobrien if (q->sec == p->sec) 65399461Sobrien { 65499461Sobrien q->pc_count += p->pc_count; 65599461Sobrien q->count += p->count; 65699461Sobrien *pp = p->next; 65799461Sobrien break; 65899461Sobrien } 65999461Sobrien if (q == NULL) 66099461Sobrien pp = &p->next; 66199461Sobrien } 66299461Sobrien *pp = edir->dyn_relocs; 66399461Sobrien } 66499461Sobrien 66599461Sobrien edir->dyn_relocs = eind->dyn_relocs; 66699461Sobrien eind->dyn_relocs = NULL; 66799461Sobrien } 66899461Sobrien 669130561Sobrien if (ind->root.type == bfd_link_hash_indirect 670130561Sobrien && dir->got.refcount <= 0) 671130561Sobrien { 672130561Sobrien edir->tls_type = eind->tls_type; 673130561Sobrien eind->tls_type = GOT_UNKNOWN; 674130561Sobrien } 675130561Sobrien 676130561Sobrien if (ELIMINATE_COPY_RELOCS 677130561Sobrien && ind->root.type != bfd_link_hash_indirect 678218822Sdim && dir->dynamic_adjusted) 679218822Sdim { 680218822Sdim /* If called to transfer flags for a weakdef during processing 681218822Sdim of elf_adjust_dynamic_symbol, don't copy non_got_ref. 682218822Sdim We clear it ourselves for ELIMINATE_COPY_RELOCS. */ 683218822Sdim dir->ref_dynamic |= ind->ref_dynamic; 684218822Sdim dir->ref_regular |= ind->ref_regular; 685218822Sdim dir->ref_regular_nonweak |= ind->ref_regular_nonweak; 686218822Sdim dir->needs_plt |= ind->needs_plt; 687218822Sdim dir->pointer_equality_needed |= ind->pointer_equality_needed; 688218822Sdim } 689130561Sobrien else 690218822Sdim _bfd_elf_link_hash_copy_indirect (info, dir, ind); 69199461Sobrien} 69299461Sobrien 693130561Sobrienstatic bfd_boolean 694130561Sobrienelf64_x86_64_mkobject (bfd *abfd) 69585815Sobrien{ 696130561Sobrien if (abfd->tdata.any == NULL) 697218822Sdim { 698218822Sdim bfd_size_type amt = sizeof (struct elf64_x86_64_obj_tdata); 699218822Sdim abfd->tdata.any = bfd_zalloc (abfd, amt); 700218822Sdim if (abfd->tdata.any == NULL) 701218822Sdim return FALSE; 702218822Sdim } 703218822Sdim return bfd_elf_mkobject (abfd); 704130561Sobrien} 705130561Sobrien 706130561Sobrienstatic bfd_boolean 707130561Sobrienelf64_x86_64_elf_object_p (bfd *abfd) 708130561Sobrien{ 70985815Sobrien /* Set the right machine number for an x86-64 elf64 file. */ 71085815Sobrien bfd_default_set_arch_mach (abfd, bfd_arch_i386, bfd_mach_x86_64); 711130561Sobrien return TRUE; 71285815Sobrien} 71385815Sobrien 714130561Sobrienstatic int 715130561Sobrienelf64_x86_64_tls_transition (struct bfd_link_info *info, int r_type, int is_local) 716130561Sobrien{ 717130561Sobrien if (info->shared) 718130561Sobrien return r_type; 719130561Sobrien 720130561Sobrien switch (r_type) 721130561Sobrien { 722130561Sobrien case R_X86_64_TLSGD: 723218822Sdim case R_X86_64_GOTPC32_TLSDESC: 724218822Sdim case R_X86_64_TLSDESC_CALL: 725130561Sobrien case R_X86_64_GOTTPOFF: 726130561Sobrien if (is_local) 727130561Sobrien return R_X86_64_TPOFF32; 728130561Sobrien return R_X86_64_GOTTPOFF; 729130561Sobrien case R_X86_64_TLSLD: 730130561Sobrien return R_X86_64_TPOFF32; 731130561Sobrien } 732130561Sobrien 733130561Sobrien return r_type; 734130561Sobrien} 735130561Sobrien 73685815Sobrien/* Look through the relocs for a section during the first phase, and 73799461Sobrien calculate needed space in the global offset table, procedure 73899461Sobrien linkage table, and dynamic reloc sections. */ 73985815Sobrien 740130561Sobrienstatic bfd_boolean 741130561Sobrienelf64_x86_64_check_relocs (bfd *abfd, struct bfd_link_info *info, asection *sec, 742130561Sobrien const Elf_Internal_Rela *relocs) 74385815Sobrien{ 74499461Sobrien struct elf64_x86_64_link_hash_table *htab; 74585815Sobrien Elf_Internal_Shdr *symtab_hdr; 74685815Sobrien struct elf_link_hash_entry **sym_hashes; 74785815Sobrien const Elf_Internal_Rela *rel; 74885815Sobrien const Elf_Internal_Rela *rel_end; 74985815Sobrien asection *sreloc; 75085815Sobrien 751130561Sobrien if (info->relocatable) 752130561Sobrien return TRUE; 75385815Sobrien 75499461Sobrien htab = elf64_x86_64_hash_table (info); 75585815Sobrien symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 75685815Sobrien sym_hashes = elf_sym_hashes (abfd); 75785815Sobrien 75899461Sobrien sreloc = NULL; 75999461Sobrien 76085815Sobrien rel_end = relocs + sec->reloc_count; 76185815Sobrien for (rel = relocs; rel < rel_end; rel++) 76285815Sobrien { 763130561Sobrien unsigned int r_type; 76485815Sobrien unsigned long r_symndx; 76585815Sobrien struct elf_link_hash_entry *h; 76685815Sobrien 76785815Sobrien r_symndx = ELF64_R_SYM (rel->r_info); 768130561Sobrien r_type = ELF64_R_TYPE (rel->r_info); 76999461Sobrien 77099461Sobrien if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr)) 77199461Sobrien { 772218822Sdim (*_bfd_error_handler) (_("%B: bad symbol index: %d"), 773218822Sdim abfd, r_symndx); 774130561Sobrien return FALSE; 77599461Sobrien } 77699461Sobrien 77785815Sobrien if (r_symndx < symtab_hdr->sh_info) 77885815Sobrien h = NULL; 77985815Sobrien else 780218822Sdim { 781218822Sdim h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 782218822Sdim while (h->root.type == bfd_link_hash_indirect 783218822Sdim || h->root.type == bfd_link_hash_warning) 784218822Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 785218822Sdim } 78685815Sobrien 787130561Sobrien r_type = elf64_x86_64_tls_transition (info, r_type, h == NULL); 788130561Sobrien switch (r_type) 78985815Sobrien { 790130561Sobrien case R_X86_64_TLSLD: 791130561Sobrien htab->tls_ld_got.refcount += 1; 792130561Sobrien goto create_got; 793130561Sobrien 794130561Sobrien case R_X86_64_TPOFF32: 795130561Sobrien if (info->shared) 796130561Sobrien { 797130561Sobrien (*_bfd_error_handler) 798218822Sdim (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), 799218822Sdim abfd, 800218822Sdim x86_64_elf_howto_table[r_type].name, 801218822Sdim (h) ? h->root.root.string : "a local symbol"); 802130561Sobrien bfd_set_error (bfd_error_bad_value); 803130561Sobrien return FALSE; 804130561Sobrien } 805130561Sobrien break; 806130561Sobrien 807130561Sobrien case R_X86_64_GOTTPOFF: 808130561Sobrien if (info->shared) 809130561Sobrien info->flags |= DF_STATIC_TLS; 810130561Sobrien /* Fall through */ 811130561Sobrien 81299461Sobrien case R_X86_64_GOT32: 81385815Sobrien case R_X86_64_GOTPCREL: 814130561Sobrien case R_X86_64_TLSGD: 815218822Sdim case R_X86_64_GOT64: 816218822Sdim case R_X86_64_GOTPCREL64: 817218822Sdim case R_X86_64_GOTPLT64: 818218822Sdim case R_X86_64_GOTPC32_TLSDESC: 819218822Sdim case R_X86_64_TLSDESC_CALL: 82085815Sobrien /* This symbol requires a global offset table entry. */ 821130561Sobrien { 822130561Sobrien int tls_type, old_tls_type; 82399461Sobrien 824130561Sobrien switch (r_type) 825130561Sobrien { 826130561Sobrien default: tls_type = GOT_NORMAL; break; 827130561Sobrien case R_X86_64_TLSGD: tls_type = GOT_TLS_GD; break; 828130561Sobrien case R_X86_64_GOTTPOFF: tls_type = GOT_TLS_IE; break; 829218822Sdim case R_X86_64_GOTPC32_TLSDESC: 830218822Sdim case R_X86_64_TLSDESC_CALL: 831218822Sdim tls_type = GOT_TLS_GDESC; break; 832130561Sobrien } 83385815Sobrien 834130561Sobrien if (h != NULL) 835130561Sobrien { 836218822Sdim if (r_type == R_X86_64_GOTPLT64) 837218822Sdim { 838218822Sdim /* This relocation indicates that we also need 839218822Sdim a PLT entry, as this is a function. We don't need 840218822Sdim a PLT entry for local symbols. */ 841218822Sdim h->needs_plt = 1; 842218822Sdim h->plt.refcount += 1; 843218822Sdim } 844130561Sobrien h->got.refcount += 1; 845130561Sobrien old_tls_type = elf64_x86_64_hash_entry (h)->tls_type; 846130561Sobrien } 847130561Sobrien else 848130561Sobrien { 849130561Sobrien bfd_signed_vma *local_got_refcounts; 850130561Sobrien 851130561Sobrien /* This is a global offset table entry for a local symbol. */ 852130561Sobrien local_got_refcounts = elf_local_got_refcounts (abfd); 853130561Sobrien if (local_got_refcounts == NULL) 854130561Sobrien { 855130561Sobrien bfd_size_type size; 856130561Sobrien 857130561Sobrien size = symtab_hdr->sh_info; 858218822Sdim size *= sizeof (bfd_signed_vma) 859218822Sdim + sizeof (bfd_vma) + sizeof (char); 860130561Sobrien local_got_refcounts = ((bfd_signed_vma *) 861130561Sobrien bfd_zalloc (abfd, size)); 862130561Sobrien if (local_got_refcounts == NULL) 863130561Sobrien return FALSE; 864130561Sobrien elf_local_got_refcounts (abfd) = local_got_refcounts; 865218822Sdim elf64_x86_64_local_tlsdesc_gotent (abfd) 866218822Sdim = (bfd_vma *) (local_got_refcounts + symtab_hdr->sh_info); 867130561Sobrien elf64_x86_64_local_got_tls_type (abfd) 868218822Sdim = (char *) (local_got_refcounts + 2 * symtab_hdr->sh_info); 869130561Sobrien } 870130561Sobrien local_got_refcounts[r_symndx] += 1; 871130561Sobrien old_tls_type 872130561Sobrien = elf64_x86_64_local_got_tls_type (abfd) [r_symndx]; 873130561Sobrien } 874130561Sobrien 875130561Sobrien /* If a TLS symbol is accessed using IE at least once, 876130561Sobrien there is no point to use dynamic model for it. */ 877130561Sobrien if (old_tls_type != tls_type && old_tls_type != GOT_UNKNOWN 878218822Sdim && (! GOT_TLS_GD_ANY_P (old_tls_type) 879218822Sdim || tls_type != GOT_TLS_IE)) 880130561Sobrien { 881218822Sdim if (old_tls_type == GOT_TLS_IE && GOT_TLS_GD_ANY_P (tls_type)) 882130561Sobrien tls_type = old_tls_type; 883218822Sdim else if (GOT_TLS_GD_ANY_P (old_tls_type) 884218822Sdim && GOT_TLS_GD_ANY_P (tls_type)) 885218822Sdim tls_type |= old_tls_type; 886130561Sobrien else 887130561Sobrien { 888130561Sobrien (*_bfd_error_handler) 889218822Sdim (_("%B: %s' accessed both as normal and thread local symbol"), 890218822Sdim abfd, h ? h->root.root.string : "<local>"); 891130561Sobrien return FALSE; 892130561Sobrien } 893130561Sobrien } 894130561Sobrien 895130561Sobrien if (old_tls_type != tls_type) 896130561Sobrien { 897130561Sobrien if (h != NULL) 898130561Sobrien elf64_x86_64_hash_entry (h)->tls_type = tls_type; 899130561Sobrien else 900130561Sobrien elf64_x86_64_local_got_tls_type (abfd) [r_symndx] = tls_type; 901130561Sobrien } 902130561Sobrien } 90399461Sobrien /* Fall through */ 90499461Sobrien 905218822Sdim case R_X86_64_GOTOFF64: 906218822Sdim case R_X86_64_GOTPC32: 907218822Sdim case R_X86_64_GOTPC64: 908130561Sobrien create_got: 90999461Sobrien if (htab->sgot == NULL) 91099461Sobrien { 91199461Sobrien if (htab->elf.dynobj == NULL) 91299461Sobrien htab->elf.dynobj = abfd; 91399461Sobrien if (!create_got_section (htab->elf.dynobj, info)) 914130561Sobrien return FALSE; 91599461Sobrien } 91685815Sobrien break; 91785815Sobrien 91885815Sobrien case R_X86_64_PLT32: 91985815Sobrien /* This symbol requires a procedure linkage table entry. We 92085815Sobrien actually build the entry in adjust_dynamic_symbol, 92185815Sobrien because this might be a case of linking PIC code which is 92285815Sobrien never referenced by a dynamic object, in which case we 92385815Sobrien don't need to generate a procedure linkage table entry 92485815Sobrien after all. */ 92585815Sobrien 92685815Sobrien /* If this is a local symbol, we resolve it directly without 92785815Sobrien creating a procedure linkage table entry. */ 92885815Sobrien if (h == NULL) 92985815Sobrien continue; 93085815Sobrien 931218822Sdim h->needs_plt = 1; 93289857Sobrien h->plt.refcount += 1; 93385815Sobrien break; 93485815Sobrien 935218822Sdim case R_X86_64_PLTOFF64: 936218822Sdim /* This tries to form the 'address' of a function relative 937218822Sdim to GOT. For global symbols we need a PLT entry. */ 938218822Sdim if (h != NULL) 939218822Sdim { 940218822Sdim h->needs_plt = 1; 941218822Sdim h->plt.refcount += 1; 942218822Sdim } 943218822Sdim goto create_got; 944218822Sdim 94585815Sobrien case R_X86_64_8: 94685815Sobrien case R_X86_64_16: 94785815Sobrien case R_X86_64_32: 94885815Sobrien case R_X86_64_32S: 949104834Sobrien /* Let's help debug shared library creation. These relocs 950104834Sobrien cannot be used in shared libs. Don't error out for 951104834Sobrien sections we don't care about, such as debug sections or 952104834Sobrien non-constant sections. */ 953104834Sobrien if (info->shared 954104834Sobrien && (sec->flags & SEC_ALLOC) != 0 955104834Sobrien && (sec->flags & SEC_READONLY) != 0) 956104834Sobrien { 957104834Sobrien (*_bfd_error_handler) 958218822Sdim (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), 959218822Sdim abfd, 960218822Sdim x86_64_elf_howto_table[r_type].name, 961218822Sdim (h) ? h->root.root.string : "a local symbol"); 962104834Sobrien bfd_set_error (bfd_error_bad_value); 963130561Sobrien return FALSE; 964104834Sobrien } 965104834Sobrien /* Fall through. */ 966104834Sobrien 96799461Sobrien case R_X86_64_PC8: 96899461Sobrien case R_X86_64_PC16: 96985815Sobrien case R_X86_64_PC32: 970218822Sdim case R_X86_64_PC64: 971104834Sobrien case R_X86_64_64: 97299461Sobrien if (h != NULL && !info->shared) 97399461Sobrien { 97499461Sobrien /* If this reloc is in a read-only section, we might 97599461Sobrien need a copy reloc. We can't check reliably at this 97699461Sobrien stage whether the section is read-only, as input 97799461Sobrien sections have not yet been mapped to output sections. 97899461Sobrien Tentatively set the flag for now, and correct in 97999461Sobrien adjust_dynamic_symbol. */ 980218822Sdim h->non_got_ref = 1; 98185815Sobrien 98299461Sobrien /* We may need a .plt entry if the function this reloc 98399461Sobrien refers to is in a shared lib. */ 98499461Sobrien h->plt.refcount += 1; 985218822Sdim if (r_type != R_X86_64_PC32 && r_type != R_X86_64_PC64) 986218822Sdim h->pointer_equality_needed = 1; 98799461Sobrien } 98899461Sobrien 98985815Sobrien /* If we are creating a shared library, and this is a reloc 99085815Sobrien against a global symbol, or a non PC relative reloc 99185815Sobrien against a local symbol, then we need to copy the reloc 99285815Sobrien into the shared library. However, if we are linking with 99385815Sobrien -Bsymbolic, we do not need to copy a reloc against a 99485815Sobrien global symbol which is defined in an object we are 99585815Sobrien including in the link (i.e., DEF_REGULAR is set). At 99685815Sobrien this point we have not seen all the input files, so it is 99785815Sobrien possible that DEF_REGULAR is not set now but will be set 99899461Sobrien later (it is never cleared). In case of a weak definition, 99999461Sobrien DEF_REGULAR may be cleared later by a strong definition in 100099461Sobrien a shared library. We account for that possibility below by 100199461Sobrien storing information in the relocs_copied field of the hash 100299461Sobrien table entry. A similar situation occurs when creating 100399461Sobrien shared libraries and symbol visibility changes render the 100499461Sobrien symbol local. 100599461Sobrien 100699461Sobrien If on the other hand, we are creating an executable, we 100799461Sobrien may need to keep relocations for symbols satisfied by a 100899461Sobrien dynamic library if we manage to avoid copy relocs for the 100999461Sobrien symbol. */ 101099461Sobrien if ((info->shared 101199461Sobrien && (sec->flags & SEC_ALLOC) != 0 1012130561Sobrien && (((r_type != R_X86_64_PC8) 1013130561Sobrien && (r_type != R_X86_64_PC16) 1014218822Sdim && (r_type != R_X86_64_PC32) 1015218822Sdim && (r_type != R_X86_64_PC64)) 101699461Sobrien || (h != NULL 1017218822Sdim && (! SYMBOLIC_BIND (info, h) 101899461Sobrien || h->root.type == bfd_link_hash_defweak 1019218822Sdim || !h->def_regular)))) 1020130561Sobrien || (ELIMINATE_COPY_RELOCS 1021130561Sobrien && !info->shared 102299461Sobrien && (sec->flags & SEC_ALLOC) != 0 102399461Sobrien && h != NULL 102499461Sobrien && (h->root.type == bfd_link_hash_defweak 1025218822Sdim || !h->def_regular))) 102685815Sobrien { 102799461Sobrien struct elf64_x86_64_dyn_relocs *p; 102899461Sobrien struct elf64_x86_64_dyn_relocs **head; 102999461Sobrien 103099461Sobrien /* We must copy these reloc types into the output file. 103199461Sobrien Create a reloc section in dynobj and make room for 103299461Sobrien this reloc. */ 103385815Sobrien if (sreloc == NULL) 103485815Sobrien { 103585815Sobrien const char *name; 103699461Sobrien bfd *dynobj; 103785815Sobrien 103885815Sobrien name = (bfd_elf_string_from_elf_section 103985815Sobrien (abfd, 104085815Sobrien elf_elfheader (abfd)->e_shstrndx, 104185815Sobrien elf_section_data (sec)->rel_hdr.sh_name)); 104285815Sobrien if (name == NULL) 1043130561Sobrien return FALSE; 104485815Sobrien 1045218822Sdim if (! CONST_STRNEQ (name, ".rela") 104699461Sobrien || strcmp (bfd_get_section_name (abfd, sec), 104799461Sobrien name + 5) != 0) 104899461Sobrien { 104999461Sobrien (*_bfd_error_handler) 1050218822Sdim (_("%B: bad relocation section name `%s\'"), 1051218822Sdim abfd, name); 105299461Sobrien } 105385815Sobrien 105499461Sobrien if (htab->elf.dynobj == NULL) 105599461Sobrien htab->elf.dynobj = abfd; 105699461Sobrien 105799461Sobrien dynobj = htab->elf.dynobj; 105899461Sobrien 105985815Sobrien sreloc = bfd_get_section_by_name (dynobj, name); 106085815Sobrien if (sreloc == NULL) 106185815Sobrien { 106285815Sobrien flagword flags; 106385815Sobrien 106485815Sobrien flags = (SEC_HAS_CONTENTS | SEC_READONLY 106585815Sobrien | SEC_IN_MEMORY | SEC_LINKER_CREATED); 106685815Sobrien if ((sec->flags & SEC_ALLOC) != 0) 106785815Sobrien flags |= SEC_ALLOC | SEC_LOAD; 1068218822Sdim sreloc = bfd_make_section_with_flags (dynobj, 1069218822Sdim name, 1070218822Sdim flags); 107185815Sobrien if (sreloc == NULL 107285815Sobrien || ! bfd_set_section_alignment (dynobj, sreloc, 3)) 1073130561Sobrien return FALSE; 107485815Sobrien } 107599461Sobrien elf_section_data (sec)->sreloc = sreloc; 107685815Sobrien } 107785815Sobrien 107899461Sobrien /* If this is a global symbol, we count the number of 107999461Sobrien relocations we need for this symbol. */ 108099461Sobrien if (h != NULL) 108185815Sobrien { 108299461Sobrien head = &((struct elf64_x86_64_link_hash_entry *) h)->dyn_relocs; 108399461Sobrien } 108499461Sobrien else 108599461Sobrien { 1086218822Sdim void **vpp; 108799461Sobrien /* Track dynamic relocs needed for local syms too. 108899461Sobrien We really need local syms available to do this 108999461Sobrien easily. Oh well. */ 109085815Sobrien 109199461Sobrien asection *s; 109299461Sobrien s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, 109399461Sobrien sec, r_symndx); 109499461Sobrien if (s == NULL) 1095130561Sobrien return FALSE; 109685815Sobrien 1097218822Sdim /* Beware of type punned pointers vs strict aliasing 1098218822Sdim rules. */ 1099218822Sdim vpp = &(elf_section_data (s)->local_dynrel); 1100218822Sdim head = (struct elf64_x86_64_dyn_relocs **)vpp; 110199461Sobrien } 110285815Sobrien 110399461Sobrien p = *head; 110499461Sobrien if (p == NULL || p->sec != sec) 110599461Sobrien { 110699461Sobrien bfd_size_type amt = sizeof *p; 110799461Sobrien p = ((struct elf64_x86_64_dyn_relocs *) 110899461Sobrien bfd_alloc (htab->elf.dynobj, amt)); 110985815Sobrien if (p == NULL) 1110130561Sobrien return FALSE; 111199461Sobrien p->next = *head; 111299461Sobrien *head = p; 111399461Sobrien p->sec = sec; 111499461Sobrien p->count = 0; 111599461Sobrien p->pc_count = 0; 111699461Sobrien } 111785815Sobrien 111899461Sobrien p->count += 1; 1119130561Sobrien if (r_type == R_X86_64_PC8 1120130561Sobrien || r_type == R_X86_64_PC16 1121218822Sdim || r_type == R_X86_64_PC32 1122218822Sdim || r_type == R_X86_64_PC64) 112399461Sobrien p->pc_count += 1; 112485815Sobrien } 112585815Sobrien break; 112689857Sobrien 112789857Sobrien /* This relocation describes the C++ object vtable hierarchy. 112889857Sobrien Reconstruct it for later use during GC. */ 112989857Sobrien case R_X86_64_GNU_VTINHERIT: 1130130561Sobrien if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) 1131130561Sobrien return FALSE; 113289857Sobrien break; 113389857Sobrien 113489857Sobrien /* This relocation describes which C++ vtable entries are actually 113589857Sobrien used. Record for later use during GC. */ 113689857Sobrien case R_X86_64_GNU_VTENTRY: 1137130561Sobrien if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) 1138130561Sobrien return FALSE; 113989857Sobrien break; 114099461Sobrien 114199461Sobrien default: 114299461Sobrien break; 114385815Sobrien } 114485815Sobrien } 114585815Sobrien 1146130561Sobrien return TRUE; 114785815Sobrien} 114885815Sobrien 114985815Sobrien/* Return the section that should be marked against GC for a given 115085815Sobrien relocation. */ 115185815Sobrien 115285815Sobrienstatic asection * 1153130561Sobrienelf64_x86_64_gc_mark_hook (asection *sec, 1154218822Sdim struct bfd_link_info *info, 1155130561Sobrien Elf_Internal_Rela *rel, 1156130561Sobrien struct elf_link_hash_entry *h, 1157130561Sobrien Elf_Internal_Sym *sym) 115885815Sobrien{ 115985815Sobrien if (h != NULL) 1160218822Sdim switch (ELF64_R_TYPE (rel->r_info)) 1161218822Sdim { 1162218822Sdim case R_X86_64_GNU_VTINHERIT: 1163218822Sdim case R_X86_64_GNU_VTENTRY: 1164218822Sdim return NULL; 1165218822Sdim } 116685815Sobrien 1167218822Sdim return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); 116885815Sobrien} 116985815Sobrien 117085815Sobrien/* Update the got entry reference counts for the section being removed. */ 117185815Sobrien 1172130561Sobrienstatic bfd_boolean 1173130561Sobrienelf64_x86_64_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, 1174130561Sobrien asection *sec, const Elf_Internal_Rela *relocs) 117585815Sobrien{ 117685815Sobrien Elf_Internal_Shdr *symtab_hdr; 117785815Sobrien struct elf_link_hash_entry **sym_hashes; 117885815Sobrien bfd_signed_vma *local_got_refcounts; 117985815Sobrien const Elf_Internal_Rela *rel, *relend; 118085815Sobrien 118199461Sobrien elf_section_data (sec)->local_dynrel = NULL; 118299461Sobrien 118385815Sobrien symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 118485815Sobrien sym_hashes = elf_sym_hashes (abfd); 118585815Sobrien local_got_refcounts = elf_local_got_refcounts (abfd); 118685815Sobrien 118785815Sobrien relend = relocs + sec->reloc_count; 118885815Sobrien for (rel = relocs; rel < relend; rel++) 1189130561Sobrien { 1190130561Sobrien unsigned long r_symndx; 1191130561Sobrien unsigned int r_type; 1192130561Sobrien struct elf_link_hash_entry *h = NULL; 119385815Sobrien 1194130561Sobrien r_symndx = ELF64_R_SYM (rel->r_info); 1195130561Sobrien if (r_symndx >= symtab_hdr->sh_info) 1196130561Sobrien { 1197130561Sobrien struct elf64_x86_64_link_hash_entry *eh; 1198130561Sobrien struct elf64_x86_64_dyn_relocs **pp; 1199130561Sobrien struct elf64_x86_64_dyn_relocs *p; 120099461Sobrien 1201130561Sobrien h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 1202218822Sdim while (h->root.type == bfd_link_hash_indirect 1203218822Sdim || h->root.type == bfd_link_hash_warning) 1204218822Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 1205130561Sobrien eh = (struct elf64_x86_64_link_hash_entry *) h; 120699461Sobrien 1207130561Sobrien for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) 1208130561Sobrien if (p->sec == sec) 1209130561Sobrien { 1210130561Sobrien /* Everything must go for SEC. */ 1211130561Sobrien *pp = p->next; 1212130561Sobrien break; 1213130561Sobrien } 1214130561Sobrien } 121599461Sobrien 1216130561Sobrien r_type = ELF64_R_TYPE (rel->r_info); 1217130561Sobrien r_type = elf64_x86_64_tls_transition (info, r_type, h != NULL); 1218130561Sobrien switch (r_type) 1219130561Sobrien { 1220130561Sobrien case R_X86_64_TLSLD: 1221130561Sobrien if (elf64_x86_64_hash_table (info)->tls_ld_got.refcount > 0) 1222130561Sobrien elf64_x86_64_hash_table (info)->tls_ld_got.refcount -= 1; 1223130561Sobrien break; 122499461Sobrien 1225130561Sobrien case R_X86_64_TLSGD: 1226218822Sdim case R_X86_64_GOTPC32_TLSDESC: 1227218822Sdim case R_X86_64_TLSDESC_CALL: 1228130561Sobrien case R_X86_64_GOTTPOFF: 1229130561Sobrien case R_X86_64_GOT32: 1230130561Sobrien case R_X86_64_GOTPCREL: 1231218822Sdim case R_X86_64_GOT64: 1232218822Sdim case R_X86_64_GOTPCREL64: 1233218822Sdim case R_X86_64_GOTPLT64: 1234130561Sobrien if (h != NULL) 1235130561Sobrien { 1236218822Sdim if (r_type == R_X86_64_GOTPLT64 && h->plt.refcount > 0) 1237218822Sdim h->plt.refcount -= 1; 1238130561Sobrien if (h->got.refcount > 0) 1239130561Sobrien h->got.refcount -= 1; 1240130561Sobrien } 1241130561Sobrien else if (local_got_refcounts != NULL) 1242130561Sobrien { 1243130561Sobrien if (local_got_refcounts[r_symndx] > 0) 1244130561Sobrien local_got_refcounts[r_symndx] -= 1; 1245130561Sobrien } 1246130561Sobrien break; 124799461Sobrien 1248130561Sobrien case R_X86_64_8: 1249130561Sobrien case R_X86_64_16: 1250130561Sobrien case R_X86_64_32: 1251130561Sobrien case R_X86_64_64: 1252130561Sobrien case R_X86_64_32S: 1253130561Sobrien case R_X86_64_PC8: 1254130561Sobrien case R_X86_64_PC16: 1255130561Sobrien case R_X86_64_PC32: 1256218822Sdim case R_X86_64_PC64: 1257130561Sobrien if (info->shared) 1258130561Sobrien break; 1259130561Sobrien /* Fall thru */ 126099461Sobrien 1261130561Sobrien case R_X86_64_PLT32: 1262218822Sdim case R_X86_64_PLTOFF64: 1263130561Sobrien if (h != NULL) 1264130561Sobrien { 1265130561Sobrien if (h->plt.refcount > 0) 1266130561Sobrien h->plt.refcount -= 1; 1267130561Sobrien } 1268130561Sobrien break; 126985815Sobrien 1270130561Sobrien default: 1271130561Sobrien break; 1272130561Sobrien } 1273130561Sobrien } 127485815Sobrien 1275130561Sobrien return TRUE; 127685815Sobrien} 127785815Sobrien 127885815Sobrien/* Adjust a symbol defined by a dynamic object and referenced by a 127985815Sobrien regular object. The current definition is in some section of the 128085815Sobrien dynamic object, but we're not including those sections. We have to 128185815Sobrien change the definition to something the rest of the link can 128285815Sobrien understand. */ 128385815Sobrien 1284130561Sobrienstatic bfd_boolean 1285130561Sobrienelf64_x86_64_adjust_dynamic_symbol (struct bfd_link_info *info, 1286130561Sobrien struct elf_link_hash_entry *h) 128785815Sobrien{ 128899461Sobrien struct elf64_x86_64_link_hash_table *htab; 128985815Sobrien asection *s; 129085815Sobrien 129185815Sobrien /* If this is a function, put it in the procedure linkage table. We 129285815Sobrien will fill in the contents of the procedure linkage table later, 129385815Sobrien when we know the address of the .got section. */ 129485815Sobrien if (h->type == STT_FUNC 1295218822Sdim || h->needs_plt) 129685815Sobrien { 129799461Sobrien if (h->plt.refcount <= 0 1298130561Sobrien || SYMBOL_CALLS_LOCAL (info, h) 1299130561Sobrien || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT 1300130561Sobrien && h->root.type == bfd_link_hash_undefweak)) 130185815Sobrien { 130285815Sobrien /* This case can occur if we saw a PLT32 reloc in an input 130385815Sobrien file, but the symbol was never referred to by a dynamic 130485815Sobrien object, or if all references were garbage collected. In 130585815Sobrien such a case, we don't actually need to build a procedure 130685815Sobrien linkage table, and we can just do a PC32 reloc instead. */ 130785815Sobrien h->plt.offset = (bfd_vma) -1; 1308218822Sdim h->needs_plt = 0; 130985815Sobrien } 131085815Sobrien 1311130561Sobrien return TRUE; 131285815Sobrien } 131389857Sobrien else 131499461Sobrien /* It's possible that we incorrectly decided a .plt reloc was 131599461Sobrien needed for an R_X86_64_PC32 reloc to a non-function sym in 131699461Sobrien check_relocs. We can't decide accurately between function and 131799461Sobrien non-function syms in check-relocs; Objects loaded later in 131899461Sobrien the link may change h->type. So fix it now. */ 131989857Sobrien h->plt.offset = (bfd_vma) -1; 132085815Sobrien 132185815Sobrien /* If this is a weak symbol, and there is a real definition, the 132285815Sobrien processor independent code will have arranged for us to see the 132385815Sobrien real definition first, and we can just use the same value. */ 1324218822Sdim if (h->u.weakdef != NULL) 132585815Sobrien { 1326218822Sdim BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined 1327218822Sdim || h->u.weakdef->root.type == bfd_link_hash_defweak); 1328218822Sdim h->root.u.def.section = h->u.weakdef->root.u.def.section; 1329218822Sdim h->root.u.def.value = h->u.weakdef->root.u.def.value; 1330130561Sobrien if (ELIMINATE_COPY_RELOCS || info->nocopyreloc) 1331218822Sdim h->non_got_ref = h->u.weakdef->non_got_ref; 1332130561Sobrien return TRUE; 133385815Sobrien } 133485815Sobrien 133585815Sobrien /* This is a reference to a symbol defined by a dynamic object which 133685815Sobrien is not a function. */ 133785815Sobrien 133885815Sobrien /* If we are creating a shared library, we must presume that the 133985815Sobrien only references to the symbol are via the global offset table. 134085815Sobrien For such cases we need not do anything here; the relocations will 134185815Sobrien be handled correctly by relocate_section. */ 134285815Sobrien if (info->shared) 1343130561Sobrien return TRUE; 134485815Sobrien 134585815Sobrien /* If there are no references to this symbol that do not use the 134685815Sobrien GOT, we don't need to generate a copy reloc. */ 1347218822Sdim if (!h->non_got_ref) 1348130561Sobrien return TRUE; 134985815Sobrien 135099461Sobrien /* If -z nocopyreloc was given, we won't generate them either. */ 135199461Sobrien if (info->nocopyreloc) 135299461Sobrien { 1353218822Sdim h->non_got_ref = 0; 1354130561Sobrien return TRUE; 135599461Sobrien } 135699461Sobrien 1357130561Sobrien if (ELIMINATE_COPY_RELOCS) 135899461Sobrien { 1359130561Sobrien struct elf64_x86_64_link_hash_entry * eh; 1360130561Sobrien struct elf64_x86_64_dyn_relocs *p; 136199461Sobrien 1362130561Sobrien eh = (struct elf64_x86_64_link_hash_entry *) h; 1363130561Sobrien for (p = eh->dyn_relocs; p != NULL; p = p->next) 1364130561Sobrien { 1365130561Sobrien s = p->sec->output_section; 1366130561Sobrien if (s != NULL && (s->flags & SEC_READONLY) != 0) 1367130561Sobrien break; 1368130561Sobrien } 1369130561Sobrien 1370130561Sobrien /* If we didn't find any dynamic relocs in read-only sections, then 1371130561Sobrien we'll be keeping the dynamic relocs and avoiding the copy reloc. */ 1372130561Sobrien if (p == NULL) 1373130561Sobrien { 1374218822Sdim h->non_got_ref = 0; 1375130561Sobrien return TRUE; 1376130561Sobrien } 137799461Sobrien } 137899461Sobrien 1379218822Sdim if (h->size == 0) 1380218822Sdim { 1381218822Sdim (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"), 1382218822Sdim h->root.root.string); 1383218822Sdim return TRUE; 1384218822Sdim } 1385218822Sdim 138685815Sobrien /* We must allocate the symbol in our .dynbss section, which will 138785815Sobrien become part of the .bss section of the executable. There will be 138885815Sobrien an entry for this symbol in the .dynsym section. The dynamic 138985815Sobrien object will contain position independent code, so all references 139085815Sobrien from the dynamic object to this symbol will go through the global 139185815Sobrien offset table. The dynamic linker will use the .dynsym entry to 139285815Sobrien determine the address it must put in the global offset table, so 139385815Sobrien both the dynamic object and the regular object will refer to the 139485815Sobrien same memory location for the variable. */ 139585815Sobrien 139699461Sobrien htab = elf64_x86_64_hash_table (info); 139785815Sobrien 139885815Sobrien /* We must generate a R_X86_64_COPY reloc to tell the dynamic linker 139985815Sobrien to copy the initial value out of the dynamic object and into the 1400104834Sobrien runtime process image. */ 140185815Sobrien if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) 140285815Sobrien { 1403218822Sdim htab->srelbss->size += sizeof (Elf64_External_Rela); 1404218822Sdim h->needs_copy = 1; 140585815Sobrien } 140685815Sobrien 140799461Sobrien s = htab->sdynbss; 140885815Sobrien 1409218822Sdim return _bfd_elf_adjust_dynamic_copy (h, s); 141085815Sobrien} 141185815Sobrien 141299461Sobrien/* Allocate space in .plt, .got and associated reloc sections for 141399461Sobrien dynamic relocs. */ 141499461Sobrien 1415130561Sobrienstatic bfd_boolean 1416130561Sobrienallocate_dynrelocs (struct elf_link_hash_entry *h, void * inf) 141799461Sobrien{ 141899461Sobrien struct bfd_link_info *info; 141999461Sobrien struct elf64_x86_64_link_hash_table *htab; 142099461Sobrien struct elf64_x86_64_link_hash_entry *eh; 142199461Sobrien struct elf64_x86_64_dyn_relocs *p; 142299461Sobrien 142399461Sobrien if (h->root.type == bfd_link_hash_indirect) 1424130561Sobrien return TRUE; 142599461Sobrien 142699461Sobrien if (h->root.type == bfd_link_hash_warning) 142799461Sobrien h = (struct elf_link_hash_entry *) h->root.u.i.link; 142899461Sobrien 142999461Sobrien info = (struct bfd_link_info *) inf; 143099461Sobrien htab = elf64_x86_64_hash_table (info); 143199461Sobrien 143299461Sobrien if (htab->elf.dynamic_sections_created 143399461Sobrien && h->plt.refcount > 0) 143499461Sobrien { 143599461Sobrien /* Make sure this symbol is output as a dynamic symbol. 143699461Sobrien Undefined weak syms won't yet be marked as dynamic. */ 143799461Sobrien if (h->dynindx == -1 1438218822Sdim && !h->forced_local) 143999461Sobrien { 1440130561Sobrien if (! bfd_elf_link_record_dynamic_symbol (info, h)) 1441130561Sobrien return FALSE; 144299461Sobrien } 144399461Sobrien 1444130561Sobrien if (info->shared 1445130561Sobrien || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) 144699461Sobrien { 144799461Sobrien asection *s = htab->splt; 144899461Sobrien 144999461Sobrien /* If this is the first .plt entry, make room for the special 145099461Sobrien first entry. */ 1451218822Sdim if (s->size == 0) 1452218822Sdim s->size += PLT_ENTRY_SIZE; 145399461Sobrien 1454218822Sdim h->plt.offset = s->size; 145599461Sobrien 145699461Sobrien /* If this symbol is not defined in a regular file, and we are 145799461Sobrien not generating a shared library, then set the symbol to this 145899461Sobrien location in the .plt. This is required to make function 145999461Sobrien pointers compare as equal between the normal executable and 146099461Sobrien the shared library. */ 146199461Sobrien if (! info->shared 1462218822Sdim && !h->def_regular) 146399461Sobrien { 146499461Sobrien h->root.u.def.section = s; 146599461Sobrien h->root.u.def.value = h->plt.offset; 146699461Sobrien } 146799461Sobrien 146899461Sobrien /* Make room for this entry. */ 1469218822Sdim s->size += PLT_ENTRY_SIZE; 147099461Sobrien 147199461Sobrien /* We also need to make an entry in the .got.plt section, which 147299461Sobrien will be placed in the .got section by the linker script. */ 1473218822Sdim htab->sgotplt->size += GOT_ENTRY_SIZE; 147499461Sobrien 147599461Sobrien /* We also need to make an entry in the .rela.plt section. */ 1476218822Sdim htab->srelplt->size += sizeof (Elf64_External_Rela); 1477218822Sdim htab->srelplt->reloc_count++; 147899461Sobrien } 147999461Sobrien else 148099461Sobrien { 148199461Sobrien h->plt.offset = (bfd_vma) -1; 1482218822Sdim h->needs_plt = 0; 148399461Sobrien } 148499461Sobrien } 148599461Sobrien else 148699461Sobrien { 148799461Sobrien h->plt.offset = (bfd_vma) -1; 1488218822Sdim h->needs_plt = 0; 148999461Sobrien } 149099461Sobrien 1491218822Sdim eh = (struct elf64_x86_64_link_hash_entry *) h; 1492218822Sdim eh->tlsdesc_got = (bfd_vma) -1; 1493218822Sdim 1494130561Sobrien /* If R_X86_64_GOTTPOFF symbol is now local to the binary, 1495130561Sobrien make it a R_X86_64_TPOFF32 requiring no GOT entry. */ 1496130561Sobrien if (h->got.refcount > 0 1497130561Sobrien && !info->shared 1498130561Sobrien && h->dynindx == -1 1499130561Sobrien && elf64_x86_64_hash_entry (h)->tls_type == GOT_TLS_IE) 1500130561Sobrien h->got.offset = (bfd_vma) -1; 1501130561Sobrien else if (h->got.refcount > 0) 150299461Sobrien { 150399461Sobrien asection *s; 1504130561Sobrien bfd_boolean dyn; 1505130561Sobrien int tls_type = elf64_x86_64_hash_entry (h)->tls_type; 150699461Sobrien 150799461Sobrien /* Make sure this symbol is output as a dynamic symbol. 150899461Sobrien Undefined weak syms won't yet be marked as dynamic. */ 150999461Sobrien if (h->dynindx == -1 1510218822Sdim && !h->forced_local) 151199461Sobrien { 1512130561Sobrien if (! bfd_elf_link_record_dynamic_symbol (info, h)) 1513130561Sobrien return FALSE; 151499461Sobrien } 151599461Sobrien 1516218822Sdim if (GOT_TLS_GDESC_P (tls_type)) 1517218822Sdim { 1518218822Sdim eh->tlsdesc_got = htab->sgotplt->size 1519218822Sdim - elf64_x86_64_compute_jump_table_size (htab); 1520218822Sdim htab->sgotplt->size += 2 * GOT_ENTRY_SIZE; 1521218822Sdim h->got.offset = (bfd_vma) -2; 1522218822Sdim } 1523218822Sdim if (! GOT_TLS_GDESC_P (tls_type) 1524218822Sdim || GOT_TLS_GD_P (tls_type)) 1525218822Sdim { 1526218822Sdim s = htab->sgot; 1527218822Sdim h->got.offset = s->size; 1528218822Sdim s->size += GOT_ENTRY_SIZE; 1529218822Sdim if (GOT_TLS_GD_P (tls_type)) 1530218822Sdim s->size += GOT_ENTRY_SIZE; 1531218822Sdim } 153299461Sobrien dyn = htab->elf.dynamic_sections_created; 1533130561Sobrien /* R_X86_64_TLSGD needs one dynamic relocation if local symbol 1534130561Sobrien and two if global. 1535130561Sobrien R_X86_64_GOTTPOFF needs one dynamic relocation. */ 1536218822Sdim if ((GOT_TLS_GD_P (tls_type) && h->dynindx == -1) 1537130561Sobrien || tls_type == GOT_TLS_IE) 1538218822Sdim htab->srelgot->size += sizeof (Elf64_External_Rela); 1539218822Sdim else if (GOT_TLS_GD_P (tls_type)) 1540218822Sdim htab->srelgot->size += 2 * sizeof (Elf64_External_Rela); 1541218822Sdim else if (! GOT_TLS_GDESC_P (tls_type) 1542218822Sdim && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT 1543218822Sdim || h->root.type != bfd_link_hash_undefweak) 1544130561Sobrien && (info->shared 1545130561Sobrien || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h))) 1546218822Sdim htab->srelgot->size += sizeof (Elf64_External_Rela); 1547218822Sdim if (GOT_TLS_GDESC_P (tls_type)) 1548218822Sdim { 1549218822Sdim htab->srelplt->size += sizeof (Elf64_External_Rela); 1550218822Sdim htab->tlsdesc_plt = (bfd_vma) -1; 1551218822Sdim } 155299461Sobrien } 155399461Sobrien else 155499461Sobrien h->got.offset = (bfd_vma) -1; 155599461Sobrien 155699461Sobrien if (eh->dyn_relocs == NULL) 1557130561Sobrien return TRUE; 155899461Sobrien 155999461Sobrien /* In the shared -Bsymbolic case, discard space allocated for 156099461Sobrien dynamic pc-relative relocs against symbols which turn out to be 156199461Sobrien defined in regular objects. For the normal shared case, discard 156299461Sobrien space for pc-relative relocs that have become local due to symbol 156399461Sobrien visibility changes. */ 156499461Sobrien 156599461Sobrien if (info->shared) 156699461Sobrien { 1567130561Sobrien /* Relocs that use pc_count are those that appear on a call 1568130561Sobrien insn, or certain REL relocs that can generated via assembly. 1569130561Sobrien We want calls to protected symbols to resolve directly to the 1570130561Sobrien function rather than going via the plt. If people want 1571130561Sobrien function pointer comparisons to work as expected then they 1572130561Sobrien should avoid writing weird assembly. */ 1573130561Sobrien if (SYMBOL_CALLS_LOCAL (info, h)) 157499461Sobrien { 157599461Sobrien struct elf64_x86_64_dyn_relocs **pp; 157699461Sobrien 157799461Sobrien for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) 157899461Sobrien { 157999461Sobrien p->count -= p->pc_count; 158099461Sobrien p->pc_count = 0; 158199461Sobrien if (p->count == 0) 158299461Sobrien *pp = p->next; 158399461Sobrien else 158499461Sobrien pp = &p->next; 158599461Sobrien } 158699461Sobrien } 1587130561Sobrien 1588130561Sobrien /* Also discard relocs on undefined weak syms with non-default 1589130561Sobrien visibility. */ 1590218822Sdim if (eh->dyn_relocs != NULL 1591130561Sobrien && h->root.type == bfd_link_hash_undefweak) 1592218822Sdim { 1593218822Sdim if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) 1594218822Sdim eh->dyn_relocs = NULL; 1595218822Sdim 1596218822Sdim /* Make sure undefined weak symbols are output as a dynamic 1597218822Sdim symbol in PIEs. */ 1598218822Sdim else if (h->dynindx == -1 1599218822Sdim && !h->forced_local) 1600218822Sdim { 1601218822Sdim if (! bfd_elf_link_record_dynamic_symbol (info, h)) 1602218822Sdim return FALSE; 1603218822Sdim } 1604218822Sdim } 160599461Sobrien } 1606130561Sobrien else if (ELIMINATE_COPY_RELOCS) 160799461Sobrien { 160899461Sobrien /* For the non-shared case, discard space for relocs against 160999461Sobrien symbols which turn out to need copy relocs or are not 161099461Sobrien dynamic. */ 161199461Sobrien 1612218822Sdim if (!h->non_got_ref 1613218822Sdim && ((h->def_dynamic 1614218822Sdim && !h->def_regular) 161599461Sobrien || (htab->elf.dynamic_sections_created 161699461Sobrien && (h->root.type == bfd_link_hash_undefweak 161799461Sobrien || h->root.type == bfd_link_hash_undefined)))) 161899461Sobrien { 161999461Sobrien /* Make sure this symbol is output as a dynamic symbol. 162099461Sobrien Undefined weak syms won't yet be marked as dynamic. */ 162199461Sobrien if (h->dynindx == -1 1622218822Sdim && !h->forced_local) 162399461Sobrien { 1624130561Sobrien if (! bfd_elf_link_record_dynamic_symbol (info, h)) 1625130561Sobrien return FALSE; 162699461Sobrien } 162799461Sobrien 162899461Sobrien /* If that succeeded, we know we'll be keeping all the 162999461Sobrien relocs. */ 163099461Sobrien if (h->dynindx != -1) 163199461Sobrien goto keep; 163299461Sobrien } 163399461Sobrien 163499461Sobrien eh->dyn_relocs = NULL; 163599461Sobrien 163699461Sobrien keep: ; 163799461Sobrien } 163899461Sobrien 163999461Sobrien /* Finally, allocate space. */ 164099461Sobrien for (p = eh->dyn_relocs; p != NULL; p = p->next) 164199461Sobrien { 164299461Sobrien asection *sreloc = elf_section_data (p->sec)->sreloc; 1643218822Sdim sreloc->size += p->count * sizeof (Elf64_External_Rela); 164499461Sobrien } 164599461Sobrien 1646130561Sobrien return TRUE; 164799461Sobrien} 164899461Sobrien 164999461Sobrien/* Find any dynamic relocs that apply to read-only sections. */ 165099461Sobrien 1651130561Sobrienstatic bfd_boolean 1652130561Sobrienreadonly_dynrelocs (struct elf_link_hash_entry *h, void * inf) 165399461Sobrien{ 165499461Sobrien struct elf64_x86_64_link_hash_entry *eh; 165599461Sobrien struct elf64_x86_64_dyn_relocs *p; 165699461Sobrien 165799461Sobrien if (h->root.type == bfd_link_hash_warning) 165899461Sobrien h = (struct elf_link_hash_entry *) h->root.u.i.link; 165999461Sobrien 166099461Sobrien eh = (struct elf64_x86_64_link_hash_entry *) h; 166199461Sobrien for (p = eh->dyn_relocs; p != NULL; p = p->next) 166299461Sobrien { 166399461Sobrien asection *s = p->sec->output_section; 166499461Sobrien 166599461Sobrien if (s != NULL && (s->flags & SEC_READONLY) != 0) 166699461Sobrien { 166799461Sobrien struct bfd_link_info *info = (struct bfd_link_info *) inf; 166899461Sobrien 166999461Sobrien info->flags |= DF_TEXTREL; 167099461Sobrien 167199461Sobrien /* Not an error, just cut short the traversal. */ 1672130561Sobrien return FALSE; 167399461Sobrien } 167499461Sobrien } 1675130561Sobrien return TRUE; 167699461Sobrien} 167799461Sobrien 167885815Sobrien/* Set the sizes of the dynamic sections. */ 167985815Sobrien 1680130561Sobrienstatic bfd_boolean 1681130561Sobrienelf64_x86_64_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, 1682130561Sobrien struct bfd_link_info *info) 168385815Sobrien{ 168499461Sobrien struct elf64_x86_64_link_hash_table *htab; 168585815Sobrien bfd *dynobj; 168685815Sobrien asection *s; 1687130561Sobrien bfd_boolean relocs; 168899461Sobrien bfd *ibfd; 168985815Sobrien 169099461Sobrien htab = elf64_x86_64_hash_table (info); 169199461Sobrien dynobj = htab->elf.dynobj; 169299461Sobrien if (dynobj == NULL) 169399461Sobrien abort (); 169485815Sobrien 169599461Sobrien if (htab->elf.dynamic_sections_created) 169685815Sobrien { 169785815Sobrien /* Set the contents of the .interp section to the interpreter. */ 1698130561Sobrien if (info->executable) 169985815Sobrien { 170085815Sobrien s = bfd_get_section_by_name (dynobj, ".interp"); 170199461Sobrien if (s == NULL) 170299461Sobrien abort (); 1703218822Sdim s->size = sizeof ELF_DYNAMIC_INTERPRETER; 170485815Sobrien s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; 170585815Sobrien } 170685815Sobrien } 170785815Sobrien 170899461Sobrien /* Set up .got offsets for local syms, and space for local dynamic 170999461Sobrien relocs. */ 171099461Sobrien for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 171185815Sobrien { 171299461Sobrien bfd_signed_vma *local_got; 171399461Sobrien bfd_signed_vma *end_local_got; 1714130561Sobrien char *local_tls_type; 1715218822Sdim bfd_vma *local_tlsdesc_gotent; 171699461Sobrien bfd_size_type locsymcount; 171799461Sobrien Elf_Internal_Shdr *symtab_hdr; 171899461Sobrien asection *srel; 171985815Sobrien 172099461Sobrien if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour) 172185815Sobrien continue; 172285815Sobrien 172399461Sobrien for (s = ibfd->sections; s != NULL; s = s->next) 172499461Sobrien { 172599461Sobrien struct elf64_x86_64_dyn_relocs *p; 172685815Sobrien 1727218822Sdim for (p = (struct elf64_x86_64_dyn_relocs *) 1728218822Sdim (elf_section_data (s)->local_dynrel); 172999461Sobrien p != NULL; 173099461Sobrien p = p->next) 173185815Sobrien { 173299461Sobrien if (!bfd_is_abs_section (p->sec) 173399461Sobrien && bfd_is_abs_section (p->sec->output_section)) 173499461Sobrien { 173599461Sobrien /* Input section has been discarded, either because 173699461Sobrien it is a copy of a linkonce section or due to 173799461Sobrien linker script /DISCARD/, so we'll be discarding 173899461Sobrien the relocs too. */ 173999461Sobrien } 174099461Sobrien else if (p->count != 0) 174199461Sobrien { 174299461Sobrien srel = elf_section_data (p->sec)->sreloc; 1743218822Sdim srel->size += p->count * sizeof (Elf64_External_Rela); 174499461Sobrien if ((p->sec->output_section->flags & SEC_READONLY) != 0) 174599461Sobrien info->flags |= DF_TEXTREL; 174699461Sobrien 174799461Sobrien } 174885815Sobrien } 174985815Sobrien } 175099461Sobrien 175199461Sobrien local_got = elf_local_got_refcounts (ibfd); 175299461Sobrien if (!local_got) 175399461Sobrien continue; 175499461Sobrien 175599461Sobrien symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; 175699461Sobrien locsymcount = symtab_hdr->sh_info; 175799461Sobrien end_local_got = local_got + locsymcount; 1758130561Sobrien local_tls_type = elf64_x86_64_local_got_tls_type (ibfd); 1759218822Sdim local_tlsdesc_gotent = elf64_x86_64_local_tlsdesc_gotent (ibfd); 176099461Sobrien s = htab->sgot; 176199461Sobrien srel = htab->srelgot; 1762218822Sdim for (; local_got < end_local_got; 1763218822Sdim ++local_got, ++local_tls_type, ++local_tlsdesc_gotent) 176485815Sobrien { 1765218822Sdim *local_tlsdesc_gotent = (bfd_vma) -1; 176699461Sobrien if (*local_got > 0) 176785815Sobrien { 1768218822Sdim if (GOT_TLS_GDESC_P (*local_tls_type)) 1769218822Sdim { 1770218822Sdim *local_tlsdesc_gotent = htab->sgotplt->size 1771218822Sdim - elf64_x86_64_compute_jump_table_size (htab); 1772218822Sdim htab->sgotplt->size += 2 * GOT_ENTRY_SIZE; 1773218822Sdim *local_got = (bfd_vma) -2; 1774218822Sdim } 1775218822Sdim if (! GOT_TLS_GDESC_P (*local_tls_type) 1776218822Sdim || GOT_TLS_GD_P (*local_tls_type)) 1777218822Sdim { 1778218822Sdim *local_got = s->size; 1779218822Sdim s->size += GOT_ENTRY_SIZE; 1780218822Sdim if (GOT_TLS_GD_P (*local_tls_type)) 1781218822Sdim s->size += GOT_ENTRY_SIZE; 1782218822Sdim } 1783130561Sobrien if (info->shared 1784218822Sdim || GOT_TLS_GD_ANY_P (*local_tls_type) 1785130561Sobrien || *local_tls_type == GOT_TLS_IE) 1786218822Sdim { 1787218822Sdim if (GOT_TLS_GDESC_P (*local_tls_type)) 1788218822Sdim { 1789218822Sdim htab->srelplt->size += sizeof (Elf64_External_Rela); 1790218822Sdim htab->tlsdesc_plt = (bfd_vma) -1; 1791218822Sdim } 1792218822Sdim if (! GOT_TLS_GDESC_P (*local_tls_type) 1793218822Sdim || GOT_TLS_GD_P (*local_tls_type)) 1794218822Sdim srel->size += sizeof (Elf64_External_Rela); 1795218822Sdim } 179685815Sobrien } 179785815Sobrien else 179899461Sobrien *local_got = (bfd_vma) -1; 179999461Sobrien } 180099461Sobrien } 180185815Sobrien 1802130561Sobrien if (htab->tls_ld_got.refcount > 0) 1803130561Sobrien { 1804130561Sobrien /* Allocate 2 got entries and 1 dynamic reloc for R_X86_64_TLSLD 1805130561Sobrien relocs. */ 1806218822Sdim htab->tls_ld_got.offset = htab->sgot->size; 1807218822Sdim htab->sgot->size += 2 * GOT_ENTRY_SIZE; 1808218822Sdim htab->srelgot->size += sizeof (Elf64_External_Rela); 1809130561Sobrien } 1810130561Sobrien else 1811130561Sobrien htab->tls_ld_got.offset = -1; 1812130561Sobrien 181399461Sobrien /* Allocate global sym .plt and .got entries, and space for global 181499461Sobrien sym dynamic relocs. */ 181599461Sobrien elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, (PTR) info); 181699461Sobrien 1817218822Sdim /* For every jump slot reserved in the sgotplt, reloc_count is 1818218822Sdim incremented. However, when we reserve space for TLS descriptors, 1819218822Sdim it's not incremented, so in order to compute the space reserved 1820218822Sdim for them, it suffices to multiply the reloc count by the jump 1821218822Sdim slot size. */ 1822218822Sdim if (htab->srelplt) 1823218822Sdim htab->sgotplt_jump_table_size 1824218822Sdim = elf64_x86_64_compute_jump_table_size (htab); 1825218822Sdim 1826218822Sdim if (htab->tlsdesc_plt) 1827218822Sdim { 1828218822Sdim /* If we're not using lazy TLS relocations, don't generate the 1829218822Sdim PLT and GOT entries they require. */ 1830218822Sdim if ((info->flags & DF_BIND_NOW)) 1831218822Sdim htab->tlsdesc_plt = 0; 1832218822Sdim else 1833218822Sdim { 1834218822Sdim htab->tlsdesc_got = htab->sgot->size; 1835218822Sdim htab->sgot->size += GOT_ENTRY_SIZE; 1836218822Sdim /* Reserve room for the initial entry. 1837218822Sdim FIXME: we could probably do away with it in this case. */ 1838218822Sdim if (htab->splt->size == 0) 1839218822Sdim htab->splt->size += PLT_ENTRY_SIZE; 1840218822Sdim htab->tlsdesc_plt = htab->splt->size; 1841218822Sdim htab->splt->size += PLT_ENTRY_SIZE; 1842218822Sdim } 1843218822Sdim } 1844218822Sdim 184599461Sobrien /* We now have determined the sizes of the various dynamic sections. 184699461Sobrien Allocate memory for them. */ 1847130561Sobrien relocs = FALSE; 184899461Sobrien for (s = dynobj->sections; s != NULL; s = s->next) 184999461Sobrien { 185099461Sobrien if ((s->flags & SEC_LINKER_CREATED) == 0) 185199461Sobrien continue; 185299461Sobrien 185399461Sobrien if (s == htab->splt 185499461Sobrien || s == htab->sgot 1855218822Sdim || s == htab->sgotplt 1856218822Sdim || s == htab->sdynbss) 185799461Sobrien { 185899461Sobrien /* Strip this section if we don't need it; see the 185999461Sobrien comment below. */ 186085815Sobrien } 1861218822Sdim else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) 186285815Sobrien { 1863218822Sdim if (s->size != 0 && s != htab->srelplt) 1864130561Sobrien relocs = TRUE; 186599461Sobrien 186699461Sobrien /* We use the reloc_count field as a counter if we need 186799461Sobrien to copy relocs into the output file. */ 1868218822Sdim if (s != htab->srelplt) 1869218822Sdim s->reloc_count = 0; 187099461Sobrien } 187199461Sobrien else 187299461Sobrien { 187385815Sobrien /* It's not one of our sections, so don't allocate space. */ 187485815Sobrien continue; 187585815Sobrien } 187685815Sobrien 1877218822Sdim if (s->size == 0) 187885815Sobrien { 187999461Sobrien /* If we don't need this section, strip it from the 188099461Sobrien output file. This is mostly to handle .rela.bss and 188199461Sobrien .rela.plt. We must create both sections in 188299461Sobrien create_dynamic_sections, because they must be created 188399461Sobrien before the linker maps input sections to output 188499461Sobrien sections. The linker does that before 188599461Sobrien adjust_dynamic_symbol is called, and it is that 188699461Sobrien function which decides whether anything needs to go 188799461Sobrien into these sections. */ 188899461Sobrien 1889218822Sdim s->flags |= SEC_EXCLUDE; 189085815Sobrien continue; 189185815Sobrien } 189285815Sobrien 1893218822Sdim if ((s->flags & SEC_HAS_CONTENTS) == 0) 1894218822Sdim continue; 1895218822Sdim 189685815Sobrien /* Allocate memory for the section contents. We use bfd_zalloc 189785815Sobrien here in case unused entries are not reclaimed before the 189885815Sobrien section's contents are written out. This should not happen, 189985815Sobrien but this way if it does, we get a R_X86_64_NONE reloc instead 190085815Sobrien of garbage. */ 1901218822Sdim s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size); 190299461Sobrien if (s->contents == NULL) 1903130561Sobrien return FALSE; 190485815Sobrien } 190585815Sobrien 190699461Sobrien if (htab->elf.dynamic_sections_created) 190785815Sobrien { 190885815Sobrien /* Add some entries to the .dynamic section. We fill in the 190985815Sobrien values later, in elf64_x86_64_finish_dynamic_sections, but we 191085815Sobrien must add the entries now so that we get the correct size for 191185815Sobrien the .dynamic section. The DT_DEBUG entry is filled in by the 191285815Sobrien dynamic linker and used by the debugger. */ 191389857Sobrien#define add_dynamic_entry(TAG, VAL) \ 1914130561Sobrien _bfd_elf_add_dynamic_entry (info, TAG, VAL) 191589857Sobrien 1916130561Sobrien if (info->executable) 191785815Sobrien { 191889857Sobrien if (!add_dynamic_entry (DT_DEBUG, 0)) 1919130561Sobrien return FALSE; 192085815Sobrien } 192185815Sobrien 1922218822Sdim if (htab->splt->size != 0) 192385815Sobrien { 192489857Sobrien if (!add_dynamic_entry (DT_PLTGOT, 0) 192589857Sobrien || !add_dynamic_entry (DT_PLTRELSZ, 0) 192689857Sobrien || !add_dynamic_entry (DT_PLTREL, DT_RELA) 192789857Sobrien || !add_dynamic_entry (DT_JMPREL, 0)) 1928130561Sobrien return FALSE; 1929218822Sdim 1930218822Sdim if (htab->tlsdesc_plt 1931218822Sdim && (!add_dynamic_entry (DT_TLSDESC_PLT, 0) 1932218822Sdim || !add_dynamic_entry (DT_TLSDESC_GOT, 0))) 1933218822Sdim return FALSE; 193485815Sobrien } 193585815Sobrien 193685815Sobrien if (relocs) 193785815Sobrien { 193889857Sobrien if (!add_dynamic_entry (DT_RELA, 0) 193989857Sobrien || !add_dynamic_entry (DT_RELASZ, 0) 194089857Sobrien || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela))) 1941130561Sobrien return FALSE; 194285815Sobrien 194399461Sobrien /* If any dynamic relocs apply to a read-only section, 194499461Sobrien then we need a DT_TEXTREL entry. */ 194599461Sobrien if ((info->flags & DF_TEXTREL) == 0) 194699461Sobrien elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, 194799461Sobrien (PTR) info); 194899461Sobrien 194999461Sobrien if ((info->flags & DF_TEXTREL) != 0) 195099461Sobrien { 195199461Sobrien if (!add_dynamic_entry (DT_TEXTREL, 0)) 1952130561Sobrien return FALSE; 195399461Sobrien } 195485815Sobrien } 195585815Sobrien } 195689857Sobrien#undef add_dynamic_entry 195785815Sobrien 1958130561Sobrien return TRUE; 195985815Sobrien} 196085815Sobrien 1961218822Sdimstatic bfd_boolean 1962218822Sdimelf64_x86_64_always_size_sections (bfd *output_bfd, 1963218822Sdim struct bfd_link_info *info) 1964218822Sdim{ 1965218822Sdim asection *tls_sec = elf_hash_table (info)->tls_sec; 1966218822Sdim 1967218822Sdim if (tls_sec) 1968218822Sdim { 1969218822Sdim struct elf_link_hash_entry *tlsbase; 1970218822Sdim 1971218822Sdim tlsbase = elf_link_hash_lookup (elf_hash_table (info), 1972218822Sdim "_TLS_MODULE_BASE_", 1973218822Sdim FALSE, FALSE, FALSE); 1974218822Sdim 1975218822Sdim if (tlsbase && tlsbase->type == STT_TLS) 1976218822Sdim { 1977218822Sdim struct bfd_link_hash_entry *bh = NULL; 1978218822Sdim const struct elf_backend_data *bed 1979218822Sdim = get_elf_backend_data (output_bfd); 1980218822Sdim 1981218822Sdim if (!(_bfd_generic_link_add_one_symbol 1982218822Sdim (info, output_bfd, "_TLS_MODULE_BASE_", BSF_LOCAL, 1983218822Sdim tls_sec, 0, NULL, FALSE, 1984218822Sdim bed->collect, &bh))) 1985218822Sdim return FALSE; 1986218822Sdim tlsbase = (struct elf_link_hash_entry *)bh; 1987218822Sdim tlsbase->def_regular = 1; 1988218822Sdim tlsbase->other = STV_HIDDEN; 1989218822Sdim (*bed->elf_backend_hide_symbol) (info, tlsbase, TRUE); 1990218822Sdim } 1991218822Sdim } 1992218822Sdim 1993218822Sdim return TRUE; 1994218822Sdim} 1995218822Sdim 1996130561Sobrien/* Return the base VMA address which should be subtracted from real addresses 1997130561Sobrien when resolving @dtpoff relocation. 1998130561Sobrien This is PT_TLS segment p_vaddr. */ 1999130561Sobrien 2000130561Sobrienstatic bfd_vma 2001130561Sobriendtpoff_base (struct bfd_link_info *info) 2002130561Sobrien{ 2003130561Sobrien /* If tls_sec is NULL, we should have signalled an error already. */ 2004130561Sobrien if (elf_hash_table (info)->tls_sec == NULL) 2005130561Sobrien return 0; 2006130561Sobrien return elf_hash_table (info)->tls_sec->vma; 2007130561Sobrien} 2008130561Sobrien 2009130561Sobrien/* Return the relocation value for @tpoff relocation 2010130561Sobrien if STT_TLS virtual address is ADDRESS. */ 2011130561Sobrien 2012130561Sobrienstatic bfd_vma 2013130561Sobrientpoff (struct bfd_link_info *info, bfd_vma address) 2014130561Sobrien{ 2015130561Sobrien struct elf_link_hash_table *htab = elf_hash_table (info); 2016130561Sobrien 2017130561Sobrien /* If tls_segment is NULL, we should have signalled an error already. */ 2018130561Sobrien if (htab->tls_sec == NULL) 2019130561Sobrien return 0; 2020130561Sobrien return address - htab->tls_size - htab->tls_sec->vma; 2021130561Sobrien} 2022130561Sobrien 2023218822Sdim/* Is the instruction before OFFSET in CONTENTS a 32bit relative 2024218822Sdim branch? */ 2025218822Sdim 2026218822Sdimstatic bfd_boolean 2027218822Sdimis_32bit_relative_branch (bfd_byte *contents, bfd_vma offset) 2028218822Sdim{ 2029218822Sdim /* Opcode Instruction 2030218822Sdim 0xe8 call 2031218822Sdim 0xe9 jump 2032218822Sdim 0x0f 0x8x conditional jump */ 2033218822Sdim return ((offset > 0 2034218822Sdim && (contents [offset - 1] == 0xe8 2035218822Sdim || contents [offset - 1] == 0xe9)) 2036218822Sdim || (offset > 1 2037218822Sdim && contents [offset - 2] == 0x0f 2038218822Sdim && (contents [offset - 1] & 0xf0) == 0x80)); 2039218822Sdim} 2040218822Sdim 204185815Sobrien/* Relocate an x86_64 ELF section. */ 204285815Sobrien 2043130561Sobrienstatic bfd_boolean 2044130561Sobrienelf64_x86_64_relocate_section (bfd *output_bfd, struct bfd_link_info *info, 2045130561Sobrien bfd *input_bfd, asection *input_section, 2046130561Sobrien bfd_byte *contents, Elf_Internal_Rela *relocs, 2047130561Sobrien Elf_Internal_Sym *local_syms, 2048130561Sobrien asection **local_sections) 204985815Sobrien{ 205099461Sobrien struct elf64_x86_64_link_hash_table *htab; 205185815Sobrien Elf_Internal_Shdr *symtab_hdr; 205285815Sobrien struct elf_link_hash_entry **sym_hashes; 205385815Sobrien bfd_vma *local_got_offsets; 2054218822Sdim bfd_vma *local_tlsdesc_gotents; 205599461Sobrien Elf_Internal_Rela *rel; 205685815Sobrien Elf_Internal_Rela *relend; 205785815Sobrien 205899461Sobrien htab = elf64_x86_64_hash_table (info); 205985815Sobrien symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; 206085815Sobrien sym_hashes = elf_sym_hashes (input_bfd); 206185815Sobrien local_got_offsets = elf_local_got_offsets (input_bfd); 2062218822Sdim local_tlsdesc_gotents = elf64_x86_64_local_tlsdesc_gotent (input_bfd); 206385815Sobrien 206499461Sobrien rel = relocs; 206585815Sobrien relend = relocs + input_section->reloc_count; 206699461Sobrien for (; rel < relend; rel++) 206785815Sobrien { 2068130561Sobrien unsigned int r_type; 206985815Sobrien reloc_howto_type *howto; 207085815Sobrien unsigned long r_symndx; 207185815Sobrien struct elf_link_hash_entry *h; 207285815Sobrien Elf_Internal_Sym *sym; 207385815Sobrien asection *sec; 2074218822Sdim bfd_vma off, offplt; 207585815Sobrien bfd_vma relocation; 2076130561Sobrien bfd_boolean unresolved_reloc; 207785815Sobrien bfd_reloc_status_type r; 2078130561Sobrien int tls_type; 207985815Sobrien 208099461Sobrien r_type = ELF64_R_TYPE (rel->r_info); 208189857Sobrien if (r_type == (int) R_X86_64_GNU_VTINHERIT 208289857Sobrien || r_type == (int) R_X86_64_GNU_VTENTRY) 208389857Sobrien continue; 208485815Sobrien 2085130561Sobrien if (r_type >= R_X86_64_max) 208685815Sobrien { 208785815Sobrien bfd_set_error (bfd_error_bad_value); 2088130561Sobrien return FALSE; 208985815Sobrien } 209085815Sobrien 209199461Sobrien howto = x86_64_elf_howto_table + r_type; 209299461Sobrien r_symndx = ELF64_R_SYM (rel->r_info); 209385815Sobrien h = NULL; 209485815Sobrien sym = NULL; 209585815Sobrien sec = NULL; 2096130561Sobrien unresolved_reloc = FALSE; 209785815Sobrien if (r_symndx < symtab_hdr->sh_info) 209885815Sobrien { 209985815Sobrien sym = local_syms + r_symndx; 210085815Sobrien sec = local_sections[r_symndx]; 210199461Sobrien 2102130561Sobrien relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); 210385815Sobrien } 210485815Sobrien else 210585815Sobrien { 2106130561Sobrien bfd_boolean warned; 210799461Sobrien 2108130561Sobrien RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, 2109130561Sobrien r_symndx, symtab_hdr, sym_hashes, 2110130561Sobrien h, sec, relocation, 2111130561Sobrien unresolved_reloc, warned); 211285815Sobrien } 2113218822Sdim 2114218822Sdim if (sec != NULL && elf_discarded_section (sec)) 2115218822Sdim { 2116218822Sdim /* For relocs against symbols from removed linkonce sections, 2117218822Sdim or sections discarded by a linker script, we just want the 2118218822Sdim section contents zeroed. Avoid any special processing. */ 2119218822Sdim _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); 2120218822Sdim rel->r_info = 0; 2121218822Sdim rel->r_addend = 0; 2122218822Sdim continue; 2123218822Sdim } 2124218822Sdim 2125218822Sdim if (info->relocatable) 2126218822Sdim continue; 2127218822Sdim 212885815Sobrien /* When generating a shared object, the relocations handled here are 212985815Sobrien copied into the output file to be resolved at run time. */ 213085815Sobrien switch (r_type) 213185815Sobrien { 2132218822Sdim asection *base_got; 213385815Sobrien case R_X86_64_GOT32: 2134218822Sdim case R_X86_64_GOT64: 213585815Sobrien /* Relocation is to the entry for this symbol in the global 213685815Sobrien offset table. */ 213785815Sobrien case R_X86_64_GOTPCREL: 2138218822Sdim case R_X86_64_GOTPCREL64: 2139218822Sdim /* Use global offset table entry as symbol value. */ 2140218822Sdim case R_X86_64_GOTPLT64: 2141218822Sdim /* This is the same as GOT64 for relocation purposes, but 2142218822Sdim indicates the existence of a PLT entry. The difficulty is, 2143218822Sdim that we must calculate the GOT slot offset from the PLT 2144218822Sdim offset, if this symbol got a PLT entry (it was global). 2145218822Sdim Additionally if it's computed from the PLT entry, then that 2146218822Sdim GOT offset is relative to .got.plt, not to .got. */ 2147218822Sdim base_got = htab->sgot; 2148218822Sdim 214999461Sobrien if (htab->sgot == NULL) 215099461Sobrien abort (); 215185815Sobrien 215285815Sobrien if (h != NULL) 215385815Sobrien { 2154130561Sobrien bfd_boolean dyn; 215585815Sobrien 215699461Sobrien off = h->got.offset; 2157218822Sdim if (h->needs_plt 2158218822Sdim && h->plt.offset != (bfd_vma)-1 2159218822Sdim && off == (bfd_vma)-1) 2160218822Sdim { 2161218822Sdim /* We can't use h->got.offset here to save 2162218822Sdim state, or even just remember the offset, as 2163218822Sdim finish_dynamic_symbol would use that as offset into 2164218822Sdim .got. */ 2165218822Sdim bfd_vma plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; 2166218822Sdim off = (plt_index + 3) * GOT_ENTRY_SIZE; 2167218822Sdim base_got = htab->sgotplt; 2168218822Sdim } 2169218822Sdim 217099461Sobrien dyn = htab->elf.dynamic_sections_created; 217199461Sobrien 2172130561Sobrien if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) 217385815Sobrien || (info->shared 2174130561Sobrien && SYMBOL_REFERENCES_LOCAL (info, h)) 2175130561Sobrien || (ELF_ST_VISIBILITY (h->other) 2176130561Sobrien && h->root.type == bfd_link_hash_undefweak)) 217785815Sobrien { 217885815Sobrien /* This is actually a static link, or it is a -Bsymbolic 217985815Sobrien link and the symbol is defined locally, or the symbol 218085815Sobrien was forced to be local because of a version file. We 218185815Sobrien must initialize this entry in the global offset table. 218285815Sobrien Since the offset must always be a multiple of 8, we 218385815Sobrien use the least significant bit to record whether we 218485815Sobrien have initialized it already. 218585815Sobrien 218685815Sobrien When doing a dynamic link, we create a .rela.got 218785815Sobrien relocation entry to initialize the value. This is 218885815Sobrien done in the finish_dynamic_symbol routine. */ 218985815Sobrien if ((off & 1) != 0) 219085815Sobrien off &= ~1; 219185815Sobrien else 219285815Sobrien { 219385815Sobrien bfd_put_64 (output_bfd, relocation, 2194218822Sdim base_got->contents + off); 2195218822Sdim /* Note that this is harmless for the GOTPLT64 case, 2196218822Sdim as -1 | 1 still is -1. */ 219785815Sobrien h->got.offset |= 1; 219885815Sobrien } 219985815Sobrien } 220085815Sobrien else 2201130561Sobrien unresolved_reloc = FALSE; 220285815Sobrien } 220385815Sobrien else 220485815Sobrien { 220599461Sobrien if (local_got_offsets == NULL) 220699461Sobrien abort (); 220785815Sobrien 220885815Sobrien off = local_got_offsets[r_symndx]; 220985815Sobrien 221085815Sobrien /* The offset must always be a multiple of 8. We use 221185815Sobrien the least significant bit to record whether we have 221285815Sobrien already generated the necessary reloc. */ 221385815Sobrien if ((off & 1) != 0) 221485815Sobrien off &= ~1; 221585815Sobrien else 221685815Sobrien { 221799461Sobrien bfd_put_64 (output_bfd, relocation, 2218218822Sdim base_got->contents + off); 221985815Sobrien 222085815Sobrien if (info->shared) 222185815Sobrien { 2222130561Sobrien asection *s; 222385815Sobrien Elf_Internal_Rela outrel; 2224130561Sobrien bfd_byte *loc; 222585815Sobrien 222685815Sobrien /* We need to generate a R_X86_64_RELATIVE reloc 222785815Sobrien for the dynamic linker. */ 2228130561Sobrien s = htab->srelgot; 2229130561Sobrien if (s == NULL) 223099461Sobrien abort (); 223185815Sobrien 2232218822Sdim outrel.r_offset = (base_got->output_section->vma 2233218822Sdim + base_got->output_offset 223485815Sobrien + off); 223585815Sobrien outrel.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE); 223685815Sobrien outrel.r_addend = relocation; 2237130561Sobrien loc = s->contents; 2238130561Sobrien loc += s->reloc_count++ * sizeof (Elf64_External_Rela); 223999461Sobrien bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); 224085815Sobrien } 224185815Sobrien 224285815Sobrien local_got_offsets[r_symndx] |= 1; 224385815Sobrien } 224485815Sobrien } 224585815Sobrien 224699461Sobrien if (off >= (bfd_vma) -2) 224799461Sobrien abort (); 224899461Sobrien 2249218822Sdim relocation = base_got->output_section->vma 2250218822Sdim + base_got->output_offset + off; 2251218822Sdim if (r_type != R_X86_64_GOTPCREL && r_type != R_X86_64_GOTPCREL64) 2252218822Sdim relocation -= htab->sgotplt->output_section->vma 2253218822Sdim - htab->sgotplt->output_offset; 225499461Sobrien 225585815Sobrien break; 225685815Sobrien 2257218822Sdim case R_X86_64_GOTOFF64: 2258218822Sdim /* Relocation is relative to the start of the global offset 2259218822Sdim table. */ 2260218822Sdim 2261218822Sdim /* Check to make sure it isn't a protected function symbol 2262218822Sdim for shared library since it may not be local when used 2263218822Sdim as function address. */ 2264218822Sdim if (info->shared 2265218822Sdim && h 2266218822Sdim && h->def_regular 2267218822Sdim && h->type == STT_FUNC 2268218822Sdim && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) 2269218822Sdim { 2270218822Sdim (*_bfd_error_handler) 2271218822Sdim (_("%B: relocation R_X86_64_GOTOFF64 against protected function `%s' can not be used when making a shared object"), 2272218822Sdim input_bfd, h->root.root.string); 2273218822Sdim bfd_set_error (bfd_error_bad_value); 2274218822Sdim return FALSE; 2275218822Sdim } 2276218822Sdim 2277218822Sdim /* Note that sgot is not involved in this 2278218822Sdim calculation. We always want the start of .got.plt. If we 2279218822Sdim defined _GLOBAL_OFFSET_TABLE_ in a different way, as is 2280218822Sdim permitted by the ABI, we might have to change this 2281218822Sdim calculation. */ 2282218822Sdim relocation -= htab->sgotplt->output_section->vma 2283218822Sdim + htab->sgotplt->output_offset; 2284218822Sdim break; 2285218822Sdim 2286218822Sdim case R_X86_64_GOTPC32: 2287218822Sdim case R_X86_64_GOTPC64: 2288218822Sdim /* Use global offset table as symbol value. */ 2289218822Sdim relocation = htab->sgotplt->output_section->vma 2290218822Sdim + htab->sgotplt->output_offset; 2291218822Sdim unresolved_reloc = FALSE; 2292218822Sdim break; 2293218822Sdim 2294218822Sdim case R_X86_64_PLTOFF64: 2295218822Sdim /* Relocation is PLT entry relative to GOT. For local 2296218822Sdim symbols it's the symbol itself relative to GOT. */ 2297218822Sdim if (h != NULL 2298218822Sdim /* See PLT32 handling. */ 2299218822Sdim && h->plt.offset != (bfd_vma) -1 2300218822Sdim && htab->splt != NULL) 2301218822Sdim { 2302218822Sdim relocation = (htab->splt->output_section->vma 2303218822Sdim + htab->splt->output_offset 2304218822Sdim + h->plt.offset); 2305218822Sdim unresolved_reloc = FALSE; 2306218822Sdim } 2307218822Sdim 2308218822Sdim relocation -= htab->sgotplt->output_section->vma 2309218822Sdim + htab->sgotplt->output_offset; 2310218822Sdim break; 2311218822Sdim 231285815Sobrien case R_X86_64_PLT32: 231385815Sobrien /* Relocation is to the entry for this symbol in the 231485815Sobrien procedure linkage table. */ 231585815Sobrien 231685815Sobrien /* Resolve a PLT32 reloc against a local symbol directly, 231785815Sobrien without using the procedure linkage table. */ 231885815Sobrien if (h == NULL) 231985815Sobrien break; 232085815Sobrien 232199461Sobrien if (h->plt.offset == (bfd_vma) -1 232299461Sobrien || htab->splt == NULL) 232385815Sobrien { 232485815Sobrien /* We didn't make a PLT entry for this symbol. This 232585815Sobrien happens when statically linking PIC code, or when 232685815Sobrien using -Bsymbolic. */ 232785815Sobrien break; 232885815Sobrien } 232985815Sobrien 233099461Sobrien relocation = (htab->splt->output_section->vma 233199461Sobrien + htab->splt->output_offset 233285815Sobrien + h->plt.offset); 2333130561Sobrien unresolved_reloc = FALSE; 233485815Sobrien break; 233585815Sobrien 233685815Sobrien case R_X86_64_PC8: 233785815Sobrien case R_X86_64_PC16: 233885815Sobrien case R_X86_64_PC32: 2339218822Sdim if (info->shared 2340218822Sdim && !SYMBOL_REFERENCES_LOCAL (info, h) 2341218822Sdim && (input_section->flags & SEC_ALLOC) != 0 2342218822Sdim && (input_section->flags & SEC_READONLY) != 0 2343218822Sdim && (!h->def_regular 2344218822Sdim || r_type != R_X86_64_PC32 2345218822Sdim || h->type != STT_FUNC 2346218822Sdim || ELF_ST_VISIBILITY (h->other) != STV_PROTECTED 2347218822Sdim || !is_32bit_relative_branch (contents, 2348218822Sdim rel->r_offset))) 2349218822Sdim { 2350218822Sdim if (h->def_regular 2351218822Sdim && r_type == R_X86_64_PC32 2352218822Sdim && h->type == STT_FUNC 2353218822Sdim && ELF_ST_VISIBILITY (h->other) == STV_PROTECTED) 2354218822Sdim (*_bfd_error_handler) 2355218822Sdim (_("%B: relocation R_X86_64_PC32 against protected function `%s' can not be used when making a shared object"), 2356218822Sdim input_bfd, h->root.root.string); 2357218822Sdim else 2358218822Sdim (*_bfd_error_handler) 2359218822Sdim (_("%B: relocation %s against `%s' can not be used when making a shared object; recompile with -fPIC"), 2360218822Sdim input_bfd, x86_64_elf_howto_table[r_type].name, 2361218822Sdim h->root.root.string); 2362218822Sdim bfd_set_error (bfd_error_bad_value); 2363218822Sdim return FALSE; 2364218822Sdim } 2365218822Sdim /* Fall through. */ 2366218822Sdim 236785815Sobrien case R_X86_64_8: 236885815Sobrien case R_X86_64_16: 236985815Sobrien case R_X86_64_32: 2370218822Sdim case R_X86_64_PC64: 237185815Sobrien case R_X86_64_64: 237285815Sobrien /* FIXME: The ABI says the linker should make sure the value is 237385815Sobrien the same when it's zeroextended to 64 bit. */ 237499461Sobrien 2375218822Sdim if ((input_section->flags & SEC_ALLOC) == 0) 237699461Sobrien break; 237799461Sobrien 237899461Sobrien if ((info->shared 2379130561Sobrien && (h == NULL 2380130561Sobrien || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT 2381130561Sobrien || h->root.type != bfd_link_hash_undefweak) 238299461Sobrien && ((r_type != R_X86_64_PC8 238399461Sobrien && r_type != R_X86_64_PC16 2384218822Sdim && r_type != R_X86_64_PC32 2385218822Sdim && r_type != R_X86_64_PC64) 2386130561Sobrien || !SYMBOL_CALLS_LOCAL (info, h))) 2387130561Sobrien || (ELIMINATE_COPY_RELOCS 2388130561Sobrien && !info->shared 238999461Sobrien && h != NULL 239099461Sobrien && h->dynindx != -1 2391218822Sdim && !h->non_got_ref 2392218822Sdim && ((h->def_dynamic 2393218822Sdim && !h->def_regular) 239499461Sobrien || h->root.type == bfd_link_hash_undefweak 239599461Sobrien || h->root.type == bfd_link_hash_undefined))) 239685815Sobrien { 239785815Sobrien Elf_Internal_Rela outrel; 2398130561Sobrien bfd_byte *loc; 2399130561Sobrien bfd_boolean skip, relocate; 240099461Sobrien asection *sreloc; 240185815Sobrien 240285815Sobrien /* When generating a shared object, these relocations 240385815Sobrien are copied into the output file to be resolved at run 240485815Sobrien time. */ 2405130561Sobrien skip = FALSE; 2406130561Sobrien relocate = FALSE; 240785815Sobrien 240889857Sobrien outrel.r_offset = 240989857Sobrien _bfd_elf_section_offset (output_bfd, info, input_section, 241099461Sobrien rel->r_offset); 241189857Sobrien if (outrel.r_offset == (bfd_vma) -1) 2412130561Sobrien skip = TRUE; 241392828Sobrien else if (outrel.r_offset == (bfd_vma) -2) 2414130561Sobrien skip = TRUE, relocate = TRUE; 241585815Sobrien 241685815Sobrien outrel.r_offset += (input_section->output_section->vma 241785815Sobrien + input_section->output_offset); 241885815Sobrien 241985815Sobrien if (skip) 242091041Sobrien memset (&outrel, 0, sizeof outrel); 242199461Sobrien 242285815Sobrien /* h->dynindx may be -1 if this symbol was marked to 242385815Sobrien become local. */ 242485815Sobrien else if (h != NULL 242599461Sobrien && h->dynindx != -1 242699461Sobrien && (r_type == R_X86_64_PC8 242799461Sobrien || r_type == R_X86_64_PC16 242899461Sobrien || r_type == R_X86_64_PC32 2429218822Sdim || r_type == R_X86_64_PC64 243099461Sobrien || !info->shared 2431218822Sdim || !SYMBOLIC_BIND (info, h) 2432218822Sdim || !h->def_regular)) 243385815Sobrien { 243485815Sobrien outrel.r_info = ELF64_R_INFO (h->dynindx, r_type); 243599461Sobrien outrel.r_addend = rel->r_addend; 243685815Sobrien } 243785815Sobrien else 243885815Sobrien { 243999461Sobrien /* This symbol is local, or marked to become local. */ 2440104834Sobrien if (r_type == R_X86_64_64) 2441104834Sobrien { 2442130561Sobrien relocate = TRUE; 2443104834Sobrien outrel.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE); 2444104834Sobrien outrel.r_addend = relocation + rel->r_addend; 2445104834Sobrien } 2446104834Sobrien else 2447104834Sobrien { 2448104834Sobrien long sindx; 2449104834Sobrien 2450130561Sobrien if (bfd_is_abs_section (sec)) 2451104834Sobrien sindx = 0; 2452104834Sobrien else if (sec == NULL || sec->owner == NULL) 2453104834Sobrien { 2454104834Sobrien bfd_set_error (bfd_error_bad_value); 2455130561Sobrien return FALSE; 2456104834Sobrien } 2457104834Sobrien else 2458104834Sobrien { 2459104834Sobrien asection *osec; 2460104834Sobrien 2461218822Sdim /* We are turning this relocation into one 2462218822Sdim against a section symbol. It would be 2463218822Sdim proper to subtract the symbol's value, 2464218822Sdim osec->vma, from the emitted reloc addend, 2465218822Sdim but ld.so expects buggy relocs. */ 2466104834Sobrien osec = sec->output_section; 2467104834Sobrien sindx = elf_section_data (osec)->dynindx; 2468218822Sdim if (sindx == 0) 2469218822Sdim { 2470218822Sdim asection *oi = htab->elf.text_index_section; 2471218822Sdim sindx = elf_section_data (oi)->dynindx; 2472218822Sdim } 2473218822Sdim BFD_ASSERT (sindx != 0); 2474104834Sobrien } 2475104834Sobrien 2476104834Sobrien outrel.r_info = ELF64_R_INFO (sindx, r_type); 2477104834Sobrien outrel.r_addend = relocation + rel->r_addend; 2478104834Sobrien } 247999461Sobrien } 248085815Sobrien 248199461Sobrien sreloc = elf_section_data (input_section)->sreloc; 248299461Sobrien if (sreloc == NULL) 248399461Sobrien abort (); 248485815Sobrien 2485130561Sobrien loc = sreloc->contents; 2486130561Sobrien loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela); 248799461Sobrien bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); 248885815Sobrien 248985815Sobrien /* If this reloc is against an external symbol, we do 249085815Sobrien not want to fiddle with the addend. Otherwise, we 249185815Sobrien need to include the symbol value so that it becomes 249285815Sobrien an addend for the dynamic reloc. */ 249385815Sobrien if (! relocate) 249485815Sobrien continue; 249585815Sobrien } 249685815Sobrien 249785815Sobrien break; 249885815Sobrien 2499130561Sobrien case R_X86_64_TLSGD: 2500218822Sdim case R_X86_64_GOTPC32_TLSDESC: 2501218822Sdim case R_X86_64_TLSDESC_CALL: 2502130561Sobrien case R_X86_64_GOTTPOFF: 2503130561Sobrien r_type = elf64_x86_64_tls_transition (info, r_type, h == NULL); 2504130561Sobrien tls_type = GOT_UNKNOWN; 2505130561Sobrien if (h == NULL && local_got_offsets) 2506130561Sobrien tls_type = elf64_x86_64_local_got_tls_type (input_bfd) [r_symndx]; 2507130561Sobrien else if (h != NULL) 2508130561Sobrien { 2509130561Sobrien tls_type = elf64_x86_64_hash_entry (h)->tls_type; 2510130561Sobrien if (!info->shared && h->dynindx == -1 && tls_type == GOT_TLS_IE) 2511130561Sobrien r_type = R_X86_64_TPOFF32; 2512130561Sobrien } 2513218822Sdim if (r_type == R_X86_64_TLSGD 2514218822Sdim || r_type == R_X86_64_GOTPC32_TLSDESC 2515218822Sdim || r_type == R_X86_64_TLSDESC_CALL) 2516130561Sobrien { 2517130561Sobrien if (tls_type == GOT_TLS_IE) 2518130561Sobrien r_type = R_X86_64_GOTTPOFF; 2519130561Sobrien } 2520130561Sobrien 2521130561Sobrien if (r_type == R_X86_64_TPOFF32) 2522130561Sobrien { 2523130561Sobrien BFD_ASSERT (! unresolved_reloc); 2524130561Sobrien if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD) 2525130561Sobrien { 2526130561Sobrien unsigned int i; 2527130561Sobrien static unsigned char tlsgd[8] 2528130561Sobrien = { 0x66, 0x48, 0x8d, 0x3d, 0x66, 0x66, 0x48, 0xe8 }; 2529130561Sobrien 2530130561Sobrien /* GD->LE transition. 2531130561Sobrien .byte 0x66; leaq foo@tlsgd(%rip), %rdi 2532130561Sobrien .word 0x6666; rex64; call __tls_get_addr@plt 2533130561Sobrien Change it into: 2534130561Sobrien movq %fs:0, %rax 2535130561Sobrien leaq foo@tpoff(%rax), %rax */ 2536130561Sobrien BFD_ASSERT (rel->r_offset >= 4); 2537130561Sobrien for (i = 0; i < 4; i++) 2538130561Sobrien BFD_ASSERT (bfd_get_8 (input_bfd, 2539130561Sobrien contents + rel->r_offset - 4 + i) 2540130561Sobrien == tlsgd[i]); 2541218822Sdim BFD_ASSERT (rel->r_offset + 12 <= input_section->size); 2542130561Sobrien for (i = 0; i < 4; i++) 2543130561Sobrien BFD_ASSERT (bfd_get_8 (input_bfd, 2544130561Sobrien contents + rel->r_offset + 4 + i) 2545130561Sobrien == tlsgd[i+4]); 2546130561Sobrien BFD_ASSERT (rel + 1 < relend); 2547130561Sobrien BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32); 2548130561Sobrien memcpy (contents + rel->r_offset - 4, 2549130561Sobrien "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x8d\x80\0\0\0", 2550130561Sobrien 16); 2551130561Sobrien bfd_put_32 (output_bfd, tpoff (info, relocation), 2552130561Sobrien contents + rel->r_offset + 8); 2553130561Sobrien /* Skip R_X86_64_PLT32. */ 2554130561Sobrien rel++; 2555130561Sobrien continue; 2556130561Sobrien } 2557218822Sdim else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC) 2558218822Sdim { 2559218822Sdim /* GDesc -> LE transition. 2560218822Sdim It's originally something like: 2561218822Sdim leaq x@tlsdesc(%rip), %rax 2562218822Sdim 2563218822Sdim Change it to: 2564218822Sdim movl $x@tpoff, %rax 2565218822Sdim 2566218822Sdim Registers other than %rax may be set up here. */ 2567218822Sdim 2568218822Sdim unsigned int val, type, type2; 2569218822Sdim bfd_vma roff; 2570218822Sdim 2571218822Sdim /* First, make sure it's a leaq adding rip to a 2572218822Sdim 32-bit offset into any register, although it's 2573218822Sdim probably almost always going to be rax. */ 2574218822Sdim roff = rel->r_offset; 2575218822Sdim BFD_ASSERT (roff >= 3); 2576218822Sdim type = bfd_get_8 (input_bfd, contents + roff - 3); 2577218822Sdim BFD_ASSERT ((type & 0xfb) == 0x48); 2578218822Sdim type2 = bfd_get_8 (input_bfd, contents + roff - 2); 2579218822Sdim BFD_ASSERT (type2 == 0x8d); 2580218822Sdim val = bfd_get_8 (input_bfd, contents + roff - 1); 2581218822Sdim BFD_ASSERT ((val & 0xc7) == 0x05); 2582218822Sdim BFD_ASSERT (roff + 4 <= input_section->size); 2583218822Sdim 2584218822Sdim /* Now modify the instruction as appropriate. */ 2585218822Sdim bfd_put_8 (output_bfd, 0x48 | ((type >> 2) & 1), 2586218822Sdim contents + roff - 3); 2587218822Sdim bfd_put_8 (output_bfd, 0xc7, contents + roff - 2); 2588218822Sdim bfd_put_8 (output_bfd, 0xc0 | ((val >> 3) & 7), 2589218822Sdim contents + roff - 1); 2590218822Sdim bfd_put_32 (output_bfd, tpoff (info, relocation), 2591218822Sdim contents + roff); 2592218822Sdim continue; 2593218822Sdim } 2594218822Sdim else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL) 2595218822Sdim { 2596218822Sdim /* GDesc -> LE transition. 2597218822Sdim It's originally: 2598218822Sdim call *(%rax) 2599218822Sdim Turn it into: 2600218822Sdim nop; nop. */ 2601218822Sdim 2602218822Sdim unsigned int val, type; 2603218822Sdim bfd_vma roff; 2604218822Sdim 2605218822Sdim /* First, make sure it's a call *(%rax). */ 2606218822Sdim roff = rel->r_offset; 2607218822Sdim BFD_ASSERT (roff + 2 <= input_section->size); 2608218822Sdim type = bfd_get_8 (input_bfd, contents + roff); 2609218822Sdim BFD_ASSERT (type == 0xff); 2610218822Sdim val = bfd_get_8 (input_bfd, contents + roff + 1); 2611218822Sdim BFD_ASSERT (val == 0x10); 2612218822Sdim 2613218822Sdim /* Now modify the instruction as appropriate. Use 2614218822Sdim xchg %ax,%ax instead of 2 nops. */ 2615218822Sdim bfd_put_8 (output_bfd, 0x66, contents + roff); 2616218822Sdim bfd_put_8 (output_bfd, 0x90, contents + roff + 1); 2617218822Sdim continue; 2618218822Sdim } 2619130561Sobrien else 2620130561Sobrien { 2621130561Sobrien unsigned int val, type, reg; 2622130561Sobrien 2623130561Sobrien /* IE->LE transition: 2624130561Sobrien Originally it can be one of: 2625130561Sobrien movq foo@gottpoff(%rip), %reg 2626130561Sobrien addq foo@gottpoff(%rip), %reg 2627130561Sobrien We change it into: 2628130561Sobrien movq $foo, %reg 2629130561Sobrien leaq foo(%reg), %reg 2630130561Sobrien addq $foo, %reg. */ 2631130561Sobrien BFD_ASSERT (rel->r_offset >= 3); 2632130561Sobrien val = bfd_get_8 (input_bfd, contents + rel->r_offset - 3); 2633130561Sobrien BFD_ASSERT (val == 0x48 || val == 0x4c); 2634130561Sobrien type = bfd_get_8 (input_bfd, contents + rel->r_offset - 2); 2635130561Sobrien BFD_ASSERT (type == 0x8b || type == 0x03); 2636130561Sobrien reg = bfd_get_8 (input_bfd, contents + rel->r_offset - 1); 2637130561Sobrien BFD_ASSERT ((reg & 0xc7) == 5); 2638130561Sobrien reg >>= 3; 2639218822Sdim BFD_ASSERT (rel->r_offset + 4 <= input_section->size); 2640130561Sobrien if (type == 0x8b) 2641130561Sobrien { 2642130561Sobrien /* movq */ 2643130561Sobrien if (val == 0x4c) 2644130561Sobrien bfd_put_8 (output_bfd, 0x49, 2645130561Sobrien contents + rel->r_offset - 3); 2646130561Sobrien bfd_put_8 (output_bfd, 0xc7, 2647130561Sobrien contents + rel->r_offset - 2); 2648130561Sobrien bfd_put_8 (output_bfd, 0xc0 | reg, 2649130561Sobrien contents + rel->r_offset - 1); 2650130561Sobrien } 2651130561Sobrien else if (reg == 4) 2652130561Sobrien { 2653130561Sobrien /* addq -> addq - addressing with %rsp/%r12 is 2654130561Sobrien special */ 2655130561Sobrien if (val == 0x4c) 2656130561Sobrien bfd_put_8 (output_bfd, 0x49, 2657130561Sobrien contents + rel->r_offset - 3); 2658130561Sobrien bfd_put_8 (output_bfd, 0x81, 2659130561Sobrien contents + rel->r_offset - 2); 2660130561Sobrien bfd_put_8 (output_bfd, 0xc0 | reg, 2661130561Sobrien contents + rel->r_offset - 1); 2662130561Sobrien } 2663130561Sobrien else 2664130561Sobrien { 2665130561Sobrien /* addq -> leaq */ 2666130561Sobrien if (val == 0x4c) 2667130561Sobrien bfd_put_8 (output_bfd, 0x4d, 2668130561Sobrien contents + rel->r_offset - 3); 2669130561Sobrien bfd_put_8 (output_bfd, 0x8d, 2670130561Sobrien contents + rel->r_offset - 2); 2671130561Sobrien bfd_put_8 (output_bfd, 0x80 | reg | (reg << 3), 2672130561Sobrien contents + rel->r_offset - 1); 2673130561Sobrien } 2674130561Sobrien bfd_put_32 (output_bfd, tpoff (info, relocation), 2675130561Sobrien contents + rel->r_offset); 2676130561Sobrien continue; 2677130561Sobrien } 2678130561Sobrien } 2679130561Sobrien 2680130561Sobrien if (htab->sgot == NULL) 2681130561Sobrien abort (); 2682130561Sobrien 2683130561Sobrien if (h != NULL) 2684218822Sdim { 2685218822Sdim off = h->got.offset; 2686218822Sdim offplt = elf64_x86_64_hash_entry (h)->tlsdesc_got; 2687218822Sdim } 2688130561Sobrien else 2689130561Sobrien { 2690130561Sobrien if (local_got_offsets == NULL) 2691130561Sobrien abort (); 2692130561Sobrien 2693130561Sobrien off = local_got_offsets[r_symndx]; 2694218822Sdim offplt = local_tlsdesc_gotents[r_symndx]; 2695130561Sobrien } 2696130561Sobrien 2697130561Sobrien if ((off & 1) != 0) 2698130561Sobrien off &= ~1; 2699130561Sobrien else 2700130561Sobrien { 2701130561Sobrien Elf_Internal_Rela outrel; 2702130561Sobrien bfd_byte *loc; 2703130561Sobrien int dr_type, indx; 2704218822Sdim asection *sreloc; 2705130561Sobrien 2706130561Sobrien if (htab->srelgot == NULL) 2707130561Sobrien abort (); 2708130561Sobrien 2709218822Sdim indx = h && h->dynindx != -1 ? h->dynindx : 0; 2710218822Sdim 2711218822Sdim if (GOT_TLS_GDESC_P (tls_type)) 2712218822Sdim { 2713218822Sdim outrel.r_info = ELF64_R_INFO (indx, R_X86_64_TLSDESC); 2714218822Sdim BFD_ASSERT (htab->sgotplt_jump_table_size + offplt 2715218822Sdim + 2 * GOT_ENTRY_SIZE <= htab->sgotplt->size); 2716218822Sdim outrel.r_offset = (htab->sgotplt->output_section->vma 2717218822Sdim + htab->sgotplt->output_offset 2718218822Sdim + offplt 2719218822Sdim + htab->sgotplt_jump_table_size); 2720218822Sdim sreloc = htab->srelplt; 2721218822Sdim loc = sreloc->contents; 2722218822Sdim loc += sreloc->reloc_count++ 2723218822Sdim * sizeof (Elf64_External_Rela); 2724218822Sdim BFD_ASSERT (loc + sizeof (Elf64_External_Rela) 2725218822Sdim <= sreloc->contents + sreloc->size); 2726218822Sdim if (indx == 0) 2727218822Sdim outrel.r_addend = relocation - dtpoff_base (info); 2728218822Sdim else 2729218822Sdim outrel.r_addend = 0; 2730218822Sdim bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); 2731218822Sdim } 2732218822Sdim 2733218822Sdim sreloc = htab->srelgot; 2734218822Sdim 2735130561Sobrien outrel.r_offset = (htab->sgot->output_section->vma 2736130561Sobrien + htab->sgot->output_offset + off); 2737130561Sobrien 2738218822Sdim if (GOT_TLS_GD_P (tls_type)) 2739130561Sobrien dr_type = R_X86_64_DTPMOD64; 2740218822Sdim else if (GOT_TLS_GDESC_P (tls_type)) 2741218822Sdim goto dr_done; 2742130561Sobrien else 2743130561Sobrien dr_type = R_X86_64_TPOFF64; 2744130561Sobrien 2745130561Sobrien bfd_put_64 (output_bfd, 0, htab->sgot->contents + off); 2746130561Sobrien outrel.r_addend = 0; 2747218822Sdim if ((dr_type == R_X86_64_TPOFF64 2748218822Sdim || dr_type == R_X86_64_TLSDESC) && indx == 0) 2749130561Sobrien outrel.r_addend = relocation - dtpoff_base (info); 2750130561Sobrien outrel.r_info = ELF64_R_INFO (indx, dr_type); 2751130561Sobrien 2752218822Sdim loc = sreloc->contents; 2753218822Sdim loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela); 2754218822Sdim BFD_ASSERT (loc + sizeof (Elf64_External_Rela) 2755218822Sdim <= sreloc->contents + sreloc->size); 2756130561Sobrien bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); 2757130561Sobrien 2758218822Sdim if (GOT_TLS_GD_P (tls_type)) 2759130561Sobrien { 2760130561Sobrien if (indx == 0) 2761130561Sobrien { 2762130561Sobrien BFD_ASSERT (! unresolved_reloc); 2763130561Sobrien bfd_put_64 (output_bfd, 2764130561Sobrien relocation - dtpoff_base (info), 2765130561Sobrien htab->sgot->contents + off + GOT_ENTRY_SIZE); 2766130561Sobrien } 2767130561Sobrien else 2768130561Sobrien { 2769130561Sobrien bfd_put_64 (output_bfd, 0, 2770130561Sobrien htab->sgot->contents + off + GOT_ENTRY_SIZE); 2771130561Sobrien outrel.r_info = ELF64_R_INFO (indx, 2772130561Sobrien R_X86_64_DTPOFF64); 2773130561Sobrien outrel.r_offset += GOT_ENTRY_SIZE; 2774218822Sdim sreloc->reloc_count++; 2775130561Sobrien loc += sizeof (Elf64_External_Rela); 2776218822Sdim BFD_ASSERT (loc + sizeof (Elf64_External_Rela) 2777218822Sdim <= sreloc->contents + sreloc->size); 2778130561Sobrien bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); 2779130561Sobrien } 2780130561Sobrien } 2781130561Sobrien 2782218822Sdim dr_done: 2783130561Sobrien if (h != NULL) 2784130561Sobrien h->got.offset |= 1; 2785130561Sobrien else 2786130561Sobrien local_got_offsets[r_symndx] |= 1; 2787130561Sobrien } 2788130561Sobrien 2789218822Sdim if (off >= (bfd_vma) -2 2790218822Sdim && ! GOT_TLS_GDESC_P (tls_type)) 2791130561Sobrien abort (); 2792130561Sobrien if (r_type == ELF64_R_TYPE (rel->r_info)) 2793130561Sobrien { 2794218822Sdim if (r_type == R_X86_64_GOTPC32_TLSDESC 2795218822Sdim || r_type == R_X86_64_TLSDESC_CALL) 2796218822Sdim relocation = htab->sgotplt->output_section->vma 2797218822Sdim + htab->sgotplt->output_offset 2798218822Sdim + offplt + htab->sgotplt_jump_table_size; 2799218822Sdim else 2800218822Sdim relocation = htab->sgot->output_section->vma 2801218822Sdim + htab->sgot->output_offset + off; 2802130561Sobrien unresolved_reloc = FALSE; 2803130561Sobrien } 2804218822Sdim else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSGD) 2805130561Sobrien { 2806130561Sobrien unsigned int i; 2807130561Sobrien static unsigned char tlsgd[8] 2808130561Sobrien = { 0x66, 0x48, 0x8d, 0x3d, 0x66, 0x66, 0x48, 0xe8 }; 2809130561Sobrien 2810130561Sobrien /* GD->IE transition. 2811130561Sobrien .byte 0x66; leaq foo@tlsgd(%rip), %rdi 2812130561Sobrien .word 0x6666; rex64; call __tls_get_addr@plt 2813130561Sobrien Change it into: 2814130561Sobrien movq %fs:0, %rax 2815130561Sobrien addq foo@gottpoff(%rip), %rax */ 2816130561Sobrien BFD_ASSERT (rel->r_offset >= 4); 2817130561Sobrien for (i = 0; i < 4; i++) 2818130561Sobrien BFD_ASSERT (bfd_get_8 (input_bfd, 2819130561Sobrien contents + rel->r_offset - 4 + i) 2820130561Sobrien == tlsgd[i]); 2821218822Sdim BFD_ASSERT (rel->r_offset + 12 <= input_section->size); 2822130561Sobrien for (i = 0; i < 4; i++) 2823130561Sobrien BFD_ASSERT (bfd_get_8 (input_bfd, 2824130561Sobrien contents + rel->r_offset + 4 + i) 2825130561Sobrien == tlsgd[i+4]); 2826130561Sobrien BFD_ASSERT (rel + 1 < relend); 2827130561Sobrien BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32); 2828130561Sobrien memcpy (contents + rel->r_offset - 4, 2829130561Sobrien "\x64\x48\x8b\x04\x25\0\0\0\0\x48\x03\x05\0\0\0", 2830130561Sobrien 16); 2831130561Sobrien 2832130561Sobrien relocation = (htab->sgot->output_section->vma 2833130561Sobrien + htab->sgot->output_offset + off 2834130561Sobrien - rel->r_offset 2835130561Sobrien - input_section->output_section->vma 2836130561Sobrien - input_section->output_offset 2837130561Sobrien - 12); 2838130561Sobrien bfd_put_32 (output_bfd, relocation, 2839130561Sobrien contents + rel->r_offset + 8); 2840130561Sobrien /* Skip R_X86_64_PLT32. */ 2841130561Sobrien rel++; 2842130561Sobrien continue; 2843130561Sobrien } 2844218822Sdim else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_GOTPC32_TLSDESC) 2845218822Sdim { 2846218822Sdim /* GDesc -> IE transition. 2847218822Sdim It's originally something like: 2848218822Sdim leaq x@tlsdesc(%rip), %rax 2849218822Sdim 2850218822Sdim Change it to: 2851218822Sdim movq x@gottpoff(%rip), %rax # before nop; nop 2852218822Sdim 2853218822Sdim Registers other than %rax may be set up here. */ 2854218822Sdim 2855218822Sdim unsigned int val, type, type2; 2856218822Sdim bfd_vma roff; 2857218822Sdim 2858218822Sdim /* First, make sure it's a leaq adding rip to a 32-bit 2859218822Sdim offset into any register, although it's probably 2860218822Sdim almost always going to be rax. */ 2861218822Sdim roff = rel->r_offset; 2862218822Sdim BFD_ASSERT (roff >= 3); 2863218822Sdim type = bfd_get_8 (input_bfd, contents + roff - 3); 2864218822Sdim BFD_ASSERT ((type & 0xfb) == 0x48); 2865218822Sdim type2 = bfd_get_8 (input_bfd, contents + roff - 2); 2866218822Sdim BFD_ASSERT (type2 == 0x8d); 2867218822Sdim val = bfd_get_8 (input_bfd, contents + roff - 1); 2868218822Sdim BFD_ASSERT ((val & 0xc7) == 0x05); 2869218822Sdim BFD_ASSERT (roff + 4 <= input_section->size); 2870218822Sdim 2871218822Sdim /* Now modify the instruction as appropriate. */ 2872218822Sdim /* To turn a leaq into a movq in the form we use it, it 2873218822Sdim suffices to change the second byte from 0x8d to 2874218822Sdim 0x8b. */ 2875218822Sdim bfd_put_8 (output_bfd, 0x8b, contents + roff - 2); 2876218822Sdim 2877218822Sdim bfd_put_32 (output_bfd, 2878218822Sdim htab->sgot->output_section->vma 2879218822Sdim + htab->sgot->output_offset + off 2880218822Sdim - rel->r_offset 2881218822Sdim - input_section->output_section->vma 2882218822Sdim - input_section->output_offset 2883218822Sdim - 4, 2884218822Sdim contents + roff); 2885218822Sdim continue; 2886218822Sdim } 2887218822Sdim else if (ELF64_R_TYPE (rel->r_info) == R_X86_64_TLSDESC_CALL) 2888218822Sdim { 2889218822Sdim /* GDesc -> IE transition. 2890218822Sdim It's originally: 2891218822Sdim call *(%rax) 2892218822Sdim 2893218822Sdim Change it to: 2894218822Sdim nop; nop. */ 2895218822Sdim 2896218822Sdim unsigned int val, type; 2897218822Sdim bfd_vma roff; 2898218822Sdim 2899218822Sdim /* First, make sure it's a call *(%eax). */ 2900218822Sdim roff = rel->r_offset; 2901218822Sdim BFD_ASSERT (roff + 2 <= input_section->size); 2902218822Sdim type = bfd_get_8 (input_bfd, contents + roff); 2903218822Sdim BFD_ASSERT (type == 0xff); 2904218822Sdim val = bfd_get_8 (input_bfd, contents + roff + 1); 2905218822Sdim BFD_ASSERT (val == 0x10); 2906218822Sdim 2907218822Sdim /* Now modify the instruction as appropriate. Use 2908218822Sdim xchg %ax,%ax instead of 2 nops. */ 2909218822Sdim bfd_put_8 (output_bfd, 0x66, contents + roff); 2910218822Sdim bfd_put_8 (output_bfd, 0x90, contents + roff + 1); 2911218822Sdim 2912218822Sdim continue; 2913218822Sdim } 2914218822Sdim else 2915218822Sdim BFD_ASSERT (FALSE); 2916130561Sobrien break; 2917130561Sobrien 2918130561Sobrien case R_X86_64_TLSLD: 2919130561Sobrien if (! info->shared) 2920130561Sobrien { 2921130561Sobrien /* LD->LE transition: 2922130561Sobrien Ensure it is: 2923130561Sobrien leaq foo@tlsld(%rip), %rdi; call __tls_get_addr@plt. 2924130561Sobrien We change it into: 2925130561Sobrien .word 0x6666; .byte 0x66; movl %fs:0, %rax. */ 2926130561Sobrien BFD_ASSERT (rel->r_offset >= 3); 2927130561Sobrien BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 3) 2928130561Sobrien == 0x48); 2929130561Sobrien BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 2) 2930130561Sobrien == 0x8d); 2931130561Sobrien BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset - 1) 2932130561Sobrien == 0x3d); 2933218822Sdim BFD_ASSERT (rel->r_offset + 9 <= input_section->size); 2934130561Sobrien BFD_ASSERT (bfd_get_8 (input_bfd, contents + rel->r_offset + 4) 2935130561Sobrien == 0xe8); 2936130561Sobrien BFD_ASSERT (rel + 1 < relend); 2937130561Sobrien BFD_ASSERT (ELF64_R_TYPE (rel[1].r_info) == R_X86_64_PLT32); 2938130561Sobrien memcpy (contents + rel->r_offset - 3, 2939130561Sobrien "\x66\x66\x66\x64\x48\x8b\x04\x25\0\0\0", 12); 2940130561Sobrien /* Skip R_X86_64_PLT32. */ 2941130561Sobrien rel++; 2942130561Sobrien continue; 2943130561Sobrien } 2944130561Sobrien 2945130561Sobrien if (htab->sgot == NULL) 2946130561Sobrien abort (); 2947130561Sobrien 2948130561Sobrien off = htab->tls_ld_got.offset; 2949130561Sobrien if (off & 1) 2950130561Sobrien off &= ~1; 2951130561Sobrien else 2952130561Sobrien { 2953130561Sobrien Elf_Internal_Rela outrel; 2954130561Sobrien bfd_byte *loc; 2955130561Sobrien 2956130561Sobrien if (htab->srelgot == NULL) 2957130561Sobrien abort (); 2958130561Sobrien 2959130561Sobrien outrel.r_offset = (htab->sgot->output_section->vma 2960130561Sobrien + htab->sgot->output_offset + off); 2961130561Sobrien 2962130561Sobrien bfd_put_64 (output_bfd, 0, 2963130561Sobrien htab->sgot->contents + off); 2964130561Sobrien bfd_put_64 (output_bfd, 0, 2965130561Sobrien htab->sgot->contents + off + GOT_ENTRY_SIZE); 2966130561Sobrien outrel.r_info = ELF64_R_INFO (0, R_X86_64_DTPMOD64); 2967130561Sobrien outrel.r_addend = 0; 2968130561Sobrien loc = htab->srelgot->contents; 2969130561Sobrien loc += htab->srelgot->reloc_count++ * sizeof (Elf64_External_Rela); 2970130561Sobrien bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); 2971130561Sobrien htab->tls_ld_got.offset |= 1; 2972130561Sobrien } 2973130561Sobrien relocation = htab->sgot->output_section->vma 2974130561Sobrien + htab->sgot->output_offset + off; 2975130561Sobrien unresolved_reloc = FALSE; 2976130561Sobrien break; 2977130561Sobrien 2978130561Sobrien case R_X86_64_DTPOFF32: 2979130561Sobrien if (info->shared || (input_section->flags & SEC_CODE) == 0) 2980130561Sobrien relocation -= dtpoff_base (info); 2981130561Sobrien else 2982130561Sobrien relocation = tpoff (info, relocation); 2983130561Sobrien break; 2984130561Sobrien 2985130561Sobrien case R_X86_64_TPOFF32: 2986130561Sobrien BFD_ASSERT (! info->shared); 2987130561Sobrien relocation = tpoff (info, relocation); 2988130561Sobrien break; 2989130561Sobrien 299085815Sobrien default: 299185815Sobrien break; 299285815Sobrien } 299385815Sobrien 2994104834Sobrien /* Dynamic relocs are not propagated for SEC_DEBUGGING sections 2995104834Sobrien because such sections are not SEC_ALLOC and thus ld.so will 2996104834Sobrien not process them. */ 299799461Sobrien if (unresolved_reloc 2998104834Sobrien && !((input_section->flags & SEC_DEBUGGING) != 0 2999218822Sdim && h->def_dynamic)) 300099461Sobrien (*_bfd_error_handler) 3001218822Sdim (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), 3002218822Sdim input_bfd, 3003218822Sdim input_section, 300499461Sobrien (long) rel->r_offset, 3005218822Sdim howto->name, 300699461Sobrien h->root.root.string); 300799461Sobrien 300885815Sobrien r = _bfd_final_link_relocate (howto, input_bfd, input_section, 300999461Sobrien contents, rel->r_offset, 301099461Sobrien relocation, rel->r_addend); 301185815Sobrien 301285815Sobrien if (r != bfd_reloc_ok) 301385815Sobrien { 301499461Sobrien const char *name; 301599461Sobrien 301699461Sobrien if (h != NULL) 301799461Sobrien name = h->root.root.string; 301899461Sobrien else 301985815Sobrien { 302099461Sobrien name = bfd_elf_string_from_elf_section (input_bfd, 302199461Sobrien symtab_hdr->sh_link, 302299461Sobrien sym->st_name); 302399461Sobrien if (name == NULL) 3024130561Sobrien return FALSE; 302599461Sobrien if (*name == '\0') 302699461Sobrien name = bfd_section_name (input_bfd, sec); 302799461Sobrien } 302885815Sobrien 302999461Sobrien if (r == bfd_reloc_overflow) 303099461Sobrien { 303199461Sobrien if (! ((*info->callbacks->reloc_overflow) 3032218822Sdim (info, (h ? &h->root : NULL), name, howto->name, 3033218822Sdim (bfd_vma) 0, input_bfd, input_section, 3034218822Sdim rel->r_offset))) 3035130561Sobrien return FALSE; 303685815Sobrien } 303799461Sobrien else 303899461Sobrien { 303999461Sobrien (*_bfd_error_handler) 3040218822Sdim (_("%B(%A+0x%lx): reloc against `%s': error %d"), 3041218822Sdim input_bfd, input_section, 304299461Sobrien (long) rel->r_offset, name, (int) r); 3043130561Sobrien return FALSE; 304499461Sobrien } 304585815Sobrien } 304685815Sobrien } 304785815Sobrien 3048130561Sobrien return TRUE; 304985815Sobrien} 305085815Sobrien 305185815Sobrien/* Finish up dynamic symbol handling. We set the contents of various 305285815Sobrien dynamic sections here. */ 305385815Sobrien 3054130561Sobrienstatic bfd_boolean 3055130561Sobrienelf64_x86_64_finish_dynamic_symbol (bfd *output_bfd, 3056130561Sobrien struct bfd_link_info *info, 3057130561Sobrien struct elf_link_hash_entry *h, 3058130561Sobrien Elf_Internal_Sym *sym) 305985815Sobrien{ 306099461Sobrien struct elf64_x86_64_link_hash_table *htab; 306185815Sobrien 306299461Sobrien htab = elf64_x86_64_hash_table (info); 306385815Sobrien 306485815Sobrien if (h->plt.offset != (bfd_vma) -1) 306585815Sobrien { 306685815Sobrien bfd_vma plt_index; 306785815Sobrien bfd_vma got_offset; 306885815Sobrien Elf_Internal_Rela rela; 3069130561Sobrien bfd_byte *loc; 307085815Sobrien 307185815Sobrien /* This symbol has an entry in the procedure linkage table. Set 307285815Sobrien it up. */ 307399461Sobrien if (h->dynindx == -1 307499461Sobrien || htab->splt == NULL 307599461Sobrien || htab->sgotplt == NULL 307699461Sobrien || htab->srelplt == NULL) 307799461Sobrien abort (); 307885815Sobrien 307985815Sobrien /* Get the index in the procedure linkage table which 308085815Sobrien corresponds to this symbol. This is the index of this symbol 308185815Sobrien in all the symbols for which we are making plt entries. The 308285815Sobrien first entry in the procedure linkage table is reserved. */ 308385815Sobrien plt_index = h->plt.offset / PLT_ENTRY_SIZE - 1; 308485815Sobrien 308585815Sobrien /* Get the offset into the .got table of the entry that 308685815Sobrien corresponds to this function. Each .got entry is GOT_ENTRY_SIZE 308785815Sobrien bytes. The first three are reserved for the dynamic linker. */ 308885815Sobrien got_offset = (plt_index + 3) * GOT_ENTRY_SIZE; 308985815Sobrien 309085815Sobrien /* Fill in the entry in the procedure linkage table. */ 309199461Sobrien memcpy (htab->splt->contents + h->plt.offset, elf64_x86_64_plt_entry, 309285815Sobrien PLT_ENTRY_SIZE); 309385815Sobrien 309485815Sobrien /* Insert the relocation positions of the plt section. The magic 309585815Sobrien numbers at the end of the statements are the positions of the 309685815Sobrien relocations in the plt section. */ 309785815Sobrien /* Put offset for jmp *name@GOTPCREL(%rip), since the 309885815Sobrien instruction uses 6 bytes, subtract this value. */ 309985815Sobrien bfd_put_32 (output_bfd, 310099461Sobrien (htab->sgotplt->output_section->vma 310199461Sobrien + htab->sgotplt->output_offset 310285815Sobrien + got_offset 310399461Sobrien - htab->splt->output_section->vma 310499461Sobrien - htab->splt->output_offset 310585815Sobrien - h->plt.offset 310685815Sobrien - 6), 310799461Sobrien htab->splt->contents + h->plt.offset + 2); 310885815Sobrien /* Put relocation index. */ 310985815Sobrien bfd_put_32 (output_bfd, plt_index, 311099461Sobrien htab->splt->contents + h->plt.offset + 7); 311185815Sobrien /* Put offset for jmp .PLT0. */ 311285815Sobrien bfd_put_32 (output_bfd, - (h->plt.offset + PLT_ENTRY_SIZE), 311399461Sobrien htab->splt->contents + h->plt.offset + 12); 311485815Sobrien 311585815Sobrien /* Fill in the entry in the global offset table, initially this 311685815Sobrien points to the pushq instruction in the PLT which is at offset 6. */ 311799461Sobrien bfd_put_64 (output_bfd, (htab->splt->output_section->vma 311899461Sobrien + htab->splt->output_offset 311985815Sobrien + h->plt.offset + 6), 312099461Sobrien htab->sgotplt->contents + got_offset); 312185815Sobrien 312285815Sobrien /* Fill in the entry in the .rela.plt section. */ 312399461Sobrien rela.r_offset = (htab->sgotplt->output_section->vma 312499461Sobrien + htab->sgotplt->output_offset 312585815Sobrien + got_offset); 312685815Sobrien rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_JUMP_SLOT); 312785815Sobrien rela.r_addend = 0; 3128130561Sobrien loc = htab->srelplt->contents + plt_index * sizeof (Elf64_External_Rela); 312999461Sobrien bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); 313085815Sobrien 3131218822Sdim if (!h->def_regular) 313285815Sobrien { 313385815Sobrien /* Mark the symbol as undefined, rather than as defined in 3134218822Sdim the .plt section. Leave the value if there were any 3135218822Sdim relocations where pointer equality matters (this is a clue 313699461Sobrien for the dynamic linker, to make function pointer 313799461Sobrien comparisons work between an application and shared 3138218822Sdim library), otherwise set it to zero. If a function is only 3139218822Sdim called from a binary, there is no need to slow down 3140218822Sdim shared libraries because of that. */ 314185815Sobrien sym->st_shndx = SHN_UNDEF; 3142218822Sdim if (!h->pointer_equality_needed) 3143218822Sdim sym->st_value = 0; 314485815Sobrien } 314585815Sobrien } 314685815Sobrien 3147130561Sobrien if (h->got.offset != (bfd_vma) -1 3148218822Sdim && ! GOT_TLS_GD_ANY_P (elf64_x86_64_hash_entry (h)->tls_type) 3149130561Sobrien && elf64_x86_64_hash_entry (h)->tls_type != GOT_TLS_IE) 315085815Sobrien { 315185815Sobrien Elf_Internal_Rela rela; 3152130561Sobrien bfd_byte *loc; 315385815Sobrien 315485815Sobrien /* This symbol has an entry in the global offset table. Set it 3155130561Sobrien up. */ 315699461Sobrien if (htab->sgot == NULL || htab->srelgot == NULL) 315799461Sobrien abort (); 315885815Sobrien 315999461Sobrien rela.r_offset = (htab->sgot->output_section->vma 316099461Sobrien + htab->sgot->output_offset 316189857Sobrien + (h->got.offset &~ (bfd_vma) 1)); 316285815Sobrien 316385815Sobrien /* If this is a static link, or it is a -Bsymbolic link and the 316485815Sobrien symbol is defined locally or was forced to be local because 316585815Sobrien of a version file, we just want to emit a RELATIVE reloc. 316685815Sobrien The entry in the global offset table will already have been 316785815Sobrien initialized in the relocate_section function. */ 316899461Sobrien if (info->shared 3169130561Sobrien && SYMBOL_REFERENCES_LOCAL (info, h)) 317085815Sobrien { 317185815Sobrien BFD_ASSERT((h->got.offset & 1) != 0); 317285815Sobrien rela.r_info = ELF64_R_INFO (0, R_X86_64_RELATIVE); 317385815Sobrien rela.r_addend = (h->root.u.def.value 317485815Sobrien + h->root.u.def.section->output_section->vma 317585815Sobrien + h->root.u.def.section->output_offset); 317685815Sobrien } 317785815Sobrien else 317885815Sobrien { 317985815Sobrien BFD_ASSERT((h->got.offset & 1) == 0); 318099461Sobrien bfd_put_64 (output_bfd, (bfd_vma) 0, 318199461Sobrien htab->sgot->contents + h->got.offset); 318285815Sobrien rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_GLOB_DAT); 318385815Sobrien rela.r_addend = 0; 318485815Sobrien } 318585815Sobrien 3186130561Sobrien loc = htab->srelgot->contents; 3187130561Sobrien loc += htab->srelgot->reloc_count++ * sizeof (Elf64_External_Rela); 318899461Sobrien bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); 318985815Sobrien } 319085815Sobrien 3191218822Sdim if (h->needs_copy) 319285815Sobrien { 319385815Sobrien Elf_Internal_Rela rela; 3194130561Sobrien bfd_byte *loc; 319585815Sobrien 319685815Sobrien /* This symbol needs a copy reloc. Set it up. */ 319785815Sobrien 319899461Sobrien if (h->dynindx == -1 319999461Sobrien || (h->root.type != bfd_link_hash_defined 320099461Sobrien && h->root.type != bfd_link_hash_defweak) 320199461Sobrien || htab->srelbss == NULL) 320299461Sobrien abort (); 320385815Sobrien 320485815Sobrien rela.r_offset = (h->root.u.def.value 320585815Sobrien + h->root.u.def.section->output_section->vma 320685815Sobrien + h->root.u.def.section->output_offset); 320785815Sobrien rela.r_info = ELF64_R_INFO (h->dynindx, R_X86_64_COPY); 320885815Sobrien rela.r_addend = 0; 3209130561Sobrien loc = htab->srelbss->contents; 3210130561Sobrien loc += htab->srelbss->reloc_count++ * sizeof (Elf64_External_Rela); 321199461Sobrien bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); 321285815Sobrien } 321385815Sobrien 321485815Sobrien /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute. */ 321585815Sobrien if (strcmp (h->root.root.string, "_DYNAMIC") == 0 3216218822Sdim || h == htab->elf.hgot) 321785815Sobrien sym->st_shndx = SHN_ABS; 321885815Sobrien 3219130561Sobrien return TRUE; 322085815Sobrien} 322185815Sobrien 322299461Sobrien/* Used to decide how to sort relocs in an optimal manner for the 322399461Sobrien dynamic linker, before writing them out. */ 322499461Sobrien 322599461Sobrienstatic enum elf_reloc_type_class 3226130561Sobrienelf64_x86_64_reloc_type_class (const Elf_Internal_Rela *rela) 322799461Sobrien{ 322899461Sobrien switch ((int) ELF64_R_TYPE (rela->r_info)) 322999461Sobrien { 323099461Sobrien case R_X86_64_RELATIVE: 323199461Sobrien return reloc_class_relative; 323299461Sobrien case R_X86_64_JUMP_SLOT: 323399461Sobrien return reloc_class_plt; 323499461Sobrien case R_X86_64_COPY: 323599461Sobrien return reloc_class_copy; 323699461Sobrien default: 323799461Sobrien return reloc_class_normal; 323899461Sobrien } 323999461Sobrien} 324099461Sobrien 324185815Sobrien/* Finish up the dynamic sections. */ 324285815Sobrien 3243130561Sobrienstatic bfd_boolean 3244130561Sobrienelf64_x86_64_finish_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info) 324585815Sobrien{ 324699461Sobrien struct elf64_x86_64_link_hash_table *htab; 324785815Sobrien bfd *dynobj; 324885815Sobrien asection *sdyn; 324985815Sobrien 325099461Sobrien htab = elf64_x86_64_hash_table (info); 325199461Sobrien dynobj = htab->elf.dynobj; 325285815Sobrien sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); 325385815Sobrien 325499461Sobrien if (htab->elf.dynamic_sections_created) 325585815Sobrien { 325685815Sobrien Elf64_External_Dyn *dyncon, *dynconend; 325785815Sobrien 325899461Sobrien if (sdyn == NULL || htab->sgot == NULL) 325999461Sobrien abort (); 326085815Sobrien 326185815Sobrien dyncon = (Elf64_External_Dyn *) sdyn->contents; 3262218822Sdim dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size); 326385815Sobrien for (; dyncon < dynconend; dyncon++) 326485815Sobrien { 326585815Sobrien Elf_Internal_Dyn dyn; 326685815Sobrien asection *s; 326785815Sobrien 326885815Sobrien bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn); 326985815Sobrien 327085815Sobrien switch (dyn.d_tag) 327185815Sobrien { 327285815Sobrien default: 327385815Sobrien continue; 327485815Sobrien 327585815Sobrien case DT_PLTGOT: 3276218822Sdim s = htab->sgotplt; 3277218822Sdim dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; 327899461Sobrien break; 327985815Sobrien 328085815Sobrien case DT_JMPREL: 328199461Sobrien dyn.d_un.d_ptr = htab->srelplt->output_section->vma; 328299461Sobrien break; 328385815Sobrien 328499461Sobrien case DT_PLTRELSZ: 328599461Sobrien s = htab->srelplt->output_section; 3286218822Sdim dyn.d_un.d_val = s->size; 328785815Sobrien break; 328885815Sobrien 328985815Sobrien case DT_RELASZ: 329099461Sobrien /* The procedure linkage table relocs (DT_JMPREL) should 329199461Sobrien not be included in the overall relocs (DT_RELA). 329299461Sobrien Therefore, we override the DT_RELASZ entry here to 329399461Sobrien make it not include the JMPREL relocs. Since the 329499461Sobrien linker script arranges for .rela.plt to follow all 329599461Sobrien other relocation sections, we don't have to worry 329699461Sobrien about changing the DT_RELA entry. */ 329799461Sobrien if (htab->srelplt != NULL) 329885815Sobrien { 329999461Sobrien s = htab->srelplt->output_section; 3300218822Sdim dyn.d_un.d_val -= s->size; 330185815Sobrien } 330285815Sobrien break; 3303218822Sdim 3304218822Sdim case DT_TLSDESC_PLT: 3305218822Sdim s = htab->splt; 3306218822Sdim dyn.d_un.d_ptr = s->output_section->vma + s->output_offset 3307218822Sdim + htab->tlsdesc_plt; 3308218822Sdim break; 3309218822Sdim 3310218822Sdim case DT_TLSDESC_GOT: 3311218822Sdim s = htab->sgot; 3312218822Sdim dyn.d_un.d_ptr = s->output_section->vma + s->output_offset 3313218822Sdim + htab->tlsdesc_got; 3314218822Sdim break; 331599461Sobrien } 331685815Sobrien 331785815Sobrien bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); 331885815Sobrien } 331985815Sobrien 332099461Sobrien /* Fill in the special first entry in the procedure linkage table. */ 3321218822Sdim if (htab->splt && htab->splt->size > 0) 332285815Sobrien { 332385815Sobrien /* Fill in the first entry in the procedure linkage table. */ 332499461Sobrien memcpy (htab->splt->contents, elf64_x86_64_plt0_entry, 332599461Sobrien PLT_ENTRY_SIZE); 332685815Sobrien /* Add offset for pushq GOT+8(%rip), since the instruction 332785815Sobrien uses 6 bytes subtract this value. */ 332885815Sobrien bfd_put_32 (output_bfd, 332999461Sobrien (htab->sgotplt->output_section->vma 333099461Sobrien + htab->sgotplt->output_offset 333185815Sobrien + 8 333299461Sobrien - htab->splt->output_section->vma 333399461Sobrien - htab->splt->output_offset 333485815Sobrien - 6), 333599461Sobrien htab->splt->contents + 2); 333685815Sobrien /* Add offset for jmp *GOT+16(%rip). The 12 is the offset to 333785815Sobrien the end of the instruction. */ 333885815Sobrien bfd_put_32 (output_bfd, 333999461Sobrien (htab->sgotplt->output_section->vma 334099461Sobrien + htab->sgotplt->output_offset 334185815Sobrien + 16 334299461Sobrien - htab->splt->output_section->vma 334399461Sobrien - htab->splt->output_offset 334485815Sobrien - 12), 334599461Sobrien htab->splt->contents + 8); 334685815Sobrien 334799461Sobrien elf_section_data (htab->splt->output_section)->this_hdr.sh_entsize = 334899461Sobrien PLT_ENTRY_SIZE; 3349218822Sdim 3350218822Sdim if (htab->tlsdesc_plt) 3351218822Sdim { 3352218822Sdim bfd_put_64 (output_bfd, (bfd_vma) 0, 3353218822Sdim htab->sgot->contents + htab->tlsdesc_got); 3354218822Sdim 3355218822Sdim memcpy (htab->splt->contents + htab->tlsdesc_plt, 3356218822Sdim elf64_x86_64_plt0_entry, 3357218822Sdim PLT_ENTRY_SIZE); 3358218822Sdim 3359218822Sdim /* Add offset for pushq GOT+8(%rip), since the 3360218822Sdim instruction uses 6 bytes subtract this value. */ 3361218822Sdim bfd_put_32 (output_bfd, 3362218822Sdim (htab->sgotplt->output_section->vma 3363218822Sdim + htab->sgotplt->output_offset 3364218822Sdim + 8 3365218822Sdim - htab->splt->output_section->vma 3366218822Sdim - htab->splt->output_offset 3367218822Sdim - htab->tlsdesc_plt 3368218822Sdim - 6), 3369218822Sdim htab->splt->contents + htab->tlsdesc_plt + 2); 3370218822Sdim /* Add offset for jmp *GOT+TDG(%rip), where TGD stands for 3371218822Sdim htab->tlsdesc_got. The 12 is the offset to the end of 3372218822Sdim the instruction. */ 3373218822Sdim bfd_put_32 (output_bfd, 3374218822Sdim (htab->sgot->output_section->vma 3375218822Sdim + htab->sgot->output_offset 3376218822Sdim + htab->tlsdesc_got 3377218822Sdim - htab->splt->output_section->vma 3378218822Sdim - htab->splt->output_offset 3379218822Sdim - htab->tlsdesc_plt 3380218822Sdim - 12), 3381218822Sdim htab->splt->contents + htab->tlsdesc_plt + 8); 3382218822Sdim } 338385815Sobrien } 338485815Sobrien } 338585815Sobrien 338699461Sobrien if (htab->sgotplt) 338785815Sobrien { 338899461Sobrien /* Fill in the first three entries in the global offset table. */ 3389218822Sdim if (htab->sgotplt->size > 0) 339099461Sobrien { 339199461Sobrien /* Set the first entry in the global offset table to the address of 339299461Sobrien the dynamic section. */ 339399461Sobrien if (sdyn == NULL) 339499461Sobrien bfd_put_64 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents); 339599461Sobrien else 339699461Sobrien bfd_put_64 (output_bfd, 339799461Sobrien sdyn->output_section->vma + sdyn->output_offset, 339899461Sobrien htab->sgotplt->contents); 339999461Sobrien /* Write GOT[1] and GOT[2], needed for the dynamic linker. */ 340099461Sobrien bfd_put_64 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + GOT_ENTRY_SIZE); 340199461Sobrien bfd_put_64 (output_bfd, (bfd_vma) 0, htab->sgotplt->contents + GOT_ENTRY_SIZE*2); 340299461Sobrien } 340399461Sobrien 340499461Sobrien elf_section_data (htab->sgotplt->output_section)->this_hdr.sh_entsize = 340599461Sobrien GOT_ENTRY_SIZE; 340685815Sobrien } 340785815Sobrien 3408218822Sdim if (htab->sgot && htab->sgot->size > 0) 3409218822Sdim elf_section_data (htab->sgot->output_section)->this_hdr.sh_entsize 3410218822Sdim = GOT_ENTRY_SIZE; 3411218822Sdim 3412130561Sobrien return TRUE; 341385815Sobrien} 341485815Sobrien 3415218822Sdim/* Return address for Ith PLT stub in section PLT, for relocation REL 3416218822Sdim or (bfd_vma) -1 if it should not be included. */ 341785815Sobrien 3418218822Sdimstatic bfd_vma 3419218822Sdimelf64_x86_64_plt_sym_val (bfd_vma i, const asection *plt, 3420218822Sdim const arelent *rel ATTRIBUTE_UNUSED) 3421218822Sdim{ 3422218822Sdim return plt->vma + (i + 1) * PLT_ENTRY_SIZE; 3423218822Sdim} 3424218822Sdim 3425218822Sdim/* Handle an x86-64 specific section when reading an object file. This 3426218822Sdim is called when elfcode.h finds a section with an unknown type. */ 3427218822Sdim 3428218822Sdimstatic bfd_boolean 3429218822Sdimelf64_x86_64_section_from_shdr (bfd *abfd, 3430218822Sdim Elf_Internal_Shdr *hdr, 3431218822Sdim const char *name, 3432218822Sdim int shindex) 3433218822Sdim{ 3434218822Sdim if (hdr->sh_type != SHT_X86_64_UNWIND) 3435218822Sdim return FALSE; 3436218822Sdim 3437218822Sdim if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) 3438218822Sdim return FALSE; 3439218822Sdim 3440218822Sdim return TRUE; 3441218822Sdim} 3442218822Sdim 3443218822Sdim/* Hook called by the linker routine which adds symbols from an object 3444218822Sdim file. We use it to put SHN_X86_64_LCOMMON items in .lbss, instead 3445218822Sdim of .bss. */ 3446218822Sdim 3447218822Sdimstatic bfd_boolean 3448218822Sdimelf64_x86_64_add_symbol_hook (bfd *abfd, 3449218822Sdim struct bfd_link_info *info ATTRIBUTE_UNUSED, 3450218822Sdim Elf_Internal_Sym *sym, 3451218822Sdim const char **namep ATTRIBUTE_UNUSED, 3452218822Sdim flagword *flagsp ATTRIBUTE_UNUSED, 3453218822Sdim asection **secp, bfd_vma *valp) 3454218822Sdim{ 3455218822Sdim asection *lcomm; 3456218822Sdim 3457218822Sdim switch (sym->st_shndx) 3458218822Sdim { 3459218822Sdim case SHN_X86_64_LCOMMON: 3460218822Sdim lcomm = bfd_get_section_by_name (abfd, "LARGE_COMMON"); 3461218822Sdim if (lcomm == NULL) 3462218822Sdim { 3463218822Sdim lcomm = bfd_make_section_with_flags (abfd, 3464218822Sdim "LARGE_COMMON", 3465218822Sdim (SEC_ALLOC 3466218822Sdim | SEC_IS_COMMON 3467218822Sdim | SEC_LINKER_CREATED)); 3468218822Sdim if (lcomm == NULL) 3469218822Sdim return FALSE; 3470218822Sdim elf_section_flags (lcomm) |= SHF_X86_64_LARGE; 3471218822Sdim } 3472218822Sdim *secp = lcomm; 3473218822Sdim *valp = sym->st_size; 3474218822Sdim break; 3475218822Sdim } 3476218822Sdim return TRUE; 3477218822Sdim} 3478218822Sdim 3479218822Sdim 3480218822Sdim/* Given a BFD section, try to locate the corresponding ELF section 3481218822Sdim index. */ 3482218822Sdim 3483218822Sdimstatic bfd_boolean 3484218822Sdimelf64_x86_64_elf_section_from_bfd_section (bfd *abfd ATTRIBUTE_UNUSED, 3485218822Sdim asection *sec, int *index) 3486218822Sdim{ 3487218822Sdim if (sec == &_bfd_elf_large_com_section) 3488218822Sdim { 3489218822Sdim *index = SHN_X86_64_LCOMMON; 3490218822Sdim return TRUE; 3491218822Sdim } 3492218822Sdim return FALSE; 3493218822Sdim} 3494218822Sdim 3495218822Sdim/* Process a symbol. */ 3496218822Sdim 3497218822Sdimstatic void 3498218822Sdimelf64_x86_64_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED, 3499218822Sdim asymbol *asym) 3500218822Sdim{ 3501218822Sdim elf_symbol_type *elfsym = (elf_symbol_type *) asym; 3502218822Sdim 3503218822Sdim switch (elfsym->internal_elf_sym.st_shndx) 3504218822Sdim { 3505218822Sdim case SHN_X86_64_LCOMMON: 3506218822Sdim asym->section = &_bfd_elf_large_com_section; 3507218822Sdim asym->value = elfsym->internal_elf_sym.st_size; 3508218822Sdim /* Common symbol doesn't set BSF_GLOBAL. */ 3509218822Sdim asym->flags &= ~BSF_GLOBAL; 3510218822Sdim break; 3511218822Sdim } 3512218822Sdim} 3513218822Sdim 3514218822Sdimstatic bfd_boolean 3515218822Sdimelf64_x86_64_common_definition (Elf_Internal_Sym *sym) 3516218822Sdim{ 3517218822Sdim return (sym->st_shndx == SHN_COMMON 3518218822Sdim || sym->st_shndx == SHN_X86_64_LCOMMON); 3519218822Sdim} 3520218822Sdim 3521218822Sdimstatic unsigned int 3522218822Sdimelf64_x86_64_common_section_index (asection *sec) 3523218822Sdim{ 3524218822Sdim if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0) 3525218822Sdim return SHN_COMMON; 3526218822Sdim else 3527218822Sdim return SHN_X86_64_LCOMMON; 3528218822Sdim} 3529218822Sdim 3530218822Sdimstatic asection * 3531218822Sdimelf64_x86_64_common_section (asection *sec) 3532218822Sdim{ 3533218822Sdim if ((elf_section_flags (sec) & SHF_X86_64_LARGE) == 0) 3534218822Sdim return bfd_com_section_ptr; 3535218822Sdim else 3536218822Sdim return &_bfd_elf_large_com_section; 3537218822Sdim} 3538218822Sdim 3539218822Sdimstatic bfd_boolean 3540218822Sdimelf64_x86_64_merge_symbol (struct bfd_link_info *info ATTRIBUTE_UNUSED, 3541218822Sdim struct elf_link_hash_entry **sym_hash ATTRIBUTE_UNUSED, 3542218822Sdim struct elf_link_hash_entry *h, 3543218822Sdim Elf_Internal_Sym *sym, 3544218822Sdim asection **psec, 3545218822Sdim bfd_vma *pvalue ATTRIBUTE_UNUSED, 3546218822Sdim unsigned int *pold_alignment ATTRIBUTE_UNUSED, 3547218822Sdim bfd_boolean *skip ATTRIBUTE_UNUSED, 3548218822Sdim bfd_boolean *override ATTRIBUTE_UNUSED, 3549218822Sdim bfd_boolean *type_change_ok ATTRIBUTE_UNUSED, 3550218822Sdim bfd_boolean *size_change_ok ATTRIBUTE_UNUSED, 3551218822Sdim bfd_boolean *newdef ATTRIBUTE_UNUSED, 3552218822Sdim bfd_boolean *newdyn, 3553218822Sdim bfd_boolean *newdyncommon ATTRIBUTE_UNUSED, 3554218822Sdim bfd_boolean *newweak ATTRIBUTE_UNUSED, 3555218822Sdim bfd *abfd ATTRIBUTE_UNUSED, 3556218822Sdim asection **sec, 3557218822Sdim bfd_boolean *olddef ATTRIBUTE_UNUSED, 3558218822Sdim bfd_boolean *olddyn, 3559218822Sdim bfd_boolean *olddyncommon ATTRIBUTE_UNUSED, 3560218822Sdim bfd_boolean *oldweak ATTRIBUTE_UNUSED, 3561218822Sdim bfd *oldbfd, 3562218822Sdim asection **oldsec) 3563218822Sdim{ 3564218822Sdim /* A normal common symbol and a large common symbol result in a 3565218822Sdim normal common symbol. We turn the large common symbol into a 3566218822Sdim normal one. */ 3567218822Sdim if (!*olddyn 3568218822Sdim && h->root.type == bfd_link_hash_common 3569218822Sdim && !*newdyn 3570218822Sdim && bfd_is_com_section (*sec) 3571218822Sdim && *oldsec != *sec) 3572218822Sdim { 3573218822Sdim if (sym->st_shndx == SHN_COMMON 3574218822Sdim && (elf_section_flags (*oldsec) & SHF_X86_64_LARGE) != 0) 3575218822Sdim { 3576218822Sdim h->root.u.c.p->section 3577218822Sdim = bfd_make_section_old_way (oldbfd, "COMMON"); 3578218822Sdim h->root.u.c.p->section->flags = SEC_ALLOC; 3579218822Sdim } 3580218822Sdim else if (sym->st_shndx == SHN_X86_64_LCOMMON 3581218822Sdim && (elf_section_flags (*oldsec) & SHF_X86_64_LARGE) == 0) 3582218822Sdim *psec = *sec = bfd_com_section_ptr; 3583218822Sdim } 3584218822Sdim 3585218822Sdim return TRUE; 3586218822Sdim} 3587218822Sdim 3588218822Sdimstatic int 3589218822Sdimelf64_x86_64_additional_program_headers (bfd *abfd, 3590218822Sdim struct bfd_link_info *info ATTRIBUTE_UNUSED) 3591218822Sdim{ 3592218822Sdim asection *s; 3593218822Sdim int count = 0; 3594218822Sdim 3595218822Sdim /* Check to see if we need a large readonly segment. */ 3596218822Sdim s = bfd_get_section_by_name (abfd, ".lrodata"); 3597218822Sdim if (s && (s->flags & SEC_LOAD)) 3598218822Sdim count++; 3599218822Sdim 3600218822Sdim /* Check to see if we need a large data segment. Since .lbss sections 3601218822Sdim is placed right after the .bss section, there should be no need for 3602218822Sdim a large data segment just because of .lbss. */ 3603218822Sdim s = bfd_get_section_by_name (abfd, ".ldata"); 3604218822Sdim if (s && (s->flags & SEC_LOAD)) 3605218822Sdim count++; 3606218822Sdim 3607218822Sdim return count; 3608218822Sdim} 3609218822Sdim 3610218822Sdim/* Return TRUE if symbol should be hashed in the `.gnu.hash' section. */ 3611218822Sdim 3612218822Sdimstatic bfd_boolean 3613218822Sdimelf64_x86_64_hash_symbol (struct elf_link_hash_entry *h) 3614218822Sdim{ 3615218822Sdim if (h->plt.offset != (bfd_vma) -1 3616218822Sdim && !h->def_regular 3617218822Sdim && !h->pointer_equality_needed) 3618218822Sdim return FALSE; 3619218822Sdim 3620218822Sdim return _bfd_elf_hash_symbol (h); 3621218822Sdim} 3622218822Sdim 3623218822Sdimstatic const struct bfd_elf_special_section 3624218822Sdim elf64_x86_64_special_sections[]= 3625218822Sdim{ 3626218822Sdim { STRING_COMMA_LEN (".gnu.linkonce.lb"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE}, 3627218822Sdim { STRING_COMMA_LEN (".gnu.linkonce.lr"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_X86_64_LARGE}, 3628218822Sdim { STRING_COMMA_LEN (".gnu.linkonce.lt"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_EXECINSTR + SHF_X86_64_LARGE}, 3629218822Sdim { STRING_COMMA_LEN (".lbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE}, 3630218822Sdim { STRING_COMMA_LEN (".ldata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE + SHF_X86_64_LARGE}, 3631218822Sdim { STRING_COMMA_LEN (".lrodata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_X86_64_LARGE}, 3632218822Sdim { NULL, 0, 0, 0, 0 } 3633218822Sdim}; 3634218822Sdim 363585815Sobrien#define TARGET_LITTLE_SYM bfd_elf64_x86_64_vec 363685815Sobrien#define TARGET_LITTLE_NAME "elf64-x86-64" 363785815Sobrien#define ELF_ARCH bfd_arch_i386 363885815Sobrien#define ELF_MACHINE_CODE EM_X86_64 3639218822Sdim#define ELF_MAXPAGESIZE 0x200000 3640218822Sdim#define ELF_MINPAGESIZE 0x1000 3641218822Sdim#define ELF_COMMONPAGESIZE 0x1000 364285815Sobrien 364385815Sobrien#define elf_backend_can_gc_sections 1 364489857Sobrien#define elf_backend_can_refcount 1 364585815Sobrien#define elf_backend_want_got_plt 1 364685815Sobrien#define elf_backend_plt_readonly 1 364785815Sobrien#define elf_backend_want_plt_sym 0 364885815Sobrien#define elf_backend_got_header_size (GOT_ENTRY_SIZE*3) 364999461Sobrien#define elf_backend_rela_normal 1 365085815Sobrien 365185815Sobrien#define elf_info_to_howto elf64_x86_64_info_to_howto 365285815Sobrien 365385815Sobrien#define bfd_elf64_bfd_link_hash_table_create \ 365485815Sobrien elf64_x86_64_link_hash_table_create 365585815Sobrien#define bfd_elf64_bfd_reloc_type_lookup elf64_x86_64_reloc_type_lookup 3656218822Sdim#define bfd_elf64_bfd_reloc_name_lookup \ 3657218822Sdim elf64_x86_64_reloc_name_lookup 365885815Sobrien 365985815Sobrien#define elf_backend_adjust_dynamic_symbol elf64_x86_64_adjust_dynamic_symbol 3660218822Sdim#define elf_backend_relocs_compatible _bfd_elf_relocs_compatible 366185815Sobrien#define elf_backend_check_relocs elf64_x86_64_check_relocs 366299461Sobrien#define elf_backend_copy_indirect_symbol elf64_x86_64_copy_indirect_symbol 366399461Sobrien#define elf_backend_create_dynamic_sections elf64_x86_64_create_dynamic_sections 366499461Sobrien#define elf_backend_finish_dynamic_sections elf64_x86_64_finish_dynamic_sections 366585815Sobrien#define elf_backend_finish_dynamic_symbol elf64_x86_64_finish_dynamic_symbol 366685815Sobrien#define elf_backend_gc_mark_hook elf64_x86_64_gc_mark_hook 366785815Sobrien#define elf_backend_gc_sweep_hook elf64_x86_64_gc_sweep_hook 3668104834Sobrien#define elf_backend_grok_prstatus elf64_x86_64_grok_prstatus 3669104834Sobrien#define elf_backend_grok_psinfo elf64_x86_64_grok_psinfo 367099461Sobrien#define elf_backend_reloc_type_class elf64_x86_64_reloc_type_class 367185815Sobrien#define elf_backend_relocate_section elf64_x86_64_relocate_section 367285815Sobrien#define elf_backend_size_dynamic_sections elf64_x86_64_size_dynamic_sections 3673218822Sdim#define elf_backend_always_size_sections elf64_x86_64_always_size_sections 3674218822Sdim#define elf_backend_init_index_section _bfd_elf_init_1_index_section 3675218822Sdim#define elf_backend_plt_sym_val elf64_x86_64_plt_sym_val 367685815Sobrien#define elf_backend_object_p elf64_x86_64_elf_object_p 3677130561Sobrien#define bfd_elf64_mkobject elf64_x86_64_mkobject 367885815Sobrien 3679218822Sdim#define elf_backend_section_from_shdr \ 3680218822Sdim elf64_x86_64_section_from_shdr 3681218822Sdim 3682218822Sdim#define elf_backend_section_from_bfd_section \ 3683218822Sdim elf64_x86_64_elf_section_from_bfd_section 3684218822Sdim#define elf_backend_add_symbol_hook \ 3685218822Sdim elf64_x86_64_add_symbol_hook 3686218822Sdim#define elf_backend_symbol_processing \ 3687218822Sdim elf64_x86_64_symbol_processing 3688218822Sdim#define elf_backend_common_section_index \ 3689218822Sdim elf64_x86_64_common_section_index 3690218822Sdim#define elf_backend_common_section \ 3691218822Sdim elf64_x86_64_common_section 3692218822Sdim#define elf_backend_common_definition \ 3693218822Sdim elf64_x86_64_common_definition 3694218822Sdim#define elf_backend_merge_symbol \ 3695218822Sdim elf64_x86_64_merge_symbol 3696218822Sdim#define elf_backend_special_sections \ 3697218822Sdim elf64_x86_64_special_sections 3698218822Sdim#define elf_backend_additional_program_headers \ 3699218822Sdim elf64_x86_64_additional_program_headers 3700218822Sdim#define elf_backend_hash_symbol \ 3701218822Sdim elf64_x86_64_hash_symbol 3702218822Sdim 370385815Sobrien#include "elf64-target.h" 3704218822Sdim 3705218822Sdim/* FreeBSD support. */ 3706218822Sdim 3707218822Sdim#undef TARGET_LITTLE_SYM 3708218822Sdim#define TARGET_LITTLE_SYM bfd_elf64_x86_64_freebsd_vec 3709218822Sdim#undef TARGET_LITTLE_NAME 3710218822Sdim#define TARGET_LITTLE_NAME "elf64-x86-64-freebsd" 3711218822Sdim 3712218822Sdim#undef ELF_OSABI 3713218822Sdim#define ELF_OSABI ELFOSABI_FREEBSD 3714218822Sdim 3715218822Sdim#undef elf_backend_post_process_headers 3716218822Sdim#define elf_backend_post_process_headers _bfd_elf_set_osabi 3717218822Sdim 3718218822Sdim#undef elf64_bed 3719218822Sdim#define elf64_bed elf64_x86_64_fbsd_bed 3720218822Sdim 3721218822Sdim#include "elf64-target.h" 3722