189857Sobrien/* PowerPC64-specific support for 64-bit ELF. 2218822Sdim Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 3130561Sobrien Free Software Foundation, Inc. 489857Sobrien Written by Linus Nordberg, Swox AB <info@swox.com>, 589857Sobrien based on elf32-ppc.c by Ian Lance Taylor. 6130561Sobrien Largely rewritten by Alan Modra <amodra@bigpond.net.au> 789857Sobrien 8130561Sobrien This file is part of BFD, the Binary File Descriptor library. 989857Sobrien 10130561Sobrien This program is free software; you can redistribute it and/or modify 11130561Sobrien it under the terms of the GNU General Public License as published by 12130561Sobrien the Free Software Foundation; either version 2 of the License, or 13130561Sobrien (at your option) any later version. 1489857Sobrien 15130561Sobrien This program is distributed in the hope that it will be useful, 16130561Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 17130561Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18130561Sobrien GNU General Public License for more details. 1989857Sobrien 20130561Sobrien You should have received a copy of the GNU General Public License along 21130561Sobrien with this program; if not, write to the Free Software Foundation, Inc., 22218822Sdim 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */ 2389857Sobrien 24130561Sobrien/* The 64-bit PowerPC ELF ABI may be found at 25130561Sobrien http://www.linuxbase.org/spec/ELF/ppc64/PPC-elf64abi.txt, and 26130561Sobrien http://www.linuxbase.org/spec/ELF/ppc64/spec/book1.html */ 2789857Sobrien 28218822Sdim#include "sysdep.h" 29218822Sdim#include <stdarg.h> 3089857Sobrien#include "bfd.h" 3189857Sobrien#include "bfdlink.h" 3289857Sobrien#include "libbfd.h" 3389857Sobrien#include "elf-bfd.h" 34130561Sobrien#include "elf/ppc64.h" 3589857Sobrien#include "elf64-ppc.h" 3689857Sobrien 3799461Sobrienstatic bfd_reloc_status_type ppc64_elf_ha_reloc 38130561Sobrien (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 39218822Sdimstatic bfd_reloc_status_type ppc64_elf_branch_reloc 40218822Sdim (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 4199461Sobrienstatic bfd_reloc_status_type ppc64_elf_brtaken_reloc 42130561Sobrien (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 4399461Sobrienstatic bfd_reloc_status_type ppc64_elf_sectoff_reloc 44130561Sobrien (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 4599461Sobrienstatic bfd_reloc_status_type ppc64_elf_sectoff_ha_reloc 46130561Sobrien (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 4799461Sobrienstatic bfd_reloc_status_type ppc64_elf_toc_reloc 48130561Sobrien (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 4999461Sobrienstatic bfd_reloc_status_type ppc64_elf_toc_ha_reloc 50130561Sobrien (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 5199461Sobrienstatic bfd_reloc_status_type ppc64_elf_toc64_reloc 52130561Sobrien (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 5399461Sobrienstatic bfd_reloc_status_type ppc64_elf_unhandled_reloc 54130561Sobrien (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 55218822Sdimstatic bfd_vma opd_entry_value 56218822Sdim (asection *, bfd_vma, asection **, bfd_vma *); 5789857Sobrien 58130561Sobrien#define TARGET_LITTLE_SYM bfd_elf64_powerpcle_vec 59130561Sobrien#define TARGET_LITTLE_NAME "elf64-powerpcle" 60130561Sobrien#define TARGET_BIG_SYM bfd_elf64_powerpc_vec 61130561Sobrien#define TARGET_BIG_NAME "elf64-powerpc" 62130561Sobrien#define ELF_ARCH bfd_arch_powerpc 63130561Sobrien#define ELF_MACHINE_CODE EM_PPC64 64130561Sobrien#define ELF_MAXPAGESIZE 0x10000 65218822Sdim#define ELF_COMMONPAGESIZE 0x1000 66130561Sobrien#define elf_info_to_howto ppc64_elf_info_to_howto 67130561Sobrien 68130561Sobrien#define elf_backend_want_got_sym 0 69130561Sobrien#define elf_backend_want_plt_sym 0 70130561Sobrien#define elf_backend_plt_alignment 3 71130561Sobrien#define elf_backend_plt_not_loaded 1 72130561Sobrien#define elf_backend_got_header_size 8 73130561Sobrien#define elf_backend_can_gc_sections 1 74130561Sobrien#define elf_backend_can_refcount 1 75130561Sobrien#define elf_backend_rela_normal 1 76218822Sdim#define elf_backend_default_execstack 0 77130561Sobrien 78130561Sobrien#define bfd_elf64_mkobject ppc64_elf_mkobject 79130561Sobrien#define bfd_elf64_bfd_reloc_type_lookup ppc64_elf_reloc_type_lookup 80218822Sdim#define bfd_elf64_bfd_reloc_name_lookup ppc64_elf_reloc_name_lookup 81130561Sobrien#define bfd_elf64_bfd_merge_private_bfd_data ppc64_elf_merge_private_bfd_data 82130561Sobrien#define bfd_elf64_new_section_hook ppc64_elf_new_section_hook 83130561Sobrien#define bfd_elf64_bfd_link_hash_table_create ppc64_elf_link_hash_table_create 84130561Sobrien#define bfd_elf64_bfd_link_hash_table_free ppc64_elf_link_hash_table_free 85218822Sdim#define bfd_elf64_get_synthetic_symtab ppc64_elf_get_synthetic_symtab 86130561Sobrien 87130561Sobrien#define elf_backend_object_p ppc64_elf_object_p 88130561Sobrien#define elf_backend_grok_prstatus ppc64_elf_grok_prstatus 89130561Sobrien#define elf_backend_grok_psinfo ppc64_elf_grok_psinfo 90218822Sdim#define elf_backend_write_core_note ppc64_elf_write_core_note 91130561Sobrien#define elf_backend_create_dynamic_sections ppc64_elf_create_dynamic_sections 92130561Sobrien#define elf_backend_copy_indirect_symbol ppc64_elf_copy_indirect_symbol 93130561Sobrien#define elf_backend_add_symbol_hook ppc64_elf_add_symbol_hook 94218822Sdim#define elf_backend_check_directives ppc64_elf_check_directives 95218822Sdim#define elf_backend_as_needed_cleanup ppc64_elf_as_needed_cleanup 96218822Sdim#define elf_backend_archive_symbol_lookup ppc64_elf_archive_symbol_lookup 97130561Sobrien#define elf_backend_check_relocs ppc64_elf_check_relocs 98218822Sdim#define elf_backend_gc_mark_dynamic_ref ppc64_elf_gc_mark_dynamic_ref 99130561Sobrien#define elf_backend_gc_mark_hook ppc64_elf_gc_mark_hook 100130561Sobrien#define elf_backend_gc_sweep_hook ppc64_elf_gc_sweep_hook 101130561Sobrien#define elf_backend_adjust_dynamic_symbol ppc64_elf_adjust_dynamic_symbol 102130561Sobrien#define elf_backend_hide_symbol ppc64_elf_hide_symbol 103130561Sobrien#define elf_backend_always_size_sections ppc64_elf_func_desc_adjust 104130561Sobrien#define elf_backend_size_dynamic_sections ppc64_elf_size_dynamic_sections 105218822Sdim#define elf_backend_init_index_section _bfd_elf_init_2_index_sections 106218822Sdim#define elf_backend_action_discarded ppc64_elf_action_discarded 107130561Sobrien#define elf_backend_relocate_section ppc64_elf_relocate_section 108130561Sobrien#define elf_backend_finish_dynamic_symbol ppc64_elf_finish_dynamic_symbol 109130561Sobrien#define elf_backend_reloc_type_class ppc64_elf_reloc_type_class 110130561Sobrien#define elf_backend_finish_dynamic_sections ppc64_elf_finish_dynamic_sections 111130561Sobrien#define elf_backend_link_output_symbol_hook ppc64_elf_output_symbol_hook 112130561Sobrien#define elf_backend_special_sections ppc64_elf_special_sections 113130561Sobrien 11489857Sobrien/* The name of the dynamic interpreter. This is put in the .interp 11589857Sobrien section. */ 11689857Sobrien#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" 11789857Sobrien 11889857Sobrien/* The size in bytes of an entry in the procedure linkage table. */ 11989857Sobrien#define PLT_ENTRY_SIZE 24 12089857Sobrien 12189857Sobrien/* The initial size of the plt reserved for the dynamic linker. */ 12289857Sobrien#define PLT_INITIAL_ENTRY_SIZE PLT_ENTRY_SIZE 12389857Sobrien 12489857Sobrien/* TOC base pointers offset from start of TOC. */ 125130561Sobrien#define TOC_BASE_OFF 0x8000 12689857Sobrien 127130561Sobrien/* Offset of tp and dtp pointers from start of TLS block. */ 128130561Sobrien#define TP_OFFSET 0x7000 129130561Sobrien#define DTP_OFFSET 0x8000 130130561Sobrien 131130561Sobrien/* .plt call stub instructions. The normal stub is like this, but 132130561Sobrien sometimes the .plt entry crosses a 64k boundary and we need to 133130561Sobrien insert an addis to adjust r12. */ 134130561Sobrien#define PLT_CALL_STUB_SIZE (7*4) 13589857Sobrien#define ADDIS_R12_R2 0x3d820000 /* addis %r12,%r2,xxx@ha */ 13689857Sobrien#define STD_R2_40R1 0xf8410028 /* std %r2,40(%r1) */ 13789857Sobrien#define LD_R11_0R12 0xe96c0000 /* ld %r11,xxx+0@l(%r12) */ 13889857Sobrien#define LD_R2_0R12 0xe84c0000 /* ld %r2,xxx+8@l(%r12) */ 13989857Sobrien#define MTCTR_R11 0x7d6903a6 /* mtctr %r11 */ 14089857Sobrien /* ld %r11,xxx+16@l(%r12) */ 14189857Sobrien#define BCTR 0x4e800420 /* bctr */ 14289857Sobrien 14389857Sobrien 144218822Sdim#define ADDIS_R12_R12 0x3d8c0000 /* addis %r12,%r12,off@ha */ 145130561Sobrien#define ADDIS_R2_R2 0x3c420000 /* addis %r2,%r2,off@ha */ 146130561Sobrien#define ADDI_R2_R2 0x38420000 /* addi %r2,%r2,off@l */ 14789857Sobrien 148130561Sobrien#define LD_R2_40R1 0xe8410028 /* ld %r2,40(%r1) */ 14989857Sobrien 150218822Sdim/* glink call stub instructions. We enter with the index in R0. */ 151130561Sobrien#define GLINK_CALL_STUB_SIZE (16*4) 152218822Sdim /* 0: */ 153218822Sdim /* .quad plt0-1f */ 154218822Sdim /* __glink: */ 155218822Sdim#define MFLR_R12 0x7d8802a6 /* mflr %12 */ 156218822Sdim#define BCL_20_31 0x429f0005 /* bcl 20,31,1f */ 157218822Sdim /* 1: */ 158218822Sdim#define MFLR_R11 0x7d6802a6 /* mflr %11 */ 159218822Sdim#define LD_R2_M16R11 0xe84bfff0 /* ld %2,(0b-1b)(%11) */ 160218822Sdim#define MTLR_R12 0x7d8803a6 /* mtlr %12 */ 161218822Sdim#define ADD_R12_R2_R11 0x7d825a14 /* add %12,%2,%11 */ 162218822Sdim /* ld %11,0(%12) */ 163218822Sdim /* ld %2,8(%12) */ 164218822Sdim /* mtctr %11 */ 165218822Sdim /* ld %11,16(%12) */ 166218822Sdim /* bctr */ 16789857Sobrien 16889857Sobrien/* Pad with this. */ 16989857Sobrien#define NOP 0x60000000 17089857Sobrien 17199461Sobrien/* Some other nops. */ 17299461Sobrien#define CROR_151515 0x4def7b82 17399461Sobrien#define CROR_313131 0x4ffffb82 17499461Sobrien 175104834Sobrien/* .glink entries for the first 32k functions are two instructions. */ 17689857Sobrien#define LI_R0_0 0x38000000 /* li %r0,0 */ 17789857Sobrien#define B_DOT 0x48000000 /* b . */ 17889857Sobrien 17989857Sobrien/* After that, we need two instructions to load the index, followed by 18089857Sobrien a branch. */ 18189857Sobrien#define LIS_R0_0 0x3c000000 /* lis %r0,0 */ 18289857Sobrien#define ORI_R0_R0_0 0x60000000 /* ori %r0,%r0,0 */ 18389857Sobrien 184218822Sdim/* Instructions used by the save and restore reg functions. */ 185218822Sdim#define STD_R0_0R1 0xf8010000 /* std %r0,0(%r1) */ 186218822Sdim#define STD_R0_0R12 0xf80c0000 /* std %r0,0(%r12) */ 187218822Sdim#define LD_R0_0R1 0xe8010000 /* ld %r0,0(%r1) */ 188218822Sdim#define LD_R0_0R12 0xe80c0000 /* ld %r0,0(%r12) */ 18992828Sobrien#define STFD_FR0_0R1 0xd8010000 /* stfd %fr0,0(%r1) */ 19092828Sobrien#define LFD_FR0_0R1 0xc8010000 /* lfd %fr0,0(%r1) */ 191218822Sdim#define LI_R12_0 0x39800000 /* li %r12,0 */ 192218822Sdim#define STVX_VR0_R12_R0 0x7c0c01ce /* stvx %v0,%r12,%r0 */ 193218822Sdim#define LVX_VR0_R12_R0 0x7c0c00ce /* lvx %v0,%r12,%r0 */ 194218822Sdim#define MTLR_R0 0x7c0803a6 /* mtlr %r0 */ 19592828Sobrien#define BLR 0x4e800020 /* blr */ 19692828Sobrien 19789857Sobrien/* Since .opd is an array of descriptors and each entry will end up 19889857Sobrien with identical R_PPC64_RELATIVE relocs, there is really no need to 19989857Sobrien propagate .opd relocs; The dynamic linker should be taught to 200104834Sobrien relocate .opd without reloc entries. */ 20189857Sobrien#ifndef NO_OPD_RELOCS 20289857Sobrien#define NO_OPD_RELOCS 0 20389857Sobrien#endif 20489857Sobrien 205104834Sobrien#define ONES(n) (((bfd_vma) 1 << ((n) - 1) << 1) - 1) 206130561Sobrien 20789857Sobrien/* Relocation HOWTO's. */ 208130561Sobrienstatic reloc_howto_type *ppc64_elf_howto_table[(int) R_PPC64_max]; 20989857Sobrien 21089857Sobrienstatic reloc_howto_type ppc64_elf_howto_raw[] = { 21189857Sobrien /* This reloc does nothing. */ 21289857Sobrien HOWTO (R_PPC64_NONE, /* type */ 21389857Sobrien 0, /* rightshift */ 214130561Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 215130561Sobrien 32, /* bitsize */ 216130561Sobrien FALSE, /* pc_relative */ 21789857Sobrien 0, /* bitpos */ 218104834Sobrien complain_overflow_dont, /* complain_on_overflow */ 21989857Sobrien bfd_elf_generic_reloc, /* special_function */ 22089857Sobrien "R_PPC64_NONE", /* name */ 221130561Sobrien FALSE, /* partial_inplace */ 22289857Sobrien 0, /* src_mask */ 22389857Sobrien 0, /* dst_mask */ 224130561Sobrien FALSE), /* pcrel_offset */ 22589857Sobrien 22689857Sobrien /* A standard 32 bit relocation. */ 22789857Sobrien HOWTO (R_PPC64_ADDR32, /* type */ 22889857Sobrien 0, /* rightshift */ 22989857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 23089857Sobrien 32, /* bitsize */ 231130561Sobrien FALSE, /* pc_relative */ 23289857Sobrien 0, /* bitpos */ 23389857Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 23489857Sobrien bfd_elf_generic_reloc, /* special_function */ 23589857Sobrien "R_PPC64_ADDR32", /* name */ 236130561Sobrien FALSE, /* partial_inplace */ 23789857Sobrien 0, /* src_mask */ 23889857Sobrien 0xffffffff, /* dst_mask */ 239130561Sobrien FALSE), /* pcrel_offset */ 24089857Sobrien 24189857Sobrien /* An absolute 26 bit branch; the lower two bits must be zero. 24289857Sobrien FIXME: we don't check that, we just clear them. */ 24389857Sobrien HOWTO (R_PPC64_ADDR24, /* type */ 24489857Sobrien 0, /* rightshift */ 24589857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 24689857Sobrien 26, /* bitsize */ 247130561Sobrien FALSE, /* pc_relative */ 24889857Sobrien 0, /* bitpos */ 24989857Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 25089857Sobrien bfd_elf_generic_reloc, /* special_function */ 25189857Sobrien "R_PPC64_ADDR24", /* name */ 252130561Sobrien FALSE, /* partial_inplace */ 25389857Sobrien 0, /* src_mask */ 254104834Sobrien 0x03fffffc, /* dst_mask */ 255130561Sobrien FALSE), /* pcrel_offset */ 25689857Sobrien 25789857Sobrien /* A standard 16 bit relocation. */ 25889857Sobrien HOWTO (R_PPC64_ADDR16, /* type */ 25989857Sobrien 0, /* rightshift */ 26089857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 26189857Sobrien 16, /* bitsize */ 262130561Sobrien FALSE, /* pc_relative */ 26389857Sobrien 0, /* bitpos */ 26489857Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 26589857Sobrien bfd_elf_generic_reloc, /* special_function */ 26689857Sobrien "R_PPC64_ADDR16", /* name */ 267130561Sobrien FALSE, /* partial_inplace */ 26889857Sobrien 0, /* src_mask */ 26989857Sobrien 0xffff, /* dst_mask */ 270130561Sobrien FALSE), /* pcrel_offset */ 27189857Sobrien 27289857Sobrien /* A 16 bit relocation without overflow. */ 27389857Sobrien HOWTO (R_PPC64_ADDR16_LO, /* type */ 27489857Sobrien 0, /* rightshift */ 27589857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 27689857Sobrien 16, /* bitsize */ 277130561Sobrien FALSE, /* pc_relative */ 27889857Sobrien 0, /* bitpos */ 27989857Sobrien complain_overflow_dont,/* complain_on_overflow */ 28089857Sobrien bfd_elf_generic_reloc, /* special_function */ 28189857Sobrien "R_PPC64_ADDR16_LO", /* name */ 282130561Sobrien FALSE, /* partial_inplace */ 28389857Sobrien 0, /* src_mask */ 28489857Sobrien 0xffff, /* dst_mask */ 285130561Sobrien FALSE), /* pcrel_offset */ 28689857Sobrien 28789857Sobrien /* Bits 16-31 of an address. */ 28889857Sobrien HOWTO (R_PPC64_ADDR16_HI, /* type */ 28989857Sobrien 16, /* rightshift */ 29089857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 29189857Sobrien 16, /* bitsize */ 292130561Sobrien FALSE, /* pc_relative */ 29389857Sobrien 0, /* bitpos */ 29489857Sobrien complain_overflow_dont, /* complain_on_overflow */ 29589857Sobrien bfd_elf_generic_reloc, /* special_function */ 29689857Sobrien "R_PPC64_ADDR16_HI", /* name */ 297130561Sobrien FALSE, /* partial_inplace */ 29889857Sobrien 0, /* src_mask */ 29989857Sobrien 0xffff, /* dst_mask */ 300130561Sobrien FALSE), /* pcrel_offset */ 30189857Sobrien 30289857Sobrien /* Bits 16-31 of an address, plus 1 if the contents of the low 16 30389857Sobrien bits, treated as a signed number, is negative. */ 30489857Sobrien HOWTO (R_PPC64_ADDR16_HA, /* type */ 30589857Sobrien 16, /* rightshift */ 30689857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 30789857Sobrien 16, /* bitsize */ 308130561Sobrien FALSE, /* pc_relative */ 30989857Sobrien 0, /* bitpos */ 31089857Sobrien complain_overflow_dont, /* complain_on_overflow */ 31199461Sobrien ppc64_elf_ha_reloc, /* special_function */ 31289857Sobrien "R_PPC64_ADDR16_HA", /* name */ 313130561Sobrien FALSE, /* partial_inplace */ 31489857Sobrien 0, /* src_mask */ 31589857Sobrien 0xffff, /* dst_mask */ 316130561Sobrien FALSE), /* pcrel_offset */ 31789857Sobrien 31889857Sobrien /* An absolute 16 bit branch; the lower two bits must be zero. 31989857Sobrien FIXME: we don't check that, we just clear them. */ 32089857Sobrien HOWTO (R_PPC64_ADDR14, /* type */ 32189857Sobrien 0, /* rightshift */ 32289857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 32389857Sobrien 16, /* bitsize */ 324130561Sobrien FALSE, /* pc_relative */ 32589857Sobrien 0, /* bitpos */ 32689857Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 327218822Sdim ppc64_elf_branch_reloc, /* special_function */ 32889857Sobrien "R_PPC64_ADDR14", /* name */ 329130561Sobrien FALSE, /* partial_inplace */ 33089857Sobrien 0, /* src_mask */ 331104834Sobrien 0x0000fffc, /* dst_mask */ 332130561Sobrien FALSE), /* pcrel_offset */ 33389857Sobrien 33489857Sobrien /* An absolute 16 bit branch, for which bit 10 should be set to 33589857Sobrien indicate that the branch is expected to be taken. The lower two 33689857Sobrien bits must be zero. */ 33789857Sobrien HOWTO (R_PPC64_ADDR14_BRTAKEN, /* type */ 33889857Sobrien 0, /* rightshift */ 33989857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 34089857Sobrien 16, /* bitsize */ 341130561Sobrien FALSE, /* pc_relative */ 34289857Sobrien 0, /* bitpos */ 34389857Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 34499461Sobrien ppc64_elf_brtaken_reloc, /* special_function */ 34589857Sobrien "R_PPC64_ADDR14_BRTAKEN",/* name */ 346130561Sobrien FALSE, /* partial_inplace */ 34789857Sobrien 0, /* src_mask */ 348104834Sobrien 0x0000fffc, /* dst_mask */ 349130561Sobrien FALSE), /* pcrel_offset */ 35089857Sobrien 35189857Sobrien /* An absolute 16 bit branch, for which bit 10 should be set to 35289857Sobrien indicate that the branch is not expected to be taken. The lower 35389857Sobrien two bits must be zero. */ 35489857Sobrien HOWTO (R_PPC64_ADDR14_BRNTAKEN, /* type */ 35589857Sobrien 0, /* rightshift */ 35689857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 35789857Sobrien 16, /* bitsize */ 358130561Sobrien FALSE, /* pc_relative */ 35989857Sobrien 0, /* bitpos */ 36089857Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 36199461Sobrien ppc64_elf_brtaken_reloc, /* special_function */ 36289857Sobrien "R_PPC64_ADDR14_BRNTAKEN",/* name */ 363130561Sobrien FALSE, /* partial_inplace */ 36489857Sobrien 0, /* src_mask */ 365104834Sobrien 0x0000fffc, /* dst_mask */ 366130561Sobrien FALSE), /* pcrel_offset */ 36789857Sobrien 36889857Sobrien /* A relative 26 bit branch; the lower two bits must be zero. */ 36989857Sobrien HOWTO (R_PPC64_REL24, /* type */ 37089857Sobrien 0, /* rightshift */ 37189857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 37289857Sobrien 26, /* bitsize */ 373130561Sobrien TRUE, /* pc_relative */ 37489857Sobrien 0, /* bitpos */ 37589857Sobrien complain_overflow_signed, /* complain_on_overflow */ 376218822Sdim ppc64_elf_branch_reloc, /* special_function */ 37789857Sobrien "R_PPC64_REL24", /* name */ 378130561Sobrien FALSE, /* partial_inplace */ 37989857Sobrien 0, /* src_mask */ 380104834Sobrien 0x03fffffc, /* dst_mask */ 381130561Sobrien TRUE), /* pcrel_offset */ 38289857Sobrien 38389857Sobrien /* A relative 16 bit branch; the lower two bits must be zero. */ 38489857Sobrien HOWTO (R_PPC64_REL14, /* type */ 38589857Sobrien 0, /* rightshift */ 38689857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 38789857Sobrien 16, /* bitsize */ 388130561Sobrien TRUE, /* pc_relative */ 38989857Sobrien 0, /* bitpos */ 39089857Sobrien complain_overflow_signed, /* complain_on_overflow */ 391218822Sdim ppc64_elf_branch_reloc, /* special_function */ 39289857Sobrien "R_PPC64_REL14", /* name */ 393130561Sobrien FALSE, /* partial_inplace */ 39489857Sobrien 0, /* src_mask */ 395104834Sobrien 0x0000fffc, /* dst_mask */ 396130561Sobrien TRUE), /* pcrel_offset */ 39789857Sobrien 39889857Sobrien /* A relative 16 bit branch. Bit 10 should be set to indicate that 39989857Sobrien the branch is expected to be taken. The lower two bits must be 40089857Sobrien zero. */ 40189857Sobrien HOWTO (R_PPC64_REL14_BRTAKEN, /* type */ 40289857Sobrien 0, /* rightshift */ 40389857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 40489857Sobrien 16, /* bitsize */ 405130561Sobrien TRUE, /* pc_relative */ 40689857Sobrien 0, /* bitpos */ 40789857Sobrien complain_overflow_signed, /* complain_on_overflow */ 40899461Sobrien ppc64_elf_brtaken_reloc, /* special_function */ 40989857Sobrien "R_PPC64_REL14_BRTAKEN", /* name */ 410130561Sobrien FALSE, /* partial_inplace */ 41189857Sobrien 0, /* src_mask */ 412104834Sobrien 0x0000fffc, /* dst_mask */ 413130561Sobrien TRUE), /* pcrel_offset */ 41489857Sobrien 41589857Sobrien /* A relative 16 bit branch. Bit 10 should be set to indicate that 41689857Sobrien the branch is not expected to be taken. The lower two bits must 41789857Sobrien be zero. */ 41889857Sobrien HOWTO (R_PPC64_REL14_BRNTAKEN, /* type */ 41989857Sobrien 0, /* rightshift */ 42089857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 42189857Sobrien 16, /* bitsize */ 422130561Sobrien TRUE, /* pc_relative */ 42389857Sobrien 0, /* bitpos */ 42489857Sobrien complain_overflow_signed, /* complain_on_overflow */ 42599461Sobrien ppc64_elf_brtaken_reloc, /* special_function */ 42689857Sobrien "R_PPC64_REL14_BRNTAKEN",/* name */ 427130561Sobrien FALSE, /* partial_inplace */ 42889857Sobrien 0, /* src_mask */ 429104834Sobrien 0x0000fffc, /* dst_mask */ 430130561Sobrien TRUE), /* pcrel_offset */ 43189857Sobrien 43289857Sobrien /* Like R_PPC64_ADDR16, but referring to the GOT table entry for the 43389857Sobrien symbol. */ 43489857Sobrien HOWTO (R_PPC64_GOT16, /* type */ 43589857Sobrien 0, /* rightshift */ 43689857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 43789857Sobrien 16, /* bitsize */ 438130561Sobrien FALSE, /* pc_relative */ 43989857Sobrien 0, /* bitpos */ 44089857Sobrien complain_overflow_signed, /* complain_on_overflow */ 44199461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 44289857Sobrien "R_PPC64_GOT16", /* name */ 443130561Sobrien FALSE, /* partial_inplace */ 44489857Sobrien 0, /* src_mask */ 44589857Sobrien 0xffff, /* dst_mask */ 446130561Sobrien FALSE), /* pcrel_offset */ 44789857Sobrien 44889857Sobrien /* Like R_PPC64_ADDR16_LO, but referring to the GOT table entry for 44989857Sobrien the symbol. */ 45089857Sobrien HOWTO (R_PPC64_GOT16_LO, /* type */ 45189857Sobrien 0, /* rightshift */ 45289857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 45389857Sobrien 16, /* bitsize */ 454130561Sobrien FALSE, /* pc_relative */ 45589857Sobrien 0, /* bitpos */ 45689857Sobrien complain_overflow_dont, /* complain_on_overflow */ 45799461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 45889857Sobrien "R_PPC64_GOT16_LO", /* name */ 459130561Sobrien FALSE, /* partial_inplace */ 46089857Sobrien 0, /* src_mask */ 46189857Sobrien 0xffff, /* dst_mask */ 462130561Sobrien FALSE), /* pcrel_offset */ 46389857Sobrien 46489857Sobrien /* Like R_PPC64_ADDR16_HI, but referring to the GOT table entry for 46589857Sobrien the symbol. */ 46689857Sobrien HOWTO (R_PPC64_GOT16_HI, /* type */ 46789857Sobrien 16, /* rightshift */ 46889857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 46989857Sobrien 16, /* bitsize */ 470130561Sobrien FALSE, /* pc_relative */ 47189857Sobrien 0, /* bitpos */ 47289857Sobrien complain_overflow_dont,/* complain_on_overflow */ 47399461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 47489857Sobrien "R_PPC64_GOT16_HI", /* name */ 475130561Sobrien FALSE, /* partial_inplace */ 47689857Sobrien 0, /* src_mask */ 47789857Sobrien 0xffff, /* dst_mask */ 478130561Sobrien FALSE), /* pcrel_offset */ 47989857Sobrien 48089857Sobrien /* Like R_PPC64_ADDR16_HA, but referring to the GOT table entry for 48189857Sobrien the symbol. */ 48289857Sobrien HOWTO (R_PPC64_GOT16_HA, /* type */ 48389857Sobrien 16, /* rightshift */ 48489857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 48589857Sobrien 16, /* bitsize */ 486130561Sobrien FALSE, /* pc_relative */ 48789857Sobrien 0, /* bitpos */ 48889857Sobrien complain_overflow_dont,/* complain_on_overflow */ 48999461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 49089857Sobrien "R_PPC64_GOT16_HA", /* name */ 491130561Sobrien FALSE, /* partial_inplace */ 49289857Sobrien 0, /* src_mask */ 49389857Sobrien 0xffff, /* dst_mask */ 494130561Sobrien FALSE), /* pcrel_offset */ 49589857Sobrien 49689857Sobrien /* This is used only by the dynamic linker. The symbol should exist 49789857Sobrien both in the object being run and in some shared library. The 49889857Sobrien dynamic linker copies the data addressed by the symbol from the 49989857Sobrien shared library into the object, because the object being 50089857Sobrien run has to have the data at some particular address. */ 50189857Sobrien HOWTO (R_PPC64_COPY, /* type */ 50289857Sobrien 0, /* rightshift */ 503104834Sobrien 0, /* this one is variable size */ 504104834Sobrien 0, /* bitsize */ 505130561Sobrien FALSE, /* pc_relative */ 50689857Sobrien 0, /* bitpos */ 507104834Sobrien complain_overflow_dont, /* complain_on_overflow */ 508104834Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 50989857Sobrien "R_PPC64_COPY", /* name */ 510130561Sobrien FALSE, /* partial_inplace */ 51189857Sobrien 0, /* src_mask */ 51289857Sobrien 0, /* dst_mask */ 513130561Sobrien FALSE), /* pcrel_offset */ 51489857Sobrien 51589857Sobrien /* Like R_PPC64_ADDR64, but used when setting global offset table 51689857Sobrien entries. */ 51789857Sobrien HOWTO (R_PPC64_GLOB_DAT, /* type */ 51889857Sobrien 0, /* rightshift */ 51989857Sobrien 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ 52089857Sobrien 64, /* bitsize */ 521130561Sobrien FALSE, /* pc_relative */ 52289857Sobrien 0, /* bitpos */ 52389857Sobrien complain_overflow_dont, /* complain_on_overflow */ 52499461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 52589857Sobrien "R_PPC64_GLOB_DAT", /* name */ 526130561Sobrien FALSE, /* partial_inplace */ 52789857Sobrien 0, /* src_mask */ 528104834Sobrien ONES (64), /* dst_mask */ 529130561Sobrien FALSE), /* pcrel_offset */ 53089857Sobrien 53189857Sobrien /* Created by the link editor. Marks a procedure linkage table 53289857Sobrien entry for a symbol. */ 53389857Sobrien HOWTO (R_PPC64_JMP_SLOT, /* type */ 53489857Sobrien 0, /* rightshift */ 53589857Sobrien 0, /* size (0 = byte, 1 = short, 2 = long) */ 53689857Sobrien 0, /* bitsize */ 537130561Sobrien FALSE, /* pc_relative */ 53889857Sobrien 0, /* bitpos */ 53989857Sobrien complain_overflow_dont, /* complain_on_overflow */ 54099461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 54189857Sobrien "R_PPC64_JMP_SLOT", /* name */ 542130561Sobrien FALSE, /* partial_inplace */ 54389857Sobrien 0, /* src_mask */ 54489857Sobrien 0, /* dst_mask */ 545130561Sobrien FALSE), /* pcrel_offset */ 54689857Sobrien 54789857Sobrien /* Used only by the dynamic linker. When the object is run, this 54889857Sobrien doubleword64 is set to the load address of the object, plus the 54989857Sobrien addend. */ 55089857Sobrien HOWTO (R_PPC64_RELATIVE, /* type */ 55189857Sobrien 0, /* rightshift */ 55289857Sobrien 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ 55389857Sobrien 64, /* bitsize */ 554130561Sobrien FALSE, /* pc_relative */ 55589857Sobrien 0, /* bitpos */ 55689857Sobrien complain_overflow_dont, /* complain_on_overflow */ 55789857Sobrien bfd_elf_generic_reloc, /* special_function */ 55889857Sobrien "R_PPC64_RELATIVE", /* name */ 559130561Sobrien FALSE, /* partial_inplace */ 56089857Sobrien 0, /* src_mask */ 561104834Sobrien ONES (64), /* dst_mask */ 562130561Sobrien FALSE), /* pcrel_offset */ 56389857Sobrien 56489857Sobrien /* Like R_PPC64_ADDR32, but may be unaligned. */ 56589857Sobrien HOWTO (R_PPC64_UADDR32, /* type */ 56689857Sobrien 0, /* rightshift */ 56789857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 56889857Sobrien 32, /* bitsize */ 569130561Sobrien FALSE, /* pc_relative */ 57089857Sobrien 0, /* bitpos */ 57189857Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 57289857Sobrien bfd_elf_generic_reloc, /* special_function */ 57389857Sobrien "R_PPC64_UADDR32", /* name */ 574130561Sobrien FALSE, /* partial_inplace */ 57589857Sobrien 0, /* src_mask */ 57689857Sobrien 0xffffffff, /* dst_mask */ 577130561Sobrien FALSE), /* pcrel_offset */ 57889857Sobrien 57989857Sobrien /* Like R_PPC64_ADDR16, but may be unaligned. */ 58089857Sobrien HOWTO (R_PPC64_UADDR16, /* type */ 58189857Sobrien 0, /* rightshift */ 58289857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 58389857Sobrien 16, /* bitsize */ 584130561Sobrien FALSE, /* pc_relative */ 58589857Sobrien 0, /* bitpos */ 58689857Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 58789857Sobrien bfd_elf_generic_reloc, /* special_function */ 58889857Sobrien "R_PPC64_UADDR16", /* name */ 589130561Sobrien FALSE, /* partial_inplace */ 59089857Sobrien 0, /* src_mask */ 59189857Sobrien 0xffff, /* dst_mask */ 592130561Sobrien FALSE), /* pcrel_offset */ 59389857Sobrien 59489857Sobrien /* 32-bit PC relative. */ 59589857Sobrien HOWTO (R_PPC64_REL32, /* type */ 59689857Sobrien 0, /* rightshift */ 59789857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 59889857Sobrien 32, /* bitsize */ 599130561Sobrien TRUE, /* pc_relative */ 60089857Sobrien 0, /* bitpos */ 601104834Sobrien /* FIXME: Verify. Was complain_overflow_bitfield. */ 60289857Sobrien complain_overflow_signed, /* complain_on_overflow */ 60389857Sobrien bfd_elf_generic_reloc, /* special_function */ 60489857Sobrien "R_PPC64_REL32", /* name */ 605130561Sobrien FALSE, /* partial_inplace */ 60689857Sobrien 0, /* src_mask */ 60789857Sobrien 0xffffffff, /* dst_mask */ 608130561Sobrien TRUE), /* pcrel_offset */ 60989857Sobrien 61089857Sobrien /* 32-bit relocation to the symbol's procedure linkage table. */ 61189857Sobrien HOWTO (R_PPC64_PLT32, /* type */ 61289857Sobrien 0, /* rightshift */ 61389857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 61489857Sobrien 32, /* bitsize */ 615130561Sobrien FALSE, /* pc_relative */ 61689857Sobrien 0, /* bitpos */ 61789857Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 61899461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 61989857Sobrien "R_PPC64_PLT32", /* name */ 620130561Sobrien FALSE, /* partial_inplace */ 62189857Sobrien 0, /* src_mask */ 622104834Sobrien 0xffffffff, /* dst_mask */ 623130561Sobrien FALSE), /* pcrel_offset */ 62489857Sobrien 62589857Sobrien /* 32-bit PC relative relocation to the symbol's procedure linkage table. 62689857Sobrien FIXME: R_PPC64_PLTREL32 not supported. */ 62789857Sobrien HOWTO (R_PPC64_PLTREL32, /* type */ 62889857Sobrien 0, /* rightshift */ 62989857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 63089857Sobrien 32, /* bitsize */ 631130561Sobrien TRUE, /* pc_relative */ 63289857Sobrien 0, /* bitpos */ 63389857Sobrien complain_overflow_signed, /* complain_on_overflow */ 63489857Sobrien bfd_elf_generic_reloc, /* special_function */ 63589857Sobrien "R_PPC64_PLTREL32", /* name */ 636130561Sobrien FALSE, /* partial_inplace */ 63789857Sobrien 0, /* src_mask */ 638104834Sobrien 0xffffffff, /* dst_mask */ 639130561Sobrien TRUE), /* pcrel_offset */ 64089857Sobrien 64189857Sobrien /* Like R_PPC64_ADDR16_LO, but referring to the PLT table entry for 64289857Sobrien the symbol. */ 64389857Sobrien HOWTO (R_PPC64_PLT16_LO, /* type */ 64489857Sobrien 0, /* rightshift */ 64589857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 64689857Sobrien 16, /* bitsize */ 647130561Sobrien FALSE, /* pc_relative */ 64889857Sobrien 0, /* bitpos */ 64989857Sobrien complain_overflow_dont, /* complain_on_overflow */ 65099461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 65189857Sobrien "R_PPC64_PLT16_LO", /* name */ 652130561Sobrien FALSE, /* partial_inplace */ 65389857Sobrien 0, /* src_mask */ 65489857Sobrien 0xffff, /* dst_mask */ 655130561Sobrien FALSE), /* pcrel_offset */ 65689857Sobrien 65789857Sobrien /* Like R_PPC64_ADDR16_HI, but referring to the PLT table entry for 65889857Sobrien the symbol. */ 65989857Sobrien HOWTO (R_PPC64_PLT16_HI, /* type */ 66089857Sobrien 16, /* rightshift */ 66189857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 66289857Sobrien 16, /* bitsize */ 663130561Sobrien FALSE, /* pc_relative */ 66489857Sobrien 0, /* bitpos */ 66589857Sobrien complain_overflow_dont, /* complain_on_overflow */ 66699461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 66789857Sobrien "R_PPC64_PLT16_HI", /* name */ 668130561Sobrien FALSE, /* partial_inplace */ 66989857Sobrien 0, /* src_mask */ 67089857Sobrien 0xffff, /* dst_mask */ 671130561Sobrien FALSE), /* pcrel_offset */ 67289857Sobrien 67389857Sobrien /* Like R_PPC64_ADDR16_HA, but referring to the PLT table entry for 67489857Sobrien the symbol. */ 67589857Sobrien HOWTO (R_PPC64_PLT16_HA, /* type */ 67689857Sobrien 16, /* rightshift */ 67789857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 67889857Sobrien 16, /* bitsize */ 679130561Sobrien FALSE, /* pc_relative */ 68089857Sobrien 0, /* bitpos */ 68189857Sobrien complain_overflow_dont, /* complain_on_overflow */ 68299461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 68389857Sobrien "R_PPC64_PLT16_HA", /* name */ 684130561Sobrien FALSE, /* partial_inplace */ 68589857Sobrien 0, /* src_mask */ 68689857Sobrien 0xffff, /* dst_mask */ 687130561Sobrien FALSE), /* pcrel_offset */ 68889857Sobrien 68999461Sobrien /* 16-bit section relative relocation. */ 69089857Sobrien HOWTO (R_PPC64_SECTOFF, /* type */ 69189857Sobrien 0, /* rightshift */ 69299461Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 69399461Sobrien 16, /* bitsize */ 694130561Sobrien FALSE, /* pc_relative */ 69589857Sobrien 0, /* bitpos */ 69689857Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 69799461Sobrien ppc64_elf_sectoff_reloc, /* special_function */ 69889857Sobrien "R_PPC64_SECTOFF", /* name */ 699130561Sobrien FALSE, /* partial_inplace */ 70089857Sobrien 0, /* src_mask */ 70199461Sobrien 0xffff, /* dst_mask */ 702130561Sobrien FALSE), /* pcrel_offset */ 70389857Sobrien 70499461Sobrien /* Like R_PPC64_SECTOFF, but no overflow warning. */ 70589857Sobrien HOWTO (R_PPC64_SECTOFF_LO, /* type */ 70689857Sobrien 0, /* rightshift */ 70789857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 70889857Sobrien 16, /* bitsize */ 709130561Sobrien FALSE, /* pc_relative */ 71089857Sobrien 0, /* bitpos */ 71189857Sobrien complain_overflow_dont, /* complain_on_overflow */ 71299461Sobrien ppc64_elf_sectoff_reloc, /* special_function */ 71389857Sobrien "R_PPC64_SECTOFF_LO", /* name */ 714130561Sobrien FALSE, /* partial_inplace */ 71589857Sobrien 0, /* src_mask */ 71689857Sobrien 0xffff, /* dst_mask */ 717130561Sobrien FALSE), /* pcrel_offset */ 71889857Sobrien 71989857Sobrien /* 16-bit upper half section relative relocation. */ 72089857Sobrien HOWTO (R_PPC64_SECTOFF_HI, /* type */ 72189857Sobrien 16, /* rightshift */ 72289857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 72389857Sobrien 16, /* bitsize */ 724130561Sobrien FALSE, /* pc_relative */ 72589857Sobrien 0, /* bitpos */ 72689857Sobrien complain_overflow_dont, /* complain_on_overflow */ 72799461Sobrien ppc64_elf_sectoff_reloc, /* special_function */ 72889857Sobrien "R_PPC64_SECTOFF_HI", /* name */ 729130561Sobrien FALSE, /* partial_inplace */ 73089857Sobrien 0, /* src_mask */ 73189857Sobrien 0xffff, /* dst_mask */ 732130561Sobrien FALSE), /* pcrel_offset */ 73389857Sobrien 73489857Sobrien /* 16-bit upper half adjusted section relative relocation. */ 73589857Sobrien HOWTO (R_PPC64_SECTOFF_HA, /* type */ 73689857Sobrien 16, /* rightshift */ 73789857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 73889857Sobrien 16, /* bitsize */ 739130561Sobrien FALSE, /* pc_relative */ 74089857Sobrien 0, /* bitpos */ 74189857Sobrien complain_overflow_dont, /* complain_on_overflow */ 74299461Sobrien ppc64_elf_sectoff_ha_reloc, /* special_function */ 74389857Sobrien "R_PPC64_SECTOFF_HA", /* name */ 744130561Sobrien FALSE, /* partial_inplace */ 74589857Sobrien 0, /* src_mask */ 74689857Sobrien 0xffff, /* dst_mask */ 747130561Sobrien FALSE), /* pcrel_offset */ 74889857Sobrien 749130561Sobrien /* Like R_PPC64_REL24 without touching the two least significant bits. */ 750130561Sobrien HOWTO (R_PPC64_REL30, /* type */ 75189857Sobrien 2, /* rightshift */ 75289857Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 75389857Sobrien 30, /* bitsize */ 754130561Sobrien TRUE, /* pc_relative */ 75589857Sobrien 0, /* bitpos */ 75689857Sobrien complain_overflow_dont, /* complain_on_overflow */ 75789857Sobrien bfd_elf_generic_reloc, /* special_function */ 758130561Sobrien "R_PPC64_REL30", /* name */ 759130561Sobrien FALSE, /* partial_inplace */ 76089857Sobrien 0, /* src_mask */ 76189857Sobrien 0xfffffffc, /* dst_mask */ 762130561Sobrien TRUE), /* pcrel_offset */ 76389857Sobrien 76489857Sobrien /* Relocs in the 64-bit PowerPC ELF ABI, not in the 32-bit ABI. */ 76589857Sobrien 76689857Sobrien /* A standard 64-bit relocation. */ 76789857Sobrien HOWTO (R_PPC64_ADDR64, /* type */ 76889857Sobrien 0, /* rightshift */ 76989857Sobrien 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ 77089857Sobrien 64, /* bitsize */ 771130561Sobrien FALSE, /* pc_relative */ 77289857Sobrien 0, /* bitpos */ 77389857Sobrien complain_overflow_dont, /* complain_on_overflow */ 77489857Sobrien bfd_elf_generic_reloc, /* special_function */ 77589857Sobrien "R_PPC64_ADDR64", /* name */ 776130561Sobrien FALSE, /* partial_inplace */ 77789857Sobrien 0, /* src_mask */ 778104834Sobrien ONES (64), /* dst_mask */ 779130561Sobrien FALSE), /* pcrel_offset */ 78089857Sobrien 78189857Sobrien /* The bits 32-47 of an address. */ 78289857Sobrien HOWTO (R_PPC64_ADDR16_HIGHER, /* type */ 78389857Sobrien 32, /* rightshift */ 78489857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 78589857Sobrien 16, /* bitsize */ 786130561Sobrien FALSE, /* pc_relative */ 78789857Sobrien 0, /* bitpos */ 78889857Sobrien complain_overflow_dont, /* complain_on_overflow */ 78989857Sobrien bfd_elf_generic_reloc, /* special_function */ 79089857Sobrien "R_PPC64_ADDR16_HIGHER", /* name */ 791130561Sobrien FALSE, /* partial_inplace */ 79289857Sobrien 0, /* src_mask */ 79389857Sobrien 0xffff, /* dst_mask */ 794130561Sobrien FALSE), /* pcrel_offset */ 79589857Sobrien 79689857Sobrien /* The bits 32-47 of an address, plus 1 if the contents of the low 79789857Sobrien 16 bits, treated as a signed number, is negative. */ 79889857Sobrien HOWTO (R_PPC64_ADDR16_HIGHERA, /* type */ 79989857Sobrien 32, /* rightshift */ 80089857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 80189857Sobrien 16, /* bitsize */ 802130561Sobrien FALSE, /* pc_relative */ 80389857Sobrien 0, /* bitpos */ 80489857Sobrien complain_overflow_dont, /* complain_on_overflow */ 80599461Sobrien ppc64_elf_ha_reloc, /* special_function */ 80689857Sobrien "R_PPC64_ADDR16_HIGHERA", /* name */ 807130561Sobrien FALSE, /* partial_inplace */ 80889857Sobrien 0, /* src_mask */ 80989857Sobrien 0xffff, /* dst_mask */ 810130561Sobrien FALSE), /* pcrel_offset */ 81189857Sobrien 81289857Sobrien /* The bits 48-63 of an address. */ 81389857Sobrien HOWTO (R_PPC64_ADDR16_HIGHEST,/* type */ 81489857Sobrien 48, /* rightshift */ 81589857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 81689857Sobrien 16, /* bitsize */ 817130561Sobrien FALSE, /* pc_relative */ 81889857Sobrien 0, /* bitpos */ 81989857Sobrien complain_overflow_dont, /* complain_on_overflow */ 82089857Sobrien bfd_elf_generic_reloc, /* special_function */ 82189857Sobrien "R_PPC64_ADDR16_HIGHEST", /* name */ 822130561Sobrien FALSE, /* partial_inplace */ 82389857Sobrien 0, /* src_mask */ 82489857Sobrien 0xffff, /* dst_mask */ 825130561Sobrien FALSE), /* pcrel_offset */ 82689857Sobrien 82789857Sobrien /* The bits 48-63 of an address, plus 1 if the contents of the low 82889857Sobrien 16 bits, treated as a signed number, is negative. */ 82989857Sobrien HOWTO (R_PPC64_ADDR16_HIGHESTA,/* type */ 83089857Sobrien 48, /* rightshift */ 83189857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 83289857Sobrien 16, /* bitsize */ 833130561Sobrien FALSE, /* pc_relative */ 83489857Sobrien 0, /* bitpos */ 83589857Sobrien complain_overflow_dont, /* complain_on_overflow */ 83699461Sobrien ppc64_elf_ha_reloc, /* special_function */ 83789857Sobrien "R_PPC64_ADDR16_HIGHESTA", /* name */ 838130561Sobrien FALSE, /* partial_inplace */ 83989857Sobrien 0, /* src_mask */ 84089857Sobrien 0xffff, /* dst_mask */ 841130561Sobrien FALSE), /* pcrel_offset */ 84289857Sobrien 84389857Sobrien /* Like ADDR64, but may be unaligned. */ 84489857Sobrien HOWTO (R_PPC64_UADDR64, /* type */ 84589857Sobrien 0, /* rightshift */ 84689857Sobrien 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ 84789857Sobrien 64, /* bitsize */ 848130561Sobrien FALSE, /* pc_relative */ 84989857Sobrien 0, /* bitpos */ 85089857Sobrien complain_overflow_dont, /* complain_on_overflow */ 85189857Sobrien bfd_elf_generic_reloc, /* special_function */ 85289857Sobrien "R_PPC64_UADDR64", /* name */ 853130561Sobrien FALSE, /* partial_inplace */ 85489857Sobrien 0, /* src_mask */ 855104834Sobrien ONES (64), /* dst_mask */ 856130561Sobrien FALSE), /* pcrel_offset */ 85789857Sobrien 85889857Sobrien /* 64-bit relative relocation. */ 85989857Sobrien HOWTO (R_PPC64_REL64, /* type */ 86089857Sobrien 0, /* rightshift */ 86189857Sobrien 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ 86289857Sobrien 64, /* bitsize */ 863130561Sobrien TRUE, /* pc_relative */ 86489857Sobrien 0, /* bitpos */ 86589857Sobrien complain_overflow_dont, /* complain_on_overflow */ 86689857Sobrien bfd_elf_generic_reloc, /* special_function */ 86789857Sobrien "R_PPC64_REL64", /* name */ 868130561Sobrien FALSE, /* partial_inplace */ 86989857Sobrien 0, /* src_mask */ 870104834Sobrien ONES (64), /* dst_mask */ 871130561Sobrien TRUE), /* pcrel_offset */ 87289857Sobrien 873104834Sobrien /* 64-bit relocation to the symbol's procedure linkage table. */ 87489857Sobrien HOWTO (R_PPC64_PLT64, /* type */ 87589857Sobrien 0, /* rightshift */ 87689857Sobrien 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ 87789857Sobrien 64, /* bitsize */ 878130561Sobrien FALSE, /* pc_relative */ 87989857Sobrien 0, /* bitpos */ 88089857Sobrien complain_overflow_dont, /* complain_on_overflow */ 88199461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 88289857Sobrien "R_PPC64_PLT64", /* name */ 883130561Sobrien FALSE, /* partial_inplace */ 88489857Sobrien 0, /* src_mask */ 885104834Sobrien ONES (64), /* dst_mask */ 886130561Sobrien FALSE), /* pcrel_offset */ 88789857Sobrien 88889857Sobrien /* 64-bit PC relative relocation to the symbol's procedure linkage 88989857Sobrien table. */ 89089857Sobrien /* FIXME: R_PPC64_PLTREL64 not supported. */ 89189857Sobrien HOWTO (R_PPC64_PLTREL64, /* type */ 89289857Sobrien 0, /* rightshift */ 89389857Sobrien 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ 89489857Sobrien 64, /* bitsize */ 895130561Sobrien TRUE, /* pc_relative */ 89689857Sobrien 0, /* bitpos */ 89789857Sobrien complain_overflow_dont, /* complain_on_overflow */ 89899461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 89989857Sobrien "R_PPC64_PLTREL64", /* name */ 900130561Sobrien FALSE, /* partial_inplace */ 90189857Sobrien 0, /* src_mask */ 902104834Sobrien ONES (64), /* dst_mask */ 903130561Sobrien TRUE), /* pcrel_offset */ 90489857Sobrien 90589857Sobrien /* 16 bit TOC-relative relocation. */ 90689857Sobrien 90789857Sobrien /* R_PPC64_TOC16 47 half16* S + A - .TOC. */ 90889857Sobrien HOWTO (R_PPC64_TOC16, /* type */ 90989857Sobrien 0, /* rightshift */ 91089857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 91189857Sobrien 16, /* bitsize */ 912130561Sobrien FALSE, /* pc_relative */ 91389857Sobrien 0, /* bitpos */ 91489857Sobrien complain_overflow_signed, /* complain_on_overflow */ 91599461Sobrien ppc64_elf_toc_reloc, /* special_function */ 91689857Sobrien "R_PPC64_TOC16", /* name */ 917130561Sobrien FALSE, /* partial_inplace */ 91889857Sobrien 0, /* src_mask */ 91989857Sobrien 0xffff, /* dst_mask */ 920130561Sobrien FALSE), /* pcrel_offset */ 92189857Sobrien 92289857Sobrien /* 16 bit TOC-relative relocation without overflow. */ 92389857Sobrien 92489857Sobrien /* R_PPC64_TOC16_LO 48 half16 #lo (S + A - .TOC.) */ 92589857Sobrien HOWTO (R_PPC64_TOC16_LO, /* type */ 92689857Sobrien 0, /* rightshift */ 92789857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 92889857Sobrien 16, /* bitsize */ 929130561Sobrien FALSE, /* pc_relative */ 93089857Sobrien 0, /* bitpos */ 93189857Sobrien complain_overflow_dont, /* complain_on_overflow */ 93299461Sobrien ppc64_elf_toc_reloc, /* special_function */ 93389857Sobrien "R_PPC64_TOC16_LO", /* name */ 934130561Sobrien FALSE, /* partial_inplace */ 93589857Sobrien 0, /* src_mask */ 93689857Sobrien 0xffff, /* dst_mask */ 937130561Sobrien FALSE), /* pcrel_offset */ 93889857Sobrien 93989857Sobrien /* 16 bit TOC-relative relocation, high 16 bits. */ 94089857Sobrien 94189857Sobrien /* R_PPC64_TOC16_HI 49 half16 #hi (S + A - .TOC.) */ 94289857Sobrien HOWTO (R_PPC64_TOC16_HI, /* type */ 94389857Sobrien 16, /* rightshift */ 94489857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 94589857Sobrien 16, /* bitsize */ 946130561Sobrien FALSE, /* pc_relative */ 94789857Sobrien 0, /* bitpos */ 94889857Sobrien complain_overflow_dont, /* complain_on_overflow */ 94999461Sobrien ppc64_elf_toc_reloc, /* special_function */ 95089857Sobrien "R_PPC64_TOC16_HI", /* name */ 951130561Sobrien FALSE, /* partial_inplace */ 95289857Sobrien 0, /* src_mask */ 95389857Sobrien 0xffff, /* dst_mask */ 954130561Sobrien FALSE), /* pcrel_offset */ 95589857Sobrien 95689857Sobrien /* 16 bit TOC-relative relocation, high 16 bits, plus 1 if the 95789857Sobrien contents of the low 16 bits, treated as a signed number, is 95889857Sobrien negative. */ 95989857Sobrien 96089857Sobrien /* R_PPC64_TOC16_HA 50 half16 #ha (S + A - .TOC.) */ 96189857Sobrien HOWTO (R_PPC64_TOC16_HA, /* type */ 96289857Sobrien 16, /* rightshift */ 96389857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 96489857Sobrien 16, /* bitsize */ 965130561Sobrien FALSE, /* pc_relative */ 96689857Sobrien 0, /* bitpos */ 96789857Sobrien complain_overflow_dont, /* complain_on_overflow */ 96899461Sobrien ppc64_elf_toc_ha_reloc, /* special_function */ 96989857Sobrien "R_PPC64_TOC16_HA", /* name */ 970130561Sobrien FALSE, /* partial_inplace */ 97189857Sobrien 0, /* src_mask */ 97289857Sobrien 0xffff, /* dst_mask */ 973130561Sobrien FALSE), /* pcrel_offset */ 97489857Sobrien 97589857Sobrien /* 64-bit relocation; insert value of TOC base (.TOC.). */ 97689857Sobrien 97789857Sobrien /* R_PPC64_TOC 51 doubleword64 .TOC. */ 97889857Sobrien HOWTO (R_PPC64_TOC, /* type */ 97989857Sobrien 0, /* rightshift */ 98089857Sobrien 4, /* size (0=byte, 1=short, 2=long, 4=64 bits) */ 98189857Sobrien 64, /* bitsize */ 982130561Sobrien FALSE, /* pc_relative */ 98389857Sobrien 0, /* bitpos */ 98489857Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 98599461Sobrien ppc64_elf_toc64_reloc, /* special_function */ 98689857Sobrien "R_PPC64_TOC", /* name */ 987130561Sobrien FALSE, /* partial_inplace */ 98889857Sobrien 0, /* src_mask */ 989104834Sobrien ONES (64), /* dst_mask */ 990130561Sobrien FALSE), /* pcrel_offset */ 99189857Sobrien 99289857Sobrien /* Like R_PPC64_GOT16, but also informs the link editor that the 99389857Sobrien value to relocate may (!) refer to a PLT entry which the link 99489857Sobrien editor (a) may replace with the symbol value. If the link editor 99589857Sobrien is unable to fully resolve the symbol, it may (b) create a PLT 99689857Sobrien entry and store the address to the new PLT entry in the GOT. 99789857Sobrien This permits lazy resolution of function symbols at run time. 99889857Sobrien The link editor may also skip all of this and just (c) emit a 99989857Sobrien R_PPC64_GLOB_DAT to tie the symbol to the GOT entry. */ 100089857Sobrien /* FIXME: R_PPC64_PLTGOT16 not implemented. */ 100189857Sobrien HOWTO (R_PPC64_PLTGOT16, /* type */ 100289857Sobrien 0, /* rightshift */ 100389857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 100489857Sobrien 16, /* bitsize */ 1005130561Sobrien FALSE, /* pc_relative */ 100689857Sobrien 0, /* bitpos */ 100789857Sobrien complain_overflow_signed, /* complain_on_overflow */ 100899461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 100989857Sobrien "R_PPC64_PLTGOT16", /* name */ 1010130561Sobrien FALSE, /* partial_inplace */ 101189857Sobrien 0, /* src_mask */ 101289857Sobrien 0xffff, /* dst_mask */ 1013130561Sobrien FALSE), /* pcrel_offset */ 101489857Sobrien 101589857Sobrien /* Like R_PPC64_PLTGOT16, but without overflow. */ 101689857Sobrien /* FIXME: R_PPC64_PLTGOT16_LO not implemented. */ 101789857Sobrien HOWTO (R_PPC64_PLTGOT16_LO, /* type */ 101889857Sobrien 0, /* rightshift */ 101989857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 102089857Sobrien 16, /* bitsize */ 1021130561Sobrien FALSE, /* pc_relative */ 102289857Sobrien 0, /* bitpos */ 102389857Sobrien complain_overflow_dont, /* complain_on_overflow */ 102499461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 102589857Sobrien "R_PPC64_PLTGOT16_LO", /* name */ 1026130561Sobrien FALSE, /* partial_inplace */ 102789857Sobrien 0, /* src_mask */ 102889857Sobrien 0xffff, /* dst_mask */ 1029130561Sobrien FALSE), /* pcrel_offset */ 103089857Sobrien 103189857Sobrien /* Like R_PPC64_PLT_GOT16, but using bits 16-31 of the address. */ 103289857Sobrien /* FIXME: R_PPC64_PLTGOT16_HI not implemented. */ 103389857Sobrien HOWTO (R_PPC64_PLTGOT16_HI, /* type */ 103489857Sobrien 16, /* rightshift */ 103589857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 103689857Sobrien 16, /* bitsize */ 1037130561Sobrien FALSE, /* pc_relative */ 103889857Sobrien 0, /* bitpos */ 103989857Sobrien complain_overflow_dont, /* complain_on_overflow */ 104099461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 104189857Sobrien "R_PPC64_PLTGOT16_HI", /* name */ 1042130561Sobrien FALSE, /* partial_inplace */ 104389857Sobrien 0, /* src_mask */ 104489857Sobrien 0xffff, /* dst_mask */ 1045130561Sobrien FALSE), /* pcrel_offset */ 104689857Sobrien 104789857Sobrien /* Like R_PPC64_PLT_GOT16, but using bits 16-31 of the address, plus 104889857Sobrien 1 if the contents of the low 16 bits, treated as a signed number, 104989857Sobrien is negative. */ 105089857Sobrien /* FIXME: R_PPC64_PLTGOT16_HA not implemented. */ 105189857Sobrien HOWTO (R_PPC64_PLTGOT16_HA, /* type */ 105289857Sobrien 16, /* rightshift */ 105389857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 105489857Sobrien 16, /* bitsize */ 1055130561Sobrien FALSE, /* pc_relative */ 105689857Sobrien 0, /* bitpos */ 105789857Sobrien complain_overflow_dont,/* complain_on_overflow */ 105899461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 105989857Sobrien "R_PPC64_PLTGOT16_HA", /* name */ 1060130561Sobrien FALSE, /* partial_inplace */ 106189857Sobrien 0, /* src_mask */ 106289857Sobrien 0xffff, /* dst_mask */ 1063130561Sobrien FALSE), /* pcrel_offset */ 106489857Sobrien 106589857Sobrien /* Like R_PPC64_ADDR16, but for instructions with a DS field. */ 106689857Sobrien HOWTO (R_PPC64_ADDR16_DS, /* type */ 106789857Sobrien 0, /* rightshift */ 106889857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 106989857Sobrien 16, /* bitsize */ 1070130561Sobrien FALSE, /* pc_relative */ 107189857Sobrien 0, /* bitpos */ 107289857Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 107389857Sobrien bfd_elf_generic_reloc, /* special_function */ 107489857Sobrien "R_PPC64_ADDR16_DS", /* name */ 1075130561Sobrien FALSE, /* partial_inplace */ 107689857Sobrien 0, /* src_mask */ 107789857Sobrien 0xfffc, /* dst_mask */ 1078130561Sobrien FALSE), /* pcrel_offset */ 107989857Sobrien 108089857Sobrien /* Like R_PPC64_ADDR16_LO, but for instructions with a DS field. */ 108189857Sobrien HOWTO (R_PPC64_ADDR16_LO_DS, /* type */ 108289857Sobrien 0, /* rightshift */ 108389857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 108489857Sobrien 16, /* bitsize */ 1085130561Sobrien FALSE, /* pc_relative */ 108689857Sobrien 0, /* bitpos */ 108789857Sobrien complain_overflow_dont,/* complain_on_overflow */ 108889857Sobrien bfd_elf_generic_reloc, /* special_function */ 108989857Sobrien "R_PPC64_ADDR16_LO_DS",/* name */ 1090130561Sobrien FALSE, /* partial_inplace */ 109189857Sobrien 0, /* src_mask */ 109289857Sobrien 0xfffc, /* dst_mask */ 1093130561Sobrien FALSE), /* pcrel_offset */ 109489857Sobrien 109589857Sobrien /* Like R_PPC64_GOT16, but for instructions with a DS field. */ 109689857Sobrien HOWTO (R_PPC64_GOT16_DS, /* type */ 109789857Sobrien 0, /* rightshift */ 109889857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 109989857Sobrien 16, /* bitsize */ 1100130561Sobrien FALSE, /* pc_relative */ 110189857Sobrien 0, /* bitpos */ 110289857Sobrien complain_overflow_signed, /* complain_on_overflow */ 110399461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 110489857Sobrien "R_PPC64_GOT16_DS", /* name */ 1105130561Sobrien FALSE, /* partial_inplace */ 110689857Sobrien 0, /* src_mask */ 110789857Sobrien 0xfffc, /* dst_mask */ 1108130561Sobrien FALSE), /* pcrel_offset */ 110989857Sobrien 111089857Sobrien /* Like R_PPC64_GOT16_LO, but for instructions with a DS field. */ 111189857Sobrien HOWTO (R_PPC64_GOT16_LO_DS, /* type */ 111289857Sobrien 0, /* rightshift */ 111389857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 111489857Sobrien 16, /* bitsize */ 1115130561Sobrien FALSE, /* pc_relative */ 111689857Sobrien 0, /* bitpos */ 111789857Sobrien complain_overflow_dont, /* complain_on_overflow */ 111899461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 111989857Sobrien "R_PPC64_GOT16_LO_DS", /* name */ 1120130561Sobrien FALSE, /* partial_inplace */ 112189857Sobrien 0, /* src_mask */ 112289857Sobrien 0xfffc, /* dst_mask */ 1123130561Sobrien FALSE), /* pcrel_offset */ 112489857Sobrien 112589857Sobrien /* Like R_PPC64_PLT16_LO, but for instructions with a DS field. */ 112689857Sobrien HOWTO (R_PPC64_PLT16_LO_DS, /* type */ 112789857Sobrien 0, /* rightshift */ 112889857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 112989857Sobrien 16, /* bitsize */ 1130130561Sobrien FALSE, /* pc_relative */ 113189857Sobrien 0, /* bitpos */ 113289857Sobrien complain_overflow_dont, /* complain_on_overflow */ 113399461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 113489857Sobrien "R_PPC64_PLT16_LO_DS", /* name */ 1135130561Sobrien FALSE, /* partial_inplace */ 113689857Sobrien 0, /* src_mask */ 113789857Sobrien 0xfffc, /* dst_mask */ 1138130561Sobrien FALSE), /* pcrel_offset */ 113989857Sobrien 114089857Sobrien /* Like R_PPC64_SECTOFF, but for instructions with a DS field. */ 114189857Sobrien HOWTO (R_PPC64_SECTOFF_DS, /* type */ 114289857Sobrien 0, /* rightshift */ 114399461Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 114499461Sobrien 16, /* bitsize */ 1145130561Sobrien FALSE, /* pc_relative */ 114689857Sobrien 0, /* bitpos */ 114789857Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 114899461Sobrien ppc64_elf_sectoff_reloc, /* special_function */ 114989857Sobrien "R_PPC64_SECTOFF_DS", /* name */ 1150130561Sobrien FALSE, /* partial_inplace */ 115189857Sobrien 0, /* src_mask */ 115299461Sobrien 0xfffc, /* dst_mask */ 1153130561Sobrien FALSE), /* pcrel_offset */ 115489857Sobrien 115589857Sobrien /* Like R_PPC64_SECTOFF_LO, but for instructions with a DS field. */ 115689857Sobrien HOWTO (R_PPC64_SECTOFF_LO_DS, /* type */ 115789857Sobrien 0, /* rightshift */ 115889857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 115989857Sobrien 16, /* bitsize */ 1160130561Sobrien FALSE, /* pc_relative */ 116189857Sobrien 0, /* bitpos */ 116289857Sobrien complain_overflow_dont, /* complain_on_overflow */ 116399461Sobrien ppc64_elf_sectoff_reloc, /* special_function */ 116489857Sobrien "R_PPC64_SECTOFF_LO_DS",/* name */ 1165130561Sobrien FALSE, /* partial_inplace */ 116689857Sobrien 0, /* src_mask */ 116789857Sobrien 0xfffc, /* dst_mask */ 1168130561Sobrien FALSE), /* pcrel_offset */ 116989857Sobrien 117089857Sobrien /* Like R_PPC64_TOC16, but for instructions with a DS field. */ 117189857Sobrien HOWTO (R_PPC64_TOC16_DS, /* type */ 117289857Sobrien 0, /* rightshift */ 117389857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 117489857Sobrien 16, /* bitsize */ 1175130561Sobrien FALSE, /* pc_relative */ 117689857Sobrien 0, /* bitpos */ 117789857Sobrien complain_overflow_signed, /* complain_on_overflow */ 117899461Sobrien ppc64_elf_toc_reloc, /* special_function */ 117989857Sobrien "R_PPC64_TOC16_DS", /* name */ 1180130561Sobrien FALSE, /* partial_inplace */ 118189857Sobrien 0, /* src_mask */ 118289857Sobrien 0xfffc, /* dst_mask */ 1183130561Sobrien FALSE), /* pcrel_offset */ 118489857Sobrien 118589857Sobrien /* Like R_PPC64_TOC16_LO, but for instructions with a DS field. */ 118689857Sobrien HOWTO (R_PPC64_TOC16_LO_DS, /* type */ 118789857Sobrien 0, /* rightshift */ 118889857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 118989857Sobrien 16, /* bitsize */ 1190130561Sobrien FALSE, /* pc_relative */ 119189857Sobrien 0, /* bitpos */ 119289857Sobrien complain_overflow_dont, /* complain_on_overflow */ 119399461Sobrien ppc64_elf_toc_reloc, /* special_function */ 119489857Sobrien "R_PPC64_TOC16_LO_DS", /* name */ 1195130561Sobrien FALSE, /* partial_inplace */ 119689857Sobrien 0, /* src_mask */ 119789857Sobrien 0xfffc, /* dst_mask */ 1198130561Sobrien FALSE), /* pcrel_offset */ 119989857Sobrien 120089857Sobrien /* Like R_PPC64_PLTGOT16, but for instructions with a DS field. */ 120189857Sobrien /* FIXME: R_PPC64_PLTGOT16_DS not implemented. */ 1202218822Sdim HOWTO (R_PPC64_PLTGOT16_DS, /* type */ 120389857Sobrien 0, /* rightshift */ 120489857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 120589857Sobrien 16, /* bitsize */ 1206130561Sobrien FALSE, /* pc_relative */ 120789857Sobrien 0, /* bitpos */ 120889857Sobrien complain_overflow_signed, /* complain_on_overflow */ 120999461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 121089857Sobrien "R_PPC64_PLTGOT16_DS", /* name */ 1211130561Sobrien FALSE, /* partial_inplace */ 121289857Sobrien 0, /* src_mask */ 121389857Sobrien 0xfffc, /* dst_mask */ 1214130561Sobrien FALSE), /* pcrel_offset */ 121589857Sobrien 121689857Sobrien /* Like R_PPC64_PLTGOT16_LO, but for instructions with a DS field. */ 121789857Sobrien /* FIXME: R_PPC64_PLTGOT16_LO not implemented. */ 121889857Sobrien HOWTO (R_PPC64_PLTGOT16_LO_DS,/* type */ 121989857Sobrien 0, /* rightshift */ 122089857Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 122189857Sobrien 16, /* bitsize */ 1222130561Sobrien FALSE, /* pc_relative */ 122389857Sobrien 0, /* bitpos */ 122489857Sobrien complain_overflow_dont, /* complain_on_overflow */ 122599461Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 122689857Sobrien "R_PPC64_PLTGOT16_LO_DS",/* name */ 1227130561Sobrien FALSE, /* partial_inplace */ 122889857Sobrien 0, /* src_mask */ 122989857Sobrien 0xfffc, /* dst_mask */ 1230130561Sobrien FALSE), /* pcrel_offset */ 123189857Sobrien 1232130561Sobrien /* Marker reloc for TLS. */ 1233130561Sobrien HOWTO (R_PPC64_TLS, 1234130561Sobrien 0, /* rightshift */ 1235130561Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 1236130561Sobrien 32, /* bitsize */ 1237130561Sobrien FALSE, /* pc_relative */ 1238130561Sobrien 0, /* bitpos */ 1239130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1240130561Sobrien bfd_elf_generic_reloc, /* special_function */ 1241130561Sobrien "R_PPC64_TLS", /* name */ 1242130561Sobrien FALSE, /* partial_inplace */ 1243130561Sobrien 0, /* src_mask */ 1244130561Sobrien 0, /* dst_mask */ 1245130561Sobrien FALSE), /* pcrel_offset */ 1246130561Sobrien 1247130561Sobrien /* Computes the load module index of the load module that contains the 1248130561Sobrien definition of its TLS sym. */ 1249130561Sobrien HOWTO (R_PPC64_DTPMOD64, 1250130561Sobrien 0, /* rightshift */ 1251130561Sobrien 4, /* size (0 = byte, 1 = short, 2 = long) */ 1252130561Sobrien 64, /* bitsize */ 1253130561Sobrien FALSE, /* pc_relative */ 1254130561Sobrien 0, /* bitpos */ 1255130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1256130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1257130561Sobrien "R_PPC64_DTPMOD64", /* name */ 1258130561Sobrien FALSE, /* partial_inplace */ 1259130561Sobrien 0, /* src_mask */ 1260130561Sobrien ONES (64), /* dst_mask */ 1261130561Sobrien FALSE), /* pcrel_offset */ 1262130561Sobrien 1263130561Sobrien /* Computes a dtv-relative displacement, the difference between the value 1264130561Sobrien of sym+add and the base address of the thread-local storage block that 1265130561Sobrien contains the definition of sym, minus 0x8000. */ 1266130561Sobrien HOWTO (R_PPC64_DTPREL64, 1267130561Sobrien 0, /* rightshift */ 1268130561Sobrien 4, /* size (0 = byte, 1 = short, 2 = long) */ 1269130561Sobrien 64, /* bitsize */ 1270130561Sobrien FALSE, /* pc_relative */ 1271130561Sobrien 0, /* bitpos */ 1272130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1273130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1274130561Sobrien "R_PPC64_DTPREL64", /* name */ 1275130561Sobrien FALSE, /* partial_inplace */ 1276130561Sobrien 0, /* src_mask */ 1277130561Sobrien ONES (64), /* dst_mask */ 1278130561Sobrien FALSE), /* pcrel_offset */ 1279130561Sobrien 1280130561Sobrien /* A 16 bit dtprel reloc. */ 1281130561Sobrien HOWTO (R_PPC64_DTPREL16, 1282130561Sobrien 0, /* rightshift */ 1283130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1284130561Sobrien 16, /* bitsize */ 1285130561Sobrien FALSE, /* pc_relative */ 1286130561Sobrien 0, /* bitpos */ 1287130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 1288130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1289130561Sobrien "R_PPC64_DTPREL16", /* name */ 1290130561Sobrien FALSE, /* partial_inplace */ 1291130561Sobrien 0, /* src_mask */ 1292130561Sobrien 0xffff, /* dst_mask */ 1293130561Sobrien FALSE), /* pcrel_offset */ 1294130561Sobrien 1295130561Sobrien /* Like DTPREL16, but no overflow. */ 1296130561Sobrien HOWTO (R_PPC64_DTPREL16_LO, 1297130561Sobrien 0, /* rightshift */ 1298130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1299130561Sobrien 16, /* bitsize */ 1300130561Sobrien FALSE, /* pc_relative */ 1301130561Sobrien 0, /* bitpos */ 1302130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1303130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1304130561Sobrien "R_PPC64_DTPREL16_LO", /* name */ 1305130561Sobrien FALSE, /* partial_inplace */ 1306130561Sobrien 0, /* src_mask */ 1307130561Sobrien 0xffff, /* dst_mask */ 1308130561Sobrien FALSE), /* pcrel_offset */ 1309130561Sobrien 1310130561Sobrien /* Like DTPREL16_LO, but next higher group of 16 bits. */ 1311130561Sobrien HOWTO (R_PPC64_DTPREL16_HI, 1312130561Sobrien 16, /* rightshift */ 1313130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1314130561Sobrien 16, /* bitsize */ 1315130561Sobrien FALSE, /* pc_relative */ 1316130561Sobrien 0, /* bitpos */ 1317130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1318130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1319130561Sobrien "R_PPC64_DTPREL16_HI", /* name */ 1320130561Sobrien FALSE, /* partial_inplace */ 1321130561Sobrien 0, /* src_mask */ 1322130561Sobrien 0xffff, /* dst_mask */ 1323130561Sobrien FALSE), /* pcrel_offset */ 1324130561Sobrien 1325130561Sobrien /* Like DTPREL16_HI, but adjust for low 16 bits. */ 1326130561Sobrien HOWTO (R_PPC64_DTPREL16_HA, 1327130561Sobrien 16, /* rightshift */ 1328130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1329130561Sobrien 16, /* bitsize */ 1330130561Sobrien FALSE, /* pc_relative */ 1331130561Sobrien 0, /* bitpos */ 1332130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1333130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1334130561Sobrien "R_PPC64_DTPREL16_HA", /* name */ 1335130561Sobrien FALSE, /* partial_inplace */ 1336130561Sobrien 0, /* src_mask */ 1337130561Sobrien 0xffff, /* dst_mask */ 1338130561Sobrien FALSE), /* pcrel_offset */ 1339130561Sobrien 1340130561Sobrien /* Like DTPREL16_HI, but next higher group of 16 bits. */ 1341130561Sobrien HOWTO (R_PPC64_DTPREL16_HIGHER, 1342130561Sobrien 32, /* rightshift */ 1343130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1344130561Sobrien 16, /* bitsize */ 1345130561Sobrien FALSE, /* pc_relative */ 1346130561Sobrien 0, /* bitpos */ 1347130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1348130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1349130561Sobrien "R_PPC64_DTPREL16_HIGHER", /* name */ 1350130561Sobrien FALSE, /* partial_inplace */ 1351130561Sobrien 0, /* src_mask */ 1352130561Sobrien 0xffff, /* dst_mask */ 1353130561Sobrien FALSE), /* pcrel_offset */ 1354130561Sobrien 1355130561Sobrien /* Like DTPREL16_HIGHER, but adjust for low 16 bits. */ 1356130561Sobrien HOWTO (R_PPC64_DTPREL16_HIGHERA, 1357130561Sobrien 32, /* rightshift */ 1358130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1359130561Sobrien 16, /* bitsize */ 1360130561Sobrien FALSE, /* pc_relative */ 1361130561Sobrien 0, /* bitpos */ 1362130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1363130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1364130561Sobrien "R_PPC64_DTPREL16_HIGHERA", /* name */ 1365130561Sobrien FALSE, /* partial_inplace */ 1366130561Sobrien 0, /* src_mask */ 1367130561Sobrien 0xffff, /* dst_mask */ 1368130561Sobrien FALSE), /* pcrel_offset */ 1369130561Sobrien 1370130561Sobrien /* Like DTPREL16_HIGHER, but next higher group of 16 bits. */ 1371130561Sobrien HOWTO (R_PPC64_DTPREL16_HIGHEST, 1372130561Sobrien 48, /* rightshift */ 1373130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1374130561Sobrien 16, /* bitsize */ 1375130561Sobrien FALSE, /* pc_relative */ 1376130561Sobrien 0, /* bitpos */ 1377130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1378130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1379130561Sobrien "R_PPC64_DTPREL16_HIGHEST", /* name */ 1380130561Sobrien FALSE, /* partial_inplace */ 1381130561Sobrien 0, /* src_mask */ 1382130561Sobrien 0xffff, /* dst_mask */ 1383130561Sobrien FALSE), /* pcrel_offset */ 1384130561Sobrien 1385130561Sobrien /* Like DTPREL16_HIGHEST, but adjust for low 16 bits. */ 1386130561Sobrien HOWTO (R_PPC64_DTPREL16_HIGHESTA, 1387130561Sobrien 48, /* rightshift */ 1388130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1389130561Sobrien 16, /* bitsize */ 1390130561Sobrien FALSE, /* pc_relative */ 1391130561Sobrien 0, /* bitpos */ 1392130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1393130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1394130561Sobrien "R_PPC64_DTPREL16_HIGHESTA", /* name */ 1395130561Sobrien FALSE, /* partial_inplace */ 1396130561Sobrien 0, /* src_mask */ 1397130561Sobrien 0xffff, /* dst_mask */ 1398130561Sobrien FALSE), /* pcrel_offset */ 1399130561Sobrien 1400130561Sobrien /* Like DTPREL16, but for insns with a DS field. */ 1401130561Sobrien HOWTO (R_PPC64_DTPREL16_DS, 1402130561Sobrien 0, /* rightshift */ 1403130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1404130561Sobrien 16, /* bitsize */ 1405130561Sobrien FALSE, /* pc_relative */ 1406130561Sobrien 0, /* bitpos */ 1407130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 1408130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1409130561Sobrien "R_PPC64_DTPREL16_DS", /* name */ 1410130561Sobrien FALSE, /* partial_inplace */ 1411130561Sobrien 0, /* src_mask */ 1412130561Sobrien 0xfffc, /* dst_mask */ 1413130561Sobrien FALSE), /* pcrel_offset */ 1414130561Sobrien 1415130561Sobrien /* Like DTPREL16_DS, but no overflow. */ 1416130561Sobrien HOWTO (R_PPC64_DTPREL16_LO_DS, 1417130561Sobrien 0, /* rightshift */ 1418130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1419130561Sobrien 16, /* bitsize */ 1420130561Sobrien FALSE, /* pc_relative */ 1421130561Sobrien 0, /* bitpos */ 1422130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1423130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1424130561Sobrien "R_PPC64_DTPREL16_LO_DS", /* name */ 1425130561Sobrien FALSE, /* partial_inplace */ 1426130561Sobrien 0, /* src_mask */ 1427130561Sobrien 0xfffc, /* dst_mask */ 1428130561Sobrien FALSE), /* pcrel_offset */ 1429130561Sobrien 1430130561Sobrien /* Computes a tp-relative displacement, the difference between the value of 1431130561Sobrien sym+add and the value of the thread pointer (r13). */ 1432130561Sobrien HOWTO (R_PPC64_TPREL64, 1433130561Sobrien 0, /* rightshift */ 1434130561Sobrien 4, /* size (0 = byte, 1 = short, 2 = long) */ 1435130561Sobrien 64, /* bitsize */ 1436130561Sobrien FALSE, /* pc_relative */ 1437130561Sobrien 0, /* bitpos */ 1438130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1439130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1440130561Sobrien "R_PPC64_TPREL64", /* name */ 1441130561Sobrien FALSE, /* partial_inplace */ 1442130561Sobrien 0, /* src_mask */ 1443130561Sobrien ONES (64), /* dst_mask */ 1444130561Sobrien FALSE), /* pcrel_offset */ 1445130561Sobrien 1446130561Sobrien /* A 16 bit tprel reloc. */ 1447130561Sobrien HOWTO (R_PPC64_TPREL16, 1448130561Sobrien 0, /* rightshift */ 1449130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1450130561Sobrien 16, /* bitsize */ 1451130561Sobrien FALSE, /* pc_relative */ 1452130561Sobrien 0, /* bitpos */ 1453130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 1454130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1455130561Sobrien "R_PPC64_TPREL16", /* name */ 1456130561Sobrien FALSE, /* partial_inplace */ 1457130561Sobrien 0, /* src_mask */ 1458130561Sobrien 0xffff, /* dst_mask */ 1459130561Sobrien FALSE), /* pcrel_offset */ 1460130561Sobrien 1461130561Sobrien /* Like TPREL16, but no overflow. */ 1462130561Sobrien HOWTO (R_PPC64_TPREL16_LO, 1463130561Sobrien 0, /* rightshift */ 1464130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1465130561Sobrien 16, /* bitsize */ 1466130561Sobrien FALSE, /* pc_relative */ 1467130561Sobrien 0, /* bitpos */ 1468130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1469130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1470130561Sobrien "R_PPC64_TPREL16_LO", /* name */ 1471130561Sobrien FALSE, /* partial_inplace */ 1472130561Sobrien 0, /* src_mask */ 1473130561Sobrien 0xffff, /* dst_mask */ 1474130561Sobrien FALSE), /* pcrel_offset */ 1475130561Sobrien 1476130561Sobrien /* Like TPREL16_LO, but next higher group of 16 bits. */ 1477130561Sobrien HOWTO (R_PPC64_TPREL16_HI, 1478130561Sobrien 16, /* rightshift */ 1479130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1480130561Sobrien 16, /* bitsize */ 1481130561Sobrien FALSE, /* pc_relative */ 1482130561Sobrien 0, /* bitpos */ 1483130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1484130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1485130561Sobrien "R_PPC64_TPREL16_HI", /* name */ 1486130561Sobrien FALSE, /* partial_inplace */ 1487130561Sobrien 0, /* src_mask */ 1488130561Sobrien 0xffff, /* dst_mask */ 1489130561Sobrien FALSE), /* pcrel_offset */ 1490130561Sobrien 1491130561Sobrien /* Like TPREL16_HI, but adjust for low 16 bits. */ 1492130561Sobrien HOWTO (R_PPC64_TPREL16_HA, 1493130561Sobrien 16, /* rightshift */ 1494130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1495130561Sobrien 16, /* bitsize */ 1496130561Sobrien FALSE, /* pc_relative */ 1497130561Sobrien 0, /* bitpos */ 1498130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1499130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1500130561Sobrien "R_PPC64_TPREL16_HA", /* name */ 1501130561Sobrien FALSE, /* partial_inplace */ 1502130561Sobrien 0, /* src_mask */ 1503130561Sobrien 0xffff, /* dst_mask */ 1504130561Sobrien FALSE), /* pcrel_offset */ 1505130561Sobrien 1506130561Sobrien /* Like TPREL16_HI, but next higher group of 16 bits. */ 1507130561Sobrien HOWTO (R_PPC64_TPREL16_HIGHER, 1508130561Sobrien 32, /* rightshift */ 1509130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1510130561Sobrien 16, /* bitsize */ 1511130561Sobrien FALSE, /* pc_relative */ 1512130561Sobrien 0, /* bitpos */ 1513130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1514130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1515130561Sobrien "R_PPC64_TPREL16_HIGHER", /* name */ 1516130561Sobrien FALSE, /* partial_inplace */ 1517130561Sobrien 0, /* src_mask */ 1518130561Sobrien 0xffff, /* dst_mask */ 1519130561Sobrien FALSE), /* pcrel_offset */ 1520130561Sobrien 1521130561Sobrien /* Like TPREL16_HIGHER, but adjust for low 16 bits. */ 1522130561Sobrien HOWTO (R_PPC64_TPREL16_HIGHERA, 1523130561Sobrien 32, /* rightshift */ 1524130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1525130561Sobrien 16, /* bitsize */ 1526130561Sobrien FALSE, /* pc_relative */ 1527130561Sobrien 0, /* bitpos */ 1528130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1529130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1530130561Sobrien "R_PPC64_TPREL16_HIGHERA", /* name */ 1531130561Sobrien FALSE, /* partial_inplace */ 1532130561Sobrien 0, /* src_mask */ 1533130561Sobrien 0xffff, /* dst_mask */ 1534130561Sobrien FALSE), /* pcrel_offset */ 1535130561Sobrien 1536130561Sobrien /* Like TPREL16_HIGHER, but next higher group of 16 bits. */ 1537130561Sobrien HOWTO (R_PPC64_TPREL16_HIGHEST, 1538130561Sobrien 48, /* rightshift */ 1539130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1540130561Sobrien 16, /* bitsize */ 1541130561Sobrien FALSE, /* pc_relative */ 1542130561Sobrien 0, /* bitpos */ 1543130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1544130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1545130561Sobrien "R_PPC64_TPREL16_HIGHEST", /* name */ 1546130561Sobrien FALSE, /* partial_inplace */ 1547130561Sobrien 0, /* src_mask */ 1548130561Sobrien 0xffff, /* dst_mask */ 1549130561Sobrien FALSE), /* pcrel_offset */ 1550130561Sobrien 1551130561Sobrien /* Like TPREL16_HIGHEST, but adjust for low 16 bits. */ 1552130561Sobrien HOWTO (R_PPC64_TPREL16_HIGHESTA, 1553130561Sobrien 48, /* rightshift */ 1554130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1555130561Sobrien 16, /* bitsize */ 1556130561Sobrien FALSE, /* pc_relative */ 1557130561Sobrien 0, /* bitpos */ 1558130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1559130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1560130561Sobrien "R_PPC64_TPREL16_HIGHESTA", /* name */ 1561130561Sobrien FALSE, /* partial_inplace */ 1562130561Sobrien 0, /* src_mask */ 1563130561Sobrien 0xffff, /* dst_mask */ 1564130561Sobrien FALSE), /* pcrel_offset */ 1565130561Sobrien 1566130561Sobrien /* Like TPREL16, but for insns with a DS field. */ 1567130561Sobrien HOWTO (R_PPC64_TPREL16_DS, 1568130561Sobrien 0, /* rightshift */ 1569130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1570130561Sobrien 16, /* bitsize */ 1571130561Sobrien FALSE, /* pc_relative */ 1572130561Sobrien 0, /* bitpos */ 1573130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 1574130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1575130561Sobrien "R_PPC64_TPREL16_DS", /* name */ 1576130561Sobrien FALSE, /* partial_inplace */ 1577130561Sobrien 0, /* src_mask */ 1578130561Sobrien 0xfffc, /* dst_mask */ 1579130561Sobrien FALSE), /* pcrel_offset */ 1580130561Sobrien 1581130561Sobrien /* Like TPREL16_DS, but no overflow. */ 1582130561Sobrien HOWTO (R_PPC64_TPREL16_LO_DS, 1583130561Sobrien 0, /* rightshift */ 1584130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1585130561Sobrien 16, /* bitsize */ 1586130561Sobrien FALSE, /* pc_relative */ 1587130561Sobrien 0, /* bitpos */ 1588130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1589130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1590130561Sobrien "R_PPC64_TPREL16_LO_DS", /* name */ 1591130561Sobrien FALSE, /* partial_inplace */ 1592130561Sobrien 0, /* src_mask */ 1593130561Sobrien 0xfffc, /* dst_mask */ 1594130561Sobrien FALSE), /* pcrel_offset */ 1595130561Sobrien 1596130561Sobrien /* Allocates two contiguous entries in the GOT to hold a tls_index structure, 1597130561Sobrien with values (sym+add)@dtpmod and (sym+add)@dtprel, and computes the offset 1598130561Sobrien to the first entry relative to the TOC base (r2). */ 1599130561Sobrien HOWTO (R_PPC64_GOT_TLSGD16, 1600130561Sobrien 0, /* rightshift */ 1601130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1602130561Sobrien 16, /* bitsize */ 1603130561Sobrien FALSE, /* pc_relative */ 1604130561Sobrien 0, /* bitpos */ 1605130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 1606130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1607130561Sobrien "R_PPC64_GOT_TLSGD16", /* name */ 1608130561Sobrien FALSE, /* partial_inplace */ 1609130561Sobrien 0, /* src_mask */ 1610130561Sobrien 0xffff, /* dst_mask */ 1611130561Sobrien FALSE), /* pcrel_offset */ 1612130561Sobrien 1613130561Sobrien /* Like GOT_TLSGD16, but no overflow. */ 1614130561Sobrien HOWTO (R_PPC64_GOT_TLSGD16_LO, 1615130561Sobrien 0, /* rightshift */ 1616130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1617130561Sobrien 16, /* bitsize */ 1618130561Sobrien FALSE, /* pc_relative */ 1619130561Sobrien 0, /* bitpos */ 1620130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1621130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1622130561Sobrien "R_PPC64_GOT_TLSGD16_LO", /* name */ 1623130561Sobrien FALSE, /* partial_inplace */ 1624130561Sobrien 0, /* src_mask */ 1625130561Sobrien 0xffff, /* dst_mask */ 1626130561Sobrien FALSE), /* pcrel_offset */ 1627130561Sobrien 1628130561Sobrien /* Like GOT_TLSGD16_LO, but next higher group of 16 bits. */ 1629130561Sobrien HOWTO (R_PPC64_GOT_TLSGD16_HI, 1630130561Sobrien 16, /* rightshift */ 1631130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1632130561Sobrien 16, /* bitsize */ 1633130561Sobrien FALSE, /* pc_relative */ 1634130561Sobrien 0, /* bitpos */ 1635130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1636130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1637130561Sobrien "R_PPC64_GOT_TLSGD16_HI", /* name */ 1638130561Sobrien FALSE, /* partial_inplace */ 1639130561Sobrien 0, /* src_mask */ 1640130561Sobrien 0xffff, /* dst_mask */ 1641130561Sobrien FALSE), /* pcrel_offset */ 1642130561Sobrien 1643130561Sobrien /* Like GOT_TLSGD16_HI, but adjust for low 16 bits. */ 1644130561Sobrien HOWTO (R_PPC64_GOT_TLSGD16_HA, 1645130561Sobrien 16, /* rightshift */ 1646130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1647130561Sobrien 16, /* bitsize */ 1648130561Sobrien FALSE, /* pc_relative */ 1649130561Sobrien 0, /* bitpos */ 1650130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1651130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1652130561Sobrien "R_PPC64_GOT_TLSGD16_HA", /* name */ 1653130561Sobrien FALSE, /* partial_inplace */ 1654130561Sobrien 0, /* src_mask */ 1655130561Sobrien 0xffff, /* dst_mask */ 1656130561Sobrien FALSE), /* pcrel_offset */ 1657130561Sobrien 1658130561Sobrien /* Allocates two contiguous entries in the GOT to hold a tls_index structure, 1659130561Sobrien with values (sym+add)@dtpmod and zero, and computes the offset to the 1660130561Sobrien first entry relative to the TOC base (r2). */ 1661130561Sobrien HOWTO (R_PPC64_GOT_TLSLD16, 1662130561Sobrien 0, /* rightshift */ 1663130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1664130561Sobrien 16, /* bitsize */ 1665130561Sobrien FALSE, /* pc_relative */ 1666130561Sobrien 0, /* bitpos */ 1667130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 1668130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1669130561Sobrien "R_PPC64_GOT_TLSLD16", /* name */ 1670130561Sobrien FALSE, /* partial_inplace */ 1671130561Sobrien 0, /* src_mask */ 1672130561Sobrien 0xffff, /* dst_mask */ 1673130561Sobrien FALSE), /* pcrel_offset */ 1674130561Sobrien 1675130561Sobrien /* Like GOT_TLSLD16, but no overflow. */ 1676130561Sobrien HOWTO (R_PPC64_GOT_TLSLD16_LO, 1677130561Sobrien 0, /* rightshift */ 1678130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1679130561Sobrien 16, /* bitsize */ 1680130561Sobrien FALSE, /* pc_relative */ 1681130561Sobrien 0, /* bitpos */ 1682130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1683130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1684130561Sobrien "R_PPC64_GOT_TLSLD16_LO", /* name */ 1685130561Sobrien FALSE, /* partial_inplace */ 1686130561Sobrien 0, /* src_mask */ 1687130561Sobrien 0xffff, /* dst_mask */ 1688130561Sobrien FALSE), /* pcrel_offset */ 1689130561Sobrien 1690130561Sobrien /* Like GOT_TLSLD16_LO, but next higher group of 16 bits. */ 1691130561Sobrien HOWTO (R_PPC64_GOT_TLSLD16_HI, 1692130561Sobrien 16, /* rightshift */ 1693130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1694130561Sobrien 16, /* bitsize */ 1695130561Sobrien FALSE, /* pc_relative */ 1696130561Sobrien 0, /* bitpos */ 1697130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1698130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1699130561Sobrien "R_PPC64_GOT_TLSLD16_HI", /* name */ 1700130561Sobrien FALSE, /* partial_inplace */ 1701130561Sobrien 0, /* src_mask */ 1702130561Sobrien 0xffff, /* dst_mask */ 1703130561Sobrien FALSE), /* pcrel_offset */ 1704130561Sobrien 1705130561Sobrien /* Like GOT_TLSLD16_HI, but adjust for low 16 bits. */ 1706130561Sobrien HOWTO (R_PPC64_GOT_TLSLD16_HA, 1707130561Sobrien 16, /* rightshift */ 1708130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1709130561Sobrien 16, /* bitsize */ 1710130561Sobrien FALSE, /* pc_relative */ 1711130561Sobrien 0, /* bitpos */ 1712130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1713130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1714130561Sobrien "R_PPC64_GOT_TLSLD16_HA", /* name */ 1715130561Sobrien FALSE, /* partial_inplace */ 1716130561Sobrien 0, /* src_mask */ 1717130561Sobrien 0xffff, /* dst_mask */ 1718130561Sobrien FALSE), /* pcrel_offset */ 1719130561Sobrien 1720130561Sobrien /* Allocates an entry in the GOT with value (sym+add)@dtprel, and computes 1721130561Sobrien the offset to the entry relative to the TOC base (r2). */ 1722130561Sobrien HOWTO (R_PPC64_GOT_DTPREL16_DS, 1723130561Sobrien 0, /* rightshift */ 1724130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1725130561Sobrien 16, /* bitsize */ 1726130561Sobrien FALSE, /* pc_relative */ 1727130561Sobrien 0, /* bitpos */ 1728130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 1729130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1730130561Sobrien "R_PPC64_GOT_DTPREL16_DS", /* name */ 1731130561Sobrien FALSE, /* partial_inplace */ 1732130561Sobrien 0, /* src_mask */ 1733130561Sobrien 0xfffc, /* dst_mask */ 1734130561Sobrien FALSE), /* pcrel_offset */ 1735130561Sobrien 1736130561Sobrien /* Like GOT_DTPREL16_DS, but no overflow. */ 1737130561Sobrien HOWTO (R_PPC64_GOT_DTPREL16_LO_DS, 1738130561Sobrien 0, /* rightshift */ 1739130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1740130561Sobrien 16, /* bitsize */ 1741130561Sobrien FALSE, /* pc_relative */ 1742130561Sobrien 0, /* bitpos */ 1743130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1744130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1745130561Sobrien "R_PPC64_GOT_DTPREL16_LO_DS", /* name */ 1746130561Sobrien FALSE, /* partial_inplace */ 1747130561Sobrien 0, /* src_mask */ 1748130561Sobrien 0xfffc, /* dst_mask */ 1749130561Sobrien FALSE), /* pcrel_offset */ 1750130561Sobrien 1751130561Sobrien /* Like GOT_DTPREL16_LO_DS, but next higher group of 16 bits. */ 1752130561Sobrien HOWTO (R_PPC64_GOT_DTPREL16_HI, 1753130561Sobrien 16, /* rightshift */ 1754130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1755130561Sobrien 16, /* bitsize */ 1756130561Sobrien FALSE, /* pc_relative */ 1757130561Sobrien 0, /* bitpos */ 1758130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1759130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1760130561Sobrien "R_PPC64_GOT_DTPREL16_HI", /* name */ 1761130561Sobrien FALSE, /* partial_inplace */ 1762130561Sobrien 0, /* src_mask */ 1763130561Sobrien 0xffff, /* dst_mask */ 1764130561Sobrien FALSE), /* pcrel_offset */ 1765130561Sobrien 1766130561Sobrien /* Like GOT_DTPREL16_HI, but adjust for low 16 bits. */ 1767130561Sobrien HOWTO (R_PPC64_GOT_DTPREL16_HA, 1768130561Sobrien 16, /* rightshift */ 1769130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1770130561Sobrien 16, /* bitsize */ 1771130561Sobrien FALSE, /* pc_relative */ 1772130561Sobrien 0, /* bitpos */ 1773130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1774130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1775130561Sobrien "R_PPC64_GOT_DTPREL16_HA", /* name */ 1776130561Sobrien FALSE, /* partial_inplace */ 1777130561Sobrien 0, /* src_mask */ 1778130561Sobrien 0xffff, /* dst_mask */ 1779130561Sobrien FALSE), /* pcrel_offset */ 1780130561Sobrien 1781130561Sobrien /* Allocates an entry in the GOT with value (sym+add)@tprel, and computes the 1782130561Sobrien offset to the entry relative to the TOC base (r2). */ 1783130561Sobrien HOWTO (R_PPC64_GOT_TPREL16_DS, 1784130561Sobrien 0, /* rightshift */ 1785130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1786130561Sobrien 16, /* bitsize */ 1787130561Sobrien FALSE, /* pc_relative */ 1788130561Sobrien 0, /* bitpos */ 1789130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 1790130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1791130561Sobrien "R_PPC64_GOT_TPREL16_DS", /* name */ 1792130561Sobrien FALSE, /* partial_inplace */ 1793130561Sobrien 0, /* src_mask */ 1794130561Sobrien 0xfffc, /* dst_mask */ 1795130561Sobrien FALSE), /* pcrel_offset */ 1796130561Sobrien 1797130561Sobrien /* Like GOT_TPREL16_DS, but no overflow. */ 1798130561Sobrien HOWTO (R_PPC64_GOT_TPREL16_LO_DS, 1799130561Sobrien 0, /* rightshift */ 1800130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1801130561Sobrien 16, /* bitsize */ 1802130561Sobrien FALSE, /* pc_relative */ 1803130561Sobrien 0, /* bitpos */ 1804130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1805130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1806130561Sobrien "R_PPC64_GOT_TPREL16_LO_DS", /* name */ 1807130561Sobrien FALSE, /* partial_inplace */ 1808130561Sobrien 0, /* src_mask */ 1809130561Sobrien 0xfffc, /* dst_mask */ 1810130561Sobrien FALSE), /* pcrel_offset */ 1811130561Sobrien 1812130561Sobrien /* Like GOT_TPREL16_LO_DS, but next higher group of 16 bits. */ 1813130561Sobrien HOWTO (R_PPC64_GOT_TPREL16_HI, 1814130561Sobrien 16, /* rightshift */ 1815130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1816130561Sobrien 16, /* bitsize */ 1817130561Sobrien FALSE, /* pc_relative */ 1818130561Sobrien 0, /* bitpos */ 1819130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1820130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1821130561Sobrien "R_PPC64_GOT_TPREL16_HI", /* name */ 1822130561Sobrien FALSE, /* partial_inplace */ 1823130561Sobrien 0, /* src_mask */ 1824130561Sobrien 0xffff, /* dst_mask */ 1825130561Sobrien FALSE), /* pcrel_offset */ 1826130561Sobrien 1827130561Sobrien /* Like GOT_TPREL16_HI, but adjust for low 16 bits. */ 1828130561Sobrien HOWTO (R_PPC64_GOT_TPREL16_HA, 1829130561Sobrien 16, /* rightshift */ 1830130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1831130561Sobrien 16, /* bitsize */ 1832130561Sobrien FALSE, /* pc_relative */ 1833130561Sobrien 0, /* bitpos */ 1834130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1835130561Sobrien ppc64_elf_unhandled_reloc, /* special_function */ 1836130561Sobrien "R_PPC64_GOT_TPREL16_HA", /* name */ 1837130561Sobrien FALSE, /* partial_inplace */ 1838130561Sobrien 0, /* src_mask */ 1839130561Sobrien 0xffff, /* dst_mask */ 1840130561Sobrien FALSE), /* pcrel_offset */ 1841130561Sobrien 184289857Sobrien /* GNU extension to record C++ vtable hierarchy. */ 184389857Sobrien HOWTO (R_PPC64_GNU_VTINHERIT, /* type */ 184489857Sobrien 0, /* rightshift */ 184589857Sobrien 0, /* size (0 = byte, 1 = short, 2 = long) */ 184689857Sobrien 0, /* bitsize */ 1847130561Sobrien FALSE, /* pc_relative */ 184889857Sobrien 0, /* bitpos */ 184989857Sobrien complain_overflow_dont, /* complain_on_overflow */ 185089857Sobrien NULL, /* special_function */ 185189857Sobrien "R_PPC64_GNU_VTINHERIT", /* name */ 1852130561Sobrien FALSE, /* partial_inplace */ 185389857Sobrien 0, /* src_mask */ 185489857Sobrien 0, /* dst_mask */ 1855130561Sobrien FALSE), /* pcrel_offset */ 185689857Sobrien 185789857Sobrien /* GNU extension to record C++ vtable member usage. */ 185889857Sobrien HOWTO (R_PPC64_GNU_VTENTRY, /* type */ 185989857Sobrien 0, /* rightshift */ 186089857Sobrien 0, /* size (0 = byte, 1 = short, 2 = long) */ 186189857Sobrien 0, /* bitsize */ 1862130561Sobrien FALSE, /* pc_relative */ 186389857Sobrien 0, /* bitpos */ 186489857Sobrien complain_overflow_dont, /* complain_on_overflow */ 186589857Sobrien NULL, /* special_function */ 186689857Sobrien "R_PPC64_GNU_VTENTRY", /* name */ 1867130561Sobrien FALSE, /* partial_inplace */ 186889857Sobrien 0, /* src_mask */ 186989857Sobrien 0, /* dst_mask */ 1870130561Sobrien FALSE), /* pcrel_offset */ 187189857Sobrien}; 187289857Sobrien 187389857Sobrien 187489857Sobrien/* Initialize the ppc64_elf_howto_table, so that linear accesses can 187589857Sobrien be done. */ 187689857Sobrien 187789857Sobrienstatic void 1878130561Sobrienppc_howto_init (void) 187989857Sobrien{ 188089857Sobrien unsigned int i, type; 188189857Sobrien 188289857Sobrien for (i = 0; 188389857Sobrien i < sizeof (ppc64_elf_howto_raw) / sizeof (ppc64_elf_howto_raw[0]); 188489857Sobrien i++) 188589857Sobrien { 188689857Sobrien type = ppc64_elf_howto_raw[i].type; 188789857Sobrien BFD_ASSERT (type < (sizeof (ppc64_elf_howto_table) 188889857Sobrien / sizeof (ppc64_elf_howto_table[0]))); 188989857Sobrien ppc64_elf_howto_table[type] = &ppc64_elf_howto_raw[i]; 189089857Sobrien } 189189857Sobrien} 189289857Sobrien 189389857Sobrienstatic reloc_howto_type * 1894130561Sobrienppc64_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 1895130561Sobrien bfd_reloc_code_real_type code) 189689857Sobrien{ 1897130561Sobrien enum elf_ppc64_reloc_type r = R_PPC64_NONE; 189889857Sobrien 189989857Sobrien if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) 190089857Sobrien /* Initialize howto table if needed. */ 190189857Sobrien ppc_howto_init (); 190289857Sobrien 1903130561Sobrien switch (code) 190489857Sobrien { 190589857Sobrien default: 1906130561Sobrien return NULL; 190789857Sobrien 1908130561Sobrien case BFD_RELOC_NONE: r = R_PPC64_NONE; 190989857Sobrien break; 1910130561Sobrien case BFD_RELOC_32: r = R_PPC64_ADDR32; 191189857Sobrien break; 1912130561Sobrien case BFD_RELOC_PPC_BA26: r = R_PPC64_ADDR24; 191389857Sobrien break; 1914130561Sobrien case BFD_RELOC_16: r = R_PPC64_ADDR16; 191589857Sobrien break; 1916130561Sobrien case BFD_RELOC_LO16: r = R_PPC64_ADDR16_LO; 191789857Sobrien break; 1918130561Sobrien case BFD_RELOC_HI16: r = R_PPC64_ADDR16_HI; 191989857Sobrien break; 1920130561Sobrien case BFD_RELOC_HI16_S: r = R_PPC64_ADDR16_HA; 192189857Sobrien break; 1922130561Sobrien case BFD_RELOC_PPC_BA16: r = R_PPC64_ADDR14; 192389857Sobrien break; 1924130561Sobrien case BFD_RELOC_PPC_BA16_BRTAKEN: r = R_PPC64_ADDR14_BRTAKEN; 192589857Sobrien break; 1926130561Sobrien case BFD_RELOC_PPC_BA16_BRNTAKEN: r = R_PPC64_ADDR14_BRNTAKEN; 192789857Sobrien break; 1928130561Sobrien case BFD_RELOC_PPC_B26: r = R_PPC64_REL24; 192989857Sobrien break; 1930130561Sobrien case BFD_RELOC_PPC_B16: r = R_PPC64_REL14; 193189857Sobrien break; 1932130561Sobrien case BFD_RELOC_PPC_B16_BRTAKEN: r = R_PPC64_REL14_BRTAKEN; 193389857Sobrien break; 1934130561Sobrien case BFD_RELOC_PPC_B16_BRNTAKEN: r = R_PPC64_REL14_BRNTAKEN; 193589857Sobrien break; 1936130561Sobrien case BFD_RELOC_16_GOTOFF: r = R_PPC64_GOT16; 193789857Sobrien break; 1938130561Sobrien case BFD_RELOC_LO16_GOTOFF: r = R_PPC64_GOT16_LO; 193989857Sobrien break; 1940130561Sobrien case BFD_RELOC_HI16_GOTOFF: r = R_PPC64_GOT16_HI; 194189857Sobrien break; 1942130561Sobrien case BFD_RELOC_HI16_S_GOTOFF: r = R_PPC64_GOT16_HA; 194389857Sobrien break; 1944130561Sobrien case BFD_RELOC_PPC_COPY: r = R_PPC64_COPY; 194589857Sobrien break; 1946130561Sobrien case BFD_RELOC_PPC_GLOB_DAT: r = R_PPC64_GLOB_DAT; 194789857Sobrien break; 1948130561Sobrien case BFD_RELOC_32_PCREL: r = R_PPC64_REL32; 194989857Sobrien break; 1950130561Sobrien case BFD_RELOC_32_PLTOFF: r = R_PPC64_PLT32; 195189857Sobrien break; 1952130561Sobrien case BFD_RELOC_32_PLT_PCREL: r = R_PPC64_PLTREL32; 195389857Sobrien break; 1954130561Sobrien case BFD_RELOC_LO16_PLTOFF: r = R_PPC64_PLT16_LO; 195589857Sobrien break; 1956130561Sobrien case BFD_RELOC_HI16_PLTOFF: r = R_PPC64_PLT16_HI; 195789857Sobrien break; 1958130561Sobrien case BFD_RELOC_HI16_S_PLTOFF: r = R_PPC64_PLT16_HA; 195989857Sobrien break; 1960130561Sobrien case BFD_RELOC_16_BASEREL: r = R_PPC64_SECTOFF; 196189857Sobrien break; 1962130561Sobrien case BFD_RELOC_LO16_BASEREL: r = R_PPC64_SECTOFF_LO; 196389857Sobrien break; 1964130561Sobrien case BFD_RELOC_HI16_BASEREL: r = R_PPC64_SECTOFF_HI; 196589857Sobrien break; 1966130561Sobrien case BFD_RELOC_HI16_S_BASEREL: r = R_PPC64_SECTOFF_HA; 196789857Sobrien break; 1968130561Sobrien case BFD_RELOC_CTOR: r = R_PPC64_ADDR64; 196989857Sobrien break; 1970130561Sobrien case BFD_RELOC_64: r = R_PPC64_ADDR64; 197189857Sobrien break; 1972130561Sobrien case BFD_RELOC_PPC64_HIGHER: r = R_PPC64_ADDR16_HIGHER; 197389857Sobrien break; 1974130561Sobrien case BFD_RELOC_PPC64_HIGHER_S: r = R_PPC64_ADDR16_HIGHERA; 197589857Sobrien break; 1976130561Sobrien case BFD_RELOC_PPC64_HIGHEST: r = R_PPC64_ADDR16_HIGHEST; 197789857Sobrien break; 1978130561Sobrien case BFD_RELOC_PPC64_HIGHEST_S: r = R_PPC64_ADDR16_HIGHESTA; 197989857Sobrien break; 1980130561Sobrien case BFD_RELOC_64_PCREL: r = R_PPC64_REL64; 198189857Sobrien break; 1982130561Sobrien case BFD_RELOC_64_PLTOFF: r = R_PPC64_PLT64; 198389857Sobrien break; 1984130561Sobrien case BFD_RELOC_64_PLT_PCREL: r = R_PPC64_PLTREL64; 198589857Sobrien break; 1986130561Sobrien case BFD_RELOC_PPC_TOC16: r = R_PPC64_TOC16; 198789857Sobrien break; 1988130561Sobrien case BFD_RELOC_PPC64_TOC16_LO: r = R_PPC64_TOC16_LO; 198989857Sobrien break; 1990130561Sobrien case BFD_RELOC_PPC64_TOC16_HI: r = R_PPC64_TOC16_HI; 199189857Sobrien break; 1992130561Sobrien case BFD_RELOC_PPC64_TOC16_HA: r = R_PPC64_TOC16_HA; 199389857Sobrien break; 1994130561Sobrien case BFD_RELOC_PPC64_TOC: r = R_PPC64_TOC; 199589857Sobrien break; 1996130561Sobrien case BFD_RELOC_PPC64_PLTGOT16: r = R_PPC64_PLTGOT16; 199789857Sobrien break; 1998130561Sobrien case BFD_RELOC_PPC64_PLTGOT16_LO: r = R_PPC64_PLTGOT16_LO; 199989857Sobrien break; 2000130561Sobrien case BFD_RELOC_PPC64_PLTGOT16_HI: r = R_PPC64_PLTGOT16_HI; 200189857Sobrien break; 2002130561Sobrien case BFD_RELOC_PPC64_PLTGOT16_HA: r = R_PPC64_PLTGOT16_HA; 200389857Sobrien break; 2004130561Sobrien case BFD_RELOC_PPC64_ADDR16_DS: r = R_PPC64_ADDR16_DS; 200589857Sobrien break; 2006130561Sobrien case BFD_RELOC_PPC64_ADDR16_LO_DS: r = R_PPC64_ADDR16_LO_DS; 200789857Sobrien break; 2008130561Sobrien case BFD_RELOC_PPC64_GOT16_DS: r = R_PPC64_GOT16_DS; 200989857Sobrien break; 2010130561Sobrien case BFD_RELOC_PPC64_GOT16_LO_DS: r = R_PPC64_GOT16_LO_DS; 201189857Sobrien break; 2012130561Sobrien case BFD_RELOC_PPC64_PLT16_LO_DS: r = R_PPC64_PLT16_LO_DS; 201389857Sobrien break; 2014130561Sobrien case BFD_RELOC_PPC64_SECTOFF_DS: r = R_PPC64_SECTOFF_DS; 201589857Sobrien break; 2016130561Sobrien case BFD_RELOC_PPC64_SECTOFF_LO_DS: r = R_PPC64_SECTOFF_LO_DS; 201789857Sobrien break; 2018130561Sobrien case BFD_RELOC_PPC64_TOC16_DS: r = R_PPC64_TOC16_DS; 201989857Sobrien break; 2020130561Sobrien case BFD_RELOC_PPC64_TOC16_LO_DS: r = R_PPC64_TOC16_LO_DS; 202189857Sobrien break; 2022130561Sobrien case BFD_RELOC_PPC64_PLTGOT16_DS: r = R_PPC64_PLTGOT16_DS; 202389857Sobrien break; 2024130561Sobrien case BFD_RELOC_PPC64_PLTGOT16_LO_DS: r = R_PPC64_PLTGOT16_LO_DS; 202589857Sobrien break; 2026130561Sobrien case BFD_RELOC_PPC_TLS: r = R_PPC64_TLS; 202789857Sobrien break; 2028130561Sobrien case BFD_RELOC_PPC_DTPMOD: r = R_PPC64_DTPMOD64; 202989857Sobrien break; 2030130561Sobrien case BFD_RELOC_PPC_TPREL16: r = R_PPC64_TPREL16; 2031130561Sobrien break; 2032130561Sobrien case BFD_RELOC_PPC_TPREL16_LO: r = R_PPC64_TPREL16_LO; 2033130561Sobrien break; 2034130561Sobrien case BFD_RELOC_PPC_TPREL16_HI: r = R_PPC64_TPREL16_HI; 2035130561Sobrien break; 2036130561Sobrien case BFD_RELOC_PPC_TPREL16_HA: r = R_PPC64_TPREL16_HA; 2037130561Sobrien break; 2038130561Sobrien case BFD_RELOC_PPC_TPREL: r = R_PPC64_TPREL64; 2039130561Sobrien break; 2040130561Sobrien case BFD_RELOC_PPC_DTPREL16: r = R_PPC64_DTPREL16; 2041130561Sobrien break; 2042130561Sobrien case BFD_RELOC_PPC_DTPREL16_LO: r = R_PPC64_DTPREL16_LO; 2043130561Sobrien break; 2044130561Sobrien case BFD_RELOC_PPC_DTPREL16_HI: r = R_PPC64_DTPREL16_HI; 2045130561Sobrien break; 2046130561Sobrien case BFD_RELOC_PPC_DTPREL16_HA: r = R_PPC64_DTPREL16_HA; 2047130561Sobrien break; 2048130561Sobrien case BFD_RELOC_PPC_DTPREL: r = R_PPC64_DTPREL64; 2049130561Sobrien break; 2050130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16: r = R_PPC64_GOT_TLSGD16; 2051130561Sobrien break; 2052130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16_LO: r = R_PPC64_GOT_TLSGD16_LO; 2053130561Sobrien break; 2054130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16_HI: r = R_PPC64_GOT_TLSGD16_HI; 2055130561Sobrien break; 2056130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16_HA: r = R_PPC64_GOT_TLSGD16_HA; 2057130561Sobrien break; 2058130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16: r = R_PPC64_GOT_TLSLD16; 2059130561Sobrien break; 2060130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16_LO: r = R_PPC64_GOT_TLSLD16_LO; 2061130561Sobrien break; 2062130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16_HI: r = R_PPC64_GOT_TLSLD16_HI; 2063130561Sobrien break; 2064130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16_HA: r = R_PPC64_GOT_TLSLD16_HA; 2065130561Sobrien break; 2066130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16: r = R_PPC64_GOT_TPREL16_DS; 2067130561Sobrien break; 2068130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16_LO: r = R_PPC64_GOT_TPREL16_LO_DS; 2069130561Sobrien break; 2070130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16_HI: r = R_PPC64_GOT_TPREL16_HI; 2071130561Sobrien break; 2072130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16_HA: r = R_PPC64_GOT_TPREL16_HA; 2073130561Sobrien break; 2074130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16: r = R_PPC64_GOT_DTPREL16_DS; 2075130561Sobrien break; 2076130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16_LO: r = R_PPC64_GOT_DTPREL16_LO_DS; 2077130561Sobrien break; 2078130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16_HI: r = R_PPC64_GOT_DTPREL16_HI; 2079130561Sobrien break; 2080130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16_HA: r = R_PPC64_GOT_DTPREL16_HA; 2081130561Sobrien break; 2082130561Sobrien case BFD_RELOC_PPC64_TPREL16_DS: r = R_PPC64_TPREL16_DS; 2083130561Sobrien break; 2084130561Sobrien case BFD_RELOC_PPC64_TPREL16_LO_DS: r = R_PPC64_TPREL16_LO_DS; 2085130561Sobrien break; 2086130561Sobrien case BFD_RELOC_PPC64_TPREL16_HIGHER: r = R_PPC64_TPREL16_HIGHER; 2087130561Sobrien break; 2088130561Sobrien case BFD_RELOC_PPC64_TPREL16_HIGHERA: r = R_PPC64_TPREL16_HIGHERA; 2089130561Sobrien break; 2090130561Sobrien case BFD_RELOC_PPC64_TPREL16_HIGHEST: r = R_PPC64_TPREL16_HIGHEST; 2091130561Sobrien break; 2092130561Sobrien case BFD_RELOC_PPC64_TPREL16_HIGHESTA: r = R_PPC64_TPREL16_HIGHESTA; 2093130561Sobrien break; 2094130561Sobrien case BFD_RELOC_PPC64_DTPREL16_DS: r = R_PPC64_DTPREL16_DS; 2095130561Sobrien break; 2096130561Sobrien case BFD_RELOC_PPC64_DTPREL16_LO_DS: r = R_PPC64_DTPREL16_LO_DS; 2097130561Sobrien break; 2098130561Sobrien case BFD_RELOC_PPC64_DTPREL16_HIGHER: r = R_PPC64_DTPREL16_HIGHER; 2099130561Sobrien break; 2100130561Sobrien case BFD_RELOC_PPC64_DTPREL16_HIGHERA: r = R_PPC64_DTPREL16_HIGHERA; 2101130561Sobrien break; 2102130561Sobrien case BFD_RELOC_PPC64_DTPREL16_HIGHEST: r = R_PPC64_DTPREL16_HIGHEST; 2103130561Sobrien break; 2104130561Sobrien case BFD_RELOC_PPC64_DTPREL16_HIGHESTA: r = R_PPC64_DTPREL16_HIGHESTA; 2105130561Sobrien break; 2106130561Sobrien case BFD_RELOC_VTABLE_INHERIT: r = R_PPC64_GNU_VTINHERIT; 2107130561Sobrien break; 2108130561Sobrien case BFD_RELOC_VTABLE_ENTRY: r = R_PPC64_GNU_VTENTRY; 2109130561Sobrien break; 211089857Sobrien } 211189857Sobrien 2112130561Sobrien return ppc64_elf_howto_table[r]; 211389857Sobrien}; 211489857Sobrien 2115218822Sdimstatic reloc_howto_type * 2116218822Sdimppc64_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 2117218822Sdim const char *r_name) 2118218822Sdim{ 2119218822Sdim unsigned int i; 2120218822Sdim 2121218822Sdim for (i = 0; 2122218822Sdim i < sizeof (ppc64_elf_howto_raw) / sizeof (ppc64_elf_howto_raw[0]); 2123218822Sdim i++) 2124218822Sdim if (ppc64_elf_howto_raw[i].name != NULL 2125218822Sdim && strcasecmp (ppc64_elf_howto_raw[i].name, r_name) == 0) 2126218822Sdim return &ppc64_elf_howto_raw[i]; 2127218822Sdim 2128218822Sdim return NULL; 2129218822Sdim} 2130218822Sdim 213189857Sobrien/* Set the howto pointer for a PowerPC ELF reloc. */ 213289857Sobrien 213389857Sobrienstatic void 2134130561Sobrienppc64_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, arelent *cache_ptr, 2135130561Sobrien Elf_Internal_Rela *dst) 213689857Sobrien{ 213789857Sobrien unsigned int type; 213889857Sobrien 2139104834Sobrien /* Initialize howto table if needed. */ 214089857Sobrien if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) 214189857Sobrien ppc_howto_init (); 214289857Sobrien 214389857Sobrien type = ELF64_R_TYPE (dst->r_info); 2144218822Sdim if (type >= (sizeof (ppc64_elf_howto_table) 2145218822Sdim / sizeof (ppc64_elf_howto_table[0]))) 2146218822Sdim { 2147218822Sdim (*_bfd_error_handler) (_("%B: invalid relocation type %d"), 2148218822Sdim abfd, (int) type); 2149218822Sdim type = R_PPC64_NONE; 2150218822Sdim } 215189857Sobrien cache_ptr->howto = ppc64_elf_howto_table[type]; 215289857Sobrien} 215389857Sobrien 2154130561Sobrien/* Handle the R_PPC64_ADDR16_HA and similar relocs. */ 215589857Sobrien 215689857Sobrienstatic bfd_reloc_status_type 2157130561Sobrienppc64_elf_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 2158130561Sobrien void *data, asection *input_section, 2159130561Sobrien bfd *output_bfd, char **error_message) 216089857Sobrien{ 216199461Sobrien /* If this is a relocatable link (output_bfd test tells us), just 216299461Sobrien call the generic function. Any adjustment will be done at final 216399461Sobrien link time. */ 216499461Sobrien if (output_bfd != NULL) 2165104834Sobrien return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 216699461Sobrien input_section, output_bfd, error_message); 216789857Sobrien 216899461Sobrien /* Adjust the addend for sign extension of the low 16 bits. 216999461Sobrien We won't actually be using the low 16 bits, so trashing them 217099461Sobrien doesn't matter. */ 217199461Sobrien reloc_entry->addend += 0x8000; 217299461Sobrien return bfd_reloc_continue; 217399461Sobrien} 217499461Sobrien 217599461Sobrienstatic bfd_reloc_status_type 2176218822Sdimppc64_elf_branch_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 2177218822Sdim void *data, asection *input_section, 2178218822Sdim bfd *output_bfd, char **error_message) 2179218822Sdim{ 2180218822Sdim if (output_bfd != NULL) 2181218822Sdim return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 2182218822Sdim input_section, output_bfd, error_message); 2183218822Sdim 2184218822Sdim if (strcmp (symbol->section->name, ".opd") == 0 2185218822Sdim && (symbol->section->owner->flags & DYNAMIC) == 0) 2186218822Sdim { 2187218822Sdim bfd_vma dest = opd_entry_value (symbol->section, 2188218822Sdim symbol->value + reloc_entry->addend, 2189218822Sdim NULL, NULL); 2190218822Sdim if (dest != (bfd_vma) -1) 2191218822Sdim reloc_entry->addend = dest - (symbol->value 2192218822Sdim + symbol->section->output_section->vma 2193218822Sdim + symbol->section->output_offset); 2194218822Sdim } 2195218822Sdim return bfd_reloc_continue; 2196218822Sdim} 2197218822Sdim 2198218822Sdimstatic bfd_reloc_status_type 2199130561Sobrienppc64_elf_brtaken_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 2200130561Sobrien void *data, asection *input_section, 2201130561Sobrien bfd *output_bfd, char **error_message) 220299461Sobrien{ 220399461Sobrien long insn; 2204130561Sobrien enum elf_ppc64_reloc_type r_type; 220599461Sobrien bfd_size_type octets; 220699461Sobrien /* Disabled until we sort out how ld should choose 'y' vs 'at'. */ 2207130561Sobrien bfd_boolean is_power4 = FALSE; 220899461Sobrien 220999461Sobrien /* If this is a relocatable link (output_bfd test tells us), just 221099461Sobrien call the generic function. Any adjustment will be done at final 221199461Sobrien link time. */ 221289857Sobrien if (output_bfd != NULL) 2213104834Sobrien return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 221499461Sobrien input_section, output_bfd, error_message); 221599461Sobrien 221699461Sobrien octets = reloc_entry->address * bfd_octets_per_byte (abfd); 221799461Sobrien insn = bfd_get_32 (abfd, (bfd_byte *) data + octets); 221899461Sobrien insn &= ~(0x01 << 21); 2219130561Sobrien r_type = reloc_entry->howto->type; 222099461Sobrien if (r_type == R_PPC64_ADDR14_BRTAKEN 222199461Sobrien || r_type == R_PPC64_REL14_BRTAKEN) 2222104834Sobrien insn |= 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field. */ 222399461Sobrien 222499461Sobrien if (is_power4) 222589857Sobrien { 222699461Sobrien /* Set 'a' bit. This is 0b00010 in BO field for branch 222799461Sobrien on CR(BI) insns (BO == 001at or 011at), and 0b01000 222899461Sobrien for branch on CTR insns (BO == 1a00t or 1a01t). */ 222999461Sobrien if ((insn & (0x14 << 21)) == (0x04 << 21)) 223099461Sobrien insn |= 0x02 << 21; 223199461Sobrien else if ((insn & (0x14 << 21)) == (0x10 << 21)) 223299461Sobrien insn |= 0x08 << 21; 223399461Sobrien else 2234218822Sdim goto out; 223589857Sobrien } 223699461Sobrien else 223799461Sobrien { 223899461Sobrien bfd_vma target = 0; 223999461Sobrien bfd_vma from; 224089857Sobrien 224199461Sobrien if (!bfd_is_com_section (symbol->section)) 224299461Sobrien target = symbol->value; 224399461Sobrien target += symbol->section->output_section->vma; 224499461Sobrien target += symbol->section->output_offset; 224599461Sobrien target += reloc_entry->addend; 224689857Sobrien 224799461Sobrien from = (reloc_entry->address 224899461Sobrien + input_section->output_offset 224999461Sobrien + input_section->output_section->vma); 225089857Sobrien 225199461Sobrien /* Invert 'y' bit if not the default. */ 225299461Sobrien if ((bfd_signed_vma) (target - from) < 0) 225399461Sobrien insn ^= 0x01 << 21; 225499461Sobrien } 2255130561Sobrien bfd_put_32 (abfd, insn, (bfd_byte *) data + octets); 2256218822Sdim out: 2257218822Sdim return ppc64_elf_branch_reloc (abfd, reloc_entry, symbol, data, 2258218822Sdim input_section, output_bfd, error_message); 225999461Sobrien} 226089857Sobrien 226199461Sobrienstatic bfd_reloc_status_type 2262130561Sobrienppc64_elf_sectoff_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 2263130561Sobrien void *data, asection *input_section, 2264130561Sobrien bfd *output_bfd, char **error_message) 226599461Sobrien{ 226699461Sobrien /* If this is a relocatable link (output_bfd test tells us), just 226799461Sobrien call the generic function. Any adjustment will be done at final 226899461Sobrien link time. */ 226999461Sobrien if (output_bfd != NULL) 2270104834Sobrien return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 227199461Sobrien input_section, output_bfd, error_message); 227289857Sobrien 227399461Sobrien /* Subtract the symbol section base address. */ 227499461Sobrien reloc_entry->addend -= symbol->section->output_section->vma; 227589857Sobrien return bfd_reloc_continue; 227689857Sobrien} 227789857Sobrien 227899461Sobrienstatic bfd_reloc_status_type 2279130561Sobrienppc64_elf_sectoff_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 2280130561Sobrien void *data, asection *input_section, 2281130561Sobrien bfd *output_bfd, char **error_message) 228299461Sobrien{ 228399461Sobrien /* If this is a relocatable link (output_bfd test tells us), just 228499461Sobrien call the generic function. Any adjustment will be done at final 228599461Sobrien link time. */ 228699461Sobrien if (output_bfd != NULL) 2287104834Sobrien return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 228899461Sobrien input_section, output_bfd, error_message); 228999461Sobrien 229099461Sobrien /* Subtract the symbol section base address. */ 229199461Sobrien reloc_entry->addend -= symbol->section->output_section->vma; 229299461Sobrien 229399461Sobrien /* Adjust the addend for sign extension of the low 16 bits. */ 229499461Sobrien reloc_entry->addend += 0x8000; 229599461Sobrien return bfd_reloc_continue; 229699461Sobrien} 229799461Sobrien 229899461Sobrienstatic bfd_reloc_status_type 2299130561Sobrienppc64_elf_toc_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 2300130561Sobrien void *data, asection *input_section, 2301130561Sobrien bfd *output_bfd, char **error_message) 230299461Sobrien{ 230399461Sobrien bfd_vma TOCstart; 230499461Sobrien 230599461Sobrien /* If this is a relocatable link (output_bfd test tells us), just 230699461Sobrien call the generic function. Any adjustment will be done at final 230799461Sobrien link time. */ 230899461Sobrien if (output_bfd != NULL) 2309104834Sobrien return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 231099461Sobrien input_section, output_bfd, error_message); 231199461Sobrien 231299461Sobrien TOCstart = _bfd_get_gp_value (input_section->output_section->owner); 231399461Sobrien if (TOCstart == 0) 231499461Sobrien TOCstart = ppc64_elf_toc (input_section->output_section->owner); 231599461Sobrien 231699461Sobrien /* Subtract the TOC base address. */ 231799461Sobrien reloc_entry->addend -= TOCstart + TOC_BASE_OFF; 231899461Sobrien return bfd_reloc_continue; 231999461Sobrien} 232099461Sobrien 232199461Sobrienstatic bfd_reloc_status_type 2322130561Sobrienppc64_elf_toc_ha_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 2323130561Sobrien void *data, asection *input_section, 2324130561Sobrien bfd *output_bfd, char **error_message) 232599461Sobrien{ 232699461Sobrien bfd_vma TOCstart; 232799461Sobrien 232899461Sobrien /* If this is a relocatable link (output_bfd test tells us), just 232999461Sobrien call the generic function. Any adjustment will be done at final 233099461Sobrien link time. */ 233199461Sobrien if (output_bfd != NULL) 2332104834Sobrien return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 233399461Sobrien input_section, output_bfd, error_message); 233499461Sobrien 233599461Sobrien TOCstart = _bfd_get_gp_value (input_section->output_section->owner); 233699461Sobrien if (TOCstart == 0) 233799461Sobrien TOCstart = ppc64_elf_toc (input_section->output_section->owner); 233899461Sobrien 233999461Sobrien /* Subtract the TOC base address. */ 234099461Sobrien reloc_entry->addend -= TOCstart + TOC_BASE_OFF; 234199461Sobrien 234299461Sobrien /* Adjust the addend for sign extension of the low 16 bits. */ 234399461Sobrien reloc_entry->addend += 0x8000; 234499461Sobrien return bfd_reloc_continue; 234599461Sobrien} 234699461Sobrien 234799461Sobrienstatic bfd_reloc_status_type 2348130561Sobrienppc64_elf_toc64_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 2349130561Sobrien void *data, asection *input_section, 2350130561Sobrien bfd *output_bfd, char **error_message) 235199461Sobrien{ 235299461Sobrien bfd_vma TOCstart; 235399461Sobrien bfd_size_type octets; 235499461Sobrien 235599461Sobrien /* If this is a relocatable link (output_bfd test tells us), just 235699461Sobrien call the generic function. Any adjustment will be done at final 235799461Sobrien link time. */ 235899461Sobrien if (output_bfd != NULL) 2359104834Sobrien return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 236099461Sobrien input_section, output_bfd, error_message); 236199461Sobrien 236299461Sobrien TOCstart = _bfd_get_gp_value (input_section->output_section->owner); 236399461Sobrien if (TOCstart == 0) 236499461Sobrien TOCstart = ppc64_elf_toc (input_section->output_section->owner); 236599461Sobrien 236699461Sobrien octets = reloc_entry->address * bfd_octets_per_byte (abfd); 236799461Sobrien bfd_put_64 (abfd, TOCstart + TOC_BASE_OFF, (bfd_byte *) data + octets); 236899461Sobrien return bfd_reloc_ok; 236999461Sobrien} 237099461Sobrien 237199461Sobrienstatic bfd_reloc_status_type 2372130561Sobrienppc64_elf_unhandled_reloc (bfd *abfd, arelent *reloc_entry, asymbol *symbol, 2373130561Sobrien void *data, asection *input_section, 2374130561Sobrien bfd *output_bfd, char **error_message) 237599461Sobrien{ 237699461Sobrien /* If this is a relocatable link (output_bfd test tells us), just 237799461Sobrien call the generic function. Any adjustment will be done at final 237899461Sobrien link time. */ 237999461Sobrien if (output_bfd != NULL) 2380104834Sobrien return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 238199461Sobrien input_section, output_bfd, error_message); 238299461Sobrien 238399461Sobrien if (error_message != NULL) 238499461Sobrien { 238599461Sobrien static char buf[60]; 238699461Sobrien sprintf (buf, "generic linker can't handle %s", 238799461Sobrien reloc_entry->howto->name); 238899461Sobrien *error_message = buf; 238999461Sobrien } 239099461Sobrien return bfd_reloc_dangerous; 239199461Sobrien} 239299461Sobrien 2393130561Sobrienstruct ppc64_elf_obj_tdata 2394130561Sobrien{ 2395130561Sobrien struct elf_obj_tdata elf; 2396130561Sobrien 2397130561Sobrien /* Shortcuts to dynamic linker sections. */ 2398130561Sobrien asection *got; 2399130561Sobrien asection *relgot; 2400130561Sobrien 2401218822Sdim /* Used during garbage collection. We attach global symbols defined 2402218822Sdim on removed .opd entries to this section so that the sym is removed. */ 2403218822Sdim asection *deleted_section; 2404218822Sdim 2405130561Sobrien /* TLS local dynamic got entry handling. Suppose for multiple GOT 2406130561Sobrien sections means we potentially need one of these for each input bfd. */ 2407130561Sobrien union { 2408130561Sobrien bfd_signed_vma refcount; 2409130561Sobrien bfd_vma offset; 2410130561Sobrien } tlsld_got; 2411218822Sdim 2412218822Sdim /* A copy of relocs before they are modified for --emit-relocs. */ 2413218822Sdim Elf_Internal_Rela *opd_relocs; 2414130561Sobrien}; 2415130561Sobrien 2416130561Sobrien#define ppc64_elf_tdata(bfd) \ 2417130561Sobrien ((struct ppc64_elf_obj_tdata *) (bfd)->tdata.any) 2418130561Sobrien 2419130561Sobrien#define ppc64_tlsld_got(bfd) \ 2420130561Sobrien (&ppc64_elf_tdata (bfd)->tlsld_got) 2421130561Sobrien 2422130561Sobrien/* Override the generic function because we store some extras. */ 2423130561Sobrien 2424130561Sobrienstatic bfd_boolean 2425130561Sobrienppc64_elf_mkobject (bfd *abfd) 2426130561Sobrien{ 2427130561Sobrien if (abfd->tdata.any == NULL) 2428218822Sdim { 2429218822Sdim bfd_size_type amt = sizeof (struct ppc64_elf_obj_tdata); 2430218822Sdim abfd->tdata.any = bfd_zalloc (abfd, amt); 2431218822Sdim if (abfd->tdata.any == NULL) 2432218822Sdim return FALSE; 2433218822Sdim } 2434218822Sdim return bfd_elf_mkobject (abfd); 2435130561Sobrien} 2436130561Sobrien 2437218822Sdim/* Return 1 if target is one of ours. */ 2438218822Sdim 2439218822Sdimstatic bfd_boolean 2440218822Sdimis_ppc64_elf_target (const struct bfd_target *targ) 2441218822Sdim{ 2442218822Sdim extern const bfd_target bfd_elf64_powerpc_vec; 2443218822Sdim extern const bfd_target bfd_elf64_powerpcle_vec; 2444218822Sdim 2445218822Sdim return targ == &bfd_elf64_powerpc_vec || targ == &bfd_elf64_powerpcle_vec; 2446218822Sdim} 2447218822Sdim 2448104834Sobrien/* Fix bad default arch selected for a 64 bit input bfd when the 2449104834Sobrien default is 32 bit. */ 245089857Sobrien 2451130561Sobrienstatic bfd_boolean 2452130561Sobrienppc64_elf_object_p (bfd *abfd) 245389857Sobrien{ 2454104834Sobrien if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 32) 2455104834Sobrien { 2456104834Sobrien Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); 245789857Sobrien 2458104834Sobrien if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS64) 2459104834Sobrien { 2460104834Sobrien /* Relies on arch after 32 bit default being 64 bit default. */ 2461104834Sobrien abfd->arch_info = abfd->arch_info->next; 2462104834Sobrien BFD_ASSERT (abfd->arch_info->bits_per_word == 64); 2463104834Sobrien } 2464104834Sobrien } 2465130561Sobrien return TRUE; 246689857Sobrien} 246789857Sobrien 2468130561Sobrien/* Support for core dump NOTE sections. */ 2469130561Sobrien 2470130561Sobrienstatic bfd_boolean 2471130561Sobrienppc64_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) 2472130561Sobrien{ 2473218822Sdim size_t offset, size; 2474130561Sobrien 2475130561Sobrien if (note->descsz != 504) 2476130561Sobrien return FALSE; 2477130561Sobrien 2478130561Sobrien /* pr_cursig */ 2479130561Sobrien elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); 2480130561Sobrien 2481130561Sobrien /* pr_pid */ 2482130561Sobrien elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 32); 2483130561Sobrien 2484130561Sobrien /* pr_reg */ 2485130561Sobrien offset = 112; 2486218822Sdim size = 384; 2487130561Sobrien 2488130561Sobrien /* Make a ".reg/999" section. */ 2489130561Sobrien return _bfd_elfcore_make_pseudosection (abfd, ".reg", 2490218822Sdim size, note->descpos + offset); 2491130561Sobrien} 2492130561Sobrien 2493130561Sobrienstatic bfd_boolean 2494130561Sobrienppc64_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) 2495130561Sobrien{ 2496130561Sobrien if (note->descsz != 136) 2497130561Sobrien return FALSE; 2498130561Sobrien 2499130561Sobrien elf_tdata (abfd)->core_program 2500130561Sobrien = _bfd_elfcore_strndup (abfd, note->descdata + 40, 16); 2501130561Sobrien elf_tdata (abfd)->core_command 2502130561Sobrien = _bfd_elfcore_strndup (abfd, note->descdata + 56, 80); 2503130561Sobrien 2504130561Sobrien return TRUE; 2505130561Sobrien} 2506130561Sobrien 2507218822Sdimstatic char * 2508218822Sdimppc64_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, 2509218822Sdim ...) 2510218822Sdim{ 2511218822Sdim switch (note_type) 2512218822Sdim { 2513218822Sdim default: 2514218822Sdim return NULL; 2515218822Sdim 2516218822Sdim case NT_PRPSINFO: 2517218822Sdim { 2518218822Sdim char data[136]; 2519218822Sdim va_list ap; 2520218822Sdim 2521218822Sdim va_start (ap, note_type); 2522218822Sdim memset (data, 0, 40); 2523218822Sdim strncpy (data + 40, va_arg (ap, const char *), 16); 2524218822Sdim strncpy (data + 56, va_arg (ap, const char *), 80); 2525218822Sdim va_end (ap); 2526218822Sdim return elfcore_write_note (abfd, buf, bufsiz, 2527218822Sdim "CORE", note_type, data, sizeof (data)); 2528218822Sdim } 2529218822Sdim 2530218822Sdim case NT_PRSTATUS: 2531218822Sdim { 2532218822Sdim char data[504]; 2533218822Sdim va_list ap; 2534218822Sdim long pid; 2535218822Sdim int cursig; 2536218822Sdim const void *greg; 2537218822Sdim 2538218822Sdim va_start (ap, note_type); 2539218822Sdim memset (data, 0, 112); 2540218822Sdim pid = va_arg (ap, long); 2541218822Sdim bfd_put_32 (abfd, pid, data + 32); 2542218822Sdim cursig = va_arg (ap, int); 2543218822Sdim bfd_put_16 (abfd, cursig, data + 12); 2544218822Sdim greg = va_arg (ap, const void *); 2545218822Sdim memcpy (data + 112, greg, 384); 2546218822Sdim memset (data + 496, 0, 8); 2547218822Sdim va_end (ap); 2548218822Sdim return elfcore_write_note (abfd, buf, bufsiz, 2549218822Sdim "CORE", note_type, data, sizeof (data)); 2550218822Sdim } 2551218822Sdim } 2552218822Sdim} 2553218822Sdim 255489857Sobrien/* Merge backend specific data from an object file to the output 255589857Sobrien object file when linking. */ 2556104834Sobrien 2557130561Sobrienstatic bfd_boolean 2558130561Sobrienppc64_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) 255989857Sobrien{ 256089857Sobrien /* Check if we have the same endianess. */ 256189857Sobrien if (ibfd->xvec->byteorder != obfd->xvec->byteorder 2562107492Sobrien && ibfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN 256389857Sobrien && obfd->xvec->byteorder != BFD_ENDIAN_UNKNOWN) 256489857Sobrien { 256589857Sobrien const char *msg; 256689857Sobrien 256789857Sobrien if (bfd_big_endian (ibfd)) 2568218822Sdim msg = _("%B: compiled for a big endian system " 2569130561Sobrien "and target is little endian"); 257089857Sobrien else 2571218822Sdim msg = _("%B: compiled for a little endian system " 2572130561Sobrien "and target is big endian"); 257389857Sobrien 2574218822Sdim (*_bfd_error_handler) (msg, ibfd); 257589857Sobrien 257689857Sobrien bfd_set_error (bfd_error_wrong_format); 2577130561Sobrien return FALSE; 257889857Sobrien } 257989857Sobrien 2580130561Sobrien return TRUE; 258189857Sobrien} 2582130561Sobrien 2583130561Sobrien/* Add extra PPC sections. */ 2584130561Sobrien 2585218822Sdimstatic const struct bfd_elf_special_section ppc64_elf_special_sections[]= 2586130561Sobrien{ 2587218822Sdim { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, 0 }, 2588218822Sdim { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, 2589218822Sdim { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, 2590218822Sdim { STRING_COMMA_LEN (".toc"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, 2591218822Sdim { STRING_COMMA_LEN (".toc1"), 0, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, 2592218822Sdim { STRING_COMMA_LEN (".tocbss"), 0, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, 2593218822Sdim { NULL, 0, 0, 0, 0 } 2594130561Sobrien}; 2595130561Sobrien 2596218822Sdimenum _ppc64_sec_type { 2597218822Sdim sec_normal = 0, 2598218822Sdim sec_opd = 1, 2599218822Sdim sec_toc = 2 2600218822Sdim}; 2601218822Sdim 2602130561Sobrienstruct _ppc64_elf_section_data 2603130561Sobrien{ 2604130561Sobrien struct bfd_elf_section_data elf; 2605130561Sobrien 2606130561Sobrien /* An array with one entry for each opd function descriptor. */ 2607130561Sobrien union 2608130561Sobrien { 2609130561Sobrien /* Points to the function code section for local opd entries. */ 2610218822Sdim asection **opd_func_sec; 2611130561Sobrien /* After editing .opd, adjust references to opd local syms. */ 2612218822Sdim long *opd_adjust; 2613130561Sobrien 2614218822Sdim /* An array for toc sections, indexed by offset/8. 2615218822Sdim Specifies the relocation symbol index used at a given toc offset. */ 2616218822Sdim unsigned *t_symndx; 2617218822Sdim } u; 2618218822Sdim 2619218822Sdim enum _ppc64_sec_type sec_type:2; 2620218822Sdim 2621218822Sdim /* Flag set when small branches are detected. Used to 2622218822Sdim select suitable defaults for the stub group size. */ 2623218822Sdim unsigned int has_14bit_branch:1; 2624130561Sobrien}; 2625130561Sobrien 2626130561Sobrien#define ppc64_elf_section_data(sec) \ 2627130561Sobrien ((struct _ppc64_elf_section_data *) elf_section_data (sec)) 2628130561Sobrien 2629130561Sobrienstatic bfd_boolean 2630130561Sobrienppc64_elf_new_section_hook (bfd *abfd, asection *sec) 2631130561Sobrien{ 2632218822Sdim if (!sec->used_by_bfd) 2633218822Sdim { 2634218822Sdim struct _ppc64_elf_section_data *sdata; 2635218822Sdim bfd_size_type amt = sizeof (*sdata); 2636130561Sobrien 2637218822Sdim sdata = bfd_zalloc (abfd, amt); 2638218822Sdim if (sdata == NULL) 2639218822Sdim return FALSE; 2640218822Sdim sec->used_by_bfd = sdata; 2641218822Sdim } 2642130561Sobrien 2643130561Sobrien return _bfd_elf_new_section_hook (abfd, sec); 2644130561Sobrien} 2645218822Sdim 2646218822Sdimstatic void * 2647218822Sdimget_opd_info (asection * sec) 2648218822Sdim{ 2649218822Sdim if (sec != NULL 2650218822Sdim && ppc64_elf_section_data (sec) != NULL 2651218822Sdim && ppc64_elf_section_data (sec)->sec_type == sec_opd) 2652218822Sdim return ppc64_elf_section_data (sec)->u.opd_adjust; 2653218822Sdim return NULL; 2654218822Sdim} 265589857Sobrien 2656218822Sdim/* Parameters for the qsort hook. */ 2657218822Sdimstatic asection *synthetic_opd; 2658218822Sdimstatic bfd_boolean synthetic_relocatable; 2659218822Sdim 2660218822Sdim/* qsort comparison function for ppc64_elf_get_synthetic_symtab. */ 2661218822Sdim 2662218822Sdimstatic int 2663218822Sdimcompare_symbols (const void *ap, const void *bp) 2664218822Sdim{ 2665218822Sdim const asymbol *a = * (const asymbol **) ap; 2666218822Sdim const asymbol *b = * (const asymbol **) bp; 2667218822Sdim 2668218822Sdim /* Section symbols first. */ 2669218822Sdim if ((a->flags & BSF_SECTION_SYM) && !(b->flags & BSF_SECTION_SYM)) 2670218822Sdim return -1; 2671218822Sdim if (!(a->flags & BSF_SECTION_SYM) && (b->flags & BSF_SECTION_SYM)) 2672218822Sdim return 1; 2673218822Sdim 2674218822Sdim /* then .opd symbols. */ 2675218822Sdim if (a->section == synthetic_opd && b->section != synthetic_opd) 2676218822Sdim return -1; 2677218822Sdim if (a->section != synthetic_opd && b->section == synthetic_opd) 2678218822Sdim return 1; 2679218822Sdim 2680218822Sdim /* then other code symbols. */ 2681218822Sdim if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL)) 2682218822Sdim == (SEC_CODE | SEC_ALLOC) 2683218822Sdim && (b->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL)) 2684218822Sdim != (SEC_CODE | SEC_ALLOC)) 2685218822Sdim return -1; 2686218822Sdim 2687218822Sdim if ((a->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL)) 2688218822Sdim != (SEC_CODE | SEC_ALLOC) 2689218822Sdim && (b->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL)) 2690218822Sdim == (SEC_CODE | SEC_ALLOC)) 2691218822Sdim return 1; 2692218822Sdim 2693218822Sdim if (synthetic_relocatable) 2694218822Sdim { 2695218822Sdim if (a->section->id < b->section->id) 2696218822Sdim return -1; 2697218822Sdim 2698218822Sdim if (a->section->id > b->section->id) 2699218822Sdim return 1; 2700218822Sdim } 2701218822Sdim 2702218822Sdim if (a->value + a->section->vma < b->value + b->section->vma) 2703218822Sdim return -1; 2704218822Sdim 2705218822Sdim if (a->value + a->section->vma > b->value + b->section->vma) 2706218822Sdim return 1; 2707218822Sdim 2708218822Sdim /* For syms with the same value, prefer strong dynamic global function 2709218822Sdim syms over other syms. */ 2710218822Sdim if ((a->flags & BSF_GLOBAL) != 0 && (b->flags & BSF_GLOBAL) == 0) 2711218822Sdim return -1; 2712218822Sdim 2713218822Sdim if ((a->flags & BSF_GLOBAL) == 0 && (b->flags & BSF_GLOBAL) != 0) 2714218822Sdim return 1; 2715218822Sdim 2716218822Sdim if ((a->flags & BSF_FUNCTION) != 0 && (b->flags & BSF_FUNCTION) == 0) 2717218822Sdim return -1; 2718218822Sdim 2719218822Sdim if ((a->flags & BSF_FUNCTION) == 0 && (b->flags & BSF_FUNCTION) != 0) 2720218822Sdim return 1; 2721218822Sdim 2722218822Sdim if ((a->flags & BSF_WEAK) == 0 && (b->flags & BSF_WEAK) != 0) 2723218822Sdim return -1; 2724218822Sdim 2725218822Sdim if ((a->flags & BSF_WEAK) != 0 && (b->flags & BSF_WEAK) == 0) 2726218822Sdim return 1; 2727218822Sdim 2728218822Sdim if ((a->flags & BSF_DYNAMIC) != 0 && (b->flags & BSF_DYNAMIC) == 0) 2729218822Sdim return -1; 2730218822Sdim 2731218822Sdim if ((a->flags & BSF_DYNAMIC) == 0 && (b->flags & BSF_DYNAMIC) != 0) 2732218822Sdim return 1; 2733218822Sdim 2734218822Sdim return 0; 2735218822Sdim} 2736218822Sdim 2737218822Sdim/* Search SYMS for a symbol of the given VALUE. */ 2738218822Sdim 2739218822Sdimstatic asymbol * 2740218822Sdimsym_exists_at (asymbol **syms, long lo, long hi, int id, bfd_vma value) 2741218822Sdim{ 2742218822Sdim long mid; 2743218822Sdim 2744218822Sdim if (id == -1) 2745218822Sdim { 2746218822Sdim while (lo < hi) 2747218822Sdim { 2748218822Sdim mid = (lo + hi) >> 1; 2749218822Sdim if (syms[mid]->value + syms[mid]->section->vma < value) 2750218822Sdim lo = mid + 1; 2751218822Sdim else if (syms[mid]->value + syms[mid]->section->vma > value) 2752218822Sdim hi = mid; 2753218822Sdim else 2754218822Sdim return syms[mid]; 2755218822Sdim } 2756218822Sdim } 2757218822Sdim else 2758218822Sdim { 2759218822Sdim while (lo < hi) 2760218822Sdim { 2761218822Sdim mid = (lo + hi) >> 1; 2762218822Sdim if (syms[mid]->section->id < id) 2763218822Sdim lo = mid + 1; 2764218822Sdim else if (syms[mid]->section->id > id) 2765218822Sdim hi = mid; 2766218822Sdim else if (syms[mid]->value < value) 2767218822Sdim lo = mid + 1; 2768218822Sdim else if (syms[mid]->value > value) 2769218822Sdim hi = mid; 2770218822Sdim else 2771218822Sdim return syms[mid]; 2772218822Sdim } 2773218822Sdim } 2774218822Sdim return NULL; 2775218822Sdim} 2776218822Sdim 2777218822Sdim/* Create synthetic symbols, effectively restoring "dot-symbol" function 2778218822Sdim entry syms. */ 2779218822Sdim 2780218822Sdimstatic long 2781218822Sdimppc64_elf_get_synthetic_symtab (bfd *abfd, 2782218822Sdim long static_count, asymbol **static_syms, 2783218822Sdim long dyn_count, asymbol **dyn_syms, 2784218822Sdim asymbol **ret) 2785218822Sdim{ 2786218822Sdim asymbol *s; 2787218822Sdim long i; 2788218822Sdim long count; 2789218822Sdim char *names; 2790218822Sdim long symcount, codesecsym, codesecsymend, secsymend, opdsymend; 2791218822Sdim asection *opd; 2792218822Sdim bfd_boolean relocatable = (abfd->flags & (EXEC_P | DYNAMIC)) == 0; 2793218822Sdim asymbol **syms; 2794218822Sdim 2795218822Sdim *ret = NULL; 2796218822Sdim 2797218822Sdim opd = bfd_get_section_by_name (abfd, ".opd"); 2798218822Sdim if (opd == NULL) 2799218822Sdim return 0; 2800218822Sdim 2801218822Sdim symcount = static_count; 2802218822Sdim if (!relocatable) 2803218822Sdim symcount += dyn_count; 2804218822Sdim if (symcount == 0) 2805218822Sdim return 0; 2806218822Sdim 2807218822Sdim syms = bfd_malloc ((symcount + 1) * sizeof (*syms)); 2808218822Sdim if (syms == NULL) 2809218822Sdim return -1; 2810218822Sdim 2811218822Sdim if (!relocatable && static_count != 0 && dyn_count != 0) 2812218822Sdim { 2813218822Sdim /* Use both symbol tables. */ 2814218822Sdim memcpy (syms, static_syms, static_count * sizeof (*syms)); 2815218822Sdim memcpy (syms + static_count, dyn_syms, (dyn_count + 1) * sizeof (*syms)); 2816218822Sdim } 2817218822Sdim else if (!relocatable && static_count == 0) 2818218822Sdim memcpy (syms, dyn_syms, (symcount + 1) * sizeof (*syms)); 2819218822Sdim else 2820218822Sdim memcpy (syms, static_syms, (symcount + 1) * sizeof (*syms)); 2821218822Sdim 2822218822Sdim synthetic_opd = opd; 2823218822Sdim synthetic_relocatable = relocatable; 2824218822Sdim qsort (syms, symcount, sizeof (*syms), compare_symbols); 2825218822Sdim 2826218822Sdim if (!relocatable && symcount > 1) 2827218822Sdim { 2828218822Sdim long j; 2829218822Sdim /* Trim duplicate syms, since we may have merged the normal and 2830218822Sdim dynamic symbols. Actually, we only care about syms that have 2831218822Sdim different values, so trim any with the same value. */ 2832218822Sdim for (i = 1, j = 1; i < symcount; ++i) 2833218822Sdim if (syms[i - 1]->value + syms[i - 1]->section->vma 2834218822Sdim != syms[i]->value + syms[i]->section->vma) 2835218822Sdim syms[j++] = syms[i]; 2836218822Sdim symcount = j; 2837218822Sdim } 2838218822Sdim 2839218822Sdim i = 0; 2840218822Sdim if (syms[i]->section == opd) 2841218822Sdim ++i; 2842218822Sdim codesecsym = i; 2843218822Sdim 2844218822Sdim for (; i < symcount; ++i) 2845218822Sdim if (((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL)) 2846218822Sdim != (SEC_CODE | SEC_ALLOC)) 2847218822Sdim || (syms[i]->flags & BSF_SECTION_SYM) == 0) 2848218822Sdim break; 2849218822Sdim codesecsymend = i; 2850218822Sdim 2851218822Sdim for (; i < symcount; ++i) 2852218822Sdim if ((syms[i]->flags & BSF_SECTION_SYM) == 0) 2853218822Sdim break; 2854218822Sdim secsymend = i; 2855218822Sdim 2856218822Sdim for (; i < symcount; ++i) 2857218822Sdim if (syms[i]->section != opd) 2858218822Sdim break; 2859218822Sdim opdsymend = i; 2860218822Sdim 2861218822Sdim for (; i < symcount; ++i) 2862218822Sdim if ((syms[i]->section->flags & (SEC_CODE | SEC_ALLOC | SEC_THREAD_LOCAL)) 2863218822Sdim != (SEC_CODE | SEC_ALLOC)) 2864218822Sdim break; 2865218822Sdim symcount = i; 2866218822Sdim 2867218822Sdim count = 0; 2868218822Sdim if (opdsymend == secsymend) 2869218822Sdim goto done; 2870218822Sdim 2871218822Sdim if (relocatable) 2872218822Sdim { 2873218822Sdim bfd_boolean (*slurp_relocs) (bfd *, asection *, asymbol **, bfd_boolean); 2874218822Sdim arelent *r; 2875218822Sdim size_t size; 2876218822Sdim long relcount; 2877218822Sdim 2878218822Sdim slurp_relocs = get_elf_backend_data (abfd)->s->slurp_reloc_table; 2879218822Sdim relcount = (opd->flags & SEC_RELOC) ? opd->reloc_count : 0; 2880218822Sdim if (relcount == 0) 2881218822Sdim goto done; 2882218822Sdim 2883218822Sdim if (!(*slurp_relocs) (abfd, opd, static_syms, FALSE)) 2884218822Sdim { 2885218822Sdim count = -1; 2886218822Sdim goto done; 2887218822Sdim } 2888218822Sdim 2889218822Sdim size = 0; 2890218822Sdim for (i = secsymend, r = opd->relocation; i < opdsymend; ++i) 2891218822Sdim { 2892218822Sdim asymbol *sym; 2893218822Sdim 2894218822Sdim while (r < opd->relocation + relcount 2895218822Sdim && r->address < syms[i]->value + opd->vma) 2896218822Sdim ++r; 2897218822Sdim 2898218822Sdim if (r == opd->relocation + relcount) 2899218822Sdim break; 2900218822Sdim 2901218822Sdim if (r->address != syms[i]->value + opd->vma) 2902218822Sdim continue; 2903218822Sdim 2904218822Sdim if (r->howto->type != R_PPC64_ADDR64) 2905218822Sdim continue; 2906218822Sdim 2907218822Sdim sym = *r->sym_ptr_ptr; 2908218822Sdim if (!sym_exists_at (syms, opdsymend, symcount, 2909218822Sdim sym->section->id, sym->value + r->addend)) 2910218822Sdim { 2911218822Sdim ++count; 2912218822Sdim size += sizeof (asymbol); 2913218822Sdim size += strlen (syms[i]->name) + 2; 2914218822Sdim } 2915218822Sdim } 2916218822Sdim 2917218822Sdim s = *ret = bfd_malloc (size); 2918218822Sdim if (s == NULL) 2919218822Sdim { 2920218822Sdim count = -1; 2921218822Sdim goto done; 2922218822Sdim } 2923218822Sdim 2924218822Sdim names = (char *) (s + count); 2925218822Sdim 2926218822Sdim for (i = secsymend, r = opd->relocation; i < opdsymend; ++i) 2927218822Sdim { 2928218822Sdim asymbol *sym; 2929218822Sdim 2930218822Sdim while (r < opd->relocation + relcount 2931218822Sdim && r->address < syms[i]->value + opd->vma) 2932218822Sdim ++r; 2933218822Sdim 2934218822Sdim if (r == opd->relocation + relcount) 2935218822Sdim break; 2936218822Sdim 2937218822Sdim if (r->address != syms[i]->value + opd->vma) 2938218822Sdim continue; 2939218822Sdim 2940218822Sdim if (r->howto->type != R_PPC64_ADDR64) 2941218822Sdim continue; 2942218822Sdim 2943218822Sdim sym = *r->sym_ptr_ptr; 2944218822Sdim if (!sym_exists_at (syms, opdsymend, symcount, 2945218822Sdim sym->section->id, sym->value + r->addend)) 2946218822Sdim { 2947218822Sdim size_t len; 2948218822Sdim 2949218822Sdim *s = *syms[i]; 2950218822Sdim s->section = sym->section; 2951218822Sdim s->value = sym->value + r->addend; 2952218822Sdim s->name = names; 2953218822Sdim *names++ = '.'; 2954218822Sdim len = strlen (syms[i]->name); 2955218822Sdim memcpy (names, syms[i]->name, len + 1); 2956218822Sdim names += len + 1; 2957218822Sdim s++; 2958218822Sdim } 2959218822Sdim } 2960218822Sdim } 2961218822Sdim else 2962218822Sdim { 2963218822Sdim bfd_byte *contents; 2964218822Sdim size_t size; 2965218822Sdim 2966218822Sdim if (!bfd_malloc_and_get_section (abfd, opd, &contents)) 2967218822Sdim { 2968218822Sdim if (contents) 2969218822Sdim { 2970218822Sdim free_contents_and_exit: 2971218822Sdim free (contents); 2972218822Sdim } 2973218822Sdim count = -1; 2974218822Sdim goto done; 2975218822Sdim } 2976218822Sdim 2977218822Sdim size = 0; 2978218822Sdim for (i = secsymend; i < opdsymend; ++i) 2979218822Sdim { 2980218822Sdim bfd_vma ent; 2981218822Sdim 2982218822Sdim ent = bfd_get_64 (abfd, contents + syms[i]->value); 2983218822Sdim if (!sym_exists_at (syms, opdsymend, symcount, -1, ent)) 2984218822Sdim { 2985218822Sdim ++count; 2986218822Sdim size += sizeof (asymbol); 2987218822Sdim size += strlen (syms[i]->name) + 2; 2988218822Sdim } 2989218822Sdim } 2990218822Sdim 2991218822Sdim s = *ret = bfd_malloc (size); 2992218822Sdim if (s == NULL) 2993218822Sdim goto free_contents_and_exit; 2994218822Sdim 2995218822Sdim names = (char *) (s + count); 2996218822Sdim 2997218822Sdim for (i = secsymend; i < opdsymend; ++i) 2998218822Sdim { 2999218822Sdim bfd_vma ent; 3000218822Sdim 3001218822Sdim ent = bfd_get_64 (abfd, contents + syms[i]->value); 3002218822Sdim if (!sym_exists_at (syms, opdsymend, symcount, -1, ent)) 3003218822Sdim { 3004218822Sdim long lo, hi; 3005218822Sdim size_t len; 3006218822Sdim asection *sec = abfd->sections; 3007218822Sdim 3008218822Sdim *s = *syms[i]; 3009218822Sdim lo = codesecsym; 3010218822Sdim hi = codesecsymend; 3011218822Sdim while (lo < hi) 3012218822Sdim { 3013218822Sdim long mid = (lo + hi) >> 1; 3014218822Sdim if (syms[mid]->section->vma < ent) 3015218822Sdim lo = mid + 1; 3016218822Sdim else if (syms[mid]->section->vma > ent) 3017218822Sdim hi = mid; 3018218822Sdim else 3019218822Sdim { 3020218822Sdim sec = syms[mid]->section; 3021218822Sdim break; 3022218822Sdim } 3023218822Sdim } 3024218822Sdim 3025218822Sdim if (lo >= hi && lo > codesecsym) 3026218822Sdim sec = syms[lo - 1]->section; 3027218822Sdim 3028218822Sdim for (; sec != NULL; sec = sec->next) 3029218822Sdim { 3030218822Sdim if (sec->vma > ent) 3031218822Sdim break; 3032218822Sdim if ((sec->flags & SEC_ALLOC) == 0 3033218822Sdim || (sec->flags & SEC_LOAD) == 0) 3034218822Sdim break; 3035218822Sdim if ((sec->flags & SEC_CODE) != 0) 3036218822Sdim s->section = sec; 3037218822Sdim } 3038218822Sdim s->value = ent - s->section->vma; 3039218822Sdim s->name = names; 3040218822Sdim *names++ = '.'; 3041218822Sdim len = strlen (syms[i]->name); 3042218822Sdim memcpy (names, syms[i]->name, len + 1); 3043218822Sdim names += len + 1; 3044218822Sdim s++; 3045218822Sdim } 3046218822Sdim } 3047218822Sdim free (contents); 3048218822Sdim } 3049218822Sdim 3050218822Sdim done: 3051218822Sdim free (syms); 3052218822Sdim return count; 3053218822Sdim} 3054218822Sdim 305589857Sobrien/* The following functions are specific to the ELF linker, while 305689857Sobrien functions above are used generally. Those named ppc64_elf_* are 305789857Sobrien called by the main ELF linker code. They appear in this file more 305889857Sobrien or less in the order in which they are called. eg. 305989857Sobrien ppc64_elf_check_relocs is called early in the link process, 306089857Sobrien ppc64_elf_finish_dynamic_sections is one of the last functions 306189857Sobrien called. 306289857Sobrien 306389857Sobrien PowerPC64-ELF uses a similar scheme to PowerPC64-XCOFF in that 306489857Sobrien functions have both a function code symbol and a function descriptor 306589857Sobrien symbol. A call to foo in a relocatable object file looks like: 306689857Sobrien 306789857Sobrien . .text 306889857Sobrien . x: 306989857Sobrien . bl .foo 307089857Sobrien . nop 307189857Sobrien 307289857Sobrien The function definition in another object file might be: 307389857Sobrien 307489857Sobrien . .section .opd 307589857Sobrien . foo: .quad .foo 307689857Sobrien . .quad .TOC.@tocbase 307789857Sobrien . .quad 0 307889857Sobrien . 307989857Sobrien . .text 308089857Sobrien . .foo: blr 308189857Sobrien 308289857Sobrien When the linker resolves the call during a static link, the branch 308389857Sobrien unsurprisingly just goes to .foo and the .opd information is unused. 308489857Sobrien If the function definition is in a shared library, things are a little 308589857Sobrien different: The call goes via a plt call stub, the opd information gets 308689857Sobrien copied to the plt, and the linker patches the nop. 308789857Sobrien 308889857Sobrien . x: 308989857Sobrien . bl .foo_stub 309089857Sobrien . ld 2,40(1) 309189857Sobrien . 309289857Sobrien . 309389857Sobrien . .foo_stub: 309489857Sobrien . addis 12,2,Lfoo@toc@ha # in practice, the call stub 3095130561Sobrien . addi 12,12,Lfoo@toc@l # is slightly optimized, but 309689857Sobrien . std 2,40(1) # this is the general idea 309789857Sobrien . ld 11,0(12) 309889857Sobrien . ld 2,8(12) 309989857Sobrien . mtctr 11 310089857Sobrien . ld 11,16(12) 310189857Sobrien . bctr 310289857Sobrien . 310389857Sobrien . .section .plt 310489857Sobrien . Lfoo: reloc (R_PPC64_JMP_SLOT, foo) 310589857Sobrien 310689857Sobrien The "reloc ()" notation is supposed to indicate that the linker emits 310789857Sobrien an R_PPC64_JMP_SLOT reloc against foo. The dynamic linker does the opd 310889857Sobrien copying. 310989857Sobrien 311089857Sobrien What are the difficulties here? Well, firstly, the relocations 311189857Sobrien examined by the linker in check_relocs are against the function code 311289857Sobrien sym .foo, while the dynamic relocation in the plt is emitted against 311389857Sobrien the function descriptor symbol, foo. Somewhere along the line, we need 311489857Sobrien to carefully copy dynamic link information from one symbol to the other. 311589857Sobrien Secondly, the generic part of the elf linker will make .foo a dynamic 311689857Sobrien symbol as is normal for most other backends. We need foo dynamic 311789857Sobrien instead, at least for an application final link. However, when 311889857Sobrien creating a shared library containing foo, we need to have both symbols 311989857Sobrien dynamic so that references to .foo are satisfied during the early 312089857Sobrien stages of linking. Otherwise the linker might decide to pull in a 3121218822Sdim definition from some other object, eg. a static library. 312289857Sobrien 3123218822Sdim Update: As of August 2004, we support a new convention. Function 3124218822Sdim calls may use the function descriptor symbol, ie. "bl foo". This 3125218822Sdim behaves exactly as "bl .foo". */ 3126218822Sdim 312789857Sobrien/* The linker needs to keep track of the number of relocs that it 312889857Sobrien decides to copy as dynamic relocs in check_relocs for each symbol. 312989857Sobrien This is so that it can later discard them if they are found to be 313089857Sobrien unnecessary. We store the information in a field extending the 313189857Sobrien regular ELF linker hash table. */ 313289857Sobrien 313389857Sobrienstruct ppc_dyn_relocs 313489857Sobrien{ 313589857Sobrien struct ppc_dyn_relocs *next; 313689857Sobrien 313789857Sobrien /* The input section of the reloc. */ 313889857Sobrien asection *sec; 313989857Sobrien 314089857Sobrien /* Total number of relocs copied for the input section. */ 314189857Sobrien bfd_size_type count; 314289857Sobrien 314389857Sobrien /* Number of pc-relative relocs copied for the input section. */ 314489857Sobrien bfd_size_type pc_count; 314589857Sobrien}; 314689857Sobrien 3147130561Sobrien/* Track GOT entries needed for a given symbol. We might need more 3148130561Sobrien than one got entry per symbol. */ 3149130561Sobrienstruct got_entry 3150130561Sobrien{ 3151130561Sobrien struct got_entry *next; 3152130561Sobrien 3153130561Sobrien /* The symbol addend that we'll be placing in the GOT. */ 3154130561Sobrien bfd_vma addend; 3155130561Sobrien 3156130561Sobrien /* Unlike other ELF targets, we use separate GOT entries for the same 3157130561Sobrien symbol referenced from different input files. This is to support 3158130561Sobrien automatic multiple TOC/GOT sections, where the TOC base can vary 3159130561Sobrien from one input file to another. 3160130561Sobrien 3161130561Sobrien Point to the BFD owning this GOT entry. */ 3162130561Sobrien bfd *owner; 3163130561Sobrien 3164130561Sobrien /* Zero for non-tls entries, or TLS_TLS and one of TLS_GD, TLS_LD, 3165130561Sobrien TLS_TPREL or TLS_DTPREL for tls entries. */ 3166130561Sobrien char tls_type; 3167130561Sobrien 3168130561Sobrien /* Reference count until size_dynamic_sections, GOT offset thereafter. */ 3169130561Sobrien union 3170130561Sobrien { 3171130561Sobrien bfd_signed_vma refcount; 3172130561Sobrien bfd_vma offset; 3173130561Sobrien } got; 3174130561Sobrien}; 3175130561Sobrien 3176130561Sobrien/* The same for PLT. */ 3177130561Sobrienstruct plt_entry 3178130561Sobrien{ 3179130561Sobrien struct plt_entry *next; 3180130561Sobrien 3181130561Sobrien bfd_vma addend; 3182130561Sobrien 3183130561Sobrien union 3184130561Sobrien { 3185130561Sobrien bfd_signed_vma refcount; 3186130561Sobrien bfd_vma offset; 3187130561Sobrien } plt; 3188130561Sobrien}; 3189130561Sobrien 319089857Sobrien/* Of those relocs that might be copied as dynamic relocs, this macro 3191130561Sobrien selects those that must be copied when linking a shared library, 3192130561Sobrien even when the symbol is local. */ 319389857Sobrien 3194130561Sobrien#define MUST_BE_DYN_RELOC(RTYPE) \ 3195104834Sobrien ((RTYPE) != R_PPC64_REL32 \ 3196104834Sobrien && (RTYPE) != R_PPC64_REL64 \ 3197130561Sobrien && (RTYPE) != R_PPC64_REL30) 319889857Sobrien 3199130561Sobrien/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid 3200130561Sobrien copying dynamic variables from a shared lib into an app's dynbss 3201130561Sobrien section, and instead use a dynamic relocation to point into the 3202130561Sobrien shared lib. With code that gcc generates, it's vital that this be 3203130561Sobrien enabled; In the PowerPC64 ABI, the address of a function is actually 3204130561Sobrien the address of a function descriptor, which resides in the .opd 3205130561Sobrien section. gcc uses the descriptor directly rather than going via the 3206130561Sobrien GOT as some other ABI's do, which means that initialized function 3207130561Sobrien pointers must reference the descriptor. Thus, a function pointer 3208130561Sobrien initialized to the address of a function in a shared library will 3209130561Sobrien either require a copy reloc, or a dynamic reloc. Using a copy reloc 3210130561Sobrien redefines the function descriptor symbol to point to the copy. This 3211130561Sobrien presents a problem as a plt entry for that function is also 3212130561Sobrien initialized from the function descriptor symbol and the copy reloc 3213130561Sobrien may not be initialized first. */ 3214130561Sobrien#define ELIMINATE_COPY_RELOCS 1 3215130561Sobrien 3216104834Sobrien/* Section name for stubs is the associated section name plus this 3217104834Sobrien string. */ 3218104834Sobrien#define STUB_SUFFIX ".stub" 321989857Sobrien 3220104834Sobrien/* Linker stubs. 3221104834Sobrien ppc_stub_long_branch: 3222104834Sobrien Used when a 14 bit branch (or even a 24 bit branch) can't reach its 3223104834Sobrien destination, but a 24 bit branch in a stub section will reach. 3224104834Sobrien . b dest 3225104834Sobrien 3226104834Sobrien ppc_stub_plt_branch: 3227104834Sobrien Similar to the above, but a 24 bit branch in the stub section won't 3228104834Sobrien reach its destination. 3229107492Sobrien . addis %r12,%r2,xxx@toc@ha 3230107492Sobrien . ld %r11,xxx@toc@l(%r12) 3231104834Sobrien . mtctr %r11 3232104834Sobrien . bctr 3233104834Sobrien 3234104834Sobrien ppc_stub_plt_call: 3235218822Sdim Used to call a function in a shared library. If it so happens that 3236218822Sdim the plt entry referenced crosses a 64k boundary, then an extra 3237218822Sdim "addis %r12,%r12,1" will be inserted before the load at xxx+8 or 3238218822Sdim xxx+16 as appropriate. 3239107492Sobrien . addis %r12,%r2,xxx@toc@ha 3240104834Sobrien . std %r2,40(%r1) 3241107492Sobrien . ld %r11,xxx+0@toc@l(%r12) 3242107492Sobrien . ld %r2,xxx+8@toc@l(%r12) 3243104834Sobrien . mtctr %r11 3244107492Sobrien . ld %r11,xxx+16@toc@l(%r12) 3245104834Sobrien . bctr 3246130561Sobrien 3247130561Sobrien ppc_stub_long_branch and ppc_stub_plt_branch may also have additional 3248130561Sobrien code to adjust the value and save r2 to support multiple toc sections. 3249130561Sobrien A ppc_stub_long_branch with an r2 offset looks like: 3250130561Sobrien . std %r2,40(%r1) 3251130561Sobrien . addis %r2,%r2,off@ha 3252130561Sobrien . addi %r2,%r2,off@l 3253130561Sobrien . b dest 3254130561Sobrien 3255130561Sobrien A ppc_stub_plt_branch with an r2 offset looks like: 3256130561Sobrien . std %r2,40(%r1) 3257130561Sobrien . addis %r12,%r2,xxx@toc@ha 3258130561Sobrien . ld %r11,xxx@toc@l(%r12) 3259130561Sobrien . addis %r2,%r2,off@ha 3260130561Sobrien . addi %r2,%r2,off@l 3261130561Sobrien . mtctr %r11 3262130561Sobrien . bctr 3263104834Sobrien*/ 3264104834Sobrien 3265104834Sobrienenum ppc_stub_type { 3266104834Sobrien ppc_stub_none, 3267104834Sobrien ppc_stub_long_branch, 3268130561Sobrien ppc_stub_long_branch_r2off, 3269104834Sobrien ppc_stub_plt_branch, 3270130561Sobrien ppc_stub_plt_branch_r2off, 3271104834Sobrien ppc_stub_plt_call 3272104834Sobrien}; 3273104834Sobrien 3274104834Sobrienstruct ppc_stub_hash_entry { 3275104834Sobrien 3276104834Sobrien /* Base hash table entry structure. */ 3277104834Sobrien struct bfd_hash_entry root; 3278104834Sobrien 3279130561Sobrien enum ppc_stub_type stub_type; 3280130561Sobrien 3281104834Sobrien /* The stub section. */ 3282104834Sobrien asection *stub_sec; 3283104834Sobrien 3284104834Sobrien /* Offset within stub_sec of the beginning of this stub. */ 3285104834Sobrien bfd_vma stub_offset; 3286104834Sobrien 3287104834Sobrien /* Given the symbol's value and its section we can determine its final 3288104834Sobrien value when building the stubs (so the stub knows where to jump. */ 3289104834Sobrien bfd_vma target_value; 3290104834Sobrien asection *target_section; 3291104834Sobrien 3292104834Sobrien /* The symbol table entry, if any, that this was derived from. */ 3293104834Sobrien struct ppc_link_hash_entry *h; 3294104834Sobrien 3295130561Sobrien /* And the reloc addend that this was derived from. */ 3296130561Sobrien bfd_vma addend; 3297130561Sobrien 3298104834Sobrien /* Where this stub is being called from, or, in the case of combined 3299104834Sobrien stub sections, the first input section in the group. */ 3300104834Sobrien asection *id_sec; 3301104834Sobrien}; 3302104834Sobrien 3303104834Sobrienstruct ppc_branch_hash_entry { 3304104834Sobrien 3305104834Sobrien /* Base hash table entry structure. */ 3306104834Sobrien struct bfd_hash_entry root; 3307104834Sobrien 3308218822Sdim /* Offset within branch lookup table. */ 3309104834Sobrien unsigned int offset; 3310104834Sobrien 3311104834Sobrien /* Generation marker. */ 3312104834Sobrien unsigned int iter; 3313104834Sobrien}; 3314104834Sobrien 331589857Sobrienstruct ppc_link_hash_entry 331689857Sobrien{ 331789857Sobrien struct elf_link_hash_entry elf; 331889857Sobrien 3319218822Sdim union { 3320218822Sdim /* A pointer to the most recently used stub hash entry against this 3321218822Sdim symbol. */ 3322218822Sdim struct ppc_stub_hash_entry *stub_cache; 3323104834Sobrien 3324218822Sdim /* A pointer to the next symbol starting with a '.' */ 3325218822Sdim struct ppc_link_hash_entry *next_dot_sym; 3326218822Sdim } u; 3327218822Sdim 332889857Sobrien /* Track dynamic relocs copied for this symbol. */ 332989857Sobrien struct ppc_dyn_relocs *dyn_relocs; 333089857Sobrien 3331104834Sobrien /* Link between function code and descriptor symbols. */ 3332218822Sdim struct ppc_link_hash_entry *oh; 3333104834Sobrien 333489857Sobrien /* Flag function code and descriptor symbols. */ 333589857Sobrien unsigned int is_func:1; 333689857Sobrien unsigned int is_func_descriptor:1; 3337218822Sdim unsigned int fake:1; 3338130561Sobrien 3339218822Sdim /* Whether global opd/toc sym has been adjusted or not. 3340218822Sdim After ppc64_elf_edit_opd/ppc64_elf_edit_toc has run, this flag 3341218822Sdim should be set for all globals defined in any opd/toc section. */ 3342130561Sobrien unsigned int adjust_done:1; 3343130561Sobrien 3344218822Sdim /* Set if we twiddled this symbol to weak at some stage. */ 3345218822Sdim unsigned int was_undefined:1; 3346218822Sdim 3347130561Sobrien /* Contexts in which symbol is used in the GOT (or TOC). 3348130561Sobrien TLS_GD .. TLS_EXPLICIT bits are or'd into the mask as the 3349130561Sobrien corresponding relocs are encountered during check_relocs. 3350130561Sobrien tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to 3351130561Sobrien indicate the corresponding GOT entry type is not needed. 3352130561Sobrien tls_optimize may also set TLS_TPRELGD when a GD reloc turns into 3353130561Sobrien a TPREL one. We use a separate flag rather than setting TPREL 3354130561Sobrien just for convenience in distinguishing the two cases. */ 3355130561Sobrien#define TLS_GD 1 /* GD reloc. */ 3356130561Sobrien#define TLS_LD 2 /* LD reloc. */ 3357130561Sobrien#define TLS_TPREL 4 /* TPREL reloc, => IE. */ 3358130561Sobrien#define TLS_DTPREL 8 /* DTPREL reloc, => LD. */ 3359130561Sobrien#define TLS_TLS 16 /* Any TLS reloc. */ 3360130561Sobrien#define TLS_EXPLICIT 32 /* Marks TOC section TLS relocs. */ 3361130561Sobrien#define TLS_TPRELGD 64 /* TPREL reloc resulting from GD->IE. */ 3362130561Sobrien char tls_mask; 336389857Sobrien}; 336489857Sobrien 336589857Sobrien/* ppc64 ELF linker hash table. */ 336689857Sobrien 336789857Sobrienstruct ppc_link_hash_table 336889857Sobrien{ 336989857Sobrien struct elf_link_hash_table elf; 337089857Sobrien 3371104834Sobrien /* The stub hash table. */ 3372104834Sobrien struct bfd_hash_table stub_hash_table; 3373104834Sobrien 3374104834Sobrien /* Another hash table for plt_branch stubs. */ 3375104834Sobrien struct bfd_hash_table branch_hash_table; 3376104834Sobrien 3377104834Sobrien /* Linker stub bfd. */ 3378104834Sobrien bfd *stub_bfd; 3379104834Sobrien 3380104834Sobrien /* Linker call-backs. */ 3381130561Sobrien asection * (*add_stub_section) (const char *, asection *); 3382130561Sobrien void (*layout_sections_again) (void); 3383104834Sobrien 3384104834Sobrien /* Array to keep track of which stub sections have been created, and 3385104834Sobrien information on stub grouping. */ 3386104834Sobrien struct map_stub { 3387104834Sobrien /* This is the section to which stubs in the group will be attached. */ 3388104834Sobrien asection *link_sec; 3389104834Sobrien /* The stub section. */ 3390104834Sobrien asection *stub_sec; 3391130561Sobrien /* Along with elf_gp, specifies the TOC pointer used in this group. */ 3392130561Sobrien bfd_vma toc_off; 3393104834Sobrien } *stub_group; 3394104834Sobrien 3395130561Sobrien /* Temp used when calculating TOC pointers. */ 3396130561Sobrien bfd_vma toc_curr; 3397130561Sobrien 3398130561Sobrien /* Highest input section id. */ 3399130561Sobrien int top_id; 3400130561Sobrien 3401130561Sobrien /* Highest output section index. */ 3402104834Sobrien int top_index; 3403130561Sobrien 3404218822Sdim /* Used when adding symbols. */ 3405218822Sdim struct ppc_link_hash_entry *dot_syms; 3406218822Sdim 3407130561Sobrien /* List of input sections for each output section. */ 3408104834Sobrien asection **input_list; 3409104834Sobrien 341089857Sobrien /* Short-cuts to get to dynamic linker sections. */ 3411130561Sobrien asection *got; 3412130561Sobrien asection *plt; 3413130561Sobrien asection *relplt; 3414130561Sobrien asection *dynbss; 3415130561Sobrien asection *relbss; 3416130561Sobrien asection *glink; 341792828Sobrien asection *sfpr; 3418130561Sobrien asection *brlt; 3419130561Sobrien asection *relbrlt; 342089857Sobrien 3421218822Sdim /* Shortcut to .__tls_get_addr and __tls_get_addr. */ 3422218822Sdim struct ppc_link_hash_entry *tls_get_addr; 3423218822Sdim struct ppc_link_hash_entry *tls_get_addr_fd; 3424130561Sobrien 3425130561Sobrien /* Statistics. */ 3426130561Sobrien unsigned long stub_count[ppc_stub_plt_call]; 3427130561Sobrien 3428218822Sdim /* Number of stubs against global syms. */ 3429218822Sdim unsigned long stub_globals; 3430218822Sdim 3431130561Sobrien /* Set if we should emit symbols for stubs. */ 3432218822Sdim unsigned int emit_stub_syms:1; 3433130561Sobrien 3434218822Sdim /* Support for multiple toc sections. */ 3435218822Sdim unsigned int no_multi_toc:1; 3436218822Sdim unsigned int multi_toc_needed:1; 3437218822Sdim 343889857Sobrien /* Set on error. */ 3439218822Sdim unsigned int stub_error:1; 344089857Sobrien 3441218822Sdim /* Temp used by ppc64_elf_check_directives. */ 3442218822Sdim unsigned int twiddled_syms:1; 3443104834Sobrien 3444104834Sobrien /* Incremented every time we size stubs. */ 3445104834Sobrien unsigned int stub_iteration; 3446104834Sobrien 344789857Sobrien /* Small local sym to section mapping cache. */ 344889857Sobrien struct sym_sec_cache sym_sec; 344989857Sobrien}; 345089857Sobrien 3451218822Sdim/* Rename some of the generic section flags to better document how they 3452218822Sdim are used here. */ 3453218822Sdim#define has_toc_reloc has_gp_reloc 3454218822Sdim#define makes_toc_func_call need_finalize_relax 3455218822Sdim#define call_check_in_progress reloc_done 3456218822Sdim 345789857Sobrien/* Get the ppc64 ELF linker hash table from a link_info structure. */ 345889857Sobrien 345989857Sobrien#define ppc_hash_table(p) \ 346089857Sobrien ((struct ppc_link_hash_table *) ((p)->hash)) 346189857Sobrien 3462104834Sobrien#define ppc_stub_hash_lookup(table, string, create, copy) \ 3463104834Sobrien ((struct ppc_stub_hash_entry *) \ 3464104834Sobrien bfd_hash_lookup ((table), (string), (create), (copy))) 3465104834Sobrien 3466104834Sobrien#define ppc_branch_hash_lookup(table, string, create, copy) \ 3467104834Sobrien ((struct ppc_branch_hash_entry *) \ 3468104834Sobrien bfd_hash_lookup ((table), (string), (create), (copy))) 3469104834Sobrien 3470104834Sobrien/* Create an entry in the stub hash table. */ 3471104834Sobrien 3472104834Sobrienstatic struct bfd_hash_entry * 3473130561Sobrienstub_hash_newfunc (struct bfd_hash_entry *entry, 3474130561Sobrien struct bfd_hash_table *table, 3475130561Sobrien const char *string) 3476104834Sobrien{ 3477104834Sobrien /* Allocate the structure if it has not already been allocated by a 3478104834Sobrien subclass. */ 3479104834Sobrien if (entry == NULL) 3480104834Sobrien { 3481104834Sobrien entry = bfd_hash_allocate (table, sizeof (struct ppc_stub_hash_entry)); 3482104834Sobrien if (entry == NULL) 3483104834Sobrien return entry; 3484104834Sobrien } 3485104834Sobrien 3486104834Sobrien /* Call the allocation method of the superclass. */ 3487104834Sobrien entry = bfd_hash_newfunc (entry, table, string); 3488104834Sobrien if (entry != NULL) 3489104834Sobrien { 3490104834Sobrien struct ppc_stub_hash_entry *eh; 3491104834Sobrien 3492104834Sobrien /* Initialize the local fields. */ 3493104834Sobrien eh = (struct ppc_stub_hash_entry *) entry; 3494130561Sobrien eh->stub_type = ppc_stub_none; 3495104834Sobrien eh->stub_sec = NULL; 3496104834Sobrien eh->stub_offset = 0; 3497104834Sobrien eh->target_value = 0; 3498104834Sobrien eh->target_section = NULL; 3499104834Sobrien eh->h = NULL; 3500104834Sobrien eh->id_sec = NULL; 3501104834Sobrien } 3502104834Sobrien 3503104834Sobrien return entry; 3504104834Sobrien} 3505104834Sobrien 3506104834Sobrien/* Create an entry in the branch hash table. */ 3507104834Sobrien 3508104834Sobrienstatic struct bfd_hash_entry * 3509130561Sobrienbranch_hash_newfunc (struct bfd_hash_entry *entry, 3510130561Sobrien struct bfd_hash_table *table, 3511130561Sobrien const char *string) 3512104834Sobrien{ 3513104834Sobrien /* Allocate the structure if it has not already been allocated by a 3514104834Sobrien subclass. */ 3515104834Sobrien if (entry == NULL) 3516104834Sobrien { 3517104834Sobrien entry = bfd_hash_allocate (table, sizeof (struct ppc_branch_hash_entry)); 3518104834Sobrien if (entry == NULL) 3519104834Sobrien return entry; 3520104834Sobrien } 3521104834Sobrien 3522104834Sobrien /* Call the allocation method of the superclass. */ 3523104834Sobrien entry = bfd_hash_newfunc (entry, table, string); 3524104834Sobrien if (entry != NULL) 3525104834Sobrien { 3526104834Sobrien struct ppc_branch_hash_entry *eh; 3527104834Sobrien 3528104834Sobrien /* Initialize the local fields. */ 3529104834Sobrien eh = (struct ppc_branch_hash_entry *) entry; 3530104834Sobrien eh->offset = 0; 3531104834Sobrien eh->iter = 0; 3532104834Sobrien } 3533104834Sobrien 3534104834Sobrien return entry; 3535104834Sobrien} 3536104834Sobrien 353789857Sobrien/* Create an entry in a ppc64 ELF linker hash table. */ 353889857Sobrien 353989857Sobrienstatic struct bfd_hash_entry * 3540130561Sobrienlink_hash_newfunc (struct bfd_hash_entry *entry, 3541130561Sobrien struct bfd_hash_table *table, 3542130561Sobrien const char *string) 354389857Sobrien{ 354489857Sobrien /* Allocate the structure if it has not already been allocated by a 354589857Sobrien subclass. */ 354689857Sobrien if (entry == NULL) 354789857Sobrien { 354889857Sobrien entry = bfd_hash_allocate (table, sizeof (struct ppc_link_hash_entry)); 354989857Sobrien if (entry == NULL) 355089857Sobrien return entry; 355189857Sobrien } 355289857Sobrien 355389857Sobrien /* Call the allocation method of the superclass. */ 355489857Sobrien entry = _bfd_elf_link_hash_newfunc (entry, table, string); 355589857Sobrien if (entry != NULL) 355689857Sobrien { 355789857Sobrien struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) entry; 355889857Sobrien 3559218822Sdim memset (&eh->u.stub_cache, 0, 3560218822Sdim (sizeof (struct ppc_link_hash_entry) 3561218822Sdim - offsetof (struct ppc_link_hash_entry, u.stub_cache))); 3562218822Sdim 3563218822Sdim /* When making function calls, old ABI code references function entry 3564218822Sdim points (dot symbols), while new ABI code references the function 3565218822Sdim descriptor symbol. We need to make any combination of reference and 3566218822Sdim definition work together, without breaking archive linking. 3567218822Sdim 3568218822Sdim For a defined function "foo" and an undefined call to "bar": 3569218822Sdim An old object defines "foo" and ".foo", references ".bar" (possibly 3570218822Sdim "bar" too). 3571218822Sdim A new object defines "foo" and references "bar". 3572218822Sdim 3573218822Sdim A new object thus has no problem with its undefined symbols being 3574218822Sdim satisfied by definitions in an old object. On the other hand, the 3575218822Sdim old object won't have ".bar" satisfied by a new object. 3576218822Sdim 3577218822Sdim Keep a list of newly added dot-symbols. */ 3578218822Sdim 3579218822Sdim if (string[0] == '.') 3580218822Sdim { 3581218822Sdim struct ppc_link_hash_table *htab; 3582218822Sdim 3583218822Sdim htab = (struct ppc_link_hash_table *) table; 3584218822Sdim eh->u.next_dot_sym = htab->dot_syms; 3585218822Sdim htab->dot_syms = eh; 3586218822Sdim } 358789857Sobrien } 358889857Sobrien 358989857Sobrien return entry; 359089857Sobrien} 359189857Sobrien 359289857Sobrien/* Create a ppc64 ELF linker hash table. */ 359389857Sobrien 359489857Sobrienstatic struct bfd_link_hash_table * 3595130561Sobrienppc64_elf_link_hash_table_create (bfd *abfd) 359689857Sobrien{ 359789857Sobrien struct ppc_link_hash_table *htab; 359889857Sobrien bfd_size_type amt = sizeof (struct ppc_link_hash_table); 359989857Sobrien 3600130561Sobrien htab = bfd_zmalloc (amt); 360189857Sobrien if (htab == NULL) 360289857Sobrien return NULL; 360389857Sobrien 3604218822Sdim if (!_bfd_elf_link_hash_table_init (&htab->elf, abfd, link_hash_newfunc, 3605218822Sdim sizeof (struct ppc_link_hash_entry))) 360689857Sobrien { 3607104834Sobrien free (htab); 360889857Sobrien return NULL; 360989857Sobrien } 361089857Sobrien 3611104834Sobrien /* Init the stub hash table too. */ 3612218822Sdim if (!bfd_hash_table_init (&htab->stub_hash_table, stub_hash_newfunc, 3613218822Sdim sizeof (struct ppc_stub_hash_entry))) 3614104834Sobrien return NULL; 3615104834Sobrien 3616104834Sobrien /* And the branch hash table. */ 3617218822Sdim if (!bfd_hash_table_init (&htab->branch_hash_table, branch_hash_newfunc, 3618218822Sdim sizeof (struct ppc_branch_hash_entry))) 3619104834Sobrien return NULL; 3620104834Sobrien 3621130561Sobrien /* Initializing two fields of the union is just cosmetic. We really 3622130561Sobrien only care about glist, but when compiled on a 32-bit host the 3623130561Sobrien bfd_vma fields are larger. Setting the bfd_vma to zero makes 3624130561Sobrien debugger inspection of these fields look nicer. */ 3625218822Sdim htab->elf.init_got_refcount.refcount = 0; 3626218822Sdim htab->elf.init_got_refcount.glist = NULL; 3627218822Sdim htab->elf.init_plt_refcount.refcount = 0; 3628218822Sdim htab->elf.init_plt_refcount.glist = NULL; 3629218822Sdim htab->elf.init_got_offset.offset = 0; 3630218822Sdim htab->elf.init_got_offset.glist = NULL; 3631218822Sdim htab->elf.init_plt_offset.offset = 0; 3632218822Sdim htab->elf.init_plt_offset.glist = NULL; 363389857Sobrien 363489857Sobrien return &htab->elf.root; 363589857Sobrien} 363689857Sobrien 3637104834Sobrien/* Free the derived linker hash table. */ 3638104834Sobrien 3639104834Sobrienstatic void 3640130561Sobrienppc64_elf_link_hash_table_free (struct bfd_link_hash_table *hash) 3641104834Sobrien{ 3642104834Sobrien struct ppc_link_hash_table *ret = (struct ppc_link_hash_table *) hash; 3643104834Sobrien 3644104834Sobrien bfd_hash_table_free (&ret->stub_hash_table); 3645104834Sobrien bfd_hash_table_free (&ret->branch_hash_table); 3646104834Sobrien _bfd_generic_link_hash_table_free (hash); 3647104834Sobrien} 3648104834Sobrien 3649130561Sobrien/* Satisfy the ELF linker by filling in some fields in our fake bfd. */ 3650130561Sobrien 3651130561Sobrienvoid 3652130561Sobrienppc64_elf_init_stub_bfd (bfd *abfd, struct bfd_link_info *info) 3653130561Sobrien{ 3654130561Sobrien struct ppc_link_hash_table *htab; 3655130561Sobrien 3656130561Sobrien elf_elfheader (abfd)->e_ident[EI_CLASS] = ELFCLASS64; 3657130561Sobrien 3658130561Sobrien/* Always hook our dynamic sections into the first bfd, which is the 3659130561Sobrien linker created stub bfd. This ensures that the GOT header is at 3660130561Sobrien the start of the output TOC section. */ 3661130561Sobrien htab = ppc_hash_table (info); 3662130561Sobrien htab->stub_bfd = abfd; 3663130561Sobrien htab->elf.dynobj = abfd; 3664130561Sobrien} 3665130561Sobrien 3666104834Sobrien/* Build a name for an entry in the stub hash table. */ 3667104834Sobrien 3668104834Sobrienstatic char * 3669130561Sobrienppc_stub_name (const asection *input_section, 3670130561Sobrien const asection *sym_sec, 3671130561Sobrien const struct ppc_link_hash_entry *h, 3672130561Sobrien const Elf_Internal_Rela *rel) 3673104834Sobrien{ 3674104834Sobrien char *stub_name; 3675104834Sobrien bfd_size_type len; 3676104834Sobrien 3677104834Sobrien /* rel->r_addend is actually 64 bit, but who uses more than +/- 2^31 3678104834Sobrien offsets from a sym as a branch target? In fact, we could 3679104834Sobrien probably assume the addend is always zero. */ 3680104834Sobrien BFD_ASSERT (((int) rel->r_addend & 0xffffffff) == rel->r_addend); 3681104834Sobrien 3682104834Sobrien if (h) 3683104834Sobrien { 3684104834Sobrien len = 8 + 1 + strlen (h->elf.root.root.string) + 1 + 8 + 1; 3685104834Sobrien stub_name = bfd_malloc (len); 3686218822Sdim if (stub_name == NULL) 3687218822Sdim return stub_name; 3688218822Sdim 3689218822Sdim sprintf (stub_name, "%08x.%s+%x", 3690218822Sdim input_section->id & 0xffffffff, 3691218822Sdim h->elf.root.root.string, 3692218822Sdim (int) rel->r_addend & 0xffffffff); 3693104834Sobrien } 3694104834Sobrien else 3695104834Sobrien { 3696130561Sobrien len = 8 + 1 + 8 + 1 + 8 + 1 + 8 + 1; 3697104834Sobrien stub_name = bfd_malloc (len); 3698218822Sdim if (stub_name == NULL) 3699218822Sdim return stub_name; 3700218822Sdim 3701218822Sdim sprintf (stub_name, "%08x.%x:%x+%x", 3702218822Sdim input_section->id & 0xffffffff, 3703218822Sdim sym_sec->id & 0xffffffff, 3704218822Sdim (int) ELF64_R_SYM (rel->r_info) & 0xffffffff, 3705218822Sdim (int) rel->r_addend & 0xffffffff); 3706104834Sobrien } 3707218822Sdim if (stub_name[len - 2] == '+' && stub_name[len - 1] == '0') 3708218822Sdim stub_name[len - 2] = 0; 3709104834Sobrien return stub_name; 3710104834Sobrien} 3711104834Sobrien 3712104834Sobrien/* Look up an entry in the stub hash. Stub entries are cached because 3713104834Sobrien creating the stub name takes a bit of time. */ 3714104834Sobrien 3715104834Sobrienstatic struct ppc_stub_hash_entry * 3716130561Sobrienppc_get_stub_entry (const asection *input_section, 3717130561Sobrien const asection *sym_sec, 3718218822Sdim struct ppc_link_hash_entry *h, 3719130561Sobrien const Elf_Internal_Rela *rel, 3720130561Sobrien struct ppc_link_hash_table *htab) 3721104834Sobrien{ 3722104834Sobrien struct ppc_stub_hash_entry *stub_entry; 3723104834Sobrien const asection *id_sec; 3724104834Sobrien 3725104834Sobrien /* If this input section is part of a group of sections sharing one 3726104834Sobrien stub section, then use the id of the first section in the group. 3727104834Sobrien Stub names need to include a section id, as there may well be 3728104834Sobrien more than one stub used to reach say, printf, and we need to 3729104834Sobrien distinguish between them. */ 3730104834Sobrien id_sec = htab->stub_group[input_section->id].link_sec; 3731104834Sobrien 3732218822Sdim if (h != NULL && h->u.stub_cache != NULL 3733218822Sdim && h->u.stub_cache->h == h 3734218822Sdim && h->u.stub_cache->id_sec == id_sec) 3735104834Sobrien { 3736218822Sdim stub_entry = h->u.stub_cache; 3737104834Sobrien } 3738104834Sobrien else 3739104834Sobrien { 3740104834Sobrien char *stub_name; 3741104834Sobrien 3742104834Sobrien stub_name = ppc_stub_name (id_sec, sym_sec, h, rel); 3743104834Sobrien if (stub_name == NULL) 3744104834Sobrien return NULL; 3745104834Sobrien 3746104834Sobrien stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table, 3747130561Sobrien stub_name, FALSE, FALSE); 3748104834Sobrien if (h != NULL) 3749218822Sdim h->u.stub_cache = stub_entry; 3750104834Sobrien 3751104834Sobrien free (stub_name); 3752104834Sobrien } 3753104834Sobrien 3754104834Sobrien return stub_entry; 3755104834Sobrien} 3756104834Sobrien 3757104834Sobrien/* Add a new stub entry to the stub hash. Not all fields of the new 3758104834Sobrien stub entry are initialised. */ 3759104834Sobrien 3760104834Sobrienstatic struct ppc_stub_hash_entry * 3761130561Sobrienppc_add_stub (const char *stub_name, 3762130561Sobrien asection *section, 3763130561Sobrien struct ppc_link_hash_table *htab) 3764104834Sobrien{ 3765104834Sobrien asection *link_sec; 3766104834Sobrien asection *stub_sec; 3767104834Sobrien struct ppc_stub_hash_entry *stub_entry; 3768104834Sobrien 3769104834Sobrien link_sec = htab->stub_group[section->id].link_sec; 3770104834Sobrien stub_sec = htab->stub_group[section->id].stub_sec; 3771104834Sobrien if (stub_sec == NULL) 3772104834Sobrien { 3773104834Sobrien stub_sec = htab->stub_group[link_sec->id].stub_sec; 3774104834Sobrien if (stub_sec == NULL) 3775104834Sobrien { 3776104834Sobrien size_t namelen; 3777104834Sobrien bfd_size_type len; 3778104834Sobrien char *s_name; 3779104834Sobrien 3780104834Sobrien namelen = strlen (link_sec->name); 3781104834Sobrien len = namelen + sizeof (STUB_SUFFIX); 3782104834Sobrien s_name = bfd_alloc (htab->stub_bfd, len); 3783104834Sobrien if (s_name == NULL) 3784104834Sobrien return NULL; 3785104834Sobrien 3786104834Sobrien memcpy (s_name, link_sec->name, namelen); 3787104834Sobrien memcpy (s_name + namelen, STUB_SUFFIX, sizeof (STUB_SUFFIX)); 3788104834Sobrien stub_sec = (*htab->add_stub_section) (s_name, link_sec); 3789104834Sobrien if (stub_sec == NULL) 3790104834Sobrien return NULL; 3791104834Sobrien htab->stub_group[link_sec->id].stub_sec = stub_sec; 3792104834Sobrien } 3793104834Sobrien htab->stub_group[section->id].stub_sec = stub_sec; 3794104834Sobrien } 3795104834Sobrien 3796104834Sobrien /* Enter this entry into the linker stub hash table. */ 3797104834Sobrien stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table, stub_name, 3798130561Sobrien TRUE, FALSE); 3799104834Sobrien if (stub_entry == NULL) 3800104834Sobrien { 3801218822Sdim (*_bfd_error_handler) (_("%B: cannot create stub entry %s"), 3802218822Sdim section->owner, stub_name); 3803104834Sobrien return NULL; 3804104834Sobrien } 3805104834Sobrien 3806104834Sobrien stub_entry->stub_sec = stub_sec; 3807104834Sobrien stub_entry->stub_offset = 0; 3808104834Sobrien stub_entry->id_sec = link_sec; 3809104834Sobrien return stub_entry; 3810104834Sobrien} 3811104834Sobrien 381292828Sobrien/* Create sections for linker generated code. */ 381392828Sobrien 3814130561Sobrienstatic bfd_boolean 3815130561Sobriencreate_linkage_sections (bfd *dynobj, struct bfd_link_info *info) 381692828Sobrien{ 381792828Sobrien struct ppc_link_hash_table *htab; 381892828Sobrien flagword flags; 381992828Sobrien 382092828Sobrien htab = ppc_hash_table (info); 382192828Sobrien 382292828Sobrien /* Create .sfpr for code to save and restore fp regs. */ 382392828Sobrien flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_READONLY 382492828Sobrien | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); 3825218822Sdim htab->sfpr = bfd_make_section_anyway_with_flags (dynobj, ".sfpr", 3826218822Sdim flags); 382792828Sobrien if (htab->sfpr == NULL 382892828Sobrien || ! bfd_set_section_alignment (dynobj, htab->sfpr, 2)) 3829130561Sobrien return FALSE; 383092828Sobrien 3831104834Sobrien /* Create .glink for lazy dynamic linking support. */ 3832218822Sdim htab->glink = bfd_make_section_anyway_with_flags (dynobj, ".glink", 3833218822Sdim flags); 3834130561Sobrien if (htab->glink == NULL 3835218822Sdim || ! bfd_set_section_alignment (dynobj, htab->glink, 3)) 3836130561Sobrien return FALSE; 383792828Sobrien 3838218822Sdim /* Create branch lookup table for plt_branch stubs. */ 3839104834Sobrien flags = (SEC_ALLOC | SEC_LOAD 3840104834Sobrien | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); 3841218822Sdim htab->brlt = bfd_make_section_anyway_with_flags (dynobj, ".branch_lt", 3842218822Sdim flags); 3843130561Sobrien if (htab->brlt == NULL 3844130561Sobrien || ! bfd_set_section_alignment (dynobj, htab->brlt, 3)) 3845130561Sobrien return FALSE; 3846104834Sobrien 3847218822Sdim if (!info->shared) 3848218822Sdim return TRUE; 3849218822Sdim 3850218822Sdim flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY 3851218822Sdim | SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED); 3852218822Sdim htab->relbrlt = bfd_make_section_anyway_with_flags (dynobj, 3853218822Sdim ".rela.branch_lt", 3854218822Sdim flags); 3855218822Sdim if (!htab->relbrlt 3856218822Sdim || ! bfd_set_section_alignment (dynobj, htab->relbrlt, 3)) 3857218822Sdim return FALSE; 3858218822Sdim 3859130561Sobrien return TRUE; 386092828Sobrien} 386192828Sobrien 3862130561Sobrien/* Create .got and .rela.got sections in ABFD, and .got in dynobj if 3863130561Sobrien not already done. */ 386489857Sobrien 3865130561Sobrienstatic bfd_boolean 3866130561Sobriencreate_got_section (bfd *abfd, struct bfd_link_info *info) 386789857Sobrien{ 3868130561Sobrien asection *got, *relgot; 3869130561Sobrien flagword flags; 3870130561Sobrien struct ppc_link_hash_table *htab = ppc_hash_table (info); 387189857Sobrien 3872130561Sobrien if (!htab->got) 3873130561Sobrien { 3874130561Sobrien if (! _bfd_elf_create_got_section (htab->elf.dynobj, info)) 3875130561Sobrien return FALSE; 387689857Sobrien 3877130561Sobrien htab->got = bfd_get_section_by_name (htab->elf.dynobj, ".got"); 3878130561Sobrien if (!htab->got) 3879130561Sobrien abort (); 3880130561Sobrien } 388189857Sobrien 3882130561Sobrien flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY 3883130561Sobrien | SEC_LINKER_CREATED); 3884130561Sobrien 3885218822Sdim got = bfd_make_section_anyway_with_flags (abfd, ".got", flags); 3886130561Sobrien if (!got 3887130561Sobrien || !bfd_set_section_alignment (abfd, got, 3)) 3888130561Sobrien return FALSE; 3889130561Sobrien 3890218822Sdim relgot = bfd_make_section_anyway_with_flags (abfd, ".rela.got", 3891218822Sdim flags | SEC_READONLY); 3892130561Sobrien if (!relgot 3893130561Sobrien || ! bfd_set_section_alignment (abfd, relgot, 3)) 3894130561Sobrien return FALSE; 3895130561Sobrien 3896130561Sobrien ppc64_elf_tdata (abfd)->got = got; 3897130561Sobrien ppc64_elf_tdata (abfd)->relgot = relgot; 3898130561Sobrien return TRUE; 389989857Sobrien} 390089857Sobrien 390192828Sobrien/* Create the dynamic sections, and set up shortcuts. */ 390289857Sobrien 3903130561Sobrienstatic bfd_boolean 3904130561Sobrienppc64_elf_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info) 390589857Sobrien{ 390689857Sobrien struct ppc_link_hash_table *htab; 390789857Sobrien 390889857Sobrien if (!_bfd_elf_create_dynamic_sections (dynobj, info)) 3909130561Sobrien return FALSE; 391089857Sobrien 3911130561Sobrien htab = ppc_hash_table (info); 3912130561Sobrien if (!htab->got) 3913130561Sobrien htab->got = bfd_get_section_by_name (dynobj, ".got"); 3914130561Sobrien htab->plt = bfd_get_section_by_name (dynobj, ".plt"); 3915130561Sobrien htab->relplt = bfd_get_section_by_name (dynobj, ".rela.plt"); 3916130561Sobrien htab->dynbss = bfd_get_section_by_name (dynobj, ".dynbss"); 391789857Sobrien if (!info->shared) 3918130561Sobrien htab->relbss = bfd_get_section_by_name (dynobj, ".rela.bss"); 391989857Sobrien 3920130561Sobrien if (!htab->got || !htab->plt || !htab->relplt || !htab->dynbss 3921130561Sobrien || (!info->shared && !htab->relbss)) 392289857Sobrien abort (); 392389857Sobrien 3924130561Sobrien return TRUE; 392589857Sobrien} 392689857Sobrien 3927218822Sdim/* Merge PLT info on FROM with that on TO. */ 3928218822Sdim 3929218822Sdimstatic void 3930218822Sdimmove_plt_plist (struct ppc_link_hash_entry *from, 3931218822Sdim struct ppc_link_hash_entry *to) 3932218822Sdim{ 3933218822Sdim if (from->elf.plt.plist != NULL) 3934218822Sdim { 3935218822Sdim if (to->elf.plt.plist != NULL) 3936218822Sdim { 3937218822Sdim struct plt_entry **entp; 3938218822Sdim struct plt_entry *ent; 3939218822Sdim 3940218822Sdim for (entp = &from->elf.plt.plist; (ent = *entp) != NULL; ) 3941218822Sdim { 3942218822Sdim struct plt_entry *dent; 3943218822Sdim 3944218822Sdim for (dent = to->elf.plt.plist; dent != NULL; dent = dent->next) 3945218822Sdim if (dent->addend == ent->addend) 3946218822Sdim { 3947218822Sdim dent->plt.refcount += ent->plt.refcount; 3948218822Sdim *entp = ent->next; 3949218822Sdim break; 3950218822Sdim } 3951218822Sdim if (dent == NULL) 3952218822Sdim entp = &ent->next; 3953218822Sdim } 3954218822Sdim *entp = to->elf.plt.plist; 3955218822Sdim } 3956218822Sdim 3957218822Sdim to->elf.plt.plist = from->elf.plt.plist; 3958218822Sdim from->elf.plt.plist = NULL; 3959218822Sdim } 3960218822Sdim} 3961218822Sdim 396289857Sobrien/* Copy the extra info we tack onto an elf_link_hash_entry. */ 396389857Sobrien 396489857Sobrienstatic void 3965218822Sdimppc64_elf_copy_indirect_symbol (struct bfd_link_info *info, 3966218822Sdim struct elf_link_hash_entry *dir, 3967218822Sdim struct elf_link_hash_entry *ind) 396889857Sobrien{ 396989857Sobrien struct ppc_link_hash_entry *edir, *eind; 397089857Sobrien 397189857Sobrien edir = (struct ppc_link_hash_entry *) dir; 397289857Sobrien eind = (struct ppc_link_hash_entry *) ind; 397389857Sobrien 3974130561Sobrien /* Copy over any dynamic relocs we may have on the indirect sym. */ 397589857Sobrien if (eind->dyn_relocs != NULL) 397689857Sobrien { 397789857Sobrien if (edir->dyn_relocs != NULL) 397889857Sobrien { 397989857Sobrien struct ppc_dyn_relocs **pp; 398089857Sobrien struct ppc_dyn_relocs *p; 398189857Sobrien 3982218822Sdim /* Add reloc counts against the indirect sym to the direct sym 398389857Sobrien list. Merge any entries against the same section. */ 398489857Sobrien for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) 398589857Sobrien { 398689857Sobrien struct ppc_dyn_relocs *q; 398789857Sobrien 398889857Sobrien for (q = edir->dyn_relocs; q != NULL; q = q->next) 398989857Sobrien if (q->sec == p->sec) 399089857Sobrien { 399189857Sobrien q->pc_count += p->pc_count; 399289857Sobrien q->count += p->count; 399389857Sobrien *pp = p->next; 399489857Sobrien break; 399589857Sobrien } 399689857Sobrien if (q == NULL) 399789857Sobrien pp = &p->next; 399889857Sobrien } 399989857Sobrien *pp = edir->dyn_relocs; 400089857Sobrien } 400189857Sobrien 400289857Sobrien edir->dyn_relocs = eind->dyn_relocs; 400389857Sobrien eind->dyn_relocs = NULL; 400489857Sobrien } 400589857Sobrien 400689857Sobrien edir->is_func |= eind->is_func; 400789857Sobrien edir->is_func_descriptor |= eind->is_func_descriptor; 4008130561Sobrien edir->tls_mask |= eind->tls_mask; 400989857Sobrien 4010130561Sobrien /* If called to transfer flags for a weakdef during processing 4011218822Sdim of elf_adjust_dynamic_symbol, don't copy NON_GOT_REF. 4012130561Sobrien We clear it ourselves for ELIMINATE_COPY_RELOCS. */ 4013218822Sdim if (!(ELIMINATE_COPY_RELOCS 4014218822Sdim && eind->elf.root.type != bfd_link_hash_indirect 4015218822Sdim && edir->elf.dynamic_adjusted)) 4016218822Sdim edir->elf.non_got_ref |= eind->elf.non_got_ref; 4017130561Sobrien 4018218822Sdim edir->elf.ref_dynamic |= eind->elf.ref_dynamic; 4019218822Sdim edir->elf.ref_regular |= eind->elf.ref_regular; 4020218822Sdim edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak; 4021218822Sdim edir->elf.needs_plt |= eind->elf.needs_plt; 4022130561Sobrien 4023130561Sobrien /* If we were called to copy over info for a weak sym, that's all. */ 4024130561Sobrien if (eind->elf.root.type != bfd_link_hash_indirect) 4025130561Sobrien return; 4026130561Sobrien 4027130561Sobrien /* Copy over got entries that we may have already seen to the 4028130561Sobrien symbol which just became indirect. */ 4029130561Sobrien if (eind->elf.got.glist != NULL) 4030130561Sobrien { 4031130561Sobrien if (edir->elf.got.glist != NULL) 4032130561Sobrien { 4033130561Sobrien struct got_entry **entp; 4034130561Sobrien struct got_entry *ent; 4035130561Sobrien 4036130561Sobrien for (entp = &eind->elf.got.glist; (ent = *entp) != NULL; ) 4037130561Sobrien { 4038130561Sobrien struct got_entry *dent; 4039130561Sobrien 4040130561Sobrien for (dent = edir->elf.got.glist; dent != NULL; dent = dent->next) 4041130561Sobrien if (dent->addend == ent->addend 4042130561Sobrien && dent->owner == ent->owner 4043130561Sobrien && dent->tls_type == ent->tls_type) 4044130561Sobrien { 4045130561Sobrien dent->got.refcount += ent->got.refcount; 4046130561Sobrien *entp = ent->next; 4047130561Sobrien break; 4048130561Sobrien } 4049130561Sobrien if (dent == NULL) 4050130561Sobrien entp = &ent->next; 4051130561Sobrien } 4052130561Sobrien *entp = edir->elf.got.glist; 4053130561Sobrien } 4054130561Sobrien 4055130561Sobrien edir->elf.got.glist = eind->elf.got.glist; 4056130561Sobrien eind->elf.got.glist = NULL; 4057130561Sobrien } 4058130561Sobrien 4059130561Sobrien /* And plt entries. */ 4060218822Sdim move_plt_plist (eind, edir); 4061130561Sobrien 4062218822Sdim if (eind->elf.dynindx != -1) 4063130561Sobrien { 4064218822Sdim if (edir->elf.dynindx != -1) 4065218822Sdim _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, 4066218822Sdim edir->elf.dynstr_index); 4067130561Sobrien edir->elf.dynindx = eind->elf.dynindx; 4068130561Sobrien edir->elf.dynstr_index = eind->elf.dynstr_index; 4069130561Sobrien eind->elf.dynindx = -1; 4070130561Sobrien eind->elf.dynstr_index = 0; 4071130561Sobrien } 407289857Sobrien} 407389857Sobrien 4074218822Sdim/* Find the function descriptor hash entry from the given function code 4075218822Sdim hash entry FH. Link the entries via their OH fields. */ 4076104834Sobrien 4077218822Sdimstatic struct ppc_link_hash_entry * 4078218822Sdimget_fdh (struct ppc_link_hash_entry *fh, struct ppc_link_hash_table *htab) 4079104834Sobrien{ 4080218822Sdim struct ppc_link_hash_entry *fdh = fh->oh; 4081104834Sobrien 4082218822Sdim if (fdh == NULL) 4083104834Sobrien { 4084218822Sdim const char *fd_name = fh->elf.root.root.string + 1; 4085104834Sobrien 4086218822Sdim fdh = (struct ppc_link_hash_entry *) 4087218822Sdim elf_link_hash_lookup (&htab->elf, fd_name, FALSE, FALSE, FALSE); 4088218822Sdim if (fdh != NULL) 4089218822Sdim { 4090218822Sdim fdh->is_func_descriptor = 1; 4091218822Sdim fdh->oh = fh; 4092218822Sdim fh->is_func = 1; 4093218822Sdim fh->oh = fdh; 4094218822Sdim } 4095104834Sobrien } 4096218822Sdim 4097218822Sdim return fdh; 4098104834Sobrien} 4099104834Sobrien 4100218822Sdim/* Make a fake function descriptor sym for the code sym FH. */ 4101130561Sobrien 4102218822Sdimstatic struct ppc_link_hash_entry * 4103218822Sdimmake_fdh (struct bfd_link_info *info, 4104218822Sdim struct ppc_link_hash_entry *fh) 4105218822Sdim{ 4106218822Sdim bfd *abfd; 4107218822Sdim asymbol *newsym; 4108218822Sdim struct bfd_link_hash_entry *bh; 4109218822Sdim struct ppc_link_hash_entry *fdh; 4110218822Sdim 4111218822Sdim abfd = fh->elf.root.u.undef.abfd; 4112218822Sdim newsym = bfd_make_empty_symbol (abfd); 4113218822Sdim newsym->name = fh->elf.root.root.string + 1; 4114218822Sdim newsym->section = bfd_und_section_ptr; 4115218822Sdim newsym->value = 0; 4116218822Sdim newsym->flags = BSF_WEAK; 4117218822Sdim 4118218822Sdim bh = NULL; 4119218822Sdim if (!_bfd_generic_link_add_one_symbol (info, abfd, newsym->name, 4120218822Sdim newsym->flags, newsym->section, 4121218822Sdim newsym->value, NULL, FALSE, FALSE, 4122218822Sdim &bh)) 4123218822Sdim return NULL; 4124218822Sdim 4125218822Sdim fdh = (struct ppc_link_hash_entry *) bh; 4126218822Sdim fdh->elf.non_elf = 0; 4127218822Sdim fdh->fake = 1; 4128218822Sdim fdh->is_func_descriptor = 1; 4129218822Sdim fdh->oh = fh; 4130218822Sdim fh->is_func = 1; 4131218822Sdim fh->oh = fdh; 4132218822Sdim return fdh; 4133218822Sdim} 4134218822Sdim 4135218822Sdim/* Fix function descriptor symbols defined in .opd sections to be 4136218822Sdim function type. */ 4137218822Sdim 4138130561Sobrienstatic bfd_boolean 4139130561Sobrienppc64_elf_add_symbol_hook (bfd *ibfd ATTRIBUTE_UNUSED, 4140130561Sobrien struct bfd_link_info *info ATTRIBUTE_UNUSED, 4141130561Sobrien Elf_Internal_Sym *isym, 4142130561Sobrien const char **name ATTRIBUTE_UNUSED, 4143130561Sobrien flagword *flags ATTRIBUTE_UNUSED, 4144130561Sobrien asection **sec, 4145130561Sobrien bfd_vma *value ATTRIBUTE_UNUSED) 4146130561Sobrien{ 4147218822Sdim if (*sec != NULL 4148218822Sdim && strcmp (bfd_get_section_name (ibfd, *sec), ".opd") == 0) 4149130561Sobrien isym->st_info = ELF_ST_INFO (ELF_ST_BIND (isym->st_info), STT_FUNC); 4150218822Sdim 4151130561Sobrien return TRUE; 4152130561Sobrien} 4153130561Sobrien 4154218822Sdim/* This function makes an old ABI object reference to ".bar" cause the 4155218822Sdim inclusion of a new ABI object archive that defines "bar". 4156218822Sdim NAME is a symbol defined in an archive. Return a symbol in the hash 4157218822Sdim table that might be satisfied by the archive symbols. */ 4158218822Sdim 4159218822Sdimstatic struct elf_link_hash_entry * 4160218822Sdimppc64_elf_archive_symbol_lookup (bfd *abfd, 4161218822Sdim struct bfd_link_info *info, 4162218822Sdim const char *name) 4163218822Sdim{ 4164218822Sdim struct elf_link_hash_entry *h; 4165218822Sdim char *dot_name; 4166218822Sdim size_t len; 4167218822Sdim 4168218822Sdim h = _bfd_elf_archive_symbol_lookup (abfd, info, name); 4169218822Sdim if (h != NULL 4170218822Sdim /* Don't return this sym if it is a fake function descriptor 4171218822Sdim created by add_symbol_adjust. */ 4172218822Sdim && !(h->root.type == bfd_link_hash_undefweak 4173218822Sdim && ((struct ppc_link_hash_entry *) h)->fake)) 4174218822Sdim return h; 4175218822Sdim 4176218822Sdim if (name[0] == '.') 4177218822Sdim return h; 4178218822Sdim 4179218822Sdim len = strlen (name); 4180218822Sdim dot_name = bfd_alloc (abfd, len + 2); 4181218822Sdim if (dot_name == NULL) 4182218822Sdim return (struct elf_link_hash_entry *) 0 - 1; 4183218822Sdim dot_name[0] = '.'; 4184218822Sdim memcpy (dot_name + 1, name, len + 1); 4185218822Sdim h = _bfd_elf_archive_symbol_lookup (abfd, info, dot_name); 4186218822Sdim bfd_release (abfd, dot_name); 4187218822Sdim return h; 4188218822Sdim} 4189218822Sdim 4190218822Sdim/* This function satisfies all old ABI object references to ".bar" if a 4191218822Sdim new ABI object defines "bar". Well, at least, undefined dot symbols 4192218822Sdim are made weak. This stops later archive searches from including an 4193218822Sdim object if we already have a function descriptor definition. It also 4194218822Sdim prevents the linker complaining about undefined symbols. 4195218822Sdim We also check and correct mismatched symbol visibility here. The 4196218822Sdim most restrictive visibility of the function descriptor and the 4197218822Sdim function entry symbol is used. */ 4198218822Sdim 4199130561Sobrienstatic bfd_boolean 4200218822Sdimadd_symbol_adjust (struct ppc_link_hash_entry *eh, struct bfd_link_info *info) 4201218822Sdim{ 4202218822Sdim struct ppc_link_hash_table *htab; 4203218822Sdim struct ppc_link_hash_entry *fdh; 4204218822Sdim 4205218822Sdim if (eh->elf.root.type == bfd_link_hash_indirect) 4206218822Sdim return TRUE; 4207218822Sdim 4208218822Sdim if (eh->elf.root.type == bfd_link_hash_warning) 4209218822Sdim eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link; 4210218822Sdim 4211218822Sdim if (eh->elf.root.root.string[0] != '.') 4212218822Sdim abort (); 4213218822Sdim 4214218822Sdim htab = ppc_hash_table (info); 4215218822Sdim fdh = get_fdh (eh, htab); 4216218822Sdim if (fdh == NULL 4217218822Sdim && !info->relocatable 4218218822Sdim && (eh->elf.root.type == bfd_link_hash_undefined 4219218822Sdim || eh->elf.root.type == bfd_link_hash_undefweak) 4220218822Sdim && eh->elf.ref_regular) 4221218822Sdim { 4222218822Sdim /* Make an undefweak function descriptor sym, which is enough to 4223218822Sdim pull in an --as-needed shared lib, but won't cause link 4224218822Sdim errors. Archives are handled elsewhere. */ 4225218822Sdim fdh = make_fdh (info, eh); 4226218822Sdim if (fdh == NULL) 4227218822Sdim return FALSE; 4228218822Sdim else 4229218822Sdim fdh->elf.ref_regular = 1; 4230218822Sdim } 4231218822Sdim else if (fdh != NULL) 4232218822Sdim { 4233218822Sdim unsigned entry_vis = ELF_ST_VISIBILITY (eh->elf.other) - 1; 4234218822Sdim unsigned descr_vis = ELF_ST_VISIBILITY (fdh->elf.other) - 1; 4235218822Sdim if (entry_vis < descr_vis) 4236218822Sdim fdh->elf.other += entry_vis - descr_vis; 4237218822Sdim else if (entry_vis > descr_vis) 4238218822Sdim eh->elf.other += descr_vis - entry_vis; 4239218822Sdim 4240218822Sdim if ((fdh->elf.root.type == bfd_link_hash_defined 4241218822Sdim || fdh->elf.root.type == bfd_link_hash_defweak) 4242218822Sdim && eh->elf.root.type == bfd_link_hash_undefined) 4243218822Sdim { 4244218822Sdim eh->elf.root.type = bfd_link_hash_undefweak; 4245218822Sdim eh->was_undefined = 1; 4246218822Sdim htab->twiddled_syms = 1; 4247218822Sdim } 4248218822Sdim } 4249218822Sdim 4250218822Sdim return TRUE; 4251218822Sdim} 4252218822Sdim 4253218822Sdim/* Process list of dot-symbols we made in link_hash_newfunc. */ 4254218822Sdim 4255218822Sdimstatic bfd_boolean 4256218822Sdimppc64_elf_check_directives (bfd *ibfd, struct bfd_link_info *info) 4257218822Sdim{ 4258218822Sdim struct ppc_link_hash_table *htab; 4259218822Sdim struct ppc_link_hash_entry **p, *eh; 4260218822Sdim 4261218822Sdim htab = ppc_hash_table (info); 4262218822Sdim if (!is_ppc64_elf_target (htab->elf.root.creator)) 4263218822Sdim return TRUE; 4264218822Sdim 4265218822Sdim if (is_ppc64_elf_target (ibfd->xvec)) 4266218822Sdim { 4267218822Sdim p = &htab->dot_syms; 4268218822Sdim while ((eh = *p) != NULL) 4269218822Sdim { 4270218822Sdim *p = NULL; 4271218822Sdim if (!add_symbol_adjust (eh, info)) 4272218822Sdim return FALSE; 4273218822Sdim p = &eh->u.next_dot_sym; 4274218822Sdim } 4275218822Sdim } 4276218822Sdim 4277218822Sdim /* Clear the list for non-ppc64 input files. */ 4278218822Sdim p = &htab->dot_syms; 4279218822Sdim while ((eh = *p) != NULL) 4280218822Sdim { 4281218822Sdim *p = NULL; 4282218822Sdim p = &eh->u.next_dot_sym; 4283218822Sdim } 4284218822Sdim 4285218822Sdim /* We need to fix the undefs list for any syms we have twiddled to 4286218822Sdim undef_weak. */ 4287218822Sdim if (htab->twiddled_syms) 4288218822Sdim { 4289218822Sdim bfd_link_repair_undef_list (&htab->elf.root); 4290218822Sdim htab->twiddled_syms = 0; 4291218822Sdim } 4292218822Sdim return TRUE; 4293218822Sdim} 4294218822Sdim 4295218822Sdim/* Undo hash table changes when an --as-needed input file is determined 4296218822Sdim not to be needed. */ 4297218822Sdim 4298218822Sdimstatic bfd_boolean 4299218822Sdimppc64_elf_as_needed_cleanup (bfd *ibfd ATTRIBUTE_UNUSED, 4300218822Sdim struct bfd_link_info *info) 4301218822Sdim{ 4302218822Sdim ppc_hash_table (info)->dot_syms = NULL; 4303218822Sdim return TRUE; 4304218822Sdim} 4305218822Sdim 4306218822Sdimstatic bfd_boolean 4307130561Sobrienupdate_local_sym_info (bfd *abfd, Elf_Internal_Shdr *symtab_hdr, 4308130561Sobrien unsigned long r_symndx, bfd_vma r_addend, int tls_type) 4309130561Sobrien{ 4310130561Sobrien struct got_entry **local_got_ents = elf_local_got_ents (abfd); 4311130561Sobrien char *local_got_tls_masks; 4312130561Sobrien 4313130561Sobrien if (local_got_ents == NULL) 4314130561Sobrien { 4315130561Sobrien bfd_size_type size = symtab_hdr->sh_info; 4316130561Sobrien 4317130561Sobrien size *= sizeof (*local_got_ents) + sizeof (*local_got_tls_masks); 4318130561Sobrien local_got_ents = bfd_zalloc (abfd, size); 4319130561Sobrien if (local_got_ents == NULL) 4320130561Sobrien return FALSE; 4321130561Sobrien elf_local_got_ents (abfd) = local_got_ents; 4322130561Sobrien } 4323130561Sobrien 4324130561Sobrien if ((tls_type & TLS_EXPLICIT) == 0) 4325130561Sobrien { 4326130561Sobrien struct got_entry *ent; 4327130561Sobrien 4328130561Sobrien for (ent = local_got_ents[r_symndx]; ent != NULL; ent = ent->next) 4329130561Sobrien if (ent->addend == r_addend 4330130561Sobrien && ent->owner == abfd 4331130561Sobrien && ent->tls_type == tls_type) 4332130561Sobrien break; 4333130561Sobrien if (ent == NULL) 4334130561Sobrien { 4335130561Sobrien bfd_size_type amt = sizeof (*ent); 4336130561Sobrien ent = bfd_alloc (abfd, amt); 4337130561Sobrien if (ent == NULL) 4338130561Sobrien return FALSE; 4339130561Sobrien ent->next = local_got_ents[r_symndx]; 4340130561Sobrien ent->addend = r_addend; 4341130561Sobrien ent->owner = abfd; 4342130561Sobrien ent->tls_type = tls_type; 4343130561Sobrien ent->got.refcount = 0; 4344130561Sobrien local_got_ents[r_symndx] = ent; 4345130561Sobrien } 4346130561Sobrien ent->got.refcount += 1; 4347130561Sobrien } 4348130561Sobrien 4349130561Sobrien local_got_tls_masks = (char *) (local_got_ents + symtab_hdr->sh_info); 4350130561Sobrien local_got_tls_masks[r_symndx] |= tls_type; 4351130561Sobrien return TRUE; 4352130561Sobrien} 4353130561Sobrien 4354130561Sobrienstatic bfd_boolean 4355130561Sobrienupdate_plt_info (bfd *abfd, struct ppc_link_hash_entry *eh, bfd_vma addend) 4356130561Sobrien{ 4357130561Sobrien struct plt_entry *ent; 4358130561Sobrien 4359130561Sobrien for (ent = eh->elf.plt.plist; ent != NULL; ent = ent->next) 4360130561Sobrien if (ent->addend == addend) 4361130561Sobrien break; 4362130561Sobrien if (ent == NULL) 4363130561Sobrien { 4364130561Sobrien bfd_size_type amt = sizeof (*ent); 4365130561Sobrien ent = bfd_alloc (abfd, amt); 4366130561Sobrien if (ent == NULL) 4367130561Sobrien return FALSE; 4368130561Sobrien ent->next = eh->elf.plt.plist; 4369130561Sobrien ent->addend = addend; 4370130561Sobrien ent->plt.refcount = 0; 4371130561Sobrien eh->elf.plt.plist = ent; 4372130561Sobrien } 4373130561Sobrien ent->plt.refcount += 1; 4374218822Sdim eh->elf.needs_plt = 1; 4375218822Sdim if (eh->elf.root.root.string[0] == '.' 4376218822Sdim && eh->elf.root.root.string[1] != '\0') 4377218822Sdim eh->is_func = 1; 4378130561Sobrien return TRUE; 4379130561Sobrien} 4380130561Sobrien 438189857Sobrien/* Look through the relocs for a section during the first phase, and 438289857Sobrien calculate needed space in the global offset table, procedure 438389857Sobrien linkage table, and dynamic reloc sections. */ 438489857Sobrien 4385130561Sobrienstatic bfd_boolean 4386130561Sobrienppc64_elf_check_relocs (bfd *abfd, struct bfd_link_info *info, 4387130561Sobrien asection *sec, const Elf_Internal_Rela *relocs) 438889857Sobrien{ 438989857Sobrien struct ppc_link_hash_table *htab; 439089857Sobrien Elf_Internal_Shdr *symtab_hdr; 439189857Sobrien struct elf_link_hash_entry **sym_hashes, **sym_hashes_end; 439289857Sobrien const Elf_Internal_Rela *rel; 439389857Sobrien const Elf_Internal_Rela *rel_end; 439489857Sobrien asection *sreloc; 4395104834Sobrien asection **opd_sym_map; 439689857Sobrien 4397130561Sobrien if (info->relocatable) 4398130561Sobrien return TRUE; 439989857Sobrien 4400130561Sobrien /* Don't do anything special with non-loaded, non-alloced sections. 4401130561Sobrien In particular, any relocs in such sections should not affect GOT 4402130561Sobrien and PLT reference counting (ie. we don't allow them to create GOT 4403130561Sobrien or PLT entries), there's no possibility or desire to optimize TLS 4404130561Sobrien relocs, and there's not much point in propagating relocs to shared 4405130561Sobrien libs that the dynamic linker won't relocate. */ 4406130561Sobrien if ((sec->flags & SEC_ALLOC) == 0) 4407130561Sobrien return TRUE; 4408130561Sobrien 440989857Sobrien htab = ppc_hash_table (info); 441089857Sobrien symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 441189857Sobrien 441289857Sobrien sym_hashes = elf_sym_hashes (abfd); 441389857Sobrien sym_hashes_end = (sym_hashes 4414104834Sobrien + symtab_hdr->sh_size / sizeof (Elf64_External_Sym) 4415104834Sobrien - symtab_hdr->sh_info); 441689857Sobrien 441789857Sobrien sreloc = NULL; 4418104834Sobrien opd_sym_map = NULL; 4419104834Sobrien if (strcmp (bfd_get_section_name (abfd, sec), ".opd") == 0) 4420104834Sobrien { 4421104834Sobrien /* Garbage collection needs some extra help with .opd sections. 4422104834Sobrien We don't want to necessarily keep everything referenced by 4423104834Sobrien relocs in .opd, as that would keep all functions. Instead, 4424104834Sobrien if we reference an .opd symbol (a function descriptor), we 4425104834Sobrien want to keep the function code symbol's section. This is 4426104834Sobrien easy for global symbols, but for local syms we need to keep 4427104834Sobrien information about the associated function section. Later, if 4428104834Sobrien edit_opd deletes entries, we'll use this array to adjust 4429104834Sobrien local syms in .opd. */ 4430104834Sobrien union opd_info { 4431104834Sobrien asection *func_section; 4432104834Sobrien long entry_adjust; 4433104834Sobrien }; 4434104834Sobrien bfd_size_type amt; 443589857Sobrien 4436218822Sdim amt = sec->size * sizeof (union opd_info) / 8; 4437130561Sobrien opd_sym_map = bfd_zalloc (abfd, amt); 4438104834Sobrien if (opd_sym_map == NULL) 4439130561Sobrien return FALSE; 4440218822Sdim ppc64_elf_section_data (sec)->u.opd_func_sec = opd_sym_map; 4441218822Sdim BFD_ASSERT (ppc64_elf_section_data (sec)->sec_type == sec_normal); 4442218822Sdim ppc64_elf_section_data (sec)->sec_type = sec_opd; 4443104834Sobrien } 4444104834Sobrien 444592828Sobrien if (htab->sfpr == NULL 444692828Sobrien && !create_linkage_sections (htab->elf.dynobj, info)) 4447130561Sobrien return FALSE; 444892828Sobrien 444989857Sobrien rel_end = relocs + sec->reloc_count; 445089857Sobrien for (rel = relocs; rel < rel_end; rel++) 445189857Sobrien { 445289857Sobrien unsigned long r_symndx; 445389857Sobrien struct elf_link_hash_entry *h; 4454130561Sobrien enum elf_ppc64_reloc_type r_type; 4455130561Sobrien int tls_type = 0; 4456218822Sdim struct _ppc64_elf_section_data *ppc64_sec; 445789857Sobrien 445889857Sobrien r_symndx = ELF64_R_SYM (rel->r_info); 445989857Sobrien if (r_symndx < symtab_hdr->sh_info) 446089857Sobrien h = NULL; 446189857Sobrien else 4462218822Sdim { 4463218822Sdim h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 4464218822Sdim while (h->root.type == bfd_link_hash_indirect 4465218822Sdim || h->root.type == bfd_link_hash_warning) 4466218822Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 4467218822Sdim } 446889857Sobrien 4469130561Sobrien r_type = ELF64_R_TYPE (rel->r_info); 447089857Sobrien switch (r_type) 447189857Sobrien { 4472130561Sobrien case R_PPC64_GOT_TLSLD16: 4473130561Sobrien case R_PPC64_GOT_TLSLD16_LO: 4474130561Sobrien case R_PPC64_GOT_TLSLD16_HI: 4475130561Sobrien case R_PPC64_GOT_TLSLD16_HA: 4476130561Sobrien ppc64_tlsld_got (abfd)->refcount += 1; 4477130561Sobrien tls_type = TLS_TLS | TLS_LD; 4478130561Sobrien goto dogottls; 4479130561Sobrien 4480130561Sobrien case R_PPC64_GOT_TLSGD16: 4481130561Sobrien case R_PPC64_GOT_TLSGD16_LO: 4482130561Sobrien case R_PPC64_GOT_TLSGD16_HI: 4483130561Sobrien case R_PPC64_GOT_TLSGD16_HA: 4484130561Sobrien tls_type = TLS_TLS | TLS_GD; 4485130561Sobrien goto dogottls; 4486130561Sobrien 4487130561Sobrien case R_PPC64_GOT_TPREL16_DS: 4488130561Sobrien case R_PPC64_GOT_TPREL16_LO_DS: 4489130561Sobrien case R_PPC64_GOT_TPREL16_HI: 4490130561Sobrien case R_PPC64_GOT_TPREL16_HA: 4491130561Sobrien if (info->shared) 4492130561Sobrien info->flags |= DF_STATIC_TLS; 4493130561Sobrien tls_type = TLS_TLS | TLS_TPREL; 4494130561Sobrien goto dogottls; 4495130561Sobrien 4496130561Sobrien case R_PPC64_GOT_DTPREL16_DS: 4497130561Sobrien case R_PPC64_GOT_DTPREL16_LO_DS: 4498130561Sobrien case R_PPC64_GOT_DTPREL16_HI: 4499130561Sobrien case R_PPC64_GOT_DTPREL16_HA: 4500130561Sobrien tls_type = TLS_TLS | TLS_DTPREL; 4501130561Sobrien dogottls: 4502130561Sobrien sec->has_tls_reloc = 1; 4503130561Sobrien /* Fall thru */ 4504130561Sobrien 450589857Sobrien case R_PPC64_GOT16: 450689857Sobrien case R_PPC64_GOT16_DS: 450789857Sobrien case R_PPC64_GOT16_HA: 450889857Sobrien case R_PPC64_GOT16_HI: 450989857Sobrien case R_PPC64_GOT16_LO: 451089857Sobrien case R_PPC64_GOT16_LO_DS: 451189857Sobrien /* This symbol requires a global offset table entry. */ 4512218822Sdim sec->has_toc_reloc = 1; 4513130561Sobrien if (ppc64_elf_tdata (abfd)->got == NULL 4514130561Sobrien && !create_got_section (abfd, info)) 4515130561Sobrien return FALSE; 451689857Sobrien 451789857Sobrien if (h != NULL) 451889857Sobrien { 4519130561Sobrien struct ppc_link_hash_entry *eh; 4520130561Sobrien struct got_entry *ent; 452189857Sobrien 4522130561Sobrien eh = (struct ppc_link_hash_entry *) h; 4523130561Sobrien for (ent = eh->elf.got.glist; ent != NULL; ent = ent->next) 4524130561Sobrien if (ent->addend == rel->r_addend 4525130561Sobrien && ent->owner == abfd 4526130561Sobrien && ent->tls_type == tls_type) 4527130561Sobrien break; 4528130561Sobrien if (ent == NULL) 452989857Sobrien { 4530130561Sobrien bfd_size_type amt = sizeof (*ent); 4531130561Sobrien ent = bfd_alloc (abfd, amt); 4532130561Sobrien if (ent == NULL) 4533130561Sobrien return FALSE; 4534130561Sobrien ent->next = eh->elf.got.glist; 4535130561Sobrien ent->addend = rel->r_addend; 4536130561Sobrien ent->owner = abfd; 4537130561Sobrien ent->tls_type = tls_type; 4538130561Sobrien ent->got.refcount = 0; 4539130561Sobrien eh->elf.got.glist = ent; 454089857Sobrien } 4541130561Sobrien ent->got.refcount += 1; 4542130561Sobrien eh->tls_mask |= tls_type; 454389857Sobrien } 4544130561Sobrien else 4545130561Sobrien /* This is a global offset table entry for a local symbol. */ 4546130561Sobrien if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, 4547130561Sobrien rel->r_addend, tls_type)) 4548130561Sobrien return FALSE; 454989857Sobrien break; 455089857Sobrien 455189857Sobrien case R_PPC64_PLT16_HA: 455289857Sobrien case R_PPC64_PLT16_HI: 455389857Sobrien case R_PPC64_PLT16_LO: 455489857Sobrien case R_PPC64_PLT32: 455589857Sobrien case R_PPC64_PLT64: 455689857Sobrien /* This symbol requires a procedure linkage table entry. We 4557104834Sobrien actually build the entry in adjust_dynamic_symbol, 4558104834Sobrien because this might be a case of linking PIC code without 4559104834Sobrien linking in any dynamic objects, in which case we don't 4560104834Sobrien need to generate a procedure linkage table after all. */ 456189857Sobrien if (h == NULL) 456289857Sobrien { 456389857Sobrien /* It does not make sense to have a procedure linkage 4564104834Sobrien table entry for a local symbol. */ 456589857Sobrien bfd_set_error (bfd_error_bad_value); 4566130561Sobrien return FALSE; 456789857Sobrien } 4568130561Sobrien else 4569130561Sobrien if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h, 4570130561Sobrien rel->r_addend)) 4571130561Sobrien return FALSE; 457289857Sobrien break; 457389857Sobrien 457489857Sobrien /* The following relocations don't need to propagate the 457589857Sobrien relocation if linking a shared object since they are 457689857Sobrien section relative. */ 457789857Sobrien case R_PPC64_SECTOFF: 457889857Sobrien case R_PPC64_SECTOFF_LO: 457989857Sobrien case R_PPC64_SECTOFF_HI: 458089857Sobrien case R_PPC64_SECTOFF_HA: 458189857Sobrien case R_PPC64_SECTOFF_DS: 458289857Sobrien case R_PPC64_SECTOFF_LO_DS: 4583130561Sobrien case R_PPC64_DTPREL16: 4584130561Sobrien case R_PPC64_DTPREL16_LO: 4585130561Sobrien case R_PPC64_DTPREL16_HI: 4586130561Sobrien case R_PPC64_DTPREL16_HA: 4587130561Sobrien case R_PPC64_DTPREL16_DS: 4588130561Sobrien case R_PPC64_DTPREL16_LO_DS: 4589130561Sobrien case R_PPC64_DTPREL16_HIGHER: 4590130561Sobrien case R_PPC64_DTPREL16_HIGHERA: 4591130561Sobrien case R_PPC64_DTPREL16_HIGHEST: 4592130561Sobrien case R_PPC64_DTPREL16_HIGHESTA: 4593130561Sobrien break; 4594130561Sobrien 4595130561Sobrien /* Nor do these. */ 459689857Sobrien case R_PPC64_TOC16: 459789857Sobrien case R_PPC64_TOC16_LO: 459889857Sobrien case R_PPC64_TOC16_HI: 459989857Sobrien case R_PPC64_TOC16_HA: 460089857Sobrien case R_PPC64_TOC16_DS: 460189857Sobrien case R_PPC64_TOC16_LO_DS: 4602218822Sdim sec->has_toc_reloc = 1; 460389857Sobrien break; 460489857Sobrien 460589857Sobrien /* This relocation describes the C++ object vtable hierarchy. 460689857Sobrien Reconstruct it for later use during GC. */ 460789857Sobrien case R_PPC64_GNU_VTINHERIT: 4608130561Sobrien if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) 4609130561Sobrien return FALSE; 461089857Sobrien break; 461189857Sobrien 461289857Sobrien /* This relocation describes which C++ vtable entries are actually 461389857Sobrien used. Record for later use during GC. */ 461489857Sobrien case R_PPC64_GNU_VTENTRY: 4615130561Sobrien if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) 4616130561Sobrien return FALSE; 461789857Sobrien break; 461889857Sobrien 4619104834Sobrien case R_PPC64_REL14: 4620104834Sobrien case R_PPC64_REL14_BRTAKEN: 4621104834Sobrien case R_PPC64_REL14_BRNTAKEN: 4622218822Sdim { 4623218822Sdim asection *dest = NULL; 4624218822Sdim 4625218822Sdim /* Heuristic: If jumping outside our section, chances are 4626218822Sdim we are going to need a stub. */ 4627218822Sdim if (h != NULL) 4628218822Sdim { 4629218822Sdim /* If the sym is weak it may be overridden later, so 4630218822Sdim don't assume we know where a weak sym lives. */ 4631218822Sdim if (h->root.type == bfd_link_hash_defined) 4632218822Sdim dest = h->root.u.def.section; 4633218822Sdim } 4634218822Sdim else 4635218822Sdim dest = bfd_section_from_r_symndx (abfd, &htab->sym_sec, 4636218822Sdim sec, r_symndx); 4637218822Sdim if (dest != sec) 4638218822Sdim ppc64_elf_section_data (sec)->has_14bit_branch = 1; 4639218822Sdim } 4640104834Sobrien /* Fall through. */ 4641104834Sobrien 464289857Sobrien case R_PPC64_REL24: 4643218822Sdim if (h != NULL) 464489857Sobrien { 464589857Sobrien /* We may need a .plt entry if the function this reloc 464689857Sobrien refers to is in a shared lib. */ 4647130561Sobrien if (!update_plt_info (abfd, (struct ppc_link_hash_entry *) h, 4648130561Sobrien rel->r_addend)) 4649130561Sobrien return FALSE; 4650218822Sdim if (h == &htab->tls_get_addr->elf 4651218822Sdim || h == &htab->tls_get_addr_fd->elf) 4652130561Sobrien sec->has_tls_reloc = 1; 4653218822Sdim else if (htab->tls_get_addr == NULL 4654218822Sdim && CONST_STRNEQ (h->root.root.string, ".__tls_get_addr") 4655130561Sobrien && (h->root.root.string[15] == 0 4656130561Sobrien || h->root.root.string[15] == '@')) 4657130561Sobrien { 4658218822Sdim htab->tls_get_addr = (struct ppc_link_hash_entry *) h; 4659130561Sobrien sec->has_tls_reloc = 1; 4660130561Sobrien } 4661218822Sdim else if (htab->tls_get_addr_fd == NULL 4662218822Sdim && CONST_STRNEQ (h->root.root.string, "__tls_get_addr") 4663218822Sdim && (h->root.root.string[14] == 0 4664218822Sdim || h->root.root.string[14] == '@')) 4665218822Sdim { 4666218822Sdim htab->tls_get_addr_fd = (struct ppc_link_hash_entry *) h; 4667218822Sdim sec->has_tls_reloc = 1; 4668218822Sdim } 466989857Sobrien } 467089857Sobrien break; 467189857Sobrien 4672130561Sobrien case R_PPC64_TPREL64: 4673130561Sobrien tls_type = TLS_EXPLICIT | TLS_TLS | TLS_TPREL; 4674130561Sobrien if (info->shared) 4675130561Sobrien info->flags |= DF_STATIC_TLS; 4676130561Sobrien goto dotlstoc; 4677130561Sobrien 4678130561Sobrien case R_PPC64_DTPMOD64: 4679130561Sobrien if (rel + 1 < rel_end 4680130561Sobrien && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64) 4681130561Sobrien && rel[1].r_offset == rel->r_offset + 8) 4682130561Sobrien tls_type = TLS_EXPLICIT | TLS_TLS | TLS_GD; 4683130561Sobrien else 4684130561Sobrien tls_type = TLS_EXPLICIT | TLS_TLS | TLS_LD; 4685130561Sobrien goto dotlstoc; 4686130561Sobrien 4687130561Sobrien case R_PPC64_DTPREL64: 4688130561Sobrien tls_type = TLS_EXPLICIT | TLS_TLS | TLS_DTPREL; 4689130561Sobrien if (rel != relocs 4690130561Sobrien && rel[-1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPMOD64) 4691130561Sobrien && rel[-1].r_offset == rel->r_offset - 8) 4692130561Sobrien /* This is the second reloc of a dtpmod, dtprel pair. 4693130561Sobrien Don't mark with TLS_DTPREL. */ 4694130561Sobrien goto dodyn; 4695130561Sobrien 4696130561Sobrien dotlstoc: 4697130561Sobrien sec->has_tls_reloc = 1; 4698130561Sobrien if (h != NULL) 4699130561Sobrien { 4700130561Sobrien struct ppc_link_hash_entry *eh; 4701130561Sobrien eh = (struct ppc_link_hash_entry *) h; 4702130561Sobrien eh->tls_mask |= tls_type; 4703130561Sobrien } 4704130561Sobrien else 4705130561Sobrien if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, 4706130561Sobrien rel->r_addend, tls_type)) 4707130561Sobrien return FALSE; 4708130561Sobrien 4709218822Sdim ppc64_sec = ppc64_elf_section_data (sec); 4710218822Sdim if (ppc64_sec->sec_type != sec_toc) 4711130561Sobrien { 4712130561Sobrien /* One extra to simplify get_tls_mask. */ 4713218822Sdim bfd_size_type amt = sec->size * sizeof (unsigned) / 8 + 1; 4714218822Sdim ppc64_sec->u.t_symndx = bfd_zalloc (abfd, amt); 4715218822Sdim if (ppc64_sec->u.t_symndx == NULL) 4716130561Sobrien return FALSE; 4717218822Sdim BFD_ASSERT (ppc64_sec->sec_type == sec_normal); 4718218822Sdim ppc64_sec->sec_type = sec_toc; 4719130561Sobrien } 4720130561Sobrien BFD_ASSERT (rel->r_offset % 8 == 0); 4721218822Sdim ppc64_sec->u.t_symndx[rel->r_offset / 8] = r_symndx; 4722130561Sobrien 4723130561Sobrien /* Mark the second slot of a GD or LD entry. 4724130561Sobrien -1 to indicate GD and -2 to indicate LD. */ 4725130561Sobrien if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_GD)) 4726218822Sdim ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -1; 4727130561Sobrien else if (tls_type == (TLS_EXPLICIT | TLS_TLS | TLS_LD)) 4728218822Sdim ppc64_sec->u.t_symndx[rel->r_offset / 8 + 1] = -2; 4729130561Sobrien goto dodyn; 4730130561Sobrien 4731130561Sobrien case R_PPC64_TPREL16: 4732130561Sobrien case R_PPC64_TPREL16_LO: 4733130561Sobrien case R_PPC64_TPREL16_HI: 4734130561Sobrien case R_PPC64_TPREL16_HA: 4735130561Sobrien case R_PPC64_TPREL16_DS: 4736130561Sobrien case R_PPC64_TPREL16_LO_DS: 4737130561Sobrien case R_PPC64_TPREL16_HIGHER: 4738130561Sobrien case R_PPC64_TPREL16_HIGHERA: 4739130561Sobrien case R_PPC64_TPREL16_HIGHEST: 4740130561Sobrien case R_PPC64_TPREL16_HIGHESTA: 4741130561Sobrien if (info->shared) 4742130561Sobrien { 4743130561Sobrien info->flags |= DF_STATIC_TLS; 4744130561Sobrien goto dodyn; 4745130561Sobrien } 4746130561Sobrien break; 4747130561Sobrien 474889857Sobrien case R_PPC64_ADDR64: 4749104834Sobrien if (opd_sym_map != NULL 4750104834Sobrien && rel + 1 < rel_end 4751130561Sobrien && ELF64_R_TYPE ((rel + 1)->r_info) == R_PPC64_TOC) 4752104834Sobrien { 4753218822Sdim if (h != NULL) 4754218822Sdim { 4755218822Sdim if (h->root.root.string[0] == '.' 4756218822Sdim && h->root.root.string[1] != 0 4757218822Sdim && get_fdh ((struct ppc_link_hash_entry *) h, htab)) 4758218822Sdim ; 4759218822Sdim else 4760218822Sdim ((struct ppc_link_hash_entry *) h)->is_func = 1; 4761218822Sdim } 4762218822Sdim else 4763218822Sdim { 4764218822Sdim asection *s; 4765104834Sobrien 4766218822Sdim s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec, 4767218822Sdim r_symndx); 4768218822Sdim if (s == NULL) 4769218822Sdim return FALSE; 4770218822Sdim else if (s != sec) 4771218822Sdim opd_sym_map[rel->r_offset / 8] = s; 4772218822Sdim } 4773104834Sobrien } 477489857Sobrien /* Fall through. */ 477589857Sobrien 4776130561Sobrien case R_PPC64_REL30: 4777130561Sobrien case R_PPC64_REL32: 477889857Sobrien case R_PPC64_REL64: 477989857Sobrien case R_PPC64_ADDR14: 478089857Sobrien case R_PPC64_ADDR14_BRNTAKEN: 478189857Sobrien case R_PPC64_ADDR14_BRTAKEN: 478289857Sobrien case R_PPC64_ADDR16: 478389857Sobrien case R_PPC64_ADDR16_DS: 478489857Sobrien case R_PPC64_ADDR16_HA: 478589857Sobrien case R_PPC64_ADDR16_HI: 478689857Sobrien case R_PPC64_ADDR16_HIGHER: 478789857Sobrien case R_PPC64_ADDR16_HIGHERA: 478889857Sobrien case R_PPC64_ADDR16_HIGHEST: 478989857Sobrien case R_PPC64_ADDR16_HIGHESTA: 479089857Sobrien case R_PPC64_ADDR16_LO: 479189857Sobrien case R_PPC64_ADDR16_LO_DS: 479289857Sobrien case R_PPC64_ADDR24: 479389857Sobrien case R_PPC64_ADDR32: 479489857Sobrien case R_PPC64_UADDR16: 479589857Sobrien case R_PPC64_UADDR32: 479689857Sobrien case R_PPC64_UADDR64: 479789857Sobrien case R_PPC64_TOC: 4798130561Sobrien if (h != NULL && !info->shared) 4799130561Sobrien /* We may need a copy reloc. */ 4800218822Sdim h->non_got_ref = 1; 4801130561Sobrien 480289857Sobrien /* Don't propagate .opd relocs. */ 4803104834Sobrien if (NO_OPD_RELOCS && opd_sym_map != NULL) 480489857Sobrien break; 480589857Sobrien 480689857Sobrien /* If we are creating a shared library, and this is a reloc 480789857Sobrien against a global symbol, or a non PC relative reloc 480889857Sobrien against a local symbol, then we need to copy the reloc 480989857Sobrien into the shared library. However, if we are linking with 481089857Sobrien -Bsymbolic, we do not need to copy a reloc against a 481189857Sobrien global symbol which is defined in an object we are 481289857Sobrien including in the link (i.e., DEF_REGULAR is set). At 481389857Sobrien this point we have not seen all the input files, so it is 481489857Sobrien possible that DEF_REGULAR is not set now but will be set 481589857Sobrien later (it is never cleared). In case of a weak definition, 481689857Sobrien DEF_REGULAR may be cleared later by a strong definition in 481789857Sobrien a shared library. We account for that possibility below by 4818130561Sobrien storing information in the dyn_relocs field of the hash 481989857Sobrien table entry. A similar situation occurs when creating 482089857Sobrien shared libraries and symbol visibility changes render the 482189857Sobrien symbol local. 482289857Sobrien 482389857Sobrien If on the other hand, we are creating an executable, we 482489857Sobrien may need to keep relocations for symbols satisfied by a 482589857Sobrien dynamic library if we manage to avoid copy relocs for the 482689857Sobrien symbol. */ 4827130561Sobrien dodyn: 482889857Sobrien if ((info->shared 4829130561Sobrien && (MUST_BE_DYN_RELOC (r_type) 483089857Sobrien || (h != NULL 483189857Sobrien && (! info->symbolic 483289857Sobrien || h->root.type == bfd_link_hash_defweak 4833218822Sdim || !h->def_regular)))) 4834130561Sobrien || (ELIMINATE_COPY_RELOCS 4835130561Sobrien && !info->shared 483689857Sobrien && h != NULL 483789857Sobrien && (h->root.type == bfd_link_hash_defweak 4838218822Sdim || !h->def_regular))) 483989857Sobrien { 484089857Sobrien struct ppc_dyn_relocs *p; 484189857Sobrien struct ppc_dyn_relocs **head; 484289857Sobrien 484389857Sobrien /* We must copy these reloc types into the output file. 484489857Sobrien Create a reloc section in dynobj and make room for 484589857Sobrien this reloc. */ 484689857Sobrien if (sreloc == NULL) 484789857Sobrien { 484889857Sobrien const char *name; 484989857Sobrien bfd *dynobj; 485089857Sobrien 485189857Sobrien name = (bfd_elf_string_from_elf_section 485289857Sobrien (abfd, 485389857Sobrien elf_elfheader (abfd)->e_shstrndx, 485489857Sobrien elf_section_data (sec)->rel_hdr.sh_name)); 485589857Sobrien if (name == NULL) 4856130561Sobrien return FALSE; 485789857Sobrien 4858218822Sdim if (! CONST_STRNEQ (name, ".rela") 485989857Sobrien || strcmp (bfd_get_section_name (abfd, sec), 486089857Sobrien name + 5) != 0) 486189857Sobrien { 486289857Sobrien (*_bfd_error_handler) 4863218822Sdim (_("%B: bad relocation section name `%s\'"), 4864218822Sdim abfd, name); 486589857Sobrien bfd_set_error (bfd_error_bad_value); 486689857Sobrien } 486789857Sobrien 486889857Sobrien dynobj = htab->elf.dynobj; 486989857Sobrien sreloc = bfd_get_section_by_name (dynobj, name); 487089857Sobrien if (sreloc == NULL) 487189857Sobrien { 487289857Sobrien flagword flags; 487389857Sobrien 487489857Sobrien flags = (SEC_HAS_CONTENTS | SEC_READONLY 4875218822Sdim | SEC_IN_MEMORY | SEC_LINKER_CREATED 4876218822Sdim | SEC_ALLOC | SEC_LOAD); 4877218822Sdim sreloc = bfd_make_section_with_flags (dynobj, 4878218822Sdim name, 4879218822Sdim flags); 488089857Sobrien if (sreloc == NULL 488189857Sobrien || ! bfd_set_section_alignment (dynobj, sreloc, 3)) 4882130561Sobrien return FALSE; 488389857Sobrien } 488489857Sobrien elf_section_data (sec)->sreloc = sreloc; 488589857Sobrien } 488689857Sobrien 488789857Sobrien /* If this is a global symbol, we count the number of 488889857Sobrien relocations we need for this symbol. */ 488989857Sobrien if (h != NULL) 489089857Sobrien { 489189857Sobrien head = &((struct ppc_link_hash_entry *) h)->dyn_relocs; 489289857Sobrien } 489389857Sobrien else 489489857Sobrien { 489589857Sobrien /* Track dynamic relocs needed for local syms too. 489689857Sobrien We really need local syms available to do this 489789857Sobrien easily. Oh well. */ 489889857Sobrien 489989857Sobrien asection *s; 4900218822Sdim void *vpp; 4901218822Sdim 490289857Sobrien s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, 490389857Sobrien sec, r_symndx); 490489857Sobrien if (s == NULL) 4905130561Sobrien return FALSE; 490689857Sobrien 4907218822Sdim vpp = &elf_section_data (s)->local_dynrel; 4908218822Sdim head = (struct ppc_dyn_relocs **) vpp; 490989857Sobrien } 491089857Sobrien 491189857Sobrien p = *head; 491289857Sobrien if (p == NULL || p->sec != sec) 491389857Sobrien { 4914130561Sobrien p = bfd_alloc (htab->elf.dynobj, sizeof *p); 491589857Sobrien if (p == NULL) 4916130561Sobrien return FALSE; 491789857Sobrien p->next = *head; 491889857Sobrien *head = p; 491989857Sobrien p->sec = sec; 492089857Sobrien p->count = 0; 492189857Sobrien p->pc_count = 0; 492289857Sobrien } 492389857Sobrien 492489857Sobrien p->count += 1; 4925130561Sobrien if (!MUST_BE_DYN_RELOC (r_type)) 492689857Sobrien p->pc_count += 1; 492789857Sobrien } 492889857Sobrien break; 492989857Sobrien 493089857Sobrien default: 493192828Sobrien break; 493289857Sobrien } 493389857Sobrien } 493489857Sobrien 4935130561Sobrien return TRUE; 493689857Sobrien} 493789857Sobrien 4938218822Sdim/* OFFSET in OPD_SEC specifies a function descriptor. Return the address 4939218822Sdim of the code entry point, and its section. */ 4940218822Sdim 4941218822Sdimstatic bfd_vma 4942218822Sdimopd_entry_value (asection *opd_sec, 4943218822Sdim bfd_vma offset, 4944218822Sdim asection **code_sec, 4945218822Sdim bfd_vma *code_off) 4946218822Sdim{ 4947218822Sdim bfd *opd_bfd = opd_sec->owner; 4948218822Sdim Elf_Internal_Rela *relocs; 4949218822Sdim Elf_Internal_Rela *lo, *hi, *look; 4950218822Sdim bfd_vma val; 4951218822Sdim 4952218822Sdim /* No relocs implies we are linking a --just-symbols object. */ 4953218822Sdim if (opd_sec->reloc_count == 0) 4954218822Sdim { 4955218822Sdim bfd_vma val; 4956218822Sdim 4957218822Sdim if (!bfd_get_section_contents (opd_bfd, opd_sec, &val, offset, 8)) 4958218822Sdim return (bfd_vma) -1; 4959218822Sdim 4960218822Sdim if (code_sec != NULL) 4961218822Sdim { 4962218822Sdim asection *sec, *likely = NULL; 4963218822Sdim for (sec = opd_bfd->sections; sec != NULL; sec = sec->next) 4964218822Sdim if (sec->vma <= val 4965218822Sdim && (sec->flags & SEC_LOAD) != 0 4966218822Sdim && (sec->flags & SEC_ALLOC) != 0) 4967218822Sdim likely = sec; 4968218822Sdim if (likely != NULL) 4969218822Sdim { 4970218822Sdim *code_sec = likely; 4971218822Sdim if (code_off != NULL) 4972218822Sdim *code_off = val - likely->vma; 4973218822Sdim } 4974218822Sdim } 4975218822Sdim return val; 4976218822Sdim } 4977218822Sdim 4978218822Sdim relocs = ppc64_elf_tdata (opd_bfd)->opd_relocs; 4979218822Sdim if (relocs == NULL) 4980218822Sdim relocs = _bfd_elf_link_read_relocs (opd_bfd, opd_sec, NULL, NULL, TRUE); 4981218822Sdim 4982218822Sdim /* Go find the opd reloc at the sym address. */ 4983218822Sdim lo = relocs; 4984218822Sdim BFD_ASSERT (lo != NULL); 4985218822Sdim hi = lo + opd_sec->reloc_count - 1; /* ignore last reloc */ 4986218822Sdim val = (bfd_vma) -1; 4987218822Sdim while (lo < hi) 4988218822Sdim { 4989218822Sdim look = lo + (hi - lo) / 2; 4990218822Sdim if (look->r_offset < offset) 4991218822Sdim lo = look + 1; 4992218822Sdim else if (look->r_offset > offset) 4993218822Sdim hi = look; 4994218822Sdim else 4995218822Sdim { 4996218822Sdim Elf_Internal_Shdr *symtab_hdr = &elf_tdata (opd_bfd)->symtab_hdr; 4997218822Sdim if (ELF64_R_TYPE (look->r_info) == R_PPC64_ADDR64 4998218822Sdim && ELF64_R_TYPE ((look + 1)->r_info) == R_PPC64_TOC) 4999218822Sdim { 5000218822Sdim unsigned long symndx = ELF64_R_SYM (look->r_info); 5001218822Sdim asection *sec; 5002218822Sdim 5003218822Sdim if (symndx < symtab_hdr->sh_info) 5004218822Sdim { 5005218822Sdim Elf_Internal_Sym *sym; 5006218822Sdim 5007218822Sdim sym = (Elf_Internal_Sym *) symtab_hdr->contents; 5008218822Sdim if (sym == NULL) 5009218822Sdim { 5010218822Sdim sym = bfd_elf_get_elf_syms (opd_bfd, symtab_hdr, 5011218822Sdim symtab_hdr->sh_info, 5012218822Sdim 0, NULL, NULL, NULL); 5013218822Sdim if (sym == NULL) 5014218822Sdim break; 5015218822Sdim symtab_hdr->contents = (bfd_byte *) sym; 5016218822Sdim } 5017218822Sdim 5018218822Sdim sym += symndx; 5019218822Sdim val = sym->st_value; 5020218822Sdim sec = NULL; 5021218822Sdim if ((sym->st_shndx != SHN_UNDEF 5022218822Sdim && sym->st_shndx < SHN_LORESERVE) 5023218822Sdim || sym->st_shndx > SHN_HIRESERVE) 5024218822Sdim sec = bfd_section_from_elf_index (opd_bfd, sym->st_shndx); 5025218822Sdim BFD_ASSERT ((sec->flags & SEC_MERGE) == 0); 5026218822Sdim } 5027218822Sdim else 5028218822Sdim { 5029218822Sdim struct elf_link_hash_entry **sym_hashes; 5030218822Sdim struct elf_link_hash_entry *rh; 5031218822Sdim 5032218822Sdim sym_hashes = elf_sym_hashes (opd_bfd); 5033218822Sdim rh = sym_hashes[symndx - symtab_hdr->sh_info]; 5034218822Sdim while (rh->root.type == bfd_link_hash_indirect 5035218822Sdim || rh->root.type == bfd_link_hash_warning) 5036218822Sdim rh = ((struct elf_link_hash_entry *) rh->root.u.i.link); 5037218822Sdim BFD_ASSERT (rh->root.type == bfd_link_hash_defined 5038218822Sdim || rh->root.type == bfd_link_hash_defweak); 5039218822Sdim val = rh->root.u.def.value; 5040218822Sdim sec = rh->root.u.def.section; 5041218822Sdim } 5042218822Sdim val += look->r_addend; 5043218822Sdim if (code_off != NULL) 5044218822Sdim *code_off = val; 5045218822Sdim if (code_sec != NULL) 5046218822Sdim *code_sec = sec; 5047218822Sdim if (sec != NULL && sec->output_section != NULL) 5048218822Sdim val += sec->output_section->vma + sec->output_offset; 5049218822Sdim } 5050218822Sdim break; 5051218822Sdim } 5052218822Sdim } 5053218822Sdim 5054218822Sdim return val; 5055218822Sdim} 5056218822Sdim 5057218822Sdim/* Mark sections containing dynamically referenced symbols. When 5058218822Sdim building shared libraries, we must assume that any visible symbol is 5059218822Sdim referenced. */ 5060218822Sdim 5061218822Sdimstatic bfd_boolean 5062218822Sdimppc64_elf_gc_mark_dynamic_ref (struct elf_link_hash_entry *h, void *inf) 5063218822Sdim{ 5064218822Sdim struct bfd_link_info *info = (struct bfd_link_info *) inf; 5065218822Sdim struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h; 5066218822Sdim 5067218822Sdim if (eh->elf.root.type == bfd_link_hash_warning) 5068218822Sdim eh = (struct ppc_link_hash_entry *) eh->elf.root.u.i.link; 5069218822Sdim 5070218822Sdim /* Dynamic linking info is on the func descriptor sym. */ 5071218822Sdim if (eh->oh != NULL 5072218822Sdim && eh->oh->is_func_descriptor 5073218822Sdim && (eh->oh->elf.root.type == bfd_link_hash_defined 5074218822Sdim || eh->oh->elf.root.type == bfd_link_hash_defweak)) 5075218822Sdim eh = eh->oh; 5076218822Sdim 5077218822Sdim if ((eh->elf.root.type == bfd_link_hash_defined 5078218822Sdim || eh->elf.root.type == bfd_link_hash_defweak) 5079218822Sdim && (eh->elf.ref_dynamic 5080218822Sdim || (!info->executable 5081218822Sdim && eh->elf.def_regular 5082218822Sdim && ELF_ST_VISIBILITY (eh->elf.other) != STV_INTERNAL 5083218822Sdim && ELF_ST_VISIBILITY (eh->elf.other) != STV_HIDDEN))) 5084218822Sdim { 5085218822Sdim asection *code_sec; 5086218822Sdim 5087218822Sdim eh->elf.root.u.def.section->flags |= SEC_KEEP; 5088218822Sdim 5089218822Sdim /* Function descriptor syms cause the associated 5090218822Sdim function code sym section to be marked. */ 5091218822Sdim if (eh->is_func_descriptor 5092218822Sdim && (eh->oh->elf.root.type == bfd_link_hash_defined 5093218822Sdim || eh->oh->elf.root.type == bfd_link_hash_defweak)) 5094218822Sdim eh->oh->elf.root.u.def.section->flags |= SEC_KEEP; 5095218822Sdim else if (get_opd_info (eh->elf.root.u.def.section) != NULL 5096218822Sdim && opd_entry_value (eh->elf.root.u.def.section, 5097218822Sdim eh->elf.root.u.def.value, 5098218822Sdim &code_sec, NULL) != (bfd_vma) -1) 5099218822Sdim code_sec->flags |= SEC_KEEP; 5100218822Sdim } 5101218822Sdim 5102218822Sdim return TRUE; 5103218822Sdim} 5104218822Sdim 510589857Sobrien/* Return the section that should be marked against GC for a given 510689857Sobrien relocation. */ 510789857Sobrien 510889857Sobrienstatic asection * 5109130561Sobrienppc64_elf_gc_mark_hook (asection *sec, 5110218822Sdim struct bfd_link_info *info, 5111130561Sobrien Elf_Internal_Rela *rel, 5112130561Sobrien struct elf_link_hash_entry *h, 5113130561Sobrien Elf_Internal_Sym *sym) 511489857Sobrien{ 5115218822Sdim asection *rsec; 5116104834Sobrien 5117218822Sdim /* First mark all our entry sym sections. */ 5118218822Sdim if (info->gc_sym_list != NULL) 5119218822Sdim { 5120218822Sdim struct ppc_link_hash_table *htab = ppc_hash_table (info); 5121218822Sdim struct bfd_sym_chain *sym = info->gc_sym_list; 5122218822Sdim 5123218822Sdim info->gc_sym_list = NULL; 5124218822Sdim for (; sym != NULL; sym = sym->next) 5125218822Sdim { 5126218822Sdim struct ppc_link_hash_entry *eh; 5127218822Sdim 5128218822Sdim eh = (struct ppc_link_hash_entry *) 5129218822Sdim elf_link_hash_lookup (&htab->elf, sym->name, FALSE, FALSE, FALSE); 5130218822Sdim if (eh == NULL) 5131218822Sdim continue; 5132218822Sdim if (eh->elf.root.type != bfd_link_hash_defined 5133218822Sdim && eh->elf.root.type != bfd_link_hash_defweak) 5134218822Sdim continue; 5135218822Sdim 5136218822Sdim if (eh->is_func_descriptor 5137218822Sdim && (eh->oh->elf.root.type == bfd_link_hash_defined 5138218822Sdim || eh->oh->elf.root.type == bfd_link_hash_defweak)) 5139218822Sdim rsec = eh->oh->elf.root.u.def.section; 5140218822Sdim else if (get_opd_info (eh->elf.root.u.def.section) != NULL 5141218822Sdim && opd_entry_value (eh->elf.root.u.def.section, 5142218822Sdim eh->elf.root.u.def.value, 5143218822Sdim &rsec, NULL) != (bfd_vma) -1) 5144218822Sdim ; 5145218822Sdim else 5146218822Sdim continue; 5147218822Sdim 5148218822Sdim if (!rsec->gc_mark) 5149218822Sdim _bfd_elf_gc_mark (info, rsec, ppc64_elf_gc_mark_hook); 5150218822Sdim 5151218822Sdim rsec = eh->elf.root.u.def.section; 5152218822Sdim if (!rsec->gc_mark) 5153218822Sdim _bfd_elf_gc_mark (info, rsec, ppc64_elf_gc_mark_hook); 5154218822Sdim } 5155218822Sdim } 5156218822Sdim 5157218822Sdim /* Syms return NULL if we're marking .opd, so we avoid marking all 5158218822Sdim function sections, as all functions are referenced in .opd. */ 5159218822Sdim rsec = NULL; 5160218822Sdim if (get_opd_info (sec) != NULL) 5161218822Sdim return rsec; 5162218822Sdim 516389857Sobrien if (h != NULL) 516489857Sobrien { 5165130561Sobrien enum elf_ppc64_reloc_type r_type; 5166218822Sdim struct ppc_link_hash_entry *eh; 516789857Sobrien 5168130561Sobrien r_type = ELF64_R_TYPE (rel->r_info); 516989857Sobrien switch (r_type) 517089857Sobrien { 517189857Sobrien case R_PPC64_GNU_VTINHERIT: 517289857Sobrien case R_PPC64_GNU_VTENTRY: 517389857Sobrien break; 517489857Sobrien 517589857Sobrien default: 517689857Sobrien switch (h->root.type) 517789857Sobrien { 517889857Sobrien case bfd_link_hash_defined: 517989857Sobrien case bfd_link_hash_defweak: 5180218822Sdim eh = (struct ppc_link_hash_entry *) h; 5181218822Sdim if (eh->oh != NULL 5182218822Sdim && eh->oh->is_func_descriptor 5183218822Sdim && (eh->oh->elf.root.type == bfd_link_hash_defined 5184218822Sdim || eh->oh->elf.root.type == bfd_link_hash_defweak)) 5185218822Sdim eh = eh->oh; 518689857Sobrien 5187104834Sobrien /* Function descriptor syms cause the associated 5188104834Sobrien function code sym section to be marked. */ 5189218822Sdim if (eh->is_func_descriptor 5190218822Sdim && (eh->oh->elf.root.type == bfd_link_hash_defined 5191218822Sdim || eh->oh->elf.root.type == bfd_link_hash_defweak)) 5192218822Sdim { 5193218822Sdim /* They also mark their opd section. */ 5194218822Sdim if (!eh->elf.root.u.def.section->gc_mark) 5195218822Sdim _bfd_elf_gc_mark (info, eh->elf.root.u.def.section, 5196218822Sdim ppc64_elf_gc_mark_hook); 5197104834Sobrien 5198218822Sdim rsec = eh->oh->elf.root.u.def.section; 5199218822Sdim } 5200218822Sdim else if (get_opd_info (eh->elf.root.u.def.section) != NULL 5201218822Sdim && opd_entry_value (eh->elf.root.u.def.section, 5202218822Sdim eh->elf.root.u.def.value, 5203218822Sdim &rsec, NULL) != (bfd_vma) -1) 5204218822Sdim { 5205218822Sdim if (!eh->elf.root.u.def.section->gc_mark) 5206218822Sdim _bfd_elf_gc_mark (info, eh->elf.root.u.def.section, 5207218822Sdim ppc64_elf_gc_mark_hook); 5208218822Sdim } 5209218822Sdim else 5210104834Sobrien rsec = h->root.u.def.section; 5211104834Sobrien break; 5212104834Sobrien 521389857Sobrien case bfd_link_hash_common: 5214104834Sobrien rsec = h->root.u.c.p->section; 5215104834Sobrien break; 521689857Sobrien 521789857Sobrien default: 521889857Sobrien break; 521989857Sobrien } 522089857Sobrien } 522189857Sobrien } 522289857Sobrien else 522389857Sobrien { 5224104834Sobrien asection **opd_sym_section; 5225104834Sobrien 5226104834Sobrien rsec = bfd_section_from_elf_index (sec->owner, sym->st_shndx); 5227218822Sdim opd_sym_section = get_opd_info (rsec); 5228104834Sobrien if (opd_sym_section != NULL) 5229218822Sdim { 5230218822Sdim if (!rsec->gc_mark) 5231218822Sdim _bfd_elf_gc_mark (info, rsec, ppc64_elf_gc_mark_hook); 5232218822Sdim 5233218822Sdim rsec = opd_sym_section[(sym->st_value + rel->r_addend) / 8]; 5234218822Sdim } 523589857Sobrien } 523689857Sobrien 5237104834Sobrien return rsec; 523889857Sobrien} 523989857Sobrien 524089857Sobrien/* Update the .got, .plt. and dynamic reloc reference counts for the 524189857Sobrien section being removed. */ 524289857Sobrien 5243130561Sobrienstatic bfd_boolean 5244130561Sobrienppc64_elf_gc_sweep_hook (bfd *abfd, struct bfd_link_info *info, 5245130561Sobrien asection *sec, const Elf_Internal_Rela *relocs) 524689857Sobrien{ 5247130561Sobrien struct ppc_link_hash_table *htab; 524889857Sobrien Elf_Internal_Shdr *symtab_hdr; 524989857Sobrien struct elf_link_hash_entry **sym_hashes; 5250130561Sobrien struct got_entry **local_got_ents; 525189857Sobrien const Elf_Internal_Rela *rel, *relend; 525289857Sobrien 5253130561Sobrien if ((sec->flags & SEC_ALLOC) == 0) 5254130561Sobrien return TRUE; 5255130561Sobrien 525689857Sobrien elf_section_data (sec)->local_dynrel = NULL; 525789857Sobrien 5258130561Sobrien htab = ppc_hash_table (info); 525989857Sobrien symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 526089857Sobrien sym_hashes = elf_sym_hashes (abfd); 5261130561Sobrien local_got_ents = elf_local_got_ents (abfd); 526289857Sobrien 526389857Sobrien relend = relocs + sec->reloc_count; 526489857Sobrien for (rel = relocs; rel < relend; rel++) 526589857Sobrien { 526689857Sobrien unsigned long r_symndx; 5267130561Sobrien enum elf_ppc64_reloc_type r_type; 5268130561Sobrien struct elf_link_hash_entry *h = NULL; 5269130561Sobrien char tls_type = 0; 527089857Sobrien 527189857Sobrien r_symndx = ELF64_R_SYM (rel->r_info); 5272130561Sobrien r_type = ELF64_R_TYPE (rel->r_info); 5273130561Sobrien if (r_symndx >= symtab_hdr->sh_info) 5274130561Sobrien { 5275130561Sobrien struct ppc_link_hash_entry *eh; 5276130561Sobrien struct ppc_dyn_relocs **pp; 5277130561Sobrien struct ppc_dyn_relocs *p; 5278130561Sobrien 5279130561Sobrien h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 5280218822Sdim while (h->root.type == bfd_link_hash_indirect 5281218822Sdim || h->root.type == bfd_link_hash_warning) 5282218822Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 5283130561Sobrien eh = (struct ppc_link_hash_entry *) h; 5284130561Sobrien 5285130561Sobrien for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) 5286130561Sobrien if (p->sec == sec) 5287130561Sobrien { 5288130561Sobrien /* Everything must go for SEC. */ 5289130561Sobrien *pp = p->next; 5290130561Sobrien break; 5291130561Sobrien } 5292130561Sobrien } 5293130561Sobrien 529489857Sobrien switch (r_type) 529589857Sobrien { 5296130561Sobrien case R_PPC64_GOT_TLSLD16: 5297130561Sobrien case R_PPC64_GOT_TLSLD16_LO: 5298130561Sobrien case R_PPC64_GOT_TLSLD16_HI: 5299130561Sobrien case R_PPC64_GOT_TLSLD16_HA: 5300130561Sobrien ppc64_tlsld_got (abfd)->refcount -= 1; 5301130561Sobrien tls_type = TLS_TLS | TLS_LD; 5302130561Sobrien goto dogot; 5303130561Sobrien 5304130561Sobrien case R_PPC64_GOT_TLSGD16: 5305130561Sobrien case R_PPC64_GOT_TLSGD16_LO: 5306130561Sobrien case R_PPC64_GOT_TLSGD16_HI: 5307130561Sobrien case R_PPC64_GOT_TLSGD16_HA: 5308130561Sobrien tls_type = TLS_TLS | TLS_GD; 5309130561Sobrien goto dogot; 5310130561Sobrien 5311130561Sobrien case R_PPC64_GOT_TPREL16_DS: 5312130561Sobrien case R_PPC64_GOT_TPREL16_LO_DS: 5313130561Sobrien case R_PPC64_GOT_TPREL16_HI: 5314130561Sobrien case R_PPC64_GOT_TPREL16_HA: 5315130561Sobrien tls_type = TLS_TLS | TLS_TPREL; 5316130561Sobrien goto dogot; 5317130561Sobrien 5318130561Sobrien case R_PPC64_GOT_DTPREL16_DS: 5319130561Sobrien case R_PPC64_GOT_DTPREL16_LO_DS: 5320130561Sobrien case R_PPC64_GOT_DTPREL16_HI: 5321130561Sobrien case R_PPC64_GOT_DTPREL16_HA: 5322130561Sobrien tls_type = TLS_TLS | TLS_DTPREL; 5323130561Sobrien goto dogot; 5324130561Sobrien 532589857Sobrien case R_PPC64_GOT16: 532689857Sobrien case R_PPC64_GOT16_DS: 532789857Sobrien case R_PPC64_GOT16_HA: 532889857Sobrien case R_PPC64_GOT16_HI: 532989857Sobrien case R_PPC64_GOT16_LO: 533089857Sobrien case R_PPC64_GOT16_LO_DS: 5331130561Sobrien dogot: 5332130561Sobrien { 5333130561Sobrien struct got_entry *ent; 5334130561Sobrien 5335130561Sobrien if (h != NULL) 5336130561Sobrien ent = h->got.glist; 5337130561Sobrien else 5338130561Sobrien ent = local_got_ents[r_symndx]; 5339130561Sobrien 5340130561Sobrien for (; ent != NULL; ent = ent->next) 5341130561Sobrien if (ent->addend == rel->r_addend 5342130561Sobrien && ent->owner == abfd 5343130561Sobrien && ent->tls_type == tls_type) 5344130561Sobrien break; 5345130561Sobrien if (ent == NULL) 5346130561Sobrien abort (); 5347130561Sobrien if (ent->got.refcount > 0) 5348130561Sobrien ent->got.refcount -= 1; 5349130561Sobrien } 535089857Sobrien break; 535189857Sobrien 535289857Sobrien case R_PPC64_PLT16_HA: 535389857Sobrien case R_PPC64_PLT16_HI: 535489857Sobrien case R_PPC64_PLT16_LO: 535589857Sobrien case R_PPC64_PLT32: 535689857Sobrien case R_PPC64_PLT64: 5357104834Sobrien case R_PPC64_REL14: 5358104834Sobrien case R_PPC64_REL14_BRNTAKEN: 5359104834Sobrien case R_PPC64_REL14_BRTAKEN: 536089857Sobrien case R_PPC64_REL24: 5361130561Sobrien if (h != NULL) 536289857Sobrien { 5363130561Sobrien struct plt_entry *ent; 536489857Sobrien 5365130561Sobrien for (ent = h->plt.plist; ent != NULL; ent = ent->next) 5366130561Sobrien if (ent->addend == rel->r_addend) 5367130561Sobrien break; 5368218822Sdim if (ent != NULL && ent->plt.refcount > 0) 5369130561Sobrien ent->plt.refcount -= 1; 537089857Sobrien } 537189857Sobrien break; 537289857Sobrien 537389857Sobrien default: 537489857Sobrien break; 537589857Sobrien } 537689857Sobrien } 5377130561Sobrien return TRUE; 537889857Sobrien} 537989857Sobrien 5380218822Sdim/* The maximum size of .sfpr. */ 5381218822Sdim#define SFPR_MAX (218*4) 5382218822Sdim 5383218822Sdimstruct sfpr_def_parms 5384218822Sdim{ 5385218822Sdim const char name[12]; 5386218822Sdim unsigned char lo, hi; 5387218822Sdim bfd_byte * (*write_ent) (bfd *, bfd_byte *, int); 5388218822Sdim bfd_byte * (*write_tail) (bfd *, bfd_byte *, int); 5389218822Sdim}; 5390218822Sdim 5391218822Sdim/* Auto-generate _save*, _rest* functions in .sfpr. */ 5392218822Sdim 5393218822Sdimstatic unsigned int 5394218822Sdimsfpr_define (struct bfd_link_info *info, const struct sfpr_def_parms *parm) 5395218822Sdim{ 5396218822Sdim struct ppc_link_hash_table *htab = ppc_hash_table (info); 5397218822Sdim unsigned int i; 5398218822Sdim size_t len = strlen (parm->name); 5399218822Sdim bfd_boolean writing = FALSE; 5400218822Sdim char sym[16]; 5401218822Sdim 5402218822Sdim memcpy (sym, parm->name, len); 5403218822Sdim sym[len + 2] = 0; 5404218822Sdim 5405218822Sdim for (i = parm->lo; i <= parm->hi; i++) 5406218822Sdim { 5407218822Sdim struct elf_link_hash_entry *h; 5408218822Sdim 5409218822Sdim sym[len + 0] = i / 10 + '0'; 5410218822Sdim sym[len + 1] = i % 10 + '0'; 5411218822Sdim h = elf_link_hash_lookup (&htab->elf, sym, FALSE, FALSE, TRUE); 5412218822Sdim if (h != NULL 5413218822Sdim && !h->def_regular) 5414218822Sdim { 5415218822Sdim h->root.type = bfd_link_hash_defined; 5416218822Sdim h->root.u.def.section = htab->sfpr; 5417218822Sdim h->root.u.def.value = htab->sfpr->size; 5418218822Sdim h->type = STT_FUNC; 5419218822Sdim h->def_regular = 1; 5420218822Sdim _bfd_elf_link_hash_hide_symbol (info, h, TRUE); 5421218822Sdim writing = TRUE; 5422218822Sdim if (htab->sfpr->contents == NULL) 5423218822Sdim { 5424218822Sdim htab->sfpr->contents = bfd_alloc (htab->elf.dynobj, SFPR_MAX); 5425218822Sdim if (htab->sfpr->contents == NULL) 5426218822Sdim return FALSE; 5427218822Sdim } 5428218822Sdim } 5429218822Sdim if (writing) 5430218822Sdim { 5431218822Sdim bfd_byte *p = htab->sfpr->contents + htab->sfpr->size; 5432218822Sdim if (i != parm->hi) 5433218822Sdim p = (*parm->write_ent) (htab->elf.dynobj, p, i); 5434218822Sdim else 5435218822Sdim p = (*parm->write_tail) (htab->elf.dynobj, p, i); 5436218822Sdim htab->sfpr->size = p - htab->sfpr->contents; 5437218822Sdim } 5438218822Sdim } 5439218822Sdim 5440218822Sdim return TRUE; 5441218822Sdim} 5442218822Sdim 5443218822Sdimstatic bfd_byte * 5444218822Sdimsavegpr0 (bfd *abfd, bfd_byte *p, int r) 5445218822Sdim{ 5446218822Sdim bfd_put_32 (abfd, STD_R0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p); 5447218822Sdim return p + 4; 5448218822Sdim} 5449218822Sdim 5450218822Sdimstatic bfd_byte * 5451218822Sdimsavegpr0_tail (bfd *abfd, bfd_byte *p, int r) 5452218822Sdim{ 5453218822Sdim p = savegpr0 (abfd, p, r); 5454218822Sdim bfd_put_32 (abfd, STD_R0_0R1 + 16, p); 5455218822Sdim p = p + 4; 5456218822Sdim bfd_put_32 (abfd, BLR, p); 5457218822Sdim return p + 4; 5458218822Sdim} 5459218822Sdim 5460218822Sdimstatic bfd_byte * 5461218822Sdimrestgpr0 (bfd *abfd, bfd_byte *p, int r) 5462218822Sdim{ 5463218822Sdim bfd_put_32 (abfd, LD_R0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p); 5464218822Sdim return p + 4; 5465218822Sdim} 5466218822Sdim 5467218822Sdimstatic bfd_byte * 5468218822Sdimrestgpr0_tail (bfd *abfd, bfd_byte *p, int r) 5469218822Sdim{ 5470218822Sdim bfd_put_32 (abfd, LD_R0_0R1 + 16, p); 5471218822Sdim p = p + 4; 5472218822Sdim p = restgpr0 (abfd, p, r); 5473218822Sdim bfd_put_32 (abfd, MTLR_R0, p); 5474218822Sdim p = p + 4; 5475218822Sdim if (r == 29) 5476218822Sdim { 5477218822Sdim p = restgpr0 (abfd, p, 30); 5478218822Sdim p = restgpr0 (abfd, p, 31); 5479218822Sdim } 5480218822Sdim bfd_put_32 (abfd, BLR, p); 5481218822Sdim return p + 4; 5482218822Sdim} 5483218822Sdim 5484218822Sdimstatic bfd_byte * 5485218822Sdimsavegpr1 (bfd *abfd, bfd_byte *p, int r) 5486218822Sdim{ 5487218822Sdim bfd_put_32 (abfd, STD_R0_0R12 + (r << 21) + (1 << 16) - (32 - r) * 8, p); 5488218822Sdim return p + 4; 5489218822Sdim} 5490218822Sdim 5491218822Sdimstatic bfd_byte * 5492218822Sdimsavegpr1_tail (bfd *abfd, bfd_byte *p, int r) 5493218822Sdim{ 5494218822Sdim p = savegpr1 (abfd, p, r); 5495218822Sdim bfd_put_32 (abfd, BLR, p); 5496218822Sdim return p + 4; 5497218822Sdim} 5498218822Sdim 5499218822Sdimstatic bfd_byte * 5500218822Sdimrestgpr1 (bfd *abfd, bfd_byte *p, int r) 5501218822Sdim{ 5502218822Sdim bfd_put_32 (abfd, LD_R0_0R12 + (r << 21) + (1 << 16) - (32 - r) * 8, p); 5503218822Sdim return p + 4; 5504218822Sdim} 5505218822Sdim 5506218822Sdimstatic bfd_byte * 5507218822Sdimrestgpr1_tail (bfd *abfd, bfd_byte *p, int r) 5508218822Sdim{ 5509218822Sdim p = restgpr1 (abfd, p, r); 5510218822Sdim bfd_put_32 (abfd, BLR, p); 5511218822Sdim return p + 4; 5512218822Sdim} 5513218822Sdim 5514218822Sdimstatic bfd_byte * 5515218822Sdimsavefpr (bfd *abfd, bfd_byte *p, int r) 5516218822Sdim{ 5517218822Sdim bfd_put_32 (abfd, STFD_FR0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p); 5518218822Sdim return p + 4; 5519218822Sdim} 5520218822Sdim 5521218822Sdimstatic bfd_byte * 5522218822Sdimsavefpr0_tail (bfd *abfd, bfd_byte *p, int r) 5523218822Sdim{ 5524218822Sdim p = savefpr (abfd, p, r); 5525218822Sdim bfd_put_32 (abfd, STD_R0_0R1 + 16, p); 5526218822Sdim p = p + 4; 5527218822Sdim bfd_put_32 (abfd, BLR, p); 5528218822Sdim return p + 4; 5529218822Sdim} 5530218822Sdim 5531218822Sdimstatic bfd_byte * 5532218822Sdimrestfpr (bfd *abfd, bfd_byte *p, int r) 5533218822Sdim{ 5534218822Sdim bfd_put_32 (abfd, LFD_FR0_0R1 + (r << 21) + (1 << 16) - (32 - r) * 8, p); 5535218822Sdim return p + 4; 5536218822Sdim} 5537218822Sdim 5538218822Sdimstatic bfd_byte * 5539218822Sdimrestfpr0_tail (bfd *abfd, bfd_byte *p, int r) 5540218822Sdim{ 5541218822Sdim bfd_put_32 (abfd, LD_R0_0R1 + 16, p); 5542218822Sdim p = p + 4; 5543218822Sdim p = restfpr (abfd, p, r); 5544218822Sdim bfd_put_32 (abfd, MTLR_R0, p); 5545218822Sdim p = p + 4; 5546218822Sdim if (r == 29) 5547218822Sdim { 5548218822Sdim p = restfpr (abfd, p, 30); 5549218822Sdim p = restfpr (abfd, p, 31); 5550218822Sdim } 5551218822Sdim bfd_put_32 (abfd, BLR, p); 5552218822Sdim return p + 4; 5553218822Sdim} 5554218822Sdim 5555218822Sdimstatic bfd_byte * 5556218822Sdimsavefpr1_tail (bfd *abfd, bfd_byte *p, int r) 5557218822Sdim{ 5558218822Sdim p = savefpr (abfd, p, r); 5559218822Sdim bfd_put_32 (abfd, BLR, p); 5560218822Sdim return p + 4; 5561218822Sdim} 5562218822Sdim 5563218822Sdimstatic bfd_byte * 5564218822Sdimrestfpr1_tail (bfd *abfd, bfd_byte *p, int r) 5565218822Sdim{ 5566218822Sdim p = restfpr (abfd, p, r); 5567218822Sdim bfd_put_32 (abfd, BLR, p); 5568218822Sdim return p + 4; 5569218822Sdim} 5570218822Sdim 5571218822Sdimstatic bfd_byte * 5572218822Sdimsavevr (bfd *abfd, bfd_byte *p, int r) 5573218822Sdim{ 5574218822Sdim bfd_put_32 (abfd, LI_R12_0 + (1 << 16) - (32 - r) * 16, p); 5575218822Sdim p = p + 4; 5576218822Sdim bfd_put_32 (abfd, STVX_VR0_R12_R0 + (r << 21), p); 5577218822Sdim return p + 4; 5578218822Sdim} 5579218822Sdim 5580218822Sdimstatic bfd_byte * 5581218822Sdimsavevr_tail (bfd *abfd, bfd_byte *p, int r) 5582218822Sdim{ 5583218822Sdim p = savevr (abfd, p, r); 5584218822Sdim bfd_put_32 (abfd, BLR, p); 5585218822Sdim return p + 4; 5586218822Sdim} 5587218822Sdim 5588218822Sdimstatic bfd_byte * 5589218822Sdimrestvr (bfd *abfd, bfd_byte *p, int r) 5590218822Sdim{ 5591218822Sdim bfd_put_32 (abfd, LI_R12_0 + (1 << 16) - (32 - r) * 16, p); 5592218822Sdim p = p + 4; 5593218822Sdim bfd_put_32 (abfd, LVX_VR0_R12_R0 + (r << 21), p); 5594218822Sdim return p + 4; 5595218822Sdim} 5596218822Sdim 5597218822Sdimstatic bfd_byte * 5598218822Sdimrestvr_tail (bfd *abfd, bfd_byte *p, int r) 5599218822Sdim{ 5600218822Sdim p = restvr (abfd, p, r); 5601218822Sdim bfd_put_32 (abfd, BLR, p); 5602218822Sdim return p + 4; 5603218822Sdim} 5604218822Sdim 560589857Sobrien/* Called via elf_link_hash_traverse to transfer dynamic linking 560689857Sobrien information on function code symbol entries to their corresponding 560789857Sobrien function descriptor symbol entries. */ 5608218822Sdim 5609130561Sobrienstatic bfd_boolean 5610130561Sobrienfunc_desc_adjust (struct elf_link_hash_entry *h, void *inf) 561189857Sobrien{ 561289857Sobrien struct bfd_link_info *info; 561389857Sobrien struct ppc_link_hash_table *htab; 5614130561Sobrien struct plt_entry *ent; 5615130561Sobrien struct ppc_link_hash_entry *fh; 5616130561Sobrien struct ppc_link_hash_entry *fdh; 5617130561Sobrien bfd_boolean force_local; 561889857Sobrien 5619130561Sobrien fh = (struct ppc_link_hash_entry *) h; 5620130561Sobrien if (fh->elf.root.type == bfd_link_hash_indirect) 5621130561Sobrien return TRUE; 562289857Sobrien 5623130561Sobrien if (fh->elf.root.type == bfd_link_hash_warning) 5624130561Sobrien fh = (struct ppc_link_hash_entry *) fh->elf.root.u.i.link; 562594536Sobrien 5626130561Sobrien info = inf; 562789857Sobrien htab = ppc_hash_table (info); 562889857Sobrien 5629218822Sdim /* Resolve undefined references to dot-symbols as the value 5630218822Sdim in the function descriptor, if we have one in a regular object. 5631218822Sdim This is to satisfy cases like ".quad .foo". Calls to functions 5632218822Sdim in dynamic objects are handled elsewhere. */ 5633218822Sdim if (fh->elf.root.type == bfd_link_hash_undefweak 5634218822Sdim && fh->was_undefined 5635218822Sdim && (fh->oh->elf.root.type == bfd_link_hash_defined 5636218822Sdim || fh->oh->elf.root.type == bfd_link_hash_defweak) 5637218822Sdim && get_opd_info (fh->oh->elf.root.u.def.section) != NULL 5638218822Sdim && opd_entry_value (fh->oh->elf.root.u.def.section, 5639218822Sdim fh->oh->elf.root.u.def.value, 5640218822Sdim &fh->elf.root.u.def.section, 5641218822Sdim &fh->elf.root.u.def.value) != (bfd_vma) -1) 5642218822Sdim { 5643218822Sdim fh->elf.root.type = fh->oh->elf.root.type; 5644218822Sdim fh->elf.forced_local = 1; 5645218822Sdim } 5646218822Sdim 564789857Sobrien /* If this is a function code symbol, transfer dynamic linking 564889857Sobrien information to the function descriptor symbol. */ 5649130561Sobrien if (!fh->is_func) 5650130561Sobrien return TRUE; 565189857Sobrien 5652130561Sobrien for (ent = fh->elf.plt.plist; ent != NULL; ent = ent->next) 5653130561Sobrien if (ent->plt.refcount > 0) 5654130561Sobrien break; 5655130561Sobrien if (ent == NULL 5656130561Sobrien || fh->elf.root.root.string[0] != '.' 5657130561Sobrien || fh->elf.root.root.string[1] == '\0') 5658130561Sobrien return TRUE; 565989857Sobrien 5660130561Sobrien /* Find the corresponding function descriptor symbol. Create it 5661130561Sobrien as undefined if necessary. */ 566289857Sobrien 5663130561Sobrien fdh = get_fdh (fh, htab); 5664130561Sobrien if (fdh != NULL) 5665130561Sobrien while (fdh->elf.root.type == bfd_link_hash_indirect 5666130561Sobrien || fdh->elf.root.type == bfd_link_hash_warning) 5667130561Sobrien fdh = (struct ppc_link_hash_entry *) fdh->elf.root.u.i.link; 566889857Sobrien 5669130561Sobrien if (fdh == NULL 5670130561Sobrien && info->shared 5671130561Sobrien && (fh->elf.root.type == bfd_link_hash_undefined 5672130561Sobrien || fh->elf.root.type == bfd_link_hash_undefweak)) 5673130561Sobrien { 5674218822Sdim fdh = make_fdh (info, fh); 5675218822Sdim if (fdh == NULL) 5676218822Sdim return FALSE; 5677218822Sdim } 567889857Sobrien 5679218822Sdim /* Fake function descriptors are made undefweak. If the function 5680218822Sdim code symbol is strong undefined, make the fake sym the same. 5681218822Sdim If the function code symbol is defined, then force the fake 5682218822Sdim descriptor local; We can't support overriding of symbols in a 5683218822Sdim shared library on a fake descriptor. */ 568489857Sobrien 5685218822Sdim if (fdh != NULL 5686218822Sdim && fdh->fake 5687218822Sdim && fdh->elf.root.type == bfd_link_hash_undefweak) 5688218822Sdim { 5689218822Sdim if (fh->elf.root.type == bfd_link_hash_undefined) 5690130561Sobrien { 5691218822Sdim fdh->elf.root.type = bfd_link_hash_undefined; 5692218822Sdim bfd_link_add_undef (&htab->elf.root, &fdh->elf.root); 569389857Sobrien } 5694218822Sdim else if (fh->elf.root.type == bfd_link_hash_defined 5695218822Sdim || fh->elf.root.type == bfd_link_hash_defweak) 5696218822Sdim { 5697218822Sdim _bfd_elf_link_hash_hide_symbol (info, &fdh->elf, TRUE); 5698218822Sdim } 5699130561Sobrien } 570089857Sobrien 5701130561Sobrien if (fdh != NULL 5702218822Sdim && !fdh->elf.forced_local 5703130561Sobrien && (info->shared 5704218822Sdim || fdh->elf.def_dynamic 5705218822Sdim || fdh->elf.ref_dynamic 5706130561Sobrien || (fdh->elf.root.type == bfd_link_hash_undefweak 5707130561Sobrien && ELF_ST_VISIBILITY (fdh->elf.other) == STV_DEFAULT))) 5708130561Sobrien { 5709130561Sobrien if (fdh->elf.dynindx == -1) 5710130561Sobrien if (! bfd_elf_link_record_dynamic_symbol (info, &fdh->elf)) 5711130561Sobrien return FALSE; 5712218822Sdim fdh->elf.ref_regular |= fh->elf.ref_regular; 5713218822Sdim fdh->elf.ref_dynamic |= fh->elf.ref_dynamic; 5714218822Sdim fdh->elf.ref_regular_nonweak |= fh->elf.ref_regular_nonweak; 5715218822Sdim fdh->elf.non_got_ref |= fh->elf.non_got_ref; 5716130561Sobrien if (ELF_ST_VISIBILITY (fh->elf.other) == STV_DEFAULT) 571789857Sobrien { 5718218822Sdim move_plt_plist (fh, fdh); 5719218822Sdim fdh->elf.needs_plt = 1; 572089857Sobrien } 5721130561Sobrien fdh->is_func_descriptor = 1; 5722218822Sdim fdh->oh = fh; 5723218822Sdim fh->oh = fdh; 572489857Sobrien } 572589857Sobrien 5726130561Sobrien /* Now that the info is on the function descriptor, clear the 5727130561Sobrien function code sym info. Any function code syms for which we 5728130561Sobrien don't have a definition in a regular file, we force local. 5729130561Sobrien This prevents a shared library from exporting syms that have 5730130561Sobrien been imported from another library. Function code syms that 5731130561Sobrien are really in the library we must leave global to prevent the 5732130561Sobrien linker dragging in a definition from a static library. */ 5733218822Sdim force_local = (!fh->elf.def_regular 5734218822Sdim || fdh == NULL 5735218822Sdim || !fdh->elf.def_regular 5736218822Sdim || fdh->elf.forced_local); 5737130561Sobrien _bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local); 5738130561Sobrien 5739130561Sobrien return TRUE; 574089857Sobrien} 574189857Sobrien 574289857Sobrien/* Called near the start of bfd_elf_size_dynamic_sections. We use 574392828Sobrien this hook to a) provide some gcc support functions, and b) transfer 574492828Sobrien dynamic linking information gathered so far on function code symbol 574592828Sobrien entries, to their corresponding function descriptor symbol entries. */ 5746218822Sdim 5747130561Sobrienstatic bfd_boolean 5748130561Sobrienppc64_elf_func_desc_adjust (bfd *obfd ATTRIBUTE_UNUSED, 5749130561Sobrien struct bfd_link_info *info) 575089857Sobrien{ 575189857Sobrien struct ppc_link_hash_table *htab; 575292828Sobrien unsigned int i; 5753218822Sdim const struct sfpr_def_parms funcs[] = 5754218822Sdim { 5755218822Sdim { "_savegpr0_", 14, 31, savegpr0, savegpr0_tail }, 5756218822Sdim { "_restgpr0_", 14, 29, restgpr0, restgpr0_tail }, 5757218822Sdim { "_restgpr0_", 30, 31, restgpr0, restgpr0_tail }, 5758218822Sdim { "_savegpr1_", 14, 31, savegpr1, savegpr1_tail }, 5759218822Sdim { "_restgpr1_", 14, 31, restgpr1, restgpr1_tail }, 5760218822Sdim { "_savefpr_", 14, 31, savefpr, savefpr0_tail }, 5761218822Sdim { "_restfpr_", 14, 29, restfpr, restfpr0_tail }, 5762218822Sdim { "_restfpr_", 30, 31, restfpr, restfpr0_tail }, 5763218822Sdim { "._savef", 14, 31, savefpr, savefpr1_tail }, 5764218822Sdim { "._restf", 14, 31, restfpr, restfpr1_tail }, 5765218822Sdim { "_savevr_", 20, 31, savevr, savevr_tail }, 5766218822Sdim { "_restvr_", 20, 31, restvr, restvr_tail } 5767218822Sdim }; 576889857Sobrien 576989857Sobrien htab = ppc_hash_table (info); 577092828Sobrien if (htab->sfpr == NULL) 577192828Sobrien /* We don't have any relocs. */ 5772130561Sobrien return TRUE; 577392828Sobrien 5774218822Sdim /* Provide any missing _save* and _rest* functions. */ 5775218822Sdim htab->sfpr->size = 0; 5776218822Sdim for (i = 0; i < sizeof (funcs) / sizeof (funcs[0]); i++) 5777218822Sdim if (!sfpr_define (info, &funcs[i])) 5778218822Sdim return FALSE; 577992828Sobrien 5780130561Sobrien elf_link_hash_traverse (&htab->elf, func_desc_adjust, info); 578199461Sobrien 5782218822Sdim if (htab->sfpr->size == 0) 5783218822Sdim htab->sfpr->flags |= SEC_EXCLUDE; 578492828Sobrien 5785130561Sobrien return TRUE; 578689857Sobrien} 578789857Sobrien 578889857Sobrien/* Adjust a symbol defined by a dynamic object and referenced by a 578989857Sobrien regular object. The current definition is in some section of the 579089857Sobrien dynamic object, but we're not including those sections. We have to 579189857Sobrien change the definition to something the rest of the link can 579289857Sobrien understand. */ 579389857Sobrien 5794130561Sobrienstatic bfd_boolean 5795130561Sobrienppc64_elf_adjust_dynamic_symbol (struct bfd_link_info *info, 5796130561Sobrien struct elf_link_hash_entry *h) 579789857Sobrien{ 579889857Sobrien struct ppc_link_hash_table *htab; 579989857Sobrien asection *s; 580089857Sobrien 580189857Sobrien htab = ppc_hash_table (info); 580289857Sobrien 580389857Sobrien /* Deal with function syms. */ 580489857Sobrien if (h->type == STT_FUNC 5805218822Sdim || h->needs_plt) 580689857Sobrien { 580789857Sobrien /* Clear procedure linkage table information for any symbol that 580889857Sobrien won't need a .plt entry. */ 5809130561Sobrien struct plt_entry *ent; 5810130561Sobrien for (ent = h->plt.plist; ent != NULL; ent = ent->next) 5811130561Sobrien if (ent->plt.refcount > 0) 5812130561Sobrien break; 5813218822Sdim if (ent == NULL 5814130561Sobrien || SYMBOL_CALLS_LOCAL (info, h) 5815130561Sobrien || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT 5816130561Sobrien && h->root.type == bfd_link_hash_undefweak)) 581789857Sobrien { 5818130561Sobrien h->plt.plist = NULL; 5819218822Sdim h->needs_plt = 0; 582089857Sobrien } 582189857Sobrien } 582289857Sobrien else 5823130561Sobrien h->plt.plist = NULL; 582489857Sobrien 582589857Sobrien /* If this is a weak symbol, and there is a real definition, the 582689857Sobrien processor independent code will have arranged for us to see the 582789857Sobrien real definition first, and we can just use the same value. */ 5828218822Sdim if (h->u.weakdef != NULL) 582989857Sobrien { 5830218822Sdim BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined 5831218822Sdim || h->u.weakdef->root.type == bfd_link_hash_defweak); 5832218822Sdim h->root.u.def.section = h->u.weakdef->root.u.def.section; 5833218822Sdim h->root.u.def.value = h->u.weakdef->root.u.def.value; 5834130561Sobrien if (ELIMINATE_COPY_RELOCS) 5835218822Sdim h->non_got_ref = h->u.weakdef->non_got_ref; 5836130561Sobrien return TRUE; 583789857Sobrien } 583889857Sobrien 583989857Sobrien /* If we are creating a shared library, we must presume that the 584089857Sobrien only references to the symbol are via the global offset table. 584189857Sobrien For such cases we need not do anything here; the relocations will 584289857Sobrien be handled correctly by relocate_section. */ 584389857Sobrien if (info->shared) 5844130561Sobrien return TRUE; 584589857Sobrien 584689857Sobrien /* If there are no references to this symbol that do not use the 584789857Sobrien GOT, we don't need to generate a copy reloc. */ 5848218822Sdim if (!h->non_got_ref) 5849130561Sobrien return TRUE; 585089857Sobrien 5851218822Sdim /* Don't generate a copy reloc for symbols defined in the executable. */ 5852218822Sdim if (!h->def_dynamic || !h->ref_regular || h->def_regular) 5853218822Sdim return TRUE; 5854218822Sdim 5855130561Sobrien if (ELIMINATE_COPY_RELOCS) 585689857Sobrien { 5857130561Sobrien struct ppc_link_hash_entry * eh; 5858130561Sobrien struct ppc_dyn_relocs *p; 5859130561Sobrien 5860130561Sobrien eh = (struct ppc_link_hash_entry *) h; 5861130561Sobrien for (p = eh->dyn_relocs; p != NULL; p = p->next) 5862130561Sobrien { 5863130561Sobrien s = p->sec->output_section; 5864130561Sobrien if (s != NULL && (s->flags & SEC_READONLY) != 0) 5865130561Sobrien break; 5866130561Sobrien } 5867130561Sobrien 5868130561Sobrien /* If we didn't find any dynamic relocs in read-only sections, then 5869130561Sobrien we'll be keeping the dynamic relocs and avoiding the copy reloc. */ 5870130561Sobrien if (p == NULL) 5871130561Sobrien { 5872218822Sdim h->non_got_ref = 0; 5873130561Sobrien return TRUE; 5874130561Sobrien } 587589857Sobrien } 587689857Sobrien 5877130561Sobrien if (h->plt.plist != NULL) 587889857Sobrien { 5879130561Sobrien /* We should never get here, but unfortunately there are versions 5880130561Sobrien of gcc out there that improperly (for this ABI) put initialized 5881130561Sobrien function pointers, vtable refs and suchlike in read-only 5882130561Sobrien sections. Allow them to proceed, but warn that this might 5883130561Sobrien break at runtime. */ 5884130561Sobrien (*_bfd_error_handler) 5885130561Sobrien (_("copy reloc against `%s' requires lazy plt linking; " 5886130561Sobrien "avoid setting LD_BIND_NOW=1 or upgrade gcc"), 5887130561Sobrien h->root.root.string); 588889857Sobrien } 588989857Sobrien 5890130561Sobrien /* This is a reference to a symbol defined by a dynamic object which 5891130561Sobrien is not a function. */ 5892130561Sobrien 5893218822Sdim if (h->size == 0) 5894218822Sdim { 5895218822Sdim (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"), 5896218822Sdim h->root.root.string); 5897218822Sdim return TRUE; 5898218822Sdim } 5899218822Sdim 590089857Sobrien /* We must allocate the symbol in our .dynbss section, which will 590189857Sobrien become part of the .bss section of the executable. There will be 590289857Sobrien an entry for this symbol in the .dynsym section. The dynamic 590389857Sobrien object will contain position independent code, so all references 590489857Sobrien from the dynamic object to this symbol will go through the global 590589857Sobrien offset table. The dynamic linker will use the .dynsym entry to 590689857Sobrien determine the address it must put in the global offset table, so 590789857Sobrien both the dynamic object and the regular object will refer to the 590889857Sobrien same memory location for the variable. */ 590989857Sobrien 5910130561Sobrien /* We must generate a R_PPC64_COPY reloc to tell the dynamic linker 5911130561Sobrien to copy the initial value out of the dynamic object and into the 591289857Sobrien runtime process image. We need to remember the offset into the 591389857Sobrien .rela.bss section we are going to use. */ 591489857Sobrien if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) 591589857Sobrien { 5916218822Sdim htab->relbss->size += sizeof (Elf64_External_Rela); 5917218822Sdim h->needs_copy = 1; 591889857Sobrien } 591989857Sobrien 5920130561Sobrien s = htab->dynbss; 592189857Sobrien 5922218822Sdim return _bfd_elf_adjust_dynamic_copy (h, s); 592389857Sobrien} 592489857Sobrien 592589857Sobrien/* If given a function descriptor symbol, hide both the function code 592689857Sobrien sym and the descriptor. */ 592789857Sobrienstatic void 5928130561Sobrienppc64_elf_hide_symbol (struct bfd_link_info *info, 5929130561Sobrien struct elf_link_hash_entry *h, 5930130561Sobrien bfd_boolean force_local) 593189857Sobrien{ 5932218822Sdim struct ppc_link_hash_entry *eh; 593389857Sobrien _bfd_elf_link_hash_hide_symbol (info, h, force_local); 593489857Sobrien 5935218822Sdim eh = (struct ppc_link_hash_entry *) h; 5936218822Sdim if (eh->is_func_descriptor) 593789857Sobrien { 5938218822Sdim struct ppc_link_hash_entry *fh = eh->oh; 593989857Sobrien 5940104834Sobrien if (fh == NULL) 5941104834Sobrien { 5942104834Sobrien const char *p, *q; 5943104834Sobrien struct ppc_link_hash_table *htab; 5944104834Sobrien char save; 5945104834Sobrien 5946104834Sobrien /* We aren't supposed to use alloca in BFD because on 5947104834Sobrien systems which do not have alloca the version in libiberty 5948104834Sobrien calls xmalloc, which might cause the program to crash 5949104834Sobrien when it runs out of memory. This function doesn't have a 5950104834Sobrien return status, so there's no way to gracefully return an 5951104834Sobrien error. So cheat. We know that string[-1] can be safely 5952218822Sdim accessed; It's either a string in an ELF string table, 5953218822Sdim or allocated in an objalloc structure. */ 5954104834Sobrien 5955218822Sdim p = eh->elf.root.root.string - 1; 5956104834Sobrien save = *p; 5957104834Sobrien *(char *) p = '.'; 5958104834Sobrien htab = ppc_hash_table (info); 5959218822Sdim fh = (struct ppc_link_hash_entry *) 5960218822Sdim elf_link_hash_lookup (&htab->elf, p, FALSE, FALSE, FALSE); 5961104834Sobrien *(char *) p = save; 5962104834Sobrien 5963104834Sobrien /* Unfortunately, if it so happens that the string we were 5964104834Sobrien looking for was allocated immediately before this string, 5965104834Sobrien then we overwrote the string terminator. That's the only 5966104834Sobrien reason the lookup should fail. */ 5967104834Sobrien if (fh == NULL) 5968104834Sobrien { 5969218822Sdim q = eh->elf.root.root.string + strlen (eh->elf.root.root.string); 5970218822Sdim while (q >= eh->elf.root.root.string && *q == *p) 5971104834Sobrien --q, --p; 5972218822Sdim if (q < eh->elf.root.root.string && *p == '.') 5973218822Sdim fh = (struct ppc_link_hash_entry *) 5974218822Sdim elf_link_hash_lookup (&htab->elf, p, FALSE, FALSE, FALSE); 5975104834Sobrien } 5976104834Sobrien if (fh != NULL) 5977104834Sobrien { 5978218822Sdim eh->oh = fh; 5979218822Sdim fh->oh = eh; 5980104834Sobrien } 5981104834Sobrien } 598289857Sobrien if (fh != NULL) 5983218822Sdim _bfd_elf_link_hash_hide_symbol (info, &fh->elf, force_local); 598489857Sobrien } 598589857Sobrien} 598689857Sobrien 5987130561Sobrienstatic bfd_boolean 5988218822Sdimget_sym_h (struct elf_link_hash_entry **hp, 5989218822Sdim Elf_Internal_Sym **symp, 5990218822Sdim asection **symsecp, 5991218822Sdim char **tls_maskp, 5992218822Sdim Elf_Internal_Sym **locsymsp, 5993218822Sdim unsigned long r_symndx, 5994218822Sdim bfd *ibfd) 5995104834Sobrien{ 5996130561Sobrien Elf_Internal_Shdr *symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; 5997130561Sobrien 5998130561Sobrien if (r_symndx >= symtab_hdr->sh_info) 5999130561Sobrien { 6000130561Sobrien struct elf_link_hash_entry **sym_hashes = elf_sym_hashes (ibfd); 6001130561Sobrien struct elf_link_hash_entry *h; 6002130561Sobrien 6003130561Sobrien h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 6004130561Sobrien while (h->root.type == bfd_link_hash_indirect 6005130561Sobrien || h->root.type == bfd_link_hash_warning) 6006130561Sobrien h = (struct elf_link_hash_entry *) h->root.u.i.link; 6007130561Sobrien 6008130561Sobrien if (hp != NULL) 6009130561Sobrien *hp = h; 6010130561Sobrien 6011130561Sobrien if (symp != NULL) 6012130561Sobrien *symp = NULL; 6013130561Sobrien 6014130561Sobrien if (symsecp != NULL) 6015130561Sobrien { 6016130561Sobrien asection *symsec = NULL; 6017130561Sobrien if (h->root.type == bfd_link_hash_defined 6018130561Sobrien || h->root.type == bfd_link_hash_defweak) 6019130561Sobrien symsec = h->root.u.def.section; 6020130561Sobrien *symsecp = symsec; 6021130561Sobrien } 6022130561Sobrien 6023130561Sobrien if (tls_maskp != NULL) 6024130561Sobrien { 6025130561Sobrien struct ppc_link_hash_entry *eh; 6026130561Sobrien 6027130561Sobrien eh = (struct ppc_link_hash_entry *) h; 6028130561Sobrien *tls_maskp = &eh->tls_mask; 6029130561Sobrien } 6030130561Sobrien } 6031130561Sobrien else 6032130561Sobrien { 6033130561Sobrien Elf_Internal_Sym *sym; 6034130561Sobrien Elf_Internal_Sym *locsyms = *locsymsp; 6035130561Sobrien 6036130561Sobrien if (locsyms == NULL) 6037130561Sobrien { 6038130561Sobrien locsyms = (Elf_Internal_Sym *) symtab_hdr->contents; 6039130561Sobrien if (locsyms == NULL) 6040130561Sobrien locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, 6041130561Sobrien symtab_hdr->sh_info, 6042130561Sobrien 0, NULL, NULL, NULL); 6043130561Sobrien if (locsyms == NULL) 6044130561Sobrien return FALSE; 6045130561Sobrien *locsymsp = locsyms; 6046130561Sobrien } 6047130561Sobrien sym = locsyms + r_symndx; 6048130561Sobrien 6049130561Sobrien if (hp != NULL) 6050130561Sobrien *hp = NULL; 6051130561Sobrien 6052130561Sobrien if (symp != NULL) 6053130561Sobrien *symp = sym; 6054130561Sobrien 6055130561Sobrien if (symsecp != NULL) 6056130561Sobrien { 6057130561Sobrien asection *symsec = NULL; 6058130561Sobrien if ((sym->st_shndx != SHN_UNDEF 6059130561Sobrien && sym->st_shndx < SHN_LORESERVE) 6060130561Sobrien || sym->st_shndx > SHN_HIRESERVE) 6061130561Sobrien symsec = bfd_section_from_elf_index (ibfd, sym->st_shndx); 6062130561Sobrien *symsecp = symsec; 6063130561Sobrien } 6064130561Sobrien 6065130561Sobrien if (tls_maskp != NULL) 6066130561Sobrien { 6067130561Sobrien struct got_entry **lgot_ents; 6068130561Sobrien char *tls_mask; 6069130561Sobrien 6070130561Sobrien tls_mask = NULL; 6071130561Sobrien lgot_ents = elf_local_got_ents (ibfd); 6072130561Sobrien if (lgot_ents != NULL) 6073130561Sobrien { 6074130561Sobrien char *lgot_masks = (char *) (lgot_ents + symtab_hdr->sh_info); 6075130561Sobrien tls_mask = &lgot_masks[r_symndx]; 6076130561Sobrien } 6077130561Sobrien *tls_maskp = tls_mask; 6078130561Sobrien } 6079130561Sobrien } 6080130561Sobrien return TRUE; 6081130561Sobrien} 6082130561Sobrien 6083130561Sobrien/* Returns TLS_MASKP for the given REL symbol. Function return is 0 on 6084130561Sobrien error, 2 on a toc GD type suitable for optimization, 3 on a toc LD 6085130561Sobrien type suitable for optimization, and 1 otherwise. */ 6086130561Sobrien 6087130561Sobrienstatic int 6088130561Sobrienget_tls_mask (char **tls_maskp, unsigned long *toc_symndx, 6089130561Sobrien Elf_Internal_Sym **locsymsp, 6090130561Sobrien const Elf_Internal_Rela *rel, bfd *ibfd) 6091130561Sobrien{ 6092130561Sobrien unsigned long r_symndx; 6093130561Sobrien int next_r; 6094130561Sobrien struct elf_link_hash_entry *h; 6095130561Sobrien Elf_Internal_Sym *sym; 6096130561Sobrien asection *sec; 6097130561Sobrien bfd_vma off; 6098130561Sobrien 6099130561Sobrien r_symndx = ELF64_R_SYM (rel->r_info); 6100130561Sobrien if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd)) 6101130561Sobrien return 0; 6102130561Sobrien 6103130561Sobrien if ((*tls_maskp != NULL && **tls_maskp != 0) 6104130561Sobrien || sec == NULL 6105218822Sdim || ppc64_elf_section_data (sec)->sec_type != sec_toc) 6106130561Sobrien return 1; 6107130561Sobrien 6108130561Sobrien /* Look inside a TOC section too. */ 6109130561Sobrien if (h != NULL) 6110130561Sobrien { 6111130561Sobrien BFD_ASSERT (h->root.type == bfd_link_hash_defined); 6112130561Sobrien off = h->root.u.def.value; 6113130561Sobrien } 6114130561Sobrien else 6115130561Sobrien off = sym->st_value; 6116130561Sobrien off += rel->r_addend; 6117130561Sobrien BFD_ASSERT (off % 8 == 0); 6118218822Sdim r_symndx = ppc64_elf_section_data (sec)->u.t_symndx[off / 8]; 6119218822Sdim next_r = ppc64_elf_section_data (sec)->u.t_symndx[off / 8 + 1]; 6120130561Sobrien if (!get_sym_h (&h, &sym, &sec, tls_maskp, locsymsp, r_symndx, ibfd)) 6121130561Sobrien return 0; 6122130561Sobrien if (toc_symndx != NULL) 6123130561Sobrien *toc_symndx = r_symndx; 6124130561Sobrien if ((h == NULL 6125130561Sobrien || ((h->root.type == bfd_link_hash_defined 6126130561Sobrien || h->root.type == bfd_link_hash_defweak) 6127218822Sdim && !h->def_dynamic)) 6128130561Sobrien && (next_r == -1 || next_r == -2)) 6129130561Sobrien return 1 - next_r; 6130130561Sobrien return 1; 6131130561Sobrien} 6132130561Sobrien 6133130561Sobrien/* Adjust all global syms defined in opd sections. In gcc generated 6134218822Sdim code for the old ABI, these will already have been done. */ 6135130561Sobrien 6136130561Sobrienstatic bfd_boolean 6137130561Sobrienadjust_opd_syms (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED) 6138130561Sobrien{ 6139130561Sobrien struct ppc_link_hash_entry *eh; 6140130561Sobrien asection *sym_sec; 6141130561Sobrien long *opd_adjust; 6142130561Sobrien 6143130561Sobrien if (h->root.type == bfd_link_hash_indirect) 6144130561Sobrien return TRUE; 6145130561Sobrien 6146130561Sobrien if (h->root.type == bfd_link_hash_warning) 6147130561Sobrien h = (struct elf_link_hash_entry *) h->root.u.i.link; 6148130561Sobrien 6149130561Sobrien if (h->root.type != bfd_link_hash_defined 6150130561Sobrien && h->root.type != bfd_link_hash_defweak) 6151130561Sobrien return TRUE; 6152130561Sobrien 6153130561Sobrien eh = (struct ppc_link_hash_entry *) h; 6154130561Sobrien if (eh->adjust_done) 6155130561Sobrien return TRUE; 6156130561Sobrien 6157130561Sobrien sym_sec = eh->elf.root.u.def.section; 6158218822Sdim opd_adjust = get_opd_info (sym_sec); 6159218822Sdim if (opd_adjust != NULL) 6160130561Sobrien { 6161218822Sdim long adjust = opd_adjust[eh->elf.root.u.def.value / 8]; 6162218822Sdim if (adjust == -1) 6163218822Sdim { 6164218822Sdim /* This entry has been deleted. */ 6165218822Sdim asection *dsec = ppc64_elf_tdata (sym_sec->owner)->deleted_section; 6166218822Sdim if (dsec == NULL) 6167218822Sdim { 6168218822Sdim for (dsec = sym_sec->owner->sections; dsec; dsec = dsec->next) 6169218822Sdim if (elf_discarded_section (dsec)) 6170218822Sdim { 6171218822Sdim ppc64_elf_tdata (sym_sec->owner)->deleted_section = dsec; 6172218822Sdim break; 6173218822Sdim } 6174218822Sdim } 6175218822Sdim eh->elf.root.u.def.value = 0; 6176218822Sdim eh->elf.root.u.def.section = dsec; 6177218822Sdim } 6178218822Sdim else 6179218822Sdim eh->elf.root.u.def.value += adjust; 6180130561Sobrien eh->adjust_done = 1; 6181130561Sobrien } 6182130561Sobrien return TRUE; 6183130561Sobrien} 6184130561Sobrien 6185218822Sdim/* Handles decrementing dynamic reloc counts for the reloc specified by 6186218822Sdim R_INFO in section SEC. If LOCAL_SYMS is NULL, then H and SYM_SEC 6187218822Sdim have already been determined. */ 6188218822Sdim 6189218822Sdimstatic bfd_boolean 6190218822Sdimdec_dynrel_count (bfd_vma r_info, 6191218822Sdim asection *sec, 6192218822Sdim struct bfd_link_info *info, 6193218822Sdim Elf_Internal_Sym **local_syms, 6194218822Sdim struct elf_link_hash_entry *h, 6195218822Sdim asection *sym_sec) 6196218822Sdim{ 6197218822Sdim enum elf_ppc64_reloc_type r_type; 6198218822Sdim struct ppc_dyn_relocs *p; 6199218822Sdim struct ppc_dyn_relocs **pp; 6200218822Sdim 6201218822Sdim /* Can this reloc be dynamic? This switch, and later tests here 6202218822Sdim should be kept in sync with the code in check_relocs. */ 6203218822Sdim r_type = ELF64_R_TYPE (r_info); 6204218822Sdim switch (r_type) 6205218822Sdim { 6206218822Sdim default: 6207218822Sdim return TRUE; 6208218822Sdim 6209218822Sdim case R_PPC64_TPREL16: 6210218822Sdim case R_PPC64_TPREL16_LO: 6211218822Sdim case R_PPC64_TPREL16_HI: 6212218822Sdim case R_PPC64_TPREL16_HA: 6213218822Sdim case R_PPC64_TPREL16_DS: 6214218822Sdim case R_PPC64_TPREL16_LO_DS: 6215218822Sdim case R_PPC64_TPREL16_HIGHER: 6216218822Sdim case R_PPC64_TPREL16_HIGHERA: 6217218822Sdim case R_PPC64_TPREL16_HIGHEST: 6218218822Sdim case R_PPC64_TPREL16_HIGHESTA: 6219218822Sdim if (!info->shared) 6220218822Sdim return TRUE; 6221218822Sdim 6222218822Sdim case R_PPC64_TPREL64: 6223218822Sdim case R_PPC64_DTPMOD64: 6224218822Sdim case R_PPC64_DTPREL64: 6225218822Sdim case R_PPC64_ADDR64: 6226218822Sdim case R_PPC64_REL30: 6227218822Sdim case R_PPC64_REL32: 6228218822Sdim case R_PPC64_REL64: 6229218822Sdim case R_PPC64_ADDR14: 6230218822Sdim case R_PPC64_ADDR14_BRNTAKEN: 6231218822Sdim case R_PPC64_ADDR14_BRTAKEN: 6232218822Sdim case R_PPC64_ADDR16: 6233218822Sdim case R_PPC64_ADDR16_DS: 6234218822Sdim case R_PPC64_ADDR16_HA: 6235218822Sdim case R_PPC64_ADDR16_HI: 6236218822Sdim case R_PPC64_ADDR16_HIGHER: 6237218822Sdim case R_PPC64_ADDR16_HIGHERA: 6238218822Sdim case R_PPC64_ADDR16_HIGHEST: 6239218822Sdim case R_PPC64_ADDR16_HIGHESTA: 6240218822Sdim case R_PPC64_ADDR16_LO: 6241218822Sdim case R_PPC64_ADDR16_LO_DS: 6242218822Sdim case R_PPC64_ADDR24: 6243218822Sdim case R_PPC64_ADDR32: 6244218822Sdim case R_PPC64_UADDR16: 6245218822Sdim case R_PPC64_UADDR32: 6246218822Sdim case R_PPC64_UADDR64: 6247218822Sdim case R_PPC64_TOC: 6248218822Sdim break; 6249218822Sdim } 6250218822Sdim 6251218822Sdim if (local_syms != NULL) 6252218822Sdim { 6253218822Sdim unsigned long r_symndx; 6254218822Sdim Elf_Internal_Sym *sym; 6255218822Sdim bfd *ibfd = sec->owner; 6256218822Sdim 6257218822Sdim r_symndx = ELF64_R_SYM (r_info); 6258218822Sdim if (!get_sym_h (&h, &sym, &sym_sec, NULL, local_syms, r_symndx, ibfd)) 6259218822Sdim return FALSE; 6260218822Sdim } 6261218822Sdim 6262218822Sdim if ((info->shared 6263218822Sdim && (MUST_BE_DYN_RELOC (r_type) 6264218822Sdim || (h != NULL 6265218822Sdim && (!info->symbolic 6266218822Sdim || h->root.type == bfd_link_hash_defweak 6267218822Sdim || !h->def_regular)))) 6268218822Sdim || (ELIMINATE_COPY_RELOCS 6269218822Sdim && !info->shared 6270218822Sdim && h != NULL 6271218822Sdim && (h->root.type == bfd_link_hash_defweak 6272218822Sdim || !h->def_regular))) 6273218822Sdim ; 6274218822Sdim else 6275218822Sdim return TRUE; 6276218822Sdim 6277218822Sdim if (h != NULL) 6278218822Sdim pp = &((struct ppc_link_hash_entry *) h)->dyn_relocs; 6279218822Sdim else 6280218822Sdim { 6281218822Sdim if (sym_sec != NULL) 6282218822Sdim { 6283218822Sdim void *vpp = &elf_section_data (sym_sec)->local_dynrel; 6284218822Sdim pp = (struct ppc_dyn_relocs **) vpp; 6285218822Sdim } 6286218822Sdim else 6287218822Sdim { 6288218822Sdim void *vpp = &elf_section_data (sec)->local_dynrel; 6289218822Sdim pp = (struct ppc_dyn_relocs **) vpp; 6290218822Sdim } 6291218822Sdim 6292218822Sdim /* elf_gc_sweep may have already removed all dyn relocs associated 6293218822Sdim with local syms for a given section. Don't report a dynreloc 6294218822Sdim miscount. */ 6295218822Sdim if (*pp == NULL) 6296218822Sdim return TRUE; 6297218822Sdim } 6298218822Sdim 6299218822Sdim while ((p = *pp) != NULL) 6300218822Sdim { 6301218822Sdim if (p->sec == sec) 6302218822Sdim { 6303218822Sdim if (!MUST_BE_DYN_RELOC (r_type)) 6304218822Sdim p->pc_count -= 1; 6305218822Sdim p->count -= 1; 6306218822Sdim if (p->count == 0) 6307218822Sdim *pp = p->next; 6308218822Sdim return TRUE; 6309218822Sdim } 6310218822Sdim pp = &p->next; 6311218822Sdim } 6312218822Sdim 6313218822Sdim (*_bfd_error_handler) (_("dynreloc miscount for %B, section %A"), 6314218822Sdim sec->owner, sec); 6315218822Sdim bfd_set_error (bfd_error_bad_value); 6316218822Sdim return FALSE; 6317218822Sdim} 6318218822Sdim 6319130561Sobrien/* Remove unused Official Procedure Descriptor entries. Currently we 6320130561Sobrien only remove those associated with functions in discarded link-once 6321130561Sobrien sections, or weakly defined functions that have been overridden. It 6322130561Sobrien would be possible to remove many more entries for statically linked 6323130561Sobrien applications. */ 6324130561Sobrien 6325130561Sobrienbfd_boolean 6326218822Sdimppc64_elf_edit_opd (bfd *obfd, struct bfd_link_info *info, 6327218822Sdim bfd_boolean no_opd_opt, 6328218822Sdim bfd_boolean non_overlapping) 6329130561Sobrien{ 6330104834Sobrien bfd *ibfd; 6331130561Sobrien bfd_boolean some_edited = FALSE; 6332218822Sdim asection *need_pad = NULL; 6333104834Sobrien 6334130561Sobrien for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 6335104834Sobrien { 6336104834Sobrien asection *sec; 6337104834Sobrien Elf_Internal_Rela *relstart, *rel, *relend; 6338104834Sobrien Elf_Internal_Shdr *symtab_hdr; 6339104834Sobrien Elf_Internal_Sym *local_syms; 6340104834Sobrien struct elf_link_hash_entry **sym_hashes; 6341104834Sobrien bfd_vma offset; 6342130561Sobrien bfd_size_type amt; 6343218822Sdim long *opd_adjust; 6344218822Sdim bfd_boolean need_edit, add_aux_fields; 6345218822Sdim bfd_size_type cnt_16b = 0; 6346104834Sobrien 6347104834Sobrien sec = bfd_get_section_by_name (ibfd, ".opd"); 6348218822Sdim if (sec == NULL || sec->size == 0) 6349104834Sobrien continue; 6350104834Sobrien 6351218822Sdim amt = sec->size * sizeof (long) / 8; 6352218822Sdim opd_adjust = get_opd_info (sec); 6353218822Sdim if (opd_adjust == NULL) 6354130561Sobrien { 6355218822Sdim /* check_relocs hasn't been called. Must be a ld -r link 6356218822Sdim or --just-symbols object. */ 6357218822Sdim opd_adjust = bfd_alloc (obfd, amt); 6358218822Sdim if (opd_adjust == NULL) 6359218822Sdim return FALSE; 6360218822Sdim ppc64_elf_section_data (sec)->u.opd_adjust = opd_adjust; 6361218822Sdim BFD_ASSERT (ppc64_elf_section_data (sec)->sec_type == sec_normal); 6362218822Sdim ppc64_elf_section_data (sec)->sec_type = sec_opd; 6363130561Sobrien } 6364218822Sdim memset (opd_adjust, 0, amt); 6365104834Sobrien 6366218822Sdim if (no_opd_opt) 6367218822Sdim continue; 6368218822Sdim 6369218822Sdim if (sec->sec_info_type == ELF_INFO_TYPE_JUST_SYMS) 6370218822Sdim continue; 6371218822Sdim 6372104834Sobrien if (sec->output_section == bfd_abs_section_ptr) 6373104834Sobrien continue; 6374104834Sobrien 6375104834Sobrien /* Look through the section relocs. */ 6376104834Sobrien if ((sec->flags & SEC_RELOC) == 0 || sec->reloc_count == 0) 6377104834Sobrien continue; 6378104834Sobrien 6379104834Sobrien local_syms = NULL; 6380104834Sobrien symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; 6381104834Sobrien sym_hashes = elf_sym_hashes (ibfd); 6382104834Sobrien 6383104834Sobrien /* Read the relocations. */ 6384130561Sobrien relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, 6385130561Sobrien info->keep_memory); 6386104834Sobrien if (relstart == NULL) 6387130561Sobrien return FALSE; 6388104834Sobrien 6389104834Sobrien /* First run through the relocs to check they are sane, and to 6390104834Sobrien determine whether we need to edit this opd section. */ 6391130561Sobrien need_edit = FALSE; 6392218822Sdim need_pad = sec; 6393104834Sobrien offset = 0; 6394104834Sobrien relend = relstart + sec->reloc_count; 6395130561Sobrien for (rel = relstart; rel < relend; ) 6396104834Sobrien { 6397130561Sobrien enum elf_ppc64_reloc_type r_type; 6398104834Sobrien unsigned long r_symndx; 6399104834Sobrien asection *sym_sec; 6400104834Sobrien struct elf_link_hash_entry *h; 6401104834Sobrien Elf_Internal_Sym *sym; 6402104834Sobrien 6403218822Sdim /* .opd contains a regular array of 16 or 24 byte entries. We're 6404104834Sobrien only interested in the reloc pointing to a function entry 6405104834Sobrien point. */ 6406130561Sobrien if (rel->r_offset != offset 6407130561Sobrien || rel + 1 >= relend 6408130561Sobrien || (rel + 1)->r_offset != offset + 8) 6409104834Sobrien { 6410104834Sobrien /* If someone messes with .opd alignment then after a 6411104834Sobrien "ld -r" we might have padding in the middle of .opd. 6412104834Sobrien Also, there's nothing to prevent someone putting 6413104834Sobrien something silly in .opd with the assembler. No .opd 6414130561Sobrien optimization for them! */ 6415218822Sdim broken_opd: 6416104834Sobrien (*_bfd_error_handler) 6417218822Sdim (_("%B: .opd is not a regular array of opd entries"), ibfd); 6418130561Sobrien need_edit = FALSE; 6419104834Sobrien break; 6420104834Sobrien } 6421104834Sobrien 6422130561Sobrien if ((r_type = ELF64_R_TYPE (rel->r_info)) != R_PPC64_ADDR64 6423130561Sobrien || (r_type = ELF64_R_TYPE ((rel + 1)->r_info)) != R_PPC64_TOC) 6424104834Sobrien { 6425130561Sobrien (*_bfd_error_handler) 6426218822Sdim (_("%B: unexpected reloc type %u in .opd section"), 6427218822Sdim ibfd, r_type); 6428130561Sobrien need_edit = FALSE; 6429130561Sobrien break; 6430104834Sobrien } 6431104834Sobrien 6432130561Sobrien r_symndx = ELF64_R_SYM (rel->r_info); 6433130561Sobrien if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, 6434130561Sobrien r_symndx, ibfd)) 6435130561Sobrien goto error_ret; 6436130561Sobrien 6437104834Sobrien if (sym_sec == NULL || sym_sec->owner == NULL) 6438104834Sobrien { 6439130561Sobrien const char *sym_name; 6440130561Sobrien if (h != NULL) 6441130561Sobrien sym_name = h->root.root.string; 6442130561Sobrien else 6443218822Sdim sym_name = bfd_elf_sym_name (ibfd, symtab_hdr, sym, 6444218822Sdim sym_sec); 6445130561Sobrien 6446104834Sobrien (*_bfd_error_handler) 6447218822Sdim (_("%B: undefined sym `%s' in .opd section"), 6448218822Sdim ibfd, sym_name); 6449130561Sobrien need_edit = FALSE; 6450104834Sobrien break; 6451104834Sobrien } 6452104834Sobrien 6453104834Sobrien /* opd entries are always for functions defined in the 6454104834Sobrien current input bfd. If the symbol isn't defined in the 6455104834Sobrien input bfd, then we won't be using the function in this 6456104834Sobrien bfd; It must be defined in a linkonce section in another 6457104834Sobrien bfd, or is weak. It's also possible that we are 6458104834Sobrien discarding the function due to a linker script /DISCARD/, 6459104834Sobrien which we test for via the output_section. */ 6460104834Sobrien if (sym_sec->owner != ibfd 6461104834Sobrien || sym_sec->output_section == bfd_abs_section_ptr) 6462130561Sobrien need_edit = TRUE; 6463104834Sobrien 6464130561Sobrien rel += 2; 6465218822Sdim if (rel == relend 6466218822Sdim || (rel + 1 == relend && rel->r_offset == offset + 16)) 6467218822Sdim { 6468218822Sdim if (sec->size == offset + 24) 6469218822Sdim { 6470218822Sdim need_pad = NULL; 6471218822Sdim break; 6472218822Sdim } 6473218822Sdim if (rel == relend && sec->size == offset + 16) 6474218822Sdim { 6475218822Sdim cnt_16b++; 6476218822Sdim break; 6477218822Sdim } 6478218822Sdim goto broken_opd; 6479218822Sdim } 6480218822Sdim 6481218822Sdim if (rel->r_offset == offset + 24) 6482218822Sdim offset += 24; 6483218822Sdim else if (rel->r_offset != offset + 16) 6484218822Sdim goto broken_opd; 6485218822Sdim else if (rel + 1 < relend 6486218822Sdim && ELF64_R_TYPE (rel[0].r_info) == R_PPC64_ADDR64 6487218822Sdim && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_TOC) 6488218822Sdim { 6489218822Sdim offset += 16; 6490218822Sdim cnt_16b++; 6491218822Sdim } 6492218822Sdim else if (rel + 2 < relend 6493218822Sdim && ELF64_R_TYPE (rel[1].r_info) == R_PPC64_ADDR64 6494218822Sdim && ELF64_R_TYPE (rel[2].r_info) == R_PPC64_TOC) 6495218822Sdim { 6496218822Sdim offset += 24; 6497218822Sdim rel += 1; 6498218822Sdim } 6499218822Sdim else 6500218822Sdim goto broken_opd; 6501104834Sobrien } 6502104834Sobrien 6503218822Sdim add_aux_fields = non_overlapping && cnt_16b > 0; 6504218822Sdim 6505218822Sdim if (need_edit || add_aux_fields) 6506104834Sobrien { 6507104834Sobrien Elf_Internal_Rela *write_rel; 6508104834Sobrien bfd_byte *rptr, *wptr; 6509218822Sdim bfd_byte *new_contents = NULL; 6510130561Sobrien bfd_boolean skip; 6511218822Sdim long opd_ent_size; 6512104834Sobrien 6513104834Sobrien /* This seems a waste of time as input .opd sections are all 6514104834Sobrien zeros as generated by gcc, but I suppose there's no reason 6515104834Sobrien this will always be so. We might start putting something in 6516104834Sobrien the third word of .opd entries. */ 6517104834Sobrien if ((sec->flags & SEC_IN_MEMORY) == 0) 6518104834Sobrien { 6519218822Sdim bfd_byte *loc; 6520218822Sdim if (!bfd_malloc_and_get_section (ibfd, sec, &loc)) 6521104834Sobrien { 6522218822Sdim if (loc != NULL) 6523218822Sdim free (loc); 6524130561Sobrien error_ret: 6525104834Sobrien if (local_syms != NULL 6526104834Sobrien && symtab_hdr->contents != (unsigned char *) local_syms) 6527104834Sobrien free (local_syms); 6528104834Sobrien if (elf_section_data (sec)->relocs != relstart) 6529104834Sobrien free (relstart); 6530130561Sobrien return FALSE; 6531104834Sobrien } 6532104834Sobrien sec->contents = loc; 6533104834Sobrien sec->flags |= (SEC_IN_MEMORY | SEC_HAS_CONTENTS); 6534104834Sobrien } 6535104834Sobrien 6536104834Sobrien elf_section_data (sec)->relocs = relstart; 6537104834Sobrien 6538218822Sdim new_contents = sec->contents; 6539218822Sdim if (add_aux_fields) 6540218822Sdim { 6541218822Sdim new_contents = bfd_malloc (sec->size + cnt_16b * 8); 6542218822Sdim if (new_contents == NULL) 6543218822Sdim return FALSE; 6544218822Sdim need_pad = FALSE; 6545218822Sdim } 6546218822Sdim wptr = new_contents; 6547104834Sobrien rptr = sec->contents; 6548218822Sdim 6549104834Sobrien write_rel = relstart; 6550130561Sobrien skip = FALSE; 6551104834Sobrien offset = 0; 6552218822Sdim opd_ent_size = 0; 6553104834Sobrien for (rel = relstart; rel < relend; rel++) 6554104834Sobrien { 6555130561Sobrien unsigned long r_symndx; 6556130561Sobrien asection *sym_sec; 6557130561Sobrien struct elf_link_hash_entry *h; 6558130561Sobrien Elf_Internal_Sym *sym; 6559130561Sobrien 6560130561Sobrien r_symndx = ELF64_R_SYM (rel->r_info); 6561130561Sobrien if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, 6562130561Sobrien r_symndx, ibfd)) 6563130561Sobrien goto error_ret; 6564130561Sobrien 6565104834Sobrien if (rel->r_offset == offset) 6566104834Sobrien { 6567130561Sobrien struct ppc_link_hash_entry *fdh = NULL; 6568104834Sobrien 6569218822Sdim /* See if the .opd entry is full 24 byte or 6570218822Sdim 16 byte (with fd_aux entry overlapped with next 6571218822Sdim fd_func). */ 6572218822Sdim opd_ent_size = 24; 6573218822Sdim if ((rel + 2 == relend && sec->size == offset + 16) 6574218822Sdim || (rel + 3 < relend 6575218822Sdim && rel[2].r_offset == offset + 16 6576218822Sdim && rel[3].r_offset == offset + 24 6577218822Sdim && ELF64_R_TYPE (rel[2].r_info) == R_PPC64_ADDR64 6578218822Sdim && ELF64_R_TYPE (rel[3].r_info) == R_PPC64_TOC)) 6579218822Sdim opd_ent_size = 16; 6580218822Sdim 6581218822Sdim if (h != NULL 6582218822Sdim && h->root.root.string[0] == '.') 6583218822Sdim { 6584218822Sdim fdh = get_fdh ((struct ppc_link_hash_entry *) h, 6585218822Sdim ppc_hash_table (info)); 6586218822Sdim if (fdh != NULL 6587218822Sdim && fdh->elf.root.type != bfd_link_hash_defined 6588218822Sdim && fdh->elf.root.type != bfd_link_hash_defweak) 6589218822Sdim fdh = NULL; 6590218822Sdim } 6591218822Sdim 6592104834Sobrien skip = (sym_sec->owner != ibfd 6593104834Sobrien || sym_sec->output_section == bfd_abs_section_ptr); 6594104834Sobrien if (skip) 6595104834Sobrien { 6596218822Sdim if (fdh != NULL && sym_sec->owner == ibfd) 6597104834Sobrien { 6598104834Sobrien /* Arrange for the function descriptor sym 6599104834Sobrien to be dropped. */ 6600130561Sobrien fdh->elf.root.u.def.value = 0; 6601130561Sobrien fdh->elf.root.u.def.section = sym_sec; 6602104834Sobrien } 6603218822Sdim opd_adjust[rel->r_offset / 8] = -1; 6604104834Sobrien } 6605104834Sobrien else 6606104834Sobrien { 6607104834Sobrien /* We'll be keeping this opd entry. */ 6608104834Sobrien 6609218822Sdim if (fdh != NULL) 6610104834Sobrien { 6611130561Sobrien /* Redefine the function descriptor symbol to 6612130561Sobrien this location in the opd section. It is 6613130561Sobrien necessary to update the value here rather 6614130561Sobrien than using an array of adjustments as we do 6615130561Sobrien for local symbols, because various places 6616130561Sobrien in the generic ELF code use the value 6617130561Sobrien stored in u.def.value. */ 6618218822Sdim fdh->elf.root.u.def.value = wptr - new_contents; 6619130561Sobrien fdh->adjust_done = 1; 6620104834Sobrien } 6621104834Sobrien 6622130561Sobrien /* Local syms are a bit tricky. We could 6623130561Sobrien tweak them as they can be cached, but 6624130561Sobrien we'd need to look through the local syms 6625130561Sobrien for the function descriptor sym which we 6626130561Sobrien don't have at the moment. So keep an 6627130561Sobrien array of adjustments. */ 6628218822Sdim opd_adjust[rel->r_offset / 8] 6629218822Sdim = (wptr - new_contents) - (rptr - sec->contents); 6630130561Sobrien 6631104834Sobrien if (wptr != rptr) 6632218822Sdim memcpy (wptr, rptr, opd_ent_size); 6633218822Sdim wptr += opd_ent_size; 6634218822Sdim if (add_aux_fields && opd_ent_size == 16) 6635218822Sdim { 6636218822Sdim memset (wptr, '\0', 8); 6637218822Sdim wptr += 8; 6638218822Sdim } 6639104834Sobrien } 6640218822Sdim rptr += opd_ent_size; 6641218822Sdim offset += opd_ent_size; 6642104834Sobrien } 6643104834Sobrien 6644130561Sobrien if (skip) 6645104834Sobrien { 6646218822Sdim if (!NO_OPD_RELOCS 6647218822Sdim && !info->relocatable 6648218822Sdim && !dec_dynrel_count (rel->r_info, sec, info, 6649218822Sdim NULL, h, sym_sec)) 6650218822Sdim goto error_ret; 6651130561Sobrien } 6652130561Sobrien else 6653130561Sobrien { 6654130561Sobrien /* We need to adjust any reloc offsets to point to the 6655130561Sobrien new opd entries. While we're at it, we may as well 6656130561Sobrien remove redundant relocs. */ 6657218822Sdim rel->r_offset += opd_adjust[(offset - opd_ent_size) / 8]; 6658104834Sobrien if (write_rel != rel) 6659104834Sobrien memcpy (write_rel, rel, sizeof (*rel)); 6660104834Sobrien ++write_rel; 6661104834Sobrien } 6662104834Sobrien } 6663104834Sobrien 6664218822Sdim sec->size = wptr - new_contents; 6665104834Sobrien sec->reloc_count = write_rel - relstart; 6666218822Sdim if (add_aux_fields) 6667218822Sdim { 6668218822Sdim free (sec->contents); 6669218822Sdim sec->contents = new_contents; 6670218822Sdim } 6671218822Sdim 6672218822Sdim /* Fudge the header size too, as this is used later in 6673130561Sobrien elf_bfd_final_link if we are emitting relocs. */ 6674130561Sobrien elf_section_data (sec)->rel_hdr.sh_size 6675130561Sobrien = sec->reloc_count * elf_section_data (sec)->rel_hdr.sh_entsize; 6676130561Sobrien BFD_ASSERT (elf_section_data (sec)->rel_hdr2 == NULL); 6677130561Sobrien some_edited = TRUE; 6678104834Sobrien } 6679104834Sobrien else if (elf_section_data (sec)->relocs != relstart) 6680104834Sobrien free (relstart); 6681104834Sobrien 6682104834Sobrien if (local_syms != NULL 6683104834Sobrien && symtab_hdr->contents != (unsigned char *) local_syms) 6684104834Sobrien { 6685104834Sobrien if (!info->keep_memory) 6686104834Sobrien free (local_syms); 6687104834Sobrien else 6688104834Sobrien symtab_hdr->contents = (unsigned char *) local_syms; 6689104834Sobrien } 6690104834Sobrien } 6691104834Sobrien 6692130561Sobrien if (some_edited) 6693130561Sobrien elf_link_hash_traverse (elf_hash_table (info), adjust_opd_syms, NULL); 6694130561Sobrien 6695218822Sdim /* If we are doing a final link and the last .opd entry is just 16 byte 6696218822Sdim long, add a 8 byte padding after it. */ 6697218822Sdim if (need_pad != NULL && !info->relocatable) 6698218822Sdim { 6699218822Sdim bfd_byte *p; 6700218822Sdim 6701218822Sdim if ((need_pad->flags & SEC_IN_MEMORY) == 0) 6702218822Sdim { 6703218822Sdim BFD_ASSERT (need_pad->size > 0); 6704218822Sdim 6705218822Sdim p = bfd_malloc (need_pad->size + 8); 6706218822Sdim if (p == NULL) 6707218822Sdim return FALSE; 6708218822Sdim 6709218822Sdim if (! bfd_get_section_contents (need_pad->owner, need_pad, 6710218822Sdim p, 0, need_pad->size)) 6711218822Sdim return FALSE; 6712218822Sdim 6713218822Sdim need_pad->contents = p; 6714218822Sdim need_pad->flags |= (SEC_IN_MEMORY | SEC_HAS_CONTENTS); 6715218822Sdim } 6716218822Sdim else 6717218822Sdim { 6718218822Sdim p = bfd_realloc (need_pad->contents, need_pad->size + 8); 6719218822Sdim if (p == NULL) 6720218822Sdim return FALSE; 6721218822Sdim 6722218822Sdim need_pad->contents = p; 6723218822Sdim } 6724218822Sdim 6725218822Sdim memset (need_pad->contents + need_pad->size, 0, 8); 6726218822Sdim need_pad->size += 8; 6727218822Sdim } 6728218822Sdim 6729130561Sobrien return TRUE; 6730104834Sobrien} 673189857Sobrien 6732130561Sobrien/* Set htab->tls_get_addr and call the generic ELF tls_setup function. */ 6733130561Sobrien 6734130561Sobrienasection * 6735130561Sobrienppc64_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) 6736130561Sobrien{ 6737130561Sobrien struct ppc_link_hash_table *htab; 6738130561Sobrien 6739130561Sobrien htab = ppc_hash_table (info); 6740130561Sobrien if (htab->tls_get_addr != NULL) 6741130561Sobrien { 6742218822Sdim struct ppc_link_hash_entry *h = htab->tls_get_addr; 6743130561Sobrien 6744218822Sdim while (h->elf.root.type == bfd_link_hash_indirect 6745218822Sdim || h->elf.root.type == bfd_link_hash_warning) 6746218822Sdim h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link; 6747130561Sobrien 6748130561Sobrien htab->tls_get_addr = h; 6749218822Sdim 6750218822Sdim if (htab->tls_get_addr_fd == NULL 6751218822Sdim && h->oh != NULL 6752218822Sdim && h->oh->is_func_descriptor 6753218822Sdim && (h->oh->elf.root.type == bfd_link_hash_defined 6754218822Sdim || h->oh->elf.root.type == bfd_link_hash_defweak)) 6755218822Sdim htab->tls_get_addr_fd = h->oh; 6756130561Sobrien } 6757130561Sobrien 6758218822Sdim if (htab->tls_get_addr_fd != NULL) 6759218822Sdim { 6760218822Sdim struct ppc_link_hash_entry *h = htab->tls_get_addr_fd; 6761218822Sdim 6762218822Sdim while (h->elf.root.type == bfd_link_hash_indirect 6763218822Sdim || h->elf.root.type == bfd_link_hash_warning) 6764218822Sdim h = (struct ppc_link_hash_entry *) h->elf.root.u.i.link; 6765218822Sdim 6766218822Sdim htab->tls_get_addr_fd = h; 6767218822Sdim } 6768218822Sdim 6769130561Sobrien return _bfd_elf_tls_setup (obfd, info); 6770130561Sobrien} 6771130561Sobrien 6772130561Sobrien/* Run through all the TLS relocs looking for optimization 6773130561Sobrien opportunities. The linker has been hacked (see ppc64elf.em) to do 6774130561Sobrien a preliminary section layout so that we know the TLS segment 6775130561Sobrien offsets. We can't optimize earlier because some optimizations need 6776130561Sobrien to know the tp offset, and we need to optimize before allocating 6777130561Sobrien dynamic relocations. */ 6778130561Sobrien 6779130561Sobrienbfd_boolean 6780130561Sobrienppc64_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) 6781130561Sobrien{ 6782130561Sobrien bfd *ibfd; 6783130561Sobrien asection *sec; 6784130561Sobrien struct ppc_link_hash_table *htab; 6785130561Sobrien 6786130561Sobrien if (info->relocatable || info->shared) 6787130561Sobrien return TRUE; 6788130561Sobrien 6789130561Sobrien htab = ppc_hash_table (info); 6790130561Sobrien for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 6791130561Sobrien { 6792130561Sobrien Elf_Internal_Sym *locsyms = NULL; 6793218822Sdim asection *toc = bfd_get_section_by_name (ibfd, ".toc"); 6794218822Sdim unsigned char *toc_ref = NULL; 6795130561Sobrien 6796218822Sdim /* Look at all the sections for this file, with TOC last. */ 6797218822Sdim for (sec = (ibfd->sections == toc && toc && toc->next ? toc->next 6798218822Sdim : ibfd->sections); 6799218822Sdim sec != NULL; 6800218822Sdim sec = (sec == toc ? NULL 6801218822Sdim : sec->next == NULL ? toc 6802218822Sdim : sec->next == toc && toc->next ? toc->next 6803218822Sdim : sec->next)) 6804130561Sobrien if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section)) 6805130561Sobrien { 6806130561Sobrien Elf_Internal_Rela *relstart, *rel, *relend; 6807130561Sobrien int expecting_tls_get_addr; 6808218822Sdim long toc_ref_index = 0; 6809130561Sobrien 6810130561Sobrien /* Read the relocations. */ 6811130561Sobrien relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, 6812130561Sobrien info->keep_memory); 6813130561Sobrien if (relstart == NULL) 6814130561Sobrien return FALSE; 6815130561Sobrien 6816130561Sobrien expecting_tls_get_addr = 0; 6817130561Sobrien relend = relstart + sec->reloc_count; 6818130561Sobrien for (rel = relstart; rel < relend; rel++) 6819130561Sobrien { 6820130561Sobrien enum elf_ppc64_reloc_type r_type; 6821130561Sobrien unsigned long r_symndx; 6822130561Sobrien struct elf_link_hash_entry *h; 6823130561Sobrien Elf_Internal_Sym *sym; 6824130561Sobrien asection *sym_sec; 6825130561Sobrien char *tls_mask; 6826130561Sobrien char tls_set, tls_clear, tls_type = 0; 6827130561Sobrien bfd_vma value; 6828130561Sobrien bfd_boolean ok_tprel, is_local; 6829130561Sobrien 6830130561Sobrien r_symndx = ELF64_R_SYM (rel->r_info); 6831130561Sobrien if (!get_sym_h (&h, &sym, &sym_sec, &tls_mask, &locsyms, 6832130561Sobrien r_symndx, ibfd)) 6833130561Sobrien { 6834130561Sobrien err_free_rel: 6835130561Sobrien if (elf_section_data (sec)->relocs != relstart) 6836130561Sobrien free (relstart); 6837218822Sdim if (toc_ref != NULL) 6838218822Sdim free (toc_ref); 6839130561Sobrien if (locsyms != NULL 6840130561Sobrien && (elf_tdata (ibfd)->symtab_hdr.contents 6841130561Sobrien != (unsigned char *) locsyms)) 6842130561Sobrien free (locsyms); 6843130561Sobrien return FALSE; 6844130561Sobrien } 6845130561Sobrien 6846130561Sobrien if (h != NULL) 6847130561Sobrien { 6848130561Sobrien if (h->root.type != bfd_link_hash_defined 6849130561Sobrien && h->root.type != bfd_link_hash_defweak) 6850130561Sobrien continue; 6851130561Sobrien value = h->root.u.def.value; 6852130561Sobrien } 6853130561Sobrien else 6854218822Sdim /* Symbols referenced by TLS relocs must be of type 6855218822Sdim STT_TLS. So no need for .opd local sym adjust. */ 6856218822Sdim value = sym->st_value; 6857130561Sobrien 6858130561Sobrien ok_tprel = FALSE; 6859130561Sobrien is_local = FALSE; 6860130561Sobrien if (h == NULL 6861218822Sdim || !h->def_dynamic) 6862130561Sobrien { 6863130561Sobrien is_local = TRUE; 6864130561Sobrien value += sym_sec->output_offset; 6865130561Sobrien value += sym_sec->output_section->vma; 6866130561Sobrien value -= htab->elf.tls_sec->vma; 6867130561Sobrien ok_tprel = (value + TP_OFFSET + ((bfd_vma) 1 << 31) 6868130561Sobrien < (bfd_vma) 1 << 32); 6869130561Sobrien } 6870130561Sobrien 6871130561Sobrien r_type = ELF64_R_TYPE (rel->r_info); 6872130561Sobrien switch (r_type) 6873130561Sobrien { 6874130561Sobrien case R_PPC64_GOT_TLSLD16: 6875130561Sobrien case R_PPC64_GOT_TLSLD16_LO: 6876130561Sobrien case R_PPC64_GOT_TLSLD16_HI: 6877130561Sobrien case R_PPC64_GOT_TLSLD16_HA: 6878130561Sobrien /* These relocs should never be against a symbol 6879130561Sobrien defined in a shared lib. Leave them alone if 6880130561Sobrien that turns out to be the case. */ 6881130561Sobrien ppc64_tlsld_got (ibfd)->refcount -= 1; 6882130561Sobrien if (!is_local) 6883130561Sobrien continue; 6884130561Sobrien 6885130561Sobrien /* LD -> LE */ 6886130561Sobrien tls_set = 0; 6887130561Sobrien tls_clear = TLS_LD; 6888130561Sobrien tls_type = TLS_TLS | TLS_LD; 6889130561Sobrien expecting_tls_get_addr = 1; 6890130561Sobrien break; 6891130561Sobrien 6892130561Sobrien case R_PPC64_GOT_TLSGD16: 6893130561Sobrien case R_PPC64_GOT_TLSGD16_LO: 6894130561Sobrien case R_PPC64_GOT_TLSGD16_HI: 6895130561Sobrien case R_PPC64_GOT_TLSGD16_HA: 6896130561Sobrien if (ok_tprel) 6897130561Sobrien /* GD -> LE */ 6898130561Sobrien tls_set = 0; 6899130561Sobrien else 6900130561Sobrien /* GD -> IE */ 6901130561Sobrien tls_set = TLS_TLS | TLS_TPRELGD; 6902130561Sobrien tls_clear = TLS_GD; 6903130561Sobrien tls_type = TLS_TLS | TLS_GD; 6904130561Sobrien expecting_tls_get_addr = 1; 6905130561Sobrien break; 6906130561Sobrien 6907130561Sobrien case R_PPC64_GOT_TPREL16_DS: 6908130561Sobrien case R_PPC64_GOT_TPREL16_LO_DS: 6909130561Sobrien case R_PPC64_GOT_TPREL16_HI: 6910130561Sobrien case R_PPC64_GOT_TPREL16_HA: 6911130561Sobrien expecting_tls_get_addr = 0; 6912130561Sobrien if (ok_tprel) 6913130561Sobrien { 6914130561Sobrien /* IE -> LE */ 6915130561Sobrien tls_set = 0; 6916130561Sobrien tls_clear = TLS_TPREL; 6917130561Sobrien tls_type = TLS_TLS | TLS_TPREL; 6918130561Sobrien break; 6919130561Sobrien } 6920130561Sobrien else 6921130561Sobrien continue; 6922130561Sobrien 6923130561Sobrien case R_PPC64_REL14: 6924130561Sobrien case R_PPC64_REL14_BRTAKEN: 6925130561Sobrien case R_PPC64_REL14_BRNTAKEN: 6926130561Sobrien case R_PPC64_REL24: 6927130561Sobrien if (h != NULL 6928218822Sdim && (h == &htab->tls_get_addr->elf 6929218822Sdim || h == &htab->tls_get_addr_fd->elf)) 6930130561Sobrien { 6931130561Sobrien if (!expecting_tls_get_addr 6932130561Sobrien && rel != relstart 6933130561Sobrien && ((ELF64_R_TYPE (rel[-1].r_info) 6934130561Sobrien == R_PPC64_TOC16) 6935130561Sobrien || (ELF64_R_TYPE (rel[-1].r_info) 6936130561Sobrien == R_PPC64_TOC16_LO))) 6937130561Sobrien { 6938130561Sobrien /* Check for toc tls entries. */ 6939130561Sobrien char *toc_tls; 6940130561Sobrien int retval; 6941130561Sobrien 6942130561Sobrien retval = get_tls_mask (&toc_tls, NULL, &locsyms, 6943130561Sobrien rel - 1, ibfd); 6944130561Sobrien if (retval == 0) 6945130561Sobrien goto err_free_rel; 6946218822Sdim if (retval > 1 && toc_tls != NULL) 6947218822Sdim { 6948218822Sdim expecting_tls_get_addr = 1; 6949218822Sdim if (toc_ref != NULL) 6950218822Sdim toc_ref[toc_ref_index] = 1; 6951218822Sdim } 6952130561Sobrien } 6953130561Sobrien 6954130561Sobrien if (expecting_tls_get_addr) 6955130561Sobrien { 6956130561Sobrien struct plt_entry *ent; 6957130561Sobrien for (ent = h->plt.plist; ent; ent = ent->next) 6958130561Sobrien if (ent->addend == 0) 6959130561Sobrien { 6960130561Sobrien if (ent->plt.refcount > 0) 6961130561Sobrien ent->plt.refcount -= 1; 6962130561Sobrien break; 6963130561Sobrien } 6964130561Sobrien } 6965130561Sobrien } 6966130561Sobrien expecting_tls_get_addr = 0; 6967130561Sobrien continue; 6968130561Sobrien 6969218822Sdim case R_PPC64_TOC16: 6970218822Sdim case R_PPC64_TOC16_LO: 6971218822Sdim case R_PPC64_TLS: 6972218822Sdim expecting_tls_get_addr = 0; 6973218822Sdim if (sym_sec == toc && toc != NULL) 6974218822Sdim { 6975218822Sdim /* Mark this toc entry as referenced by a TLS 6976218822Sdim code sequence. We can do that now in the 6977218822Sdim case of R_PPC64_TLS, and after checking for 6978218822Sdim tls_get_addr for the TOC16 relocs. */ 6979218822Sdim if (toc_ref == NULL) 6980218822Sdim { 6981218822Sdim toc_ref = bfd_zmalloc (toc->size / 8); 6982218822Sdim if (toc_ref == NULL) 6983218822Sdim goto err_free_rel; 6984218822Sdim } 6985218822Sdim if (h != NULL) 6986218822Sdim value = h->root.u.def.value; 6987218822Sdim else 6988218822Sdim value = sym->st_value; 6989218822Sdim value += rel->r_addend; 6990218822Sdim BFD_ASSERT (value < toc->size && value % 8 == 0); 6991218822Sdim toc_ref_index = value / 8; 6992218822Sdim if (r_type == R_PPC64_TLS) 6993218822Sdim toc_ref[toc_ref_index] = 1; 6994218822Sdim } 6995218822Sdim continue; 6996218822Sdim 6997130561Sobrien case R_PPC64_TPREL64: 6998130561Sobrien expecting_tls_get_addr = 0; 6999218822Sdim if (sec != toc 7000218822Sdim || toc_ref == NULL 7001218822Sdim || !toc_ref[rel->r_offset / 8]) 7002218822Sdim continue; 7003130561Sobrien if (ok_tprel) 7004130561Sobrien { 7005130561Sobrien /* IE -> LE */ 7006130561Sobrien tls_set = TLS_EXPLICIT; 7007130561Sobrien tls_clear = TLS_TPREL; 7008130561Sobrien break; 7009130561Sobrien } 7010130561Sobrien else 7011130561Sobrien continue; 7012130561Sobrien 7013130561Sobrien case R_PPC64_DTPMOD64: 7014130561Sobrien expecting_tls_get_addr = 0; 7015218822Sdim if (sec != toc 7016218822Sdim || toc_ref == NULL 7017218822Sdim || !toc_ref[rel->r_offset / 8]) 7018218822Sdim continue; 7019130561Sobrien if (rel + 1 < relend 7020130561Sobrien && (rel[1].r_info 7021130561Sobrien == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64)) 7022130561Sobrien && rel[1].r_offset == rel->r_offset + 8) 7023130561Sobrien { 7024130561Sobrien if (ok_tprel) 7025130561Sobrien /* GD -> LE */ 7026130561Sobrien tls_set = TLS_EXPLICIT | TLS_GD; 7027130561Sobrien else 7028130561Sobrien /* GD -> IE */ 7029130561Sobrien tls_set = TLS_EXPLICIT | TLS_GD | TLS_TPRELGD; 7030130561Sobrien tls_clear = TLS_GD; 7031130561Sobrien } 7032130561Sobrien else 7033130561Sobrien { 7034130561Sobrien if (!is_local) 7035130561Sobrien continue; 7036130561Sobrien 7037130561Sobrien /* LD -> LE */ 7038130561Sobrien tls_set = TLS_EXPLICIT; 7039130561Sobrien tls_clear = TLS_LD; 7040130561Sobrien } 7041130561Sobrien break; 7042130561Sobrien 7043130561Sobrien default: 7044130561Sobrien expecting_tls_get_addr = 0; 7045130561Sobrien continue; 7046130561Sobrien } 7047130561Sobrien 7048130561Sobrien if ((tls_set & TLS_EXPLICIT) == 0) 7049130561Sobrien { 7050130561Sobrien struct got_entry *ent; 7051130561Sobrien 7052130561Sobrien /* Adjust got entry for this reloc. */ 7053130561Sobrien if (h != NULL) 7054130561Sobrien ent = h->got.glist; 7055130561Sobrien else 7056130561Sobrien ent = elf_local_got_ents (ibfd)[r_symndx]; 7057130561Sobrien 7058130561Sobrien for (; ent != NULL; ent = ent->next) 7059130561Sobrien if (ent->addend == rel->r_addend 7060130561Sobrien && ent->owner == ibfd 7061130561Sobrien && ent->tls_type == tls_type) 7062130561Sobrien break; 7063130561Sobrien if (ent == NULL) 7064130561Sobrien abort (); 7065130561Sobrien 7066130561Sobrien if (tls_set == 0) 7067130561Sobrien { 7068130561Sobrien /* We managed to get rid of a got entry. */ 7069130561Sobrien if (ent->got.refcount > 0) 7070130561Sobrien ent->got.refcount -= 1; 7071130561Sobrien } 7072130561Sobrien } 7073218822Sdim else 7074130561Sobrien { 7075218822Sdim /* If we got rid of a DTPMOD/DTPREL reloc pair then 7076218822Sdim we'll lose one or two dyn relocs. */ 7077218822Sdim if (!dec_dynrel_count (rel->r_info, sec, info, 7078218822Sdim NULL, h, sym_sec)) 7079218822Sdim return FALSE; 7080130561Sobrien 7081218822Sdim if (tls_set == (TLS_EXPLICIT | TLS_GD)) 7082218822Sdim { 7083218822Sdim if (!dec_dynrel_count ((rel + 1)->r_info, sec, info, 7084218822Sdim NULL, h, sym_sec)) 7085218822Sdim return FALSE; 7086218822Sdim } 7087130561Sobrien } 7088130561Sobrien 7089130561Sobrien *tls_mask |= tls_set; 7090130561Sobrien *tls_mask &= ~tls_clear; 7091130561Sobrien } 7092130561Sobrien 7093130561Sobrien if (elf_section_data (sec)->relocs != relstart) 7094130561Sobrien free (relstart); 7095130561Sobrien } 7096130561Sobrien 7097218822Sdim if (toc_ref != NULL) 7098218822Sdim free (toc_ref); 7099218822Sdim 7100130561Sobrien if (locsyms != NULL 7101130561Sobrien && (elf_tdata (ibfd)->symtab_hdr.contents 7102130561Sobrien != (unsigned char *) locsyms)) 7103130561Sobrien { 7104130561Sobrien if (!info->keep_memory) 7105130561Sobrien free (locsyms); 7106130561Sobrien else 7107130561Sobrien elf_tdata (ibfd)->symtab_hdr.contents = (unsigned char *) locsyms; 7108130561Sobrien } 7109130561Sobrien } 7110130561Sobrien return TRUE; 7111130561Sobrien} 7112130561Sobrien 7113218822Sdim/* Called via elf_link_hash_traverse from ppc64_elf_edit_toc to adjust 7114218822Sdim the values of any global symbols in a toc section that has been 7115218822Sdim edited. Globals in toc sections should be a rarity, so this function 7116218822Sdim sets a flag if any are found in toc sections other than the one just 7117218822Sdim edited, so that futher hash table traversals can be avoided. */ 7118218822Sdim 7119218822Sdimstruct adjust_toc_info 7120218822Sdim{ 7121218822Sdim asection *toc; 7122218822Sdim unsigned long *skip; 7123218822Sdim bfd_boolean global_toc_syms; 7124218822Sdim}; 7125218822Sdim 7126218822Sdimstatic bfd_boolean 7127218822Sdimadjust_toc_syms (struct elf_link_hash_entry *h, void *inf) 7128218822Sdim{ 7129218822Sdim struct ppc_link_hash_entry *eh; 7130218822Sdim struct adjust_toc_info *toc_inf = (struct adjust_toc_info *) inf; 7131218822Sdim 7132218822Sdim if (h->root.type == bfd_link_hash_indirect) 7133218822Sdim return TRUE; 7134218822Sdim 7135218822Sdim if (h->root.type == bfd_link_hash_warning) 7136218822Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 7137218822Sdim 7138218822Sdim if (h->root.type != bfd_link_hash_defined 7139218822Sdim && h->root.type != bfd_link_hash_defweak) 7140218822Sdim return TRUE; 7141218822Sdim 7142218822Sdim eh = (struct ppc_link_hash_entry *) h; 7143218822Sdim if (eh->adjust_done) 7144218822Sdim return TRUE; 7145218822Sdim 7146218822Sdim if (eh->elf.root.u.def.section == toc_inf->toc) 7147218822Sdim { 7148218822Sdim unsigned long skip = toc_inf->skip[eh->elf.root.u.def.value >> 3]; 7149218822Sdim if (skip != (unsigned long) -1) 7150218822Sdim eh->elf.root.u.def.value -= skip; 7151218822Sdim else 7152218822Sdim { 7153218822Sdim (*_bfd_error_handler) 7154218822Sdim (_("%s defined in removed toc entry"), eh->elf.root.root.string); 7155218822Sdim eh->elf.root.u.def.section = &bfd_abs_section; 7156218822Sdim eh->elf.root.u.def.value = 0; 7157218822Sdim } 7158218822Sdim eh->adjust_done = 1; 7159218822Sdim } 7160218822Sdim else if (strcmp (eh->elf.root.u.def.section->name, ".toc") == 0) 7161218822Sdim toc_inf->global_toc_syms = TRUE; 7162218822Sdim 7163218822Sdim return TRUE; 7164218822Sdim} 7165218822Sdim 7166218822Sdim/* Examine all relocs referencing .toc sections in order to remove 7167218822Sdim unused .toc entries. */ 7168218822Sdim 7169218822Sdimbfd_boolean 7170218822Sdimppc64_elf_edit_toc (bfd *obfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) 7171218822Sdim{ 7172218822Sdim bfd *ibfd; 7173218822Sdim struct adjust_toc_info toc_inf; 7174218822Sdim 7175218822Sdim toc_inf.global_toc_syms = TRUE; 7176218822Sdim for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 7177218822Sdim { 7178218822Sdim asection *toc, *sec; 7179218822Sdim Elf_Internal_Shdr *symtab_hdr; 7180218822Sdim Elf_Internal_Sym *local_syms; 7181218822Sdim struct elf_link_hash_entry **sym_hashes; 7182218822Sdim Elf_Internal_Rela *relstart, *rel; 7183218822Sdim unsigned long *skip, *drop; 7184218822Sdim unsigned char *used; 7185218822Sdim unsigned char *keep, last, some_unused; 7186218822Sdim 7187218822Sdim toc = bfd_get_section_by_name (ibfd, ".toc"); 7188218822Sdim if (toc == NULL 7189218822Sdim || toc->size == 0 7190218822Sdim || toc->sec_info_type == ELF_INFO_TYPE_JUST_SYMS 7191218822Sdim || elf_discarded_section (toc)) 7192218822Sdim continue; 7193218822Sdim 7194218822Sdim local_syms = NULL; 7195218822Sdim symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; 7196218822Sdim sym_hashes = elf_sym_hashes (ibfd); 7197218822Sdim 7198218822Sdim /* Look at sections dropped from the final link. */ 7199218822Sdim skip = NULL; 7200218822Sdim relstart = NULL; 7201218822Sdim for (sec = ibfd->sections; sec != NULL; sec = sec->next) 7202218822Sdim { 7203218822Sdim if (sec->reloc_count == 0 7204218822Sdim || !elf_discarded_section (sec) 7205218822Sdim || get_opd_info (sec) 7206218822Sdim || (sec->flags & SEC_ALLOC) == 0 7207218822Sdim || (sec->flags & SEC_DEBUGGING) != 0) 7208218822Sdim continue; 7209218822Sdim 7210218822Sdim relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, FALSE); 7211218822Sdim if (relstart == NULL) 7212218822Sdim goto error_ret; 7213218822Sdim 7214218822Sdim /* Run through the relocs to see which toc entries might be 7215218822Sdim unused. */ 7216218822Sdim for (rel = relstart; rel < relstart + sec->reloc_count; ++rel) 7217218822Sdim { 7218218822Sdim enum elf_ppc64_reloc_type r_type; 7219218822Sdim unsigned long r_symndx; 7220218822Sdim asection *sym_sec; 7221218822Sdim struct elf_link_hash_entry *h; 7222218822Sdim Elf_Internal_Sym *sym; 7223218822Sdim bfd_vma val; 7224218822Sdim 7225218822Sdim r_type = ELF64_R_TYPE (rel->r_info); 7226218822Sdim switch (r_type) 7227218822Sdim { 7228218822Sdim default: 7229218822Sdim continue; 7230218822Sdim 7231218822Sdim case R_PPC64_TOC16: 7232218822Sdim case R_PPC64_TOC16_LO: 7233218822Sdim case R_PPC64_TOC16_HI: 7234218822Sdim case R_PPC64_TOC16_HA: 7235218822Sdim case R_PPC64_TOC16_DS: 7236218822Sdim case R_PPC64_TOC16_LO_DS: 7237218822Sdim break; 7238218822Sdim } 7239218822Sdim 7240218822Sdim r_symndx = ELF64_R_SYM (rel->r_info); 7241218822Sdim if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, 7242218822Sdim r_symndx, ibfd)) 7243218822Sdim goto error_ret; 7244218822Sdim 7245218822Sdim if (sym_sec != toc) 7246218822Sdim continue; 7247218822Sdim 7248218822Sdim if (h != NULL) 7249218822Sdim val = h->root.u.def.value; 7250218822Sdim else 7251218822Sdim val = sym->st_value; 7252218822Sdim val += rel->r_addend; 7253218822Sdim 7254218822Sdim if (val >= toc->size) 7255218822Sdim continue; 7256218822Sdim 7257218822Sdim /* Anything in the toc ought to be aligned to 8 bytes. 7258218822Sdim If not, don't mark as unused. */ 7259218822Sdim if (val & 7) 7260218822Sdim continue; 7261218822Sdim 7262218822Sdim if (skip == NULL) 7263218822Sdim { 7264218822Sdim skip = bfd_zmalloc (sizeof (*skip) * (toc->size + 7) / 8); 7265218822Sdim if (skip == NULL) 7266218822Sdim goto error_ret; 7267218822Sdim } 7268218822Sdim 7269218822Sdim skip[val >> 3] = 1; 7270218822Sdim } 7271218822Sdim 7272218822Sdim if (elf_section_data (sec)->relocs != relstart) 7273218822Sdim free (relstart); 7274218822Sdim } 7275218822Sdim 7276218822Sdim if (skip == NULL) 7277218822Sdim continue; 7278218822Sdim 7279218822Sdim used = bfd_zmalloc (sizeof (*used) * (toc->size + 7) / 8); 7280218822Sdim if (used == NULL) 7281218822Sdim { 7282218822Sdim error_ret: 7283218822Sdim if (local_syms != NULL 7284218822Sdim && symtab_hdr->contents != (unsigned char *) local_syms) 7285218822Sdim free (local_syms); 7286218822Sdim if (sec != NULL 7287218822Sdim && relstart != NULL 7288218822Sdim && elf_section_data (sec)->relocs != relstart) 7289218822Sdim free (relstart); 7290218822Sdim if (skip != NULL) 7291218822Sdim free (skip); 7292218822Sdim return FALSE; 7293218822Sdim } 7294218822Sdim 7295218822Sdim /* Now check all kept sections that might reference the toc. 7296218822Sdim Check the toc itself last. */ 7297218822Sdim for (sec = (ibfd->sections == toc && toc->next ? toc->next 7298218822Sdim : ibfd->sections); 7299218822Sdim sec != NULL; 7300218822Sdim sec = (sec == toc ? NULL 7301218822Sdim : sec->next == NULL ? toc 7302218822Sdim : sec->next == toc && toc->next ? toc->next 7303218822Sdim : sec->next)) 7304218822Sdim { 7305218822Sdim int repeat; 7306218822Sdim 7307218822Sdim if (sec->reloc_count == 0 7308218822Sdim || elf_discarded_section (sec) 7309218822Sdim || get_opd_info (sec) 7310218822Sdim || (sec->flags & SEC_ALLOC) == 0 7311218822Sdim || (sec->flags & SEC_DEBUGGING) != 0) 7312218822Sdim continue; 7313218822Sdim 7314218822Sdim relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, TRUE); 7315218822Sdim if (relstart == NULL) 7316218822Sdim goto error_ret; 7317218822Sdim 7318218822Sdim /* Mark toc entries referenced as used. */ 7319218822Sdim repeat = 0; 7320218822Sdim do 7321218822Sdim for (rel = relstart; rel < relstart + sec->reloc_count; ++rel) 7322218822Sdim { 7323218822Sdim enum elf_ppc64_reloc_type r_type; 7324218822Sdim unsigned long r_symndx; 7325218822Sdim asection *sym_sec; 7326218822Sdim struct elf_link_hash_entry *h; 7327218822Sdim Elf_Internal_Sym *sym; 7328218822Sdim bfd_vma val; 7329218822Sdim 7330218822Sdim r_type = ELF64_R_TYPE (rel->r_info); 7331218822Sdim switch (r_type) 7332218822Sdim { 7333218822Sdim case R_PPC64_TOC16: 7334218822Sdim case R_PPC64_TOC16_LO: 7335218822Sdim case R_PPC64_TOC16_HI: 7336218822Sdim case R_PPC64_TOC16_HA: 7337218822Sdim case R_PPC64_TOC16_DS: 7338218822Sdim case R_PPC64_TOC16_LO_DS: 7339218822Sdim /* In case we're taking addresses of toc entries. */ 7340218822Sdim case R_PPC64_ADDR64: 7341218822Sdim break; 7342218822Sdim 7343218822Sdim default: 7344218822Sdim continue; 7345218822Sdim } 7346218822Sdim 7347218822Sdim r_symndx = ELF64_R_SYM (rel->r_info); 7348218822Sdim if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, 7349218822Sdim r_symndx, ibfd)) 7350218822Sdim { 7351218822Sdim free (used); 7352218822Sdim goto error_ret; 7353218822Sdim } 7354218822Sdim 7355218822Sdim if (sym_sec != toc) 7356218822Sdim continue; 7357218822Sdim 7358218822Sdim if (h != NULL) 7359218822Sdim val = h->root.u.def.value; 7360218822Sdim else 7361218822Sdim val = sym->st_value; 7362218822Sdim val += rel->r_addend; 7363218822Sdim 7364218822Sdim if (val >= toc->size) 7365218822Sdim continue; 7366218822Sdim 7367218822Sdim /* For the toc section, we only mark as used if 7368218822Sdim this entry itself isn't unused. */ 7369218822Sdim if (sec == toc 7370218822Sdim && !used[val >> 3] 7371218822Sdim && (used[rel->r_offset >> 3] 7372218822Sdim || !skip[rel->r_offset >> 3])) 7373218822Sdim /* Do all the relocs again, to catch reference 7374218822Sdim chains. */ 7375218822Sdim repeat = 1; 7376218822Sdim 7377218822Sdim used[val >> 3] = 1; 7378218822Sdim } 7379218822Sdim while (repeat); 7380218822Sdim } 7381218822Sdim 7382218822Sdim /* Merge the used and skip arrays. Assume that TOC 7383218822Sdim doublewords not appearing as either used or unused belong 7384218822Sdim to to an entry more than one doubleword in size. */ 7385218822Sdim for (drop = skip, keep = used, last = 0, some_unused = 0; 7386218822Sdim drop < skip + (toc->size + 7) / 8; 7387218822Sdim ++drop, ++keep) 7388218822Sdim { 7389218822Sdim if (*keep) 7390218822Sdim { 7391218822Sdim *drop = 0; 7392218822Sdim last = 0; 7393218822Sdim } 7394218822Sdim else if (*drop) 7395218822Sdim { 7396218822Sdim some_unused = 1; 7397218822Sdim last = 1; 7398218822Sdim } 7399218822Sdim else 7400218822Sdim *drop = last; 7401218822Sdim } 7402218822Sdim 7403218822Sdim free (used); 7404218822Sdim 7405218822Sdim if (some_unused) 7406218822Sdim { 7407218822Sdim bfd_byte *contents, *src; 7408218822Sdim unsigned long off; 7409218822Sdim 7410218822Sdim /* Shuffle the toc contents, and at the same time convert the 7411218822Sdim skip array from booleans into offsets. */ 7412218822Sdim if (!bfd_malloc_and_get_section (ibfd, toc, &contents)) 7413218822Sdim goto error_ret; 7414218822Sdim 7415218822Sdim elf_section_data (toc)->this_hdr.contents = contents; 7416218822Sdim 7417218822Sdim for (src = contents, off = 0, drop = skip; 7418218822Sdim src < contents + toc->size; 7419218822Sdim src += 8, ++drop) 7420218822Sdim { 7421218822Sdim if (*drop) 7422218822Sdim { 7423218822Sdim *drop = (unsigned long) -1; 7424218822Sdim off += 8; 7425218822Sdim } 7426218822Sdim else if (off != 0) 7427218822Sdim { 7428218822Sdim *drop = off; 7429218822Sdim memcpy (src - off, src, 8); 7430218822Sdim } 7431218822Sdim } 7432218822Sdim toc->rawsize = toc->size; 7433218822Sdim toc->size = src - contents - off; 7434218822Sdim 7435218822Sdim if (toc->reloc_count != 0) 7436218822Sdim { 7437218822Sdim Elf_Internal_Rela *wrel; 7438218822Sdim bfd_size_type sz; 7439218822Sdim 7440218822Sdim /* Read toc relocs. */ 7441218822Sdim relstart = _bfd_elf_link_read_relocs (ibfd, toc, NULL, NULL, 7442218822Sdim TRUE); 7443218822Sdim if (relstart == NULL) 7444218822Sdim goto error_ret; 7445218822Sdim 7446218822Sdim /* Remove unused toc relocs, and adjust those we keep. */ 7447218822Sdim wrel = relstart; 7448218822Sdim for (rel = relstart; rel < relstart + toc->reloc_count; ++rel) 7449218822Sdim if (skip[rel->r_offset >> 3] != (unsigned long) -1) 7450218822Sdim { 7451218822Sdim wrel->r_offset = rel->r_offset - skip[rel->r_offset >> 3]; 7452218822Sdim wrel->r_info = rel->r_info; 7453218822Sdim wrel->r_addend = rel->r_addend; 7454218822Sdim ++wrel; 7455218822Sdim } 7456218822Sdim else if (!dec_dynrel_count (rel->r_info, toc, info, 7457218822Sdim &local_syms, NULL, NULL)) 7458218822Sdim goto error_ret; 7459218822Sdim 7460218822Sdim toc->reloc_count = wrel - relstart; 7461218822Sdim sz = elf_section_data (toc)->rel_hdr.sh_entsize; 7462218822Sdim elf_section_data (toc)->rel_hdr.sh_size = toc->reloc_count * sz; 7463218822Sdim BFD_ASSERT (elf_section_data (toc)->rel_hdr2 == NULL); 7464218822Sdim } 7465218822Sdim 7466218822Sdim /* Adjust addends for relocs against the toc section sym. */ 7467218822Sdim for (sec = ibfd->sections; sec != NULL; sec = sec->next) 7468218822Sdim { 7469218822Sdim if (sec->reloc_count == 0 7470218822Sdim || elf_discarded_section (sec)) 7471218822Sdim continue; 7472218822Sdim 7473218822Sdim relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, 7474218822Sdim TRUE); 7475218822Sdim if (relstart == NULL) 7476218822Sdim goto error_ret; 7477218822Sdim 7478218822Sdim for (rel = relstart; rel < relstart + sec->reloc_count; ++rel) 7479218822Sdim { 7480218822Sdim enum elf_ppc64_reloc_type r_type; 7481218822Sdim unsigned long r_symndx; 7482218822Sdim asection *sym_sec; 7483218822Sdim struct elf_link_hash_entry *h; 7484218822Sdim Elf_Internal_Sym *sym; 7485218822Sdim 7486218822Sdim r_type = ELF64_R_TYPE (rel->r_info); 7487218822Sdim switch (r_type) 7488218822Sdim { 7489218822Sdim default: 7490218822Sdim continue; 7491218822Sdim 7492218822Sdim case R_PPC64_TOC16: 7493218822Sdim case R_PPC64_TOC16_LO: 7494218822Sdim case R_PPC64_TOC16_HI: 7495218822Sdim case R_PPC64_TOC16_HA: 7496218822Sdim case R_PPC64_TOC16_DS: 7497218822Sdim case R_PPC64_TOC16_LO_DS: 7498218822Sdim case R_PPC64_ADDR64: 7499218822Sdim break; 7500218822Sdim } 7501218822Sdim 7502218822Sdim r_symndx = ELF64_R_SYM (rel->r_info); 7503218822Sdim if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, 7504218822Sdim r_symndx, ibfd)) 7505218822Sdim goto error_ret; 7506218822Sdim 7507218822Sdim if (sym_sec != toc || h != NULL || sym->st_value != 0) 7508218822Sdim continue; 7509218822Sdim 7510218822Sdim rel->r_addend -= skip[rel->r_addend >> 3]; 7511218822Sdim } 7512218822Sdim } 7513218822Sdim 7514218822Sdim /* We shouldn't have local or global symbols defined in the TOC, 7515218822Sdim but handle them anyway. */ 7516218822Sdim if (local_syms != NULL) 7517218822Sdim { 7518218822Sdim Elf_Internal_Sym *sym; 7519218822Sdim 7520218822Sdim for (sym = local_syms; 7521218822Sdim sym < local_syms + symtab_hdr->sh_info; 7522218822Sdim ++sym) 7523218822Sdim if (sym->st_shndx != SHN_UNDEF 7524218822Sdim && (sym->st_shndx < SHN_LORESERVE 7525218822Sdim || sym->st_shndx > SHN_HIRESERVE) 7526218822Sdim && sym->st_value != 0 7527218822Sdim && bfd_section_from_elf_index (ibfd, sym->st_shndx) == toc) 7528218822Sdim { 7529218822Sdim if (skip[sym->st_value >> 3] != (unsigned long) -1) 7530218822Sdim sym->st_value -= skip[sym->st_value >> 3]; 7531218822Sdim else 7532218822Sdim { 7533218822Sdim (*_bfd_error_handler) 7534218822Sdim (_("%s defined in removed toc entry"), 7535218822Sdim bfd_elf_sym_name (ibfd, symtab_hdr, sym, 7536218822Sdim NULL)); 7537218822Sdim sym->st_value = 0; 7538218822Sdim sym->st_shndx = SHN_ABS; 7539218822Sdim } 7540218822Sdim symtab_hdr->contents = (unsigned char *) local_syms; 7541218822Sdim } 7542218822Sdim } 7543218822Sdim 7544218822Sdim /* Finally, adjust any global syms defined in the toc. */ 7545218822Sdim if (toc_inf.global_toc_syms) 7546218822Sdim { 7547218822Sdim toc_inf.toc = toc; 7548218822Sdim toc_inf.skip = skip; 7549218822Sdim toc_inf.global_toc_syms = FALSE; 7550218822Sdim elf_link_hash_traverse (elf_hash_table (info), adjust_toc_syms, 7551218822Sdim &toc_inf); 7552218822Sdim } 7553218822Sdim } 7554218822Sdim 7555218822Sdim if (local_syms != NULL 7556218822Sdim && symtab_hdr->contents != (unsigned char *) local_syms) 7557218822Sdim { 7558218822Sdim if (!info->keep_memory) 7559218822Sdim free (local_syms); 7560218822Sdim else 7561218822Sdim symtab_hdr->contents = (unsigned char *) local_syms; 7562218822Sdim } 7563218822Sdim free (skip); 7564218822Sdim } 7565218822Sdim 7566218822Sdim return TRUE; 7567218822Sdim} 7568218822Sdim 756989857Sobrien/* Allocate space in .plt, .got and associated reloc sections for 757089857Sobrien dynamic relocs. */ 757189857Sobrien 7572130561Sobrienstatic bfd_boolean 7573130561Sobrienallocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) 757489857Sobrien{ 757589857Sobrien struct bfd_link_info *info; 757689857Sobrien struct ppc_link_hash_table *htab; 757789857Sobrien asection *s; 757889857Sobrien struct ppc_link_hash_entry *eh; 757989857Sobrien struct ppc_dyn_relocs *p; 7580130561Sobrien struct got_entry *gent; 758189857Sobrien 758294536Sobrien if (h->root.type == bfd_link_hash_indirect) 7583130561Sobrien return TRUE; 758489857Sobrien 758594536Sobrien if (h->root.type == bfd_link_hash_warning) 758694536Sobrien h = (struct elf_link_hash_entry *) h->root.u.i.link; 758794536Sobrien 758889857Sobrien info = (struct bfd_link_info *) inf; 758989857Sobrien htab = ppc_hash_table (info); 759089857Sobrien 759189857Sobrien if (htab->elf.dynamic_sections_created 7592130561Sobrien && h->dynindx != -1 7593130561Sobrien && WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, info->shared, h)) 759489857Sobrien { 7595130561Sobrien struct plt_entry *pent; 7596130561Sobrien bfd_boolean doneone = FALSE; 7597130561Sobrien for (pent = h->plt.plist; pent != NULL; pent = pent->next) 7598130561Sobrien if (pent->plt.refcount > 0) 7599130561Sobrien { 7600130561Sobrien /* If this is the first .plt entry, make room for the special 7601130561Sobrien first entry. */ 7602130561Sobrien s = htab->plt; 7603218822Sdim if (s->size == 0) 7604218822Sdim s->size += PLT_INITIAL_ENTRY_SIZE; 760589857Sobrien 7606218822Sdim pent->plt.offset = s->size; 760789857Sobrien 7608130561Sobrien /* Make room for this entry. */ 7609218822Sdim s->size += PLT_ENTRY_SIZE; 761089857Sobrien 7611130561Sobrien /* Make room for the .glink code. */ 7612130561Sobrien s = htab->glink; 7613218822Sdim if (s->size == 0) 7614218822Sdim s->size += GLINK_CALL_STUB_SIZE; 7615130561Sobrien /* We need bigger stubs past index 32767. */ 7616218822Sdim if (s->size >= GLINK_CALL_STUB_SIZE + 32768*2*4) 7617218822Sdim s->size += 4; 7618218822Sdim s->size += 2*4; 761989857Sobrien 7620130561Sobrien /* We also need to make an entry in the .rela.plt section. */ 7621130561Sobrien s = htab->relplt; 7622218822Sdim s->size += sizeof (Elf64_External_Rela); 7623130561Sobrien doneone = TRUE; 7624130561Sobrien } 7625130561Sobrien else 7626130561Sobrien pent->plt.offset = (bfd_vma) -1; 7627130561Sobrien if (!doneone) 762889857Sobrien { 7629130561Sobrien h->plt.plist = NULL; 7630218822Sdim h->needs_plt = 0; 763189857Sobrien } 763289857Sobrien } 763389857Sobrien else 763489857Sobrien { 7635130561Sobrien h->plt.plist = NULL; 7636218822Sdim h->needs_plt = 0; 763789857Sobrien } 763889857Sobrien 7639130561Sobrien eh = (struct ppc_link_hash_entry *) h; 7640130561Sobrien /* Run through the TLS GD got entries first if we're changing them 7641130561Sobrien to TPREL. */ 7642130561Sobrien if ((eh->tls_mask & TLS_TPRELGD) != 0) 7643130561Sobrien for (gent = h->got.glist; gent != NULL; gent = gent->next) 7644130561Sobrien if (gent->got.refcount > 0 7645130561Sobrien && (gent->tls_type & TLS_GD) != 0) 7646130561Sobrien { 7647130561Sobrien /* This was a GD entry that has been converted to TPREL. If 7648130561Sobrien there happens to be a TPREL entry we can use that one. */ 7649130561Sobrien struct got_entry *ent; 7650130561Sobrien for (ent = h->got.glist; ent != NULL; ent = ent->next) 7651130561Sobrien if (ent->got.refcount > 0 7652130561Sobrien && (ent->tls_type & TLS_TPREL) != 0 7653130561Sobrien && ent->addend == gent->addend 7654130561Sobrien && ent->owner == gent->owner) 7655130561Sobrien { 7656130561Sobrien gent->got.refcount = 0; 7657130561Sobrien break; 7658130561Sobrien } 765989857Sobrien 7660130561Sobrien /* If not, then we'll be using our own TPREL entry. */ 7661130561Sobrien if (gent->got.refcount != 0) 7662130561Sobrien gent->tls_type = TLS_TLS | TLS_TPREL; 766389857Sobrien } 766489857Sobrien 7665130561Sobrien for (gent = h->got.glist; gent != NULL; gent = gent->next) 7666130561Sobrien if (gent->got.refcount > 0) 7667130561Sobrien { 7668130561Sobrien bfd_boolean dyn; 766989857Sobrien 7670130561Sobrien /* Make sure this symbol is output as a dynamic symbol. 7671130561Sobrien Undefined weak syms won't yet be marked as dynamic, 7672130561Sobrien nor will all TLS symbols. */ 7673130561Sobrien if (h->dynindx == -1 7674218822Sdim && !h->forced_local) 7675130561Sobrien { 7676130561Sobrien if (! bfd_elf_link_record_dynamic_symbol (info, h)) 7677130561Sobrien return FALSE; 7678130561Sobrien } 7679130561Sobrien 7680130561Sobrien if ((gent->tls_type & TLS_LD) != 0 7681218822Sdim && !h->def_dynamic) 7682130561Sobrien { 7683130561Sobrien gent->got.offset = ppc64_tlsld_got (gent->owner)->offset; 7684130561Sobrien continue; 7685130561Sobrien } 7686130561Sobrien 7687130561Sobrien s = ppc64_elf_tdata (gent->owner)->got; 7688218822Sdim gent->got.offset = s->size; 7689218822Sdim s->size 7690130561Sobrien += (gent->tls_type & eh->tls_mask & (TLS_GD | TLS_LD)) ? 16 : 8; 7691130561Sobrien dyn = htab->elf.dynamic_sections_created; 7692130561Sobrien if ((info->shared 7693130561Sobrien || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)) 7694130561Sobrien && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT 7695130561Sobrien || h->root.type != bfd_link_hash_undefweak)) 7696218822Sdim ppc64_elf_tdata (gent->owner)->relgot->size 7697130561Sobrien += (gent->tls_type & eh->tls_mask & TLS_GD 7698130561Sobrien ? 2 * sizeof (Elf64_External_Rela) 7699130561Sobrien : sizeof (Elf64_External_Rela)); 7700130561Sobrien } 7701130561Sobrien else 7702130561Sobrien gent->got.offset = (bfd_vma) -1; 7703130561Sobrien 770489857Sobrien if (eh->dyn_relocs == NULL) 7705130561Sobrien return TRUE; 770689857Sobrien 770789857Sobrien /* In the shared -Bsymbolic case, discard space allocated for 770889857Sobrien dynamic pc-relative relocs against symbols which turn out to be 770989857Sobrien defined in regular objects. For the normal shared case, discard 771089857Sobrien space for relocs that have become local due to symbol visibility 771189857Sobrien changes. */ 771289857Sobrien 771389857Sobrien if (info->shared) 771489857Sobrien { 7715130561Sobrien /* Relocs that use pc_count are those that appear on a call insn, 7716130561Sobrien or certain REL relocs (see MUST_BE_DYN_RELOC) that can be 7717130561Sobrien generated via assembly. We want calls to protected symbols to 7718130561Sobrien resolve directly to the function rather than going via the plt. 7719130561Sobrien If people want function pointer comparisons to work as expected 7720130561Sobrien then they should avoid writing weird assembly. */ 7721130561Sobrien if (SYMBOL_CALLS_LOCAL (info, h)) 772289857Sobrien { 772389857Sobrien struct ppc_dyn_relocs **pp; 772489857Sobrien 772589857Sobrien for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) 772689857Sobrien { 772789857Sobrien p->count -= p->pc_count; 772889857Sobrien p->pc_count = 0; 772989857Sobrien if (p->count == 0) 773089857Sobrien *pp = p->next; 773189857Sobrien else 773289857Sobrien pp = &p->next; 773389857Sobrien } 773489857Sobrien } 7735130561Sobrien 7736130561Sobrien /* Also discard relocs on undefined weak syms with non-default 7737130561Sobrien visibility. */ 7738218822Sdim if (eh->dyn_relocs != NULL 7739130561Sobrien && h->root.type == bfd_link_hash_undefweak) 7740218822Sdim { 7741218822Sdim if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) 7742218822Sdim eh->dyn_relocs = NULL; 7743218822Sdim 7744218822Sdim /* Make sure this symbol is output as a dynamic symbol. 7745218822Sdim Undefined weak syms won't yet be marked as dynamic. */ 7746218822Sdim else if (h->dynindx == -1 7747218822Sdim && !h->forced_local) 7748218822Sdim { 7749218822Sdim if (! bfd_elf_link_record_dynamic_symbol (info, h)) 7750218822Sdim return FALSE; 7751218822Sdim } 7752218822Sdim } 775389857Sobrien } 7754130561Sobrien else if (ELIMINATE_COPY_RELOCS) 775589857Sobrien { 775689857Sobrien /* For the non-shared case, discard space for relocs against 775789857Sobrien symbols which turn out to need copy relocs or are not 775889857Sobrien dynamic. */ 775989857Sobrien 7760218822Sdim if (!h->non_got_ref 7761218822Sdim && h->def_dynamic 7762218822Sdim && !h->def_regular) 776389857Sobrien { 776489857Sobrien /* Make sure this symbol is output as a dynamic symbol. 776589857Sobrien Undefined weak syms won't yet be marked as dynamic. */ 776689857Sobrien if (h->dynindx == -1 7767218822Sdim && !h->forced_local) 776889857Sobrien { 7769130561Sobrien if (! bfd_elf_link_record_dynamic_symbol (info, h)) 7770130561Sobrien return FALSE; 777189857Sobrien } 777289857Sobrien 777389857Sobrien /* If that succeeded, we know we'll be keeping all the 777489857Sobrien relocs. */ 777589857Sobrien if (h->dynindx != -1) 777689857Sobrien goto keep; 777789857Sobrien } 777889857Sobrien 777989857Sobrien eh->dyn_relocs = NULL; 778089857Sobrien 778189857Sobrien keep: ; 778289857Sobrien } 778389857Sobrien 778489857Sobrien /* Finally, allocate space. */ 778589857Sobrien for (p = eh->dyn_relocs; p != NULL; p = p->next) 778689857Sobrien { 778789857Sobrien asection *sreloc = elf_section_data (p->sec)->sreloc; 7788218822Sdim sreloc->size += p->count * sizeof (Elf64_External_Rela); 778989857Sobrien } 779089857Sobrien 7791130561Sobrien return TRUE; 779289857Sobrien} 779389857Sobrien 779489857Sobrien/* Find any dynamic relocs that apply to read-only sections. */ 779589857Sobrien 7796130561Sobrienstatic bfd_boolean 7797130561Sobrienreadonly_dynrelocs (struct elf_link_hash_entry *h, void *inf) 779889857Sobrien{ 779989857Sobrien struct ppc_link_hash_entry *eh; 780089857Sobrien struct ppc_dyn_relocs *p; 780189857Sobrien 780294536Sobrien if (h->root.type == bfd_link_hash_warning) 780394536Sobrien h = (struct elf_link_hash_entry *) h->root.u.i.link; 780494536Sobrien 780589857Sobrien eh = (struct ppc_link_hash_entry *) h; 780689857Sobrien for (p = eh->dyn_relocs; p != NULL; p = p->next) 780789857Sobrien { 780889857Sobrien asection *s = p->sec->output_section; 780989857Sobrien 781089857Sobrien if (s != NULL && (s->flags & SEC_READONLY) != 0) 781189857Sobrien { 7812130561Sobrien struct bfd_link_info *info = inf; 781389857Sobrien 781489857Sobrien info->flags |= DF_TEXTREL; 781589857Sobrien 781689857Sobrien /* Not an error, just cut short the traversal. */ 7817130561Sobrien return FALSE; 781889857Sobrien } 781989857Sobrien } 7820130561Sobrien return TRUE; 782189857Sobrien} 782289857Sobrien 782389857Sobrien/* Set the sizes of the dynamic sections. */ 782489857Sobrien 7825130561Sobrienstatic bfd_boolean 7826130561Sobrienppc64_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, 7827130561Sobrien struct bfd_link_info *info) 782889857Sobrien{ 782989857Sobrien struct ppc_link_hash_table *htab; 783089857Sobrien bfd *dynobj; 783189857Sobrien asection *s; 7832130561Sobrien bfd_boolean relocs; 783389857Sobrien bfd *ibfd; 783489857Sobrien 783589857Sobrien htab = ppc_hash_table (info); 783689857Sobrien dynobj = htab->elf.dynobj; 783789857Sobrien if (dynobj == NULL) 783889857Sobrien abort (); 783989857Sobrien 784089857Sobrien if (htab->elf.dynamic_sections_created) 784189857Sobrien { 784289857Sobrien /* Set the contents of the .interp section to the interpreter. */ 7843130561Sobrien if (info->executable) 784489857Sobrien { 784589857Sobrien s = bfd_get_section_by_name (dynobj, ".interp"); 784689857Sobrien if (s == NULL) 784789857Sobrien abort (); 7848218822Sdim s->size = sizeof ELF_DYNAMIC_INTERPRETER; 784989857Sobrien s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; 785089857Sobrien } 785189857Sobrien } 785289857Sobrien 785389857Sobrien /* Set up .got offsets for local syms, and space for local dynamic 785489857Sobrien relocs. */ 785589857Sobrien for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 785689857Sobrien { 7857130561Sobrien struct got_entry **lgot_ents; 7858130561Sobrien struct got_entry **end_lgot_ents; 7859130561Sobrien char *lgot_masks; 786089857Sobrien bfd_size_type locsymcount; 786189857Sobrien Elf_Internal_Shdr *symtab_hdr; 786289857Sobrien asection *srel; 786389857Sobrien 7864218822Sdim if (!is_ppc64_elf_target (ibfd->xvec)) 786589857Sobrien continue; 786689857Sobrien 7867130561Sobrien if (ppc64_tlsld_got (ibfd)->refcount > 0) 7868130561Sobrien { 7869130561Sobrien s = ppc64_elf_tdata (ibfd)->got; 7870218822Sdim ppc64_tlsld_got (ibfd)->offset = s->size; 7871218822Sdim s->size += 16; 7872130561Sobrien if (info->shared) 7873130561Sobrien { 7874130561Sobrien srel = ppc64_elf_tdata (ibfd)->relgot; 7875218822Sdim srel->size += sizeof (Elf64_External_Rela); 7876130561Sobrien } 7877130561Sobrien } 7878130561Sobrien else 7879130561Sobrien ppc64_tlsld_got (ibfd)->offset = (bfd_vma) -1; 7880130561Sobrien 788189857Sobrien for (s = ibfd->sections; s != NULL; s = s->next) 788289857Sobrien { 788389857Sobrien struct ppc_dyn_relocs *p; 788489857Sobrien 7885218822Sdim for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next) 788689857Sobrien { 788789857Sobrien if (!bfd_is_abs_section (p->sec) 788889857Sobrien && bfd_is_abs_section (p->sec->output_section)) 788989857Sobrien { 789089857Sobrien /* Input section has been discarded, either because 789189857Sobrien it is a copy of a linkonce section or due to 789289857Sobrien linker script /DISCARD/, so we'll be discarding 789389857Sobrien the relocs too. */ 789489857Sobrien } 789591041Sobrien else if (p->count != 0) 789689857Sobrien { 789789857Sobrien srel = elf_section_data (p->sec)->sreloc; 7898218822Sdim srel->size += p->count * sizeof (Elf64_External_Rela); 789991041Sobrien if ((p->sec->output_section->flags & SEC_READONLY) != 0) 790091041Sobrien info->flags |= DF_TEXTREL; 790189857Sobrien } 790289857Sobrien } 790389857Sobrien } 790489857Sobrien 7905130561Sobrien lgot_ents = elf_local_got_ents (ibfd); 7906130561Sobrien if (!lgot_ents) 790789857Sobrien continue; 790889857Sobrien 790989857Sobrien symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; 791089857Sobrien locsymcount = symtab_hdr->sh_info; 7911130561Sobrien end_lgot_ents = lgot_ents + locsymcount; 7912130561Sobrien lgot_masks = (char *) end_lgot_ents; 7913130561Sobrien s = ppc64_elf_tdata (ibfd)->got; 7914130561Sobrien srel = ppc64_elf_tdata (ibfd)->relgot; 7915130561Sobrien for (; lgot_ents < end_lgot_ents; ++lgot_ents, ++lgot_masks) 791689857Sobrien { 7917130561Sobrien struct got_entry *ent; 7918130561Sobrien 7919130561Sobrien for (ent = *lgot_ents; ent != NULL; ent = ent->next) 7920130561Sobrien if (ent->got.refcount > 0) 7921130561Sobrien { 7922130561Sobrien if ((ent->tls_type & *lgot_masks & TLS_LD) != 0) 7923130561Sobrien { 7924130561Sobrien if (ppc64_tlsld_got (ibfd)->offset == (bfd_vma) -1) 7925130561Sobrien { 7926218822Sdim ppc64_tlsld_got (ibfd)->offset = s->size; 7927218822Sdim s->size += 16; 7928130561Sobrien if (info->shared) 7929218822Sdim srel->size += sizeof (Elf64_External_Rela); 7930130561Sobrien } 7931130561Sobrien ent->got.offset = ppc64_tlsld_got (ibfd)->offset; 7932130561Sobrien } 7933130561Sobrien else 7934130561Sobrien { 7935218822Sdim ent->got.offset = s->size; 7936130561Sobrien if ((ent->tls_type & *lgot_masks & TLS_GD) != 0) 7937130561Sobrien { 7938218822Sdim s->size += 16; 7939130561Sobrien if (info->shared) 7940218822Sdim srel->size += 2 * sizeof (Elf64_External_Rela); 7941130561Sobrien } 7942130561Sobrien else 7943130561Sobrien { 7944218822Sdim s->size += 8; 7945130561Sobrien if (info->shared) 7946218822Sdim srel->size += sizeof (Elf64_External_Rela); 7947130561Sobrien } 7948130561Sobrien } 7949130561Sobrien } 7950130561Sobrien else 7951130561Sobrien ent->got.offset = (bfd_vma) -1; 795289857Sobrien } 795389857Sobrien } 795489857Sobrien 795589857Sobrien /* Allocate global sym .plt and .got entries, and space for global 795689857Sobrien sym dynamic relocs. */ 7957130561Sobrien elf_link_hash_traverse (&htab->elf, allocate_dynrelocs, info); 795889857Sobrien 795989857Sobrien /* We now have determined the sizes of the various dynamic sections. 796089857Sobrien Allocate memory for them. */ 7961130561Sobrien relocs = FALSE; 796289857Sobrien for (s = dynobj->sections; s != NULL; s = s->next) 796389857Sobrien { 796489857Sobrien if ((s->flags & SEC_LINKER_CREATED) == 0) 796589857Sobrien continue; 796689857Sobrien 7967130561Sobrien if (s == htab->brlt || s == htab->relbrlt) 7968104834Sobrien /* These haven't been allocated yet; don't strip. */ 7969104834Sobrien continue; 7970130561Sobrien else if (s == htab->got 7971130561Sobrien || s == htab->plt 7972218822Sdim || s == htab->glink 7973218822Sdim || s == htab->dynbss) 797489857Sobrien { 797589857Sobrien /* Strip this section if we don't need it; see the 797689857Sobrien comment below. */ 797789857Sobrien } 7978218822Sdim else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) 797989857Sobrien { 7980218822Sdim if (s->size != 0) 798189857Sobrien { 7982130561Sobrien if (s != htab->relplt) 7983130561Sobrien relocs = TRUE; 798489857Sobrien 798589857Sobrien /* We use the reloc_count field as a counter if we need 798689857Sobrien to copy relocs into the output file. */ 798789857Sobrien s->reloc_count = 0; 798889857Sobrien } 798989857Sobrien } 799089857Sobrien else 799189857Sobrien { 799289857Sobrien /* It's not one of our sections, so don't allocate space. */ 799389857Sobrien continue; 799489857Sobrien } 799589857Sobrien 7996218822Sdim if (s->size == 0) 799789857Sobrien { 7998218822Sdim /* If we don't need this section, strip it from the 7999218822Sdim output file. This is mostly to handle .rela.bss and 8000218822Sdim .rela.plt. We must create both sections in 8001218822Sdim create_dynamic_sections, because they must be created 8002218822Sdim before the linker maps input sections to output 8003218822Sdim sections. The linker does that before 8004218822Sdim adjust_dynamic_symbol is called, and it is that 8005218822Sdim function which decides whether anything needs to go 8006218822Sdim into these sections. */ 8007218822Sdim s->flags |= SEC_EXCLUDE; 800889857Sobrien continue; 800989857Sobrien } 801089857Sobrien 8011218822Sdim if ((s->flags & SEC_HAS_CONTENTS) == 0) 8012104834Sobrien continue; 8013104834Sobrien 801489857Sobrien /* Allocate memory for the section contents. We use bfd_zalloc 801589857Sobrien here in case unused entries are not reclaimed before the 801689857Sobrien section's contents are written out. This should not happen, 8017130561Sobrien but this way if it does we get a R_PPC64_NONE reloc in .rela 8018130561Sobrien sections instead of garbage. 8019130561Sobrien We also rely on the section contents being zero when writing 8020130561Sobrien the GOT. */ 8021218822Sdim s->contents = bfd_zalloc (dynobj, s->size); 802289857Sobrien if (s->contents == NULL) 8023130561Sobrien return FALSE; 802489857Sobrien } 802589857Sobrien 8026130561Sobrien for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 8027130561Sobrien { 8028218822Sdim if (!is_ppc64_elf_target (ibfd->xvec)) 8029209867Snwhitehorn continue; 8030209867Snwhitehorn 8031130561Sobrien s = ppc64_elf_tdata (ibfd)->got; 8032130561Sobrien if (s != NULL && s != htab->got) 8033130561Sobrien { 8034218822Sdim if (s->size == 0) 8035218822Sdim s->flags |= SEC_EXCLUDE; 8036130561Sobrien else 8037130561Sobrien { 8038218822Sdim s->contents = bfd_zalloc (ibfd, s->size); 8039130561Sobrien if (s->contents == NULL) 8040130561Sobrien return FALSE; 8041130561Sobrien } 8042130561Sobrien } 8043130561Sobrien s = ppc64_elf_tdata (ibfd)->relgot; 8044130561Sobrien if (s != NULL) 8045130561Sobrien { 8046218822Sdim if (s->size == 0) 8047218822Sdim s->flags |= SEC_EXCLUDE; 8048130561Sobrien else 8049130561Sobrien { 8050218822Sdim s->contents = bfd_zalloc (ibfd, s->size); 8051130561Sobrien if (s->contents == NULL) 8052130561Sobrien return FALSE; 8053130561Sobrien relocs = TRUE; 8054130561Sobrien s->reloc_count = 0; 8055130561Sobrien } 8056130561Sobrien } 8057130561Sobrien } 8058130561Sobrien 805989857Sobrien if (htab->elf.dynamic_sections_created) 806089857Sobrien { 806189857Sobrien /* Add some entries to the .dynamic section. We fill in the 806289857Sobrien values later, in ppc64_elf_finish_dynamic_sections, but we 806389857Sobrien must add the entries now so that we get the correct size for 806489857Sobrien the .dynamic section. The DT_DEBUG entry is filled in by the 806589857Sobrien dynamic linker and used by the debugger. */ 806689857Sobrien#define add_dynamic_entry(TAG, VAL) \ 8067130561Sobrien _bfd_elf_add_dynamic_entry (info, TAG, VAL) 806889857Sobrien 8069130561Sobrien if (info->executable) 807089857Sobrien { 807189857Sobrien if (!add_dynamic_entry (DT_DEBUG, 0)) 8072130561Sobrien return FALSE; 807389857Sobrien } 807489857Sobrien 8075218822Sdim if (htab->plt != NULL && htab->plt->size != 0) 807689857Sobrien { 807789857Sobrien if (!add_dynamic_entry (DT_PLTGOT, 0) 807889857Sobrien || !add_dynamic_entry (DT_PLTRELSZ, 0) 807989857Sobrien || !add_dynamic_entry (DT_PLTREL, DT_RELA) 808089857Sobrien || !add_dynamic_entry (DT_JMPREL, 0) 808189857Sobrien || !add_dynamic_entry (DT_PPC64_GLINK, 0)) 8082130561Sobrien return FALSE; 808389857Sobrien } 808489857Sobrien 808591041Sobrien if (NO_OPD_RELOCS) 808691041Sobrien { 808791041Sobrien if (!add_dynamic_entry (DT_PPC64_OPD, 0) 808891041Sobrien || !add_dynamic_entry (DT_PPC64_OPDSZ, 0)) 8089130561Sobrien return FALSE; 809091041Sobrien } 809191041Sobrien 809289857Sobrien if (relocs) 809389857Sobrien { 809489857Sobrien if (!add_dynamic_entry (DT_RELA, 0) 809589857Sobrien || !add_dynamic_entry (DT_RELASZ, 0) 809689857Sobrien || !add_dynamic_entry (DT_RELAENT, sizeof (Elf64_External_Rela))) 8097130561Sobrien return FALSE; 809889857Sobrien 809989857Sobrien /* If any dynamic relocs apply to a read-only section, 810089857Sobrien then we need a DT_TEXTREL entry. */ 810191041Sobrien if ((info->flags & DF_TEXTREL) == 0) 8102130561Sobrien elf_link_hash_traverse (&htab->elf, readonly_dynrelocs, info); 810389857Sobrien 810489857Sobrien if ((info->flags & DF_TEXTREL) != 0) 810589857Sobrien { 810689857Sobrien if (!add_dynamic_entry (DT_TEXTREL, 0)) 8107130561Sobrien return FALSE; 810889857Sobrien } 810989857Sobrien } 811089857Sobrien } 811189857Sobrien#undef add_dynamic_entry 811289857Sobrien 8113130561Sobrien return TRUE; 811489857Sobrien} 811589857Sobrien 8116104834Sobrien/* Determine the type of stub needed, if any, for a call. */ 811789857Sobrien 8118130561Sobrienstatic inline enum ppc_stub_type 8119130561Sobrienppc_type_of_stub (asection *input_sec, 8120130561Sobrien const Elf_Internal_Rela *rel, 8121130561Sobrien struct ppc_link_hash_entry **hash, 8122130561Sobrien bfd_vma destination) 812389857Sobrien{ 8124104834Sobrien struct ppc_link_hash_entry *h = *hash; 8125104834Sobrien bfd_vma location; 8126104834Sobrien bfd_vma branch_offset; 8127104834Sobrien bfd_vma max_branch_offset; 8128130561Sobrien enum elf_ppc64_reloc_type r_type; 812999461Sobrien 8130104834Sobrien if (h != NULL) 813189857Sobrien { 8132218822Sdim struct ppc_link_hash_entry *fdh = h; 8133218822Sdim if (fdh->oh != NULL 8134218822Sdim && fdh->oh->is_func_descriptor) 8135218822Sdim fdh = fdh->oh; 8136218822Sdim 8137218822Sdim if (fdh->elf.dynindx != -1) 8138104834Sobrien { 8139130561Sobrien struct plt_entry *ent; 8140218822Sdim 8141218822Sdim for (ent = fdh->elf.plt.plist; ent != NULL; ent = ent->next) 8142130561Sobrien if (ent->addend == rel->r_addend 8143130561Sobrien && ent->plt.offset != (bfd_vma) -1) 8144130561Sobrien { 8145218822Sdim *hash = fdh; 8146130561Sobrien return ppc_stub_plt_call; 8147130561Sobrien } 8148104834Sobrien } 814989857Sobrien 8150218822Sdim /* Here, we know we don't have a plt entry. If we don't have a 8151218822Sdim either a defined function descriptor or a defined entry symbol 8152218822Sdim in a regular object file, then it is pointless trying to make 8153218822Sdim any other type of stub. */ 8154218822Sdim if (!((fdh->elf.root.type == bfd_link_hash_defined 8155218822Sdim || fdh->elf.root.type == bfd_link_hash_defweak) 8156218822Sdim && fdh->elf.root.u.def.section->output_section != NULL) 8157218822Sdim && !((h->elf.root.type == bfd_link_hash_defined 8158218822Sdim || h->elf.root.type == bfd_link_hash_defweak) 8159218822Sdim && h->elf.root.u.def.section->output_section != NULL)) 8160104834Sobrien return ppc_stub_none; 816199461Sobrien } 816289857Sobrien 8163104834Sobrien /* Determine where the call point is. */ 8164104834Sobrien location = (input_sec->output_offset 8165104834Sobrien + input_sec->output_section->vma 8166104834Sobrien + rel->r_offset); 816789857Sobrien 8168104834Sobrien branch_offset = destination - location; 8169104834Sobrien r_type = ELF64_R_TYPE (rel->r_info); 817089857Sobrien 8171104834Sobrien /* Determine if a long branch stub is needed. */ 8172104834Sobrien max_branch_offset = 1 << 25; 8173130561Sobrien if (r_type != R_PPC64_REL24) 8174104834Sobrien max_branch_offset = 1 << 15; 817589857Sobrien 8176104834Sobrien if (branch_offset + max_branch_offset >= 2 * max_branch_offset) 8177104834Sobrien /* We need a stub. Figure out whether a long_branch or plt_branch 8178104834Sobrien is needed later. */ 8179104834Sobrien return ppc_stub_long_branch; 818089857Sobrien 8181104834Sobrien return ppc_stub_none; 818289857Sobrien} 818389857Sobrien 818489857Sobrien/* Build a .plt call stub. */ 818589857Sobrien 8186130561Sobrienstatic inline bfd_byte * 8187130561Sobrienbuild_plt_stub (bfd *obfd, bfd_byte *p, int offset) 818889857Sobrien{ 818989857Sobrien#define PPC_LO(v) ((v) & 0xffff) 819089857Sobrien#define PPC_HI(v) (((v) >> 16) & 0xffff) 819189857Sobrien#define PPC_HA(v) PPC_HI ((v) + 0x8000) 819289857Sobrien 819389857Sobrien bfd_put_32 (obfd, ADDIS_R12_R2 | PPC_HA (offset), p), p += 4; 8194130561Sobrien bfd_put_32 (obfd, STD_R2_40R1, p), p += 4; 819589857Sobrien bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p), p += 4; 819689857Sobrien if (PPC_HA (offset + 8) != PPC_HA (offset)) 8197130561Sobrien bfd_put_32 (obfd, ADDIS_R12_R12 | 1, p), p += 4; 819889857Sobrien offset += 8; 819989857Sobrien bfd_put_32 (obfd, LD_R2_0R12 | PPC_LO (offset), p), p += 4; 820089857Sobrien if (PPC_HA (offset + 8) != PPC_HA (offset)) 8201130561Sobrien bfd_put_32 (obfd, ADDIS_R12_R12 | 1, p), p += 4; 820289857Sobrien offset += 8; 820389857Sobrien bfd_put_32 (obfd, MTCTR_R11, p), p += 4; 820489857Sobrien bfd_put_32 (obfd, LD_R11_0R12 | PPC_LO (offset), p), p += 4; 820589857Sobrien bfd_put_32 (obfd, BCTR, p), p += 4; 820689857Sobrien return p; 820789857Sobrien} 820889857Sobrien 8209130561Sobrienstatic bfd_boolean 8210130561Sobrienppc_build_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) 821189857Sobrien{ 8212104834Sobrien struct ppc_stub_hash_entry *stub_entry; 8213104834Sobrien struct ppc_branch_hash_entry *br_entry; 821489857Sobrien struct bfd_link_info *info; 821589857Sobrien struct ppc_link_hash_table *htab; 8216104834Sobrien bfd_byte *loc; 8217104834Sobrien bfd_byte *p; 8218104834Sobrien unsigned int indx; 8219130561Sobrien struct plt_entry *ent; 8220218822Sdim bfd_vma dest, off; 8221104834Sobrien int size; 822289857Sobrien 8223104834Sobrien /* Massage our args to the form they really have. */ 8224104834Sobrien stub_entry = (struct ppc_stub_hash_entry *) gen_entry; 8225130561Sobrien info = in_arg; 822689857Sobrien 822789857Sobrien htab = ppc_hash_table (info); 822889857Sobrien 8229104834Sobrien /* Make a note of the offset within the stubs for this entry. */ 8230218822Sdim stub_entry->stub_offset = stub_entry->stub_sec->size; 8231130561Sobrien loc = stub_entry->stub_sec->contents + stub_entry->stub_offset; 8232104834Sobrien 8233130561Sobrien htab->stub_count[stub_entry->stub_type - 1] += 1; 8234104834Sobrien switch (stub_entry->stub_type) 823589857Sobrien { 8236104834Sobrien case ppc_stub_long_branch: 8237130561Sobrien case ppc_stub_long_branch_r2off: 8238104834Sobrien /* Branches are relative. This is where we are going to. */ 8239218822Sdim off = dest = (stub_entry->target_value 8240218822Sdim + stub_entry->target_section->output_offset 8241218822Sdim + stub_entry->target_section->output_section->vma); 824289857Sobrien 8243104834Sobrien /* And this is where we are coming from. */ 8244104834Sobrien off -= (stub_entry->stub_offset 8245130561Sobrien + stub_entry->stub_sec->output_offset 8246130561Sobrien + stub_entry->stub_sec->output_section->vma); 824789857Sobrien 8248130561Sobrien if (stub_entry->stub_type != ppc_stub_long_branch_r2off) 8249130561Sobrien size = 4; 8250130561Sobrien else 8251130561Sobrien { 8252130561Sobrien bfd_vma r2off; 8253130561Sobrien 8254130561Sobrien r2off = (htab->stub_group[stub_entry->target_section->id].toc_off 8255130561Sobrien - htab->stub_group[stub_entry->id_sec->id].toc_off); 8256130561Sobrien bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc); 8257130561Sobrien loc += 4; 8258130561Sobrien bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc); 8259130561Sobrien loc += 4; 8260130561Sobrien bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc); 8261130561Sobrien loc += 4; 8262130561Sobrien off -= 12; 8263130561Sobrien size = 16; 8264130561Sobrien } 8265130561Sobrien bfd_put_32 (htab->stub_bfd, B_DOT | (off & 0x3fffffc), loc); 8266130561Sobrien 8267218822Sdim if (off + (1 << 25) >= (bfd_vma) (1 << 26)) 8268218822Sdim { 8269218822Sdim (*_bfd_error_handler) (_("long branch stub `%s' offset overflow"), 8270218822Sdim stub_entry->root.string); 8271218822Sdim htab->stub_error = TRUE; 8272218822Sdim return FALSE; 8273218822Sdim } 8274218822Sdim 8275218822Sdim if (info->emitrelocations) 8276218822Sdim { 8277218822Sdim Elf_Internal_Rela *relocs, *r; 8278218822Sdim struct bfd_elf_section_data *elfsec_data; 8279218822Sdim 8280218822Sdim elfsec_data = elf_section_data (stub_entry->stub_sec); 8281218822Sdim relocs = elfsec_data->relocs; 8282218822Sdim if (relocs == NULL) 8283218822Sdim { 8284218822Sdim bfd_size_type relsize; 8285218822Sdim relsize = stub_entry->stub_sec->reloc_count * sizeof (*relocs); 8286218822Sdim relocs = bfd_alloc (htab->stub_bfd, relsize); 8287218822Sdim if (relocs == NULL) 8288218822Sdim return FALSE; 8289218822Sdim elfsec_data->relocs = relocs; 8290218822Sdim elfsec_data->rel_hdr.sh_size = relsize; 8291218822Sdim elfsec_data->rel_hdr.sh_entsize = 24; 8292218822Sdim stub_entry->stub_sec->reloc_count = 0; 8293218822Sdim } 8294218822Sdim r = relocs + stub_entry->stub_sec->reloc_count; 8295218822Sdim stub_entry->stub_sec->reloc_count += 1; 8296218822Sdim r->r_offset = loc - stub_entry->stub_sec->contents; 8297218822Sdim r->r_info = ELF64_R_INFO (0, R_PPC64_REL24); 8298218822Sdim r->r_addend = dest; 8299218822Sdim if (stub_entry->h != NULL) 8300218822Sdim { 8301218822Sdim struct elf_link_hash_entry **hashes; 8302218822Sdim unsigned long symndx; 8303218822Sdim struct ppc_link_hash_entry *h; 8304218822Sdim 8305218822Sdim hashes = elf_sym_hashes (htab->stub_bfd); 8306218822Sdim if (hashes == NULL) 8307218822Sdim { 8308218822Sdim bfd_size_type hsize; 8309218822Sdim 8310218822Sdim hsize = (htab->stub_globals + 1) * sizeof (*hashes); 8311218822Sdim hashes = bfd_zalloc (htab->stub_bfd, hsize); 8312218822Sdim if (hashes == NULL) 8313218822Sdim return FALSE; 8314218822Sdim elf_sym_hashes (htab->stub_bfd) = hashes; 8315218822Sdim htab->stub_globals = 1; 8316218822Sdim } 8317218822Sdim symndx = htab->stub_globals++; 8318218822Sdim h = stub_entry->h; 8319218822Sdim hashes[symndx] = &h->elf; 8320218822Sdim r->r_info = ELF64_R_INFO (symndx, R_PPC64_REL24); 8321218822Sdim if (h->oh != NULL && h->oh->is_func) 8322218822Sdim h = h->oh; 8323218822Sdim if (h->elf.root.u.def.section != stub_entry->target_section) 8324218822Sdim /* H is an opd symbol. The addend must be zero. */ 8325218822Sdim r->r_addend = 0; 8326218822Sdim else 8327218822Sdim { 8328218822Sdim off = (h->elf.root.u.def.value 8329218822Sdim + h->elf.root.u.def.section->output_offset 8330218822Sdim + h->elf.root.u.def.section->output_section->vma); 8331218822Sdim r->r_addend -= off; 8332218822Sdim } 8333218822Sdim } 8334218822Sdim } 8335104834Sobrien break; 833689857Sobrien 8337104834Sobrien case ppc_stub_plt_branch: 8338130561Sobrien case ppc_stub_plt_branch_r2off: 8339104834Sobrien br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table, 8340104834Sobrien stub_entry->root.string + 9, 8341130561Sobrien FALSE, FALSE); 8342104834Sobrien if (br_entry == NULL) 8343104834Sobrien { 8344104834Sobrien (*_bfd_error_handler) (_("can't find branch stub `%s'"), 8345218822Sdim stub_entry->root.string); 8346130561Sobrien htab->stub_error = TRUE; 8347130561Sobrien return FALSE; 8348104834Sobrien } 834989857Sobrien 8350104834Sobrien off = (stub_entry->target_value 8351104834Sobrien + stub_entry->target_section->output_offset 8352104834Sobrien + stub_entry->target_section->output_section->vma); 8353104834Sobrien 8354130561Sobrien bfd_put_64 (htab->brlt->owner, off, 8355130561Sobrien htab->brlt->contents + br_entry->offset); 8356104834Sobrien 8357218822Sdim if (htab->relbrlt != NULL) 835889857Sobrien { 8359104834Sobrien /* Create a reloc for the branch lookup table entry. */ 8360104834Sobrien Elf_Internal_Rela rela; 8361130561Sobrien bfd_byte *rl; 8362104834Sobrien 8363104834Sobrien rela.r_offset = (br_entry->offset 8364130561Sobrien + htab->brlt->output_offset 8365130561Sobrien + htab->brlt->output_section->vma); 8366104834Sobrien rela.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); 8367104834Sobrien rela.r_addend = off; 8368104834Sobrien 8369130561Sobrien rl = htab->relbrlt->contents; 8370130561Sobrien rl += htab->relbrlt->reloc_count++ * sizeof (Elf64_External_Rela); 8371130561Sobrien bfd_elf64_swap_reloca_out (htab->relbrlt->owner, &rela, rl); 8372104834Sobrien } 8373218822Sdim else if (info->emitrelocations) 8374218822Sdim { 8375218822Sdim Elf_Internal_Rela *relocs, *r; 8376218822Sdim struct bfd_elf_section_data *elfsec_data; 8377104834Sobrien 8378218822Sdim elfsec_data = elf_section_data (htab->brlt); 8379218822Sdim relocs = elfsec_data->relocs; 8380218822Sdim if (relocs == NULL) 8381218822Sdim { 8382218822Sdim bfd_size_type relsize; 8383218822Sdim relsize = htab->brlt->reloc_count * sizeof (*relocs); 8384218822Sdim relocs = bfd_alloc (htab->brlt->owner, relsize); 8385218822Sdim if (relocs == NULL) 8386218822Sdim return FALSE; 8387218822Sdim elfsec_data->relocs = relocs; 8388218822Sdim elfsec_data->rel_hdr.sh_size = relsize; 8389218822Sdim elfsec_data->rel_hdr.sh_entsize = 24; 8390218822Sdim htab->brlt->reloc_count = 0; 8391218822Sdim } 8392218822Sdim r = relocs + htab->brlt->reloc_count; 8393218822Sdim htab->brlt->reloc_count += 1; 8394218822Sdim r->r_offset = (br_entry->offset 8395218822Sdim + htab->brlt->output_offset 8396218822Sdim + htab->brlt->output_section->vma); 8397218822Sdim r->r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); 8398218822Sdim r->r_addend = off; 8399218822Sdim } 8400218822Sdim 8401104834Sobrien off = (br_entry->offset 8402130561Sobrien + htab->brlt->output_offset 8403130561Sobrien + htab->brlt->output_section->vma 8404130561Sobrien - elf_gp (htab->brlt->output_section->owner) 8405130561Sobrien - htab->stub_group[stub_entry->id_sec->id].toc_off); 8406104834Sobrien 8407130561Sobrien if (off + 0x80008000 > 0xffffffff || (off & 7) != 0) 8408104834Sobrien { 840989857Sobrien (*_bfd_error_handler) 841089857Sobrien (_("linkage table error against `%s'"), 8411104834Sobrien stub_entry->root.string); 841289857Sobrien bfd_set_error (bfd_error_bad_value); 8413130561Sobrien htab->stub_error = TRUE; 8414130561Sobrien return FALSE; 841589857Sobrien } 841689857Sobrien 8417104834Sobrien indx = off; 8418130561Sobrien if (stub_entry->stub_type != ppc_stub_plt_branch_r2off) 8419130561Sobrien { 8420130561Sobrien bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc); 8421130561Sobrien loc += 4; 8422130561Sobrien bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc); 8423130561Sobrien size = 16; 8424130561Sobrien } 8425130561Sobrien else 8426130561Sobrien { 8427130561Sobrien bfd_vma r2off; 8428130561Sobrien 8429130561Sobrien r2off = (htab->stub_group[stub_entry->target_section->id].toc_off 8430130561Sobrien - htab->stub_group[stub_entry->id_sec->id].toc_off); 8431130561Sobrien bfd_put_32 (htab->stub_bfd, STD_R2_40R1, loc); 8432130561Sobrien loc += 4; 8433130561Sobrien bfd_put_32 (htab->stub_bfd, ADDIS_R12_R2 | PPC_HA (indx), loc); 8434130561Sobrien loc += 4; 8435130561Sobrien bfd_put_32 (htab->stub_bfd, LD_R11_0R12 | PPC_LO (indx), loc); 8436130561Sobrien loc += 4; 8437130561Sobrien bfd_put_32 (htab->stub_bfd, ADDIS_R2_R2 | PPC_HA (r2off), loc); 8438130561Sobrien loc += 4; 8439130561Sobrien bfd_put_32 (htab->stub_bfd, ADDI_R2_R2 | PPC_LO (r2off), loc); 8440130561Sobrien size = 28; 8441130561Sobrien } 8442130561Sobrien loc += 4; 8443130561Sobrien bfd_put_32 (htab->stub_bfd, MTCTR_R11, loc); 8444130561Sobrien loc += 4; 8445130561Sobrien bfd_put_32 (htab->stub_bfd, BCTR, loc); 8446104834Sobrien break; 844789857Sobrien 8448104834Sobrien case ppc_stub_plt_call: 8449104834Sobrien /* Do the best we can for shared libraries built without 8450104834Sobrien exporting ".foo" for each "foo". This can happen when symbol 8451104834Sobrien versioning scripts strip all bar a subset of symbols. */ 8452218822Sdim if (stub_entry->h->oh != NULL 8453218822Sdim && stub_entry->h->oh->elf.root.type != bfd_link_hash_defined 8454218822Sdim && stub_entry->h->oh->elf.root.type != bfd_link_hash_defweak) 845589857Sobrien { 8456104834Sobrien /* Point the symbol at the stub. There may be multiple stubs, 8457104834Sobrien we don't really care; The main thing is to make this sym 8458130561Sobrien defined somewhere. Maybe defining the symbol in the stub 8459130561Sobrien section is a silly idea. If we didn't do this, htab->top_id 8460130561Sobrien could disappear. */ 8461218822Sdim stub_entry->h->oh->elf.root.type = bfd_link_hash_defined; 8462218822Sdim stub_entry->h->oh->elf.root.u.def.section = stub_entry->stub_sec; 8463218822Sdim stub_entry->h->oh->elf.root.u.def.value = stub_entry->stub_offset; 846489857Sobrien } 8465104834Sobrien 8466104834Sobrien /* Now build the stub. */ 8467130561Sobrien off = (bfd_vma) -1; 8468130561Sobrien for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next) 8469130561Sobrien if (ent->addend == stub_entry->addend) 8470130561Sobrien { 8471130561Sobrien off = ent->plt.offset; 8472130561Sobrien break; 8473130561Sobrien } 8474104834Sobrien if (off >= (bfd_vma) -2) 8475104834Sobrien abort (); 8476104834Sobrien 8477104834Sobrien off &= ~ (bfd_vma) 1; 8478130561Sobrien off += (htab->plt->output_offset 8479130561Sobrien + htab->plt->output_section->vma 8480130561Sobrien - elf_gp (htab->plt->output_section->owner) 8481130561Sobrien - htab->stub_group[stub_entry->id_sec->id].toc_off); 8482104834Sobrien 8483130561Sobrien if (off + 0x80008000 > 0xffffffff || (off & 7) != 0) 848489857Sobrien { 8485104834Sobrien (*_bfd_error_handler) 8486104834Sobrien (_("linkage table error against `%s'"), 8487104834Sobrien stub_entry->h->elf.root.root.string); 8488104834Sobrien bfd_set_error (bfd_error_bad_value); 8489130561Sobrien htab->stub_error = TRUE; 8490130561Sobrien return FALSE; 849189857Sobrien } 8492104834Sobrien 8493130561Sobrien p = build_plt_stub (htab->stub_bfd, loc, off); 8494104834Sobrien size = p - loc; 8495104834Sobrien break; 8496104834Sobrien 8497104834Sobrien default: 8498104834Sobrien BFD_FAIL (); 8499130561Sobrien return FALSE; 850089857Sobrien } 8501104834Sobrien 8502218822Sdim stub_entry->stub_sec->size += size; 8503130561Sobrien 8504218822Sdim if (htab->emit_stub_syms) 8505130561Sobrien { 8506130561Sobrien struct elf_link_hash_entry *h; 8507218822Sdim size_t len1, len2; 8508218822Sdim char *name; 8509218822Sdim const char *const stub_str[] = { "long_branch", 8510218822Sdim "long_branch_r2off", 8511218822Sdim "plt_branch", 8512218822Sdim "plt_branch_r2off", 8513218822Sdim "plt_call" }; 8514218822Sdim 8515218822Sdim len1 = strlen (stub_str[stub_entry->stub_type - 1]); 8516218822Sdim len2 = strlen (stub_entry->root.string); 8517218822Sdim name = bfd_malloc (len1 + len2 + 2); 8518218822Sdim if (name == NULL) 8519218822Sdim return FALSE; 8520218822Sdim memcpy (name, stub_entry->root.string, 9); 8521218822Sdim memcpy (name + 9, stub_str[stub_entry->stub_type - 1], len1); 8522218822Sdim memcpy (name + len1 + 9, stub_entry->root.string + 8, len2 - 8 + 1); 8523218822Sdim h = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE); 8524130561Sobrien if (h == NULL) 8525130561Sobrien return FALSE; 8526130561Sobrien if (h->root.type == bfd_link_hash_new) 8527130561Sobrien { 8528130561Sobrien h->root.type = bfd_link_hash_defined; 8529130561Sobrien h->root.u.def.section = stub_entry->stub_sec; 8530130561Sobrien h->root.u.def.value = stub_entry->stub_offset; 8531218822Sdim h->ref_regular = 1; 8532218822Sdim h->def_regular = 1; 8533218822Sdim h->ref_regular_nonweak = 1; 8534218822Sdim h->forced_local = 1; 8535218822Sdim h->non_elf = 0; 8536130561Sobrien } 8537130561Sobrien } 8538130561Sobrien 8539130561Sobrien return TRUE; 854089857Sobrien} 854189857Sobrien 8542104834Sobrien/* As above, but don't actually build the stub. Just bump offset so 8543104834Sobrien we know stub section sizes, and select plt_branch stubs where 8544104834Sobrien long_branch stubs won't do. */ 8545104834Sobrien 8546130561Sobrienstatic bfd_boolean 8547130561Sobrienppc_size_one_stub (struct bfd_hash_entry *gen_entry, void *in_arg) 8548104834Sobrien{ 8549104834Sobrien struct ppc_stub_hash_entry *stub_entry; 8550130561Sobrien struct bfd_link_info *info; 8551104834Sobrien struct ppc_link_hash_table *htab; 8552104834Sobrien bfd_vma off; 8553104834Sobrien int size; 8554104834Sobrien 8555104834Sobrien /* Massage our args to the form they really have. */ 8556104834Sobrien stub_entry = (struct ppc_stub_hash_entry *) gen_entry; 8557130561Sobrien info = in_arg; 8558104834Sobrien 8559130561Sobrien htab = ppc_hash_table (info); 8560130561Sobrien 8561104834Sobrien if (stub_entry->stub_type == ppc_stub_plt_call) 8562104834Sobrien { 8563130561Sobrien struct plt_entry *ent; 8564130561Sobrien off = (bfd_vma) -1; 8565130561Sobrien for (ent = stub_entry->h->elf.plt.plist; ent != NULL; ent = ent->next) 8566130561Sobrien if (ent->addend == stub_entry->addend) 8567130561Sobrien { 8568130561Sobrien off = ent->plt.offset & ~(bfd_vma) 1; 8569130561Sobrien break; 8570130561Sobrien } 8571130561Sobrien if (off >= (bfd_vma) -2) 8572130561Sobrien abort (); 8573130561Sobrien off += (htab->plt->output_offset 8574130561Sobrien + htab->plt->output_section->vma 8575130561Sobrien - elf_gp (htab->plt->output_section->owner) 8576130561Sobrien - htab->stub_group[stub_entry->id_sec->id].toc_off); 8577104834Sobrien 8578130561Sobrien size = PLT_CALL_STUB_SIZE; 8579130561Sobrien if (PPC_HA (off + 16) != PPC_HA (off)) 8580104834Sobrien size += 4; 8581104834Sobrien } 8582104834Sobrien else 8583104834Sobrien { 8584130561Sobrien /* ppc_stub_long_branch or ppc_stub_plt_branch, or their r2off 8585130561Sobrien variants. */ 8586104834Sobrien off = (stub_entry->target_value 8587104834Sobrien + stub_entry->target_section->output_offset 8588104834Sobrien + stub_entry->target_section->output_section->vma); 8589218822Sdim off -= (stub_entry->stub_sec->size 8590104834Sobrien + stub_entry->stub_sec->output_offset 8591104834Sobrien + stub_entry->stub_sec->output_section->vma); 8592104834Sobrien 8593130561Sobrien /* Reset the stub type from the plt variant in case we now 8594130561Sobrien can reach with a shorter stub. */ 8595130561Sobrien if (stub_entry->stub_type >= ppc_stub_plt_branch) 8596130561Sobrien stub_entry->stub_type += ppc_stub_long_branch - ppc_stub_plt_branch; 8597130561Sobrien 8598130561Sobrien size = 4; 8599130561Sobrien if (stub_entry->stub_type == ppc_stub_long_branch_r2off) 8600130561Sobrien { 8601130561Sobrien off -= 12; 8602130561Sobrien size = 16; 8603130561Sobrien } 8604130561Sobrien 8605130561Sobrien /* If the branch offset if too big, use a ppc_stub_plt_branch. */ 8606104834Sobrien if (off + (1 << 25) >= (bfd_vma) (1 << 26)) 8607104834Sobrien { 8608104834Sobrien struct ppc_branch_hash_entry *br_entry; 8609104834Sobrien 8610104834Sobrien br_entry = ppc_branch_hash_lookup (&htab->branch_hash_table, 8611104834Sobrien stub_entry->root.string + 9, 8612130561Sobrien TRUE, FALSE); 8613104834Sobrien if (br_entry == NULL) 8614104834Sobrien { 8615104834Sobrien (*_bfd_error_handler) (_("can't build branch stub `%s'"), 8616218822Sdim stub_entry->root.string); 8617130561Sobrien htab->stub_error = TRUE; 8618130561Sobrien return FALSE; 8619104834Sobrien } 8620104834Sobrien 8621104834Sobrien if (br_entry->iter != htab->stub_iteration) 8622104834Sobrien { 8623104834Sobrien br_entry->iter = htab->stub_iteration; 8624218822Sdim br_entry->offset = htab->brlt->size; 8625218822Sdim htab->brlt->size += 8; 8626130561Sobrien 8627218822Sdim if (htab->relbrlt != NULL) 8628218822Sdim htab->relbrlt->size += sizeof (Elf64_External_Rela); 8629218822Sdim else if (info->emitrelocations) 8630218822Sdim { 8631218822Sdim htab->brlt->reloc_count += 1; 8632218822Sdim htab->brlt->flags |= SEC_RELOC; 8633218822Sdim } 8634104834Sobrien } 8635130561Sobrien 8636130561Sobrien stub_entry->stub_type += ppc_stub_plt_branch - ppc_stub_long_branch; 8637104834Sobrien size = 16; 8638130561Sobrien if (stub_entry->stub_type != ppc_stub_plt_branch) 8639130561Sobrien size = 28; 8640104834Sobrien } 8641218822Sdim else if (info->emitrelocations) 8642218822Sdim { 8643218822Sdim stub_entry->stub_sec->reloc_count += 1; 8644218822Sdim stub_entry->stub_sec->flags |= SEC_RELOC; 8645218822Sdim } 8646104834Sobrien } 8647104834Sobrien 8648218822Sdim stub_entry->stub_sec->size += size; 8649130561Sobrien return TRUE; 8650104834Sobrien} 8651104834Sobrien 8652104834Sobrien/* Set up various things so that we can make a list of input sections 8653104834Sobrien for each output section included in the link. Returns -1 on error, 8654104834Sobrien 0 when no stubs will be needed, and 1 on success. */ 8655104834Sobrien 8656104834Sobrienint 8657218822Sdimppc64_elf_setup_section_lists (bfd *output_bfd, 8658218822Sdim struct bfd_link_info *info, 8659218822Sdim int no_multi_toc) 866089857Sobrien{ 8661104834Sobrien bfd *input_bfd; 8662130561Sobrien int top_id, top_index, id; 8663104834Sobrien asection *section; 8664130561Sobrien asection **input_list; 8665104834Sobrien bfd_size_type amt; 866689857Sobrien struct ppc_link_hash_table *htab = ppc_hash_table (info); 866789857Sobrien 8668218822Sdim htab->no_multi_toc = no_multi_toc; 8669218822Sdim 8670130561Sobrien if (htab->brlt == NULL) 8671104834Sobrien return 0; 867289857Sobrien 8673104834Sobrien /* Find the top input section id. */ 8674130561Sobrien for (input_bfd = info->input_bfds, top_id = 3; 8675104834Sobrien input_bfd != NULL; 8676104834Sobrien input_bfd = input_bfd->link_next) 8677104834Sobrien { 8678104834Sobrien for (section = input_bfd->sections; 8679104834Sobrien section != NULL; 8680104834Sobrien section = section->next) 8681104834Sobrien { 8682104834Sobrien if (top_id < section->id) 8683104834Sobrien top_id = section->id; 8684104834Sobrien } 8685104834Sobrien } 868689857Sobrien 8687130561Sobrien htab->top_id = top_id; 8688104834Sobrien amt = sizeof (struct map_stub) * (top_id + 1); 8689130561Sobrien htab->stub_group = bfd_zmalloc (amt); 8690104834Sobrien if (htab->stub_group == NULL) 8691104834Sobrien return -1; 8692104834Sobrien 8693130561Sobrien /* Set toc_off for com, und, abs and ind sections. */ 8694130561Sobrien for (id = 0; id < 3; id++) 8695130561Sobrien htab->stub_group[id].toc_off = TOC_BASE_OFF; 8696130561Sobrien 8697130561Sobrien elf_gp (output_bfd) = htab->toc_curr = ppc64_elf_toc (output_bfd); 8698130561Sobrien 8699104834Sobrien /* We can't use output_bfd->section_count here to find the top output 8700104834Sobrien section index as some sections may have been removed, and 8701218822Sdim strip_excluded_output_sections doesn't renumber the indices. */ 8702104834Sobrien for (section = output_bfd->sections, top_index = 0; 8703104834Sobrien section != NULL; 8704104834Sobrien section = section->next) 870589857Sobrien { 8706104834Sobrien if (top_index < section->index) 8707104834Sobrien top_index = section->index; 870889857Sobrien } 870989857Sobrien 8710104834Sobrien htab->top_index = top_index; 8711104834Sobrien amt = sizeof (asection *) * (top_index + 1); 8712130561Sobrien input_list = bfd_zmalloc (amt); 8713104834Sobrien htab->input_list = input_list; 8714104834Sobrien if (input_list == NULL) 8715104834Sobrien return -1; 871689857Sobrien 8717130561Sobrien return 1; 8718130561Sobrien} 871989857Sobrien 8720130561Sobrien/* The linker repeatedly calls this function for each TOC input section 8721130561Sobrien and linker generated GOT section. Group input bfds such that the toc 8722130561Sobrien within a group is less than 64k in size. Will break with cute linker 8723130561Sobrien scripts that play games with dot in the output toc section. */ 8724130561Sobrien 8725130561Sobrienvoid 8726130561Sobrienppc64_elf_next_toc_section (struct bfd_link_info *info, asection *isec) 8727130561Sobrien{ 8728130561Sobrien struct ppc_link_hash_table *htab = ppc_hash_table (info); 8729130561Sobrien 8730130561Sobrien if (!htab->no_multi_toc) 8731104834Sobrien { 8732130561Sobrien bfd_vma addr = isec->output_offset + isec->output_section->vma; 8733130561Sobrien bfd_vma off = addr - htab->toc_curr; 8734218822Sdim 8735218822Sdim if (off + isec->size > 0x10000) 8736218822Sdim htab->toc_curr = addr; 8737218822Sdim 8738130561Sobrien elf_gp (isec->owner) = (htab->toc_curr 8739130561Sobrien - elf_gp (isec->output_section->owner) 8740130561Sobrien + TOC_BASE_OFF); 8741104834Sobrien } 8742130561Sobrien} 874389857Sobrien 8744130561Sobrien/* Called after the last call to the above function. */ 8745130561Sobrien 8746130561Sobrienvoid 8747218822Sdimppc64_elf_reinit_toc (bfd *output_bfd, struct bfd_link_info *info) 8748130561Sobrien{ 8749130561Sobrien struct ppc_link_hash_table *htab = ppc_hash_table (info); 8750130561Sobrien 8751218822Sdim htab->multi_toc_needed = htab->toc_curr != elf_gp (output_bfd); 8752218822Sdim 8753130561Sobrien /* toc_curr tracks the TOC offset used for code sections below in 8754130561Sobrien ppc64_elf_next_input_section. Start off at 0x8000. */ 8755130561Sobrien htab->toc_curr = TOC_BASE_OFF; 8756104834Sobrien} 8757104834Sobrien 8758130561Sobrien/* No toc references were found in ISEC. If the code in ISEC makes no 8759130561Sobrien calls, then there's no need to use toc adjusting stubs when branching 8760130561Sobrien into ISEC. Actually, indirect calls from ISEC are OK as they will 8761218822Sdim load r2. Returns -1 on error, 0 for no stub needed, 1 for stub 8762218822Sdim needed, and 2 if a cyclical call-graph was found but no other reason 8763218822Sdim for a stub was detected. If called from the top level, a return of 8764218822Sdim 2 means the same as a return of 0. */ 8765130561Sobrien 8766130561Sobrienstatic int 8767130561Sobrientoc_adjusting_stub_needed (struct bfd_link_info *info, asection *isec) 8768130561Sobrien{ 8769218822Sdim Elf_Internal_Rela *relstart, *rel; 8770218822Sdim Elf_Internal_Sym *local_syms; 8771130561Sobrien int ret; 8772218822Sdim struct ppc_link_hash_table *htab; 8773130561Sobrien 8774130561Sobrien /* We know none of our code bearing sections will need toc stubs. */ 8775130561Sobrien if ((isec->flags & SEC_LINKER_CREATED) != 0) 8776130561Sobrien return 0; 8777130561Sobrien 8778218822Sdim if (isec->size == 0) 8779130561Sobrien return 0; 8780130561Sobrien 8781218822Sdim if (isec->output_section == NULL) 8782218822Sdim return 0; 8783218822Sdim 8784130561Sobrien /* Hack for linux kernel. .fixup contains branches, but only back to 8785130561Sobrien the function that hit an exception. */ 8786218822Sdim if (strcmp (isec->name, ".fixup") == 0) 8787218822Sdim return 0; 8788130561Sobrien 8789218822Sdim if (isec->reloc_count == 0) 8790218822Sdim return 0; 8791218822Sdim 8792218822Sdim relstart = _bfd_elf_link_read_relocs (isec->owner, isec, NULL, NULL, 8793218822Sdim info->keep_memory); 8794218822Sdim if (relstart == NULL) 8795218822Sdim return -1; 8796218822Sdim 8797218822Sdim /* Look for branches to outside of this section. */ 8798218822Sdim local_syms = NULL; 8799218822Sdim ret = 0; 8800218822Sdim htab = ppc_hash_table (info); 8801218822Sdim for (rel = relstart; rel < relstart + isec->reloc_count; ++rel) 8802130561Sobrien { 8803218822Sdim enum elf_ppc64_reloc_type r_type; 8804218822Sdim unsigned long r_symndx; 8805218822Sdim struct elf_link_hash_entry *h; 8806218822Sdim Elf_Internal_Sym *sym; 8807218822Sdim asection *sym_sec; 8808218822Sdim long *opd_adjust; 8809218822Sdim bfd_vma sym_value; 8810218822Sdim bfd_vma dest; 8811218822Sdim 8812218822Sdim r_type = ELF64_R_TYPE (rel->r_info); 8813218822Sdim if (r_type != R_PPC64_REL24 8814218822Sdim && r_type != R_PPC64_REL14 8815218822Sdim && r_type != R_PPC64_REL14_BRTAKEN 8816218822Sdim && r_type != R_PPC64_REL14_BRNTAKEN) 8817218822Sdim continue; 8818218822Sdim 8819218822Sdim r_symndx = ELF64_R_SYM (rel->r_info); 8820218822Sdim if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, r_symndx, 8821218822Sdim isec->owner)) 8822130561Sobrien { 8823218822Sdim ret = -1; 8824218822Sdim break; 8825130561Sobrien } 8826130561Sobrien 8827218822Sdim /* Calls to dynamic lib functions go through a plt call stub 8828218822Sdim that uses r2. Branches to undefined symbols might be a call 8829218822Sdim using old-style dot symbols that can be satisfied by a plt 8830218822Sdim call into a new-style dynamic library. */ 8831218822Sdim if (sym_sec == NULL) 8832130561Sobrien { 8833218822Sdim struct ppc_link_hash_entry *eh = (struct ppc_link_hash_entry *) h; 8834218822Sdim if (eh != NULL 8835218822Sdim && eh->oh != NULL 8836218822Sdim && eh->oh->elf.plt.plist != NULL) 8837218822Sdim { 8838218822Sdim ret = 1; 8839218822Sdim break; 8840218822Sdim } 8841218822Sdim 8842218822Sdim /* Ignore other undefined symbols. */ 8843218822Sdim continue; 8844218822Sdim } 8845218822Sdim 8846218822Sdim /* Assume branches to other sections not included in the link need 8847218822Sdim stubs too, to cover -R and absolute syms. */ 8848218822Sdim if (sym_sec->output_section == NULL) 8849218822Sdim { 8850130561Sobrien ret = 1; 8851130561Sobrien break; 8852130561Sobrien } 8853218822Sdim 8854218822Sdim if (h == NULL) 8855218822Sdim sym_value = sym->st_value; 8856218822Sdim else 8857218822Sdim { 8858218822Sdim if (h->root.type != bfd_link_hash_defined 8859218822Sdim && h->root.type != bfd_link_hash_defweak) 8860218822Sdim abort (); 8861218822Sdim sym_value = h->root.u.def.value; 8862218822Sdim } 8863218822Sdim sym_value += rel->r_addend; 8864218822Sdim 8865218822Sdim /* If this branch reloc uses an opd sym, find the code section. */ 8866218822Sdim opd_adjust = get_opd_info (sym_sec); 8867218822Sdim if (opd_adjust != NULL) 8868218822Sdim { 8869218822Sdim if (h == NULL) 8870218822Sdim { 8871218822Sdim long adjust; 8872218822Sdim 8873218822Sdim adjust = opd_adjust[sym->st_value / 8]; 8874218822Sdim if (adjust == -1) 8875218822Sdim /* Assume deleted functions won't ever be called. */ 8876218822Sdim continue; 8877218822Sdim sym_value += adjust; 8878218822Sdim } 8879218822Sdim 8880218822Sdim dest = opd_entry_value (sym_sec, sym_value, &sym_sec, NULL); 8881218822Sdim if (dest == (bfd_vma) -1) 8882218822Sdim continue; 8883218822Sdim } 8884218822Sdim else 8885218822Sdim dest = (sym_value 8886218822Sdim + sym_sec->output_offset 8887218822Sdim + sym_sec->output_section->vma); 8888218822Sdim 8889218822Sdim /* Ignore branch to self. */ 8890218822Sdim if (sym_sec == isec) 8891218822Sdim continue; 8892218822Sdim 8893218822Sdim /* If the called function uses the toc, we need a stub. */ 8894218822Sdim if (sym_sec->has_toc_reloc 8895218822Sdim || sym_sec->makes_toc_func_call) 8896218822Sdim { 8897218822Sdim ret = 1; 8898218822Sdim break; 8899218822Sdim } 8900218822Sdim 8901218822Sdim /* Assume any branch that needs a long branch stub might in fact 8902218822Sdim need a plt_branch stub. A plt_branch stub uses r2. */ 8903218822Sdim else if (dest - (isec->output_offset 8904218822Sdim + isec->output_section->vma 8905218822Sdim + rel->r_offset) + (1 << 25) >= (2 << 25)) 8906218822Sdim { 8907218822Sdim ret = 1; 8908218822Sdim break; 8909218822Sdim } 8910218822Sdim 8911218822Sdim /* If calling back to a section in the process of being tested, we 8912218822Sdim can't say for sure that no toc adjusting stubs are needed, so 8913218822Sdim don't return zero. */ 8914218822Sdim else if (sym_sec->call_check_in_progress) 8915218822Sdim ret = 2; 8916218822Sdim 8917218822Sdim /* Branches to another section that itself doesn't have any TOC 8918218822Sdim references are OK. Recursively call ourselves to check. */ 8919218822Sdim else if (sym_sec->id <= htab->top_id 8920218822Sdim && htab->stub_group[sym_sec->id].toc_off == 0) 8921218822Sdim { 8922218822Sdim int recur; 8923218822Sdim 8924218822Sdim /* Mark current section as indeterminate, so that other 8925218822Sdim sections that call back to current won't be marked as 8926218822Sdim known. */ 8927218822Sdim isec->call_check_in_progress = 1; 8928218822Sdim recur = toc_adjusting_stub_needed (info, sym_sec); 8929218822Sdim isec->call_check_in_progress = 0; 8930218822Sdim 8931218822Sdim if (recur < 0) 8932218822Sdim { 8933218822Sdim /* An error. Exit. */ 8934218822Sdim ret = -1; 8935218822Sdim break; 8936218822Sdim } 8937218822Sdim else if (recur <= 1) 8938218822Sdim { 8939218822Sdim /* Known result. Mark as checked and set section flag. */ 8940218822Sdim htab->stub_group[sym_sec->id].toc_off = 1; 8941218822Sdim if (recur != 0) 8942218822Sdim { 8943218822Sdim sym_sec->makes_toc_func_call = 1; 8944218822Sdim ret = 1; 8945218822Sdim break; 8946218822Sdim } 8947218822Sdim } 8948218822Sdim else 8949218822Sdim { 8950218822Sdim /* Unknown result. Continue checking. */ 8951218822Sdim ret = 2; 8952218822Sdim } 8953218822Sdim } 8954130561Sobrien } 8955130561Sobrien 8956218822Sdim if (local_syms != NULL 8957218822Sdim && (elf_tdata (isec->owner)->symtab_hdr.contents 8958218822Sdim != (unsigned char *) local_syms)) 8959218822Sdim free (local_syms); 8960218822Sdim if (elf_section_data (isec)->relocs != relstart) 8961218822Sdim free (relstart); 8962218822Sdim 8963130561Sobrien return ret; 8964130561Sobrien} 8965130561Sobrien 8966104834Sobrien/* The linker repeatedly calls this function for each input section, 8967104834Sobrien in the order that input sections are linked into output sections. 8968104834Sobrien Build lists of input sections to determine groupings between which 8969104834Sobrien we may insert linker stubs. */ 8970104834Sobrien 8971130561Sobrienbfd_boolean 8972130561Sobrienppc64_elf_next_input_section (struct bfd_link_info *info, asection *isec) 8973104834Sobrien{ 8974104834Sobrien struct ppc_link_hash_table *htab = ppc_hash_table (info); 8975104834Sobrien 8976130561Sobrien if ((isec->output_section->flags & SEC_CODE) != 0 8977130561Sobrien && isec->output_section->index <= htab->top_index) 897889857Sobrien { 8979104834Sobrien asection **list = htab->input_list + isec->output_section->index; 8980130561Sobrien /* Steal the link_sec pointer for our list. */ 8981104834Sobrien#define PREV_SEC(sec) (htab->stub_group[(sec)->id].link_sec) 8982130561Sobrien /* This happens to make the list in reverse order, 8983130561Sobrien which is what we want. */ 8984130561Sobrien PREV_SEC (isec) = *list; 8985130561Sobrien *list = isec; 898689857Sobrien } 8987130561Sobrien 8988218822Sdim if (htab->multi_toc_needed) 8989130561Sobrien { 8990218822Sdim /* If a code section has a function that uses the TOC then we need 8991218822Sdim to use the right TOC (obviously). Also, make sure that .opd gets 8992218822Sdim the correct TOC value for R_PPC64_TOC relocs that don't have or 8993218822Sdim can't find their function symbol (shouldn't ever happen now). */ 8994218822Sdim if (isec->has_toc_reloc || (isec->flags & SEC_CODE) == 0) 8995218822Sdim { 8996218822Sdim if (elf_gp (isec->owner) != 0) 8997218822Sdim htab->toc_curr = elf_gp (isec->owner); 8998218822Sdim } 8999218822Sdim else if (htab->stub_group[isec->id].toc_off == 0) 9000218822Sdim { 9001218822Sdim int ret = toc_adjusting_stub_needed (info, isec); 9002218822Sdim if (ret < 0) 9003218822Sdim return FALSE; 9004218822Sdim else 9005218822Sdim isec->makes_toc_func_call = ret & 1; 9006218822Sdim } 9007130561Sobrien } 9008130561Sobrien 9009130561Sobrien /* Functions that don't use the TOC can belong in any TOC group. 9010130561Sobrien Use the last TOC base. This happens to make _init and _fini 9011130561Sobrien pasting work. */ 9012130561Sobrien htab->stub_group[isec->id].toc_off = htab->toc_curr; 9013130561Sobrien return TRUE; 901489857Sobrien} 901589857Sobrien 9016104834Sobrien/* See whether we can group stub sections together. Grouping stub 9017104834Sobrien sections may result in fewer stubs. More importantly, we need to 9018104834Sobrien put all .init* and .fini* stubs at the beginning of the .init or 9019104834Sobrien .fini output sections respectively, because glibc splits the 9020104834Sobrien _init and _fini functions into multiple parts. Putting a stub in 9021104834Sobrien the middle of a function is not a good idea. */ 902289857Sobrien 9023104834Sobrienstatic void 9024130561Sobriengroup_sections (struct ppc_link_hash_table *htab, 9025130561Sobrien bfd_size_type stub_group_size, 9026130561Sobrien bfd_boolean stubs_always_before_branch) 902789857Sobrien{ 9028218822Sdim asection **list; 9029218822Sdim bfd_size_type stub14_group_size; 9030218822Sdim bfd_boolean suppress_size_errors; 9031218822Sdim 9032218822Sdim suppress_size_errors = FALSE; 9033218822Sdim stub14_group_size = stub_group_size; 9034218822Sdim if (stub_group_size == 1) 9035218822Sdim { 9036218822Sdim /* Default values. */ 9037218822Sdim if (stubs_always_before_branch) 9038218822Sdim { 9039218822Sdim stub_group_size = 0x1e00000; 9040218822Sdim stub14_group_size = 0x7800; 9041218822Sdim } 9042218822Sdim else 9043218822Sdim { 9044218822Sdim stub_group_size = 0x1c00000; 9045218822Sdim stub14_group_size = 0x7000; 9046218822Sdim } 9047218822Sdim suppress_size_errors = TRUE; 9048218822Sdim } 9049218822Sdim 9050218822Sdim list = htab->input_list + htab->top_index; 9051104834Sobrien do 9052104834Sobrien { 9053104834Sobrien asection *tail = *list; 9054104834Sobrien while (tail != NULL) 9055104834Sobrien { 9056104834Sobrien asection *curr; 9057104834Sobrien asection *prev; 9058104834Sobrien bfd_size_type total; 9059130561Sobrien bfd_boolean big_sec; 9060130561Sobrien bfd_vma curr_toc; 906189857Sobrien 9062104834Sobrien curr = tail; 9063218822Sdim total = tail->size; 9064218822Sdim big_sec = total > (ppc64_elf_section_data (tail)->has_14bit_branch 9065218822Sdim ? stub14_group_size : stub_group_size); 9066218822Sdim if (big_sec && !suppress_size_errors) 9067218822Sdim (*_bfd_error_handler) (_("%B section %A exceeds stub group size"), 9068218822Sdim tail->owner, tail); 9069130561Sobrien curr_toc = htab->stub_group[tail->id].toc_off; 9070130561Sobrien 9071104834Sobrien while ((prev = PREV_SEC (curr)) != NULL 9072104834Sobrien && ((total += curr->output_offset - prev->output_offset) 9073218822Sdim < (ppc64_elf_section_data (prev)->has_14bit_branch 9074218822Sdim ? stub14_group_size : stub_group_size)) 9075130561Sobrien && htab->stub_group[prev->id].toc_off == curr_toc) 9076104834Sobrien curr = prev; 907789857Sobrien 9078104834Sobrien /* OK, the size from the start of CURR to the end is less 9079104834Sobrien than stub_group_size and thus can be handled by one stub 9080104834Sobrien section. (or the tail section is itself larger than 9081104834Sobrien stub_group_size, in which case we may be toast.) We 9082104834Sobrien should really be keeping track of the total size of stubs 9083104834Sobrien added here, as stubs contribute to the final output 9084104834Sobrien section size. That's a little tricky, and this way will 9085104834Sobrien only break if stubs added make the total size more than 9086104834Sobrien 2^25, ie. for the default stub_group_size, if stubs total 9087130561Sobrien more than 2097152 bytes, or nearly 75000 plt call stubs. */ 9088104834Sobrien do 9089104834Sobrien { 9090104834Sobrien prev = PREV_SEC (tail); 9091104834Sobrien /* Set up this stub group. */ 9092104834Sobrien htab->stub_group[tail->id].link_sec = curr; 9093104834Sobrien } 9094104834Sobrien while (tail != curr && (tail = prev) != NULL); 9095104834Sobrien 9096104834Sobrien /* But wait, there's more! Input sections up to stub_group_size 9097130561Sobrien bytes before the stub section can be handled by it too. 9098130561Sobrien Don't do this if we have a really large section after the 9099130561Sobrien stubs, as adding more stubs increases the chance that 9100130561Sobrien branches may not reach into the stub section. */ 9101130561Sobrien if (!stubs_always_before_branch && !big_sec) 9102104834Sobrien { 9103104834Sobrien total = 0; 9104104834Sobrien while (prev != NULL 9105104834Sobrien && ((total += tail->output_offset - prev->output_offset) 9106218822Sdim < (ppc64_elf_section_data (prev)->has_14bit_branch 9107218822Sdim ? stub14_group_size : stub_group_size)) 9108130561Sobrien && htab->stub_group[prev->id].toc_off == curr_toc) 9109104834Sobrien { 9110104834Sobrien tail = prev; 9111104834Sobrien prev = PREV_SEC (tail); 9112104834Sobrien htab->stub_group[tail->id].link_sec = curr; 9113104834Sobrien } 9114104834Sobrien } 9115104834Sobrien tail = prev; 9116104834Sobrien } 9117104834Sobrien } 9118104834Sobrien while (list-- != htab->input_list); 9119104834Sobrien free (htab->input_list); 9120104834Sobrien#undef PREV_SEC 9121104834Sobrien} 9122104834Sobrien 9123104834Sobrien/* Determine and set the size of the stub section for a final link. 9124104834Sobrien 9125104834Sobrien The basic idea here is to examine all the relocations looking for 9126104834Sobrien PC-relative calls to a target that is unreachable with a "bl" 9127104834Sobrien instruction. */ 9128104834Sobrien 9129130561Sobrienbfd_boolean 9130130561Sobrienppc64_elf_size_stubs (bfd *output_bfd, 9131130561Sobrien struct bfd_link_info *info, 9132130561Sobrien bfd_signed_vma group_size, 9133130561Sobrien asection *(*add_stub_section) (const char *, asection *), 9134130561Sobrien void (*layout_sections_again) (void)) 9135104834Sobrien{ 9136104834Sobrien bfd_size_type stub_group_size; 9137130561Sobrien bfd_boolean stubs_always_before_branch; 9138104834Sobrien struct ppc_link_hash_table *htab = ppc_hash_table (info); 9139104834Sobrien 9140104834Sobrien /* Stash our params away. */ 9141104834Sobrien htab->add_stub_section = add_stub_section; 9142104834Sobrien htab->layout_sections_again = layout_sections_again; 9143104834Sobrien stubs_always_before_branch = group_size < 0; 9144104834Sobrien if (group_size < 0) 9145104834Sobrien stub_group_size = -group_size; 9146104834Sobrien else 9147104834Sobrien stub_group_size = group_size; 9148104834Sobrien 9149104834Sobrien group_sections (htab, stub_group_size, stubs_always_before_branch); 9150104834Sobrien 9151104834Sobrien while (1) 9152104834Sobrien { 9153104834Sobrien bfd *input_bfd; 9154104834Sobrien unsigned int bfd_indx; 9155104834Sobrien asection *stub_sec; 9156104834Sobrien 9157104834Sobrien htab->stub_iteration += 1; 9158104834Sobrien 9159104834Sobrien for (input_bfd = info->input_bfds, bfd_indx = 0; 9160104834Sobrien input_bfd != NULL; 9161104834Sobrien input_bfd = input_bfd->link_next, bfd_indx++) 9162104834Sobrien { 9163104834Sobrien Elf_Internal_Shdr *symtab_hdr; 9164104834Sobrien asection *section; 9165104834Sobrien Elf_Internal_Sym *local_syms = NULL; 9166104834Sobrien 9167218822Sdim if (!is_ppc64_elf_target (input_bfd->xvec)) 9168218822Sdim continue; 9169218822Sdim 9170104834Sobrien /* We'll need the symbol table in a second. */ 9171104834Sobrien symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; 9172104834Sobrien if (symtab_hdr->sh_info == 0) 9173104834Sobrien continue; 9174104834Sobrien 9175104834Sobrien /* Walk over each section attached to the input bfd. */ 9176104834Sobrien for (section = input_bfd->sections; 9177104834Sobrien section != NULL; 9178104834Sobrien section = section->next) 9179104834Sobrien { 9180104834Sobrien Elf_Internal_Rela *internal_relocs, *irelaend, *irela; 9181104834Sobrien 9182104834Sobrien /* If there aren't any relocs, then there's nothing more 9183104834Sobrien to do. */ 9184104834Sobrien if ((section->flags & SEC_RELOC) == 0 9185218822Sdim || (section->flags & SEC_ALLOC) == 0 9186218822Sdim || (section->flags & SEC_LOAD) == 0 9187218822Sdim || (section->flags & SEC_CODE) == 0 9188104834Sobrien || section->reloc_count == 0) 9189104834Sobrien continue; 9190104834Sobrien 9191104834Sobrien /* If this section is a link-once section that will be 9192104834Sobrien discarded, then don't create any stubs. */ 9193104834Sobrien if (section->output_section == NULL 9194104834Sobrien || section->output_section->owner != output_bfd) 9195104834Sobrien continue; 9196104834Sobrien 9197104834Sobrien /* Get the relocs. */ 9198104834Sobrien internal_relocs 9199130561Sobrien = _bfd_elf_link_read_relocs (input_bfd, section, NULL, NULL, 9200130561Sobrien info->keep_memory); 9201104834Sobrien if (internal_relocs == NULL) 9202104834Sobrien goto error_ret_free_local; 9203104834Sobrien 9204104834Sobrien /* Now examine each relocation. */ 9205104834Sobrien irela = internal_relocs; 9206104834Sobrien irelaend = irela + section->reloc_count; 9207104834Sobrien for (; irela < irelaend; irela++) 9208104834Sobrien { 9209130561Sobrien enum elf_ppc64_reloc_type r_type; 9210130561Sobrien unsigned int r_indx; 9211104834Sobrien enum ppc_stub_type stub_type; 9212104834Sobrien struct ppc_stub_hash_entry *stub_entry; 9213218822Sdim asection *sym_sec, *code_sec; 9214104834Sobrien bfd_vma sym_value; 9215104834Sobrien bfd_vma destination; 9216218822Sdim bfd_boolean ok_dest; 9217104834Sobrien struct ppc_link_hash_entry *hash; 9218218822Sdim struct ppc_link_hash_entry *fdh; 9219130561Sobrien struct elf_link_hash_entry *h; 9220130561Sobrien Elf_Internal_Sym *sym; 9221104834Sobrien char *stub_name; 9222104834Sobrien const asection *id_sec; 9223218822Sdim long *opd_adjust; 9224104834Sobrien 9225104834Sobrien r_type = ELF64_R_TYPE (irela->r_info); 9226104834Sobrien r_indx = ELF64_R_SYM (irela->r_info); 9227104834Sobrien 9228130561Sobrien if (r_type >= R_PPC64_max) 9229104834Sobrien { 9230104834Sobrien bfd_set_error (bfd_error_bad_value); 9231104834Sobrien goto error_ret_free_internal; 9232104834Sobrien } 9233104834Sobrien 9234104834Sobrien /* Only look for stubs on branch instructions. */ 9235130561Sobrien if (r_type != R_PPC64_REL24 9236130561Sobrien && r_type != R_PPC64_REL14 9237130561Sobrien && r_type != R_PPC64_REL14_BRTAKEN 9238130561Sobrien && r_type != R_PPC64_REL14_BRNTAKEN) 9239104834Sobrien continue; 9240104834Sobrien 9241104834Sobrien /* Now determine the call target, its name, value, 9242104834Sobrien section. */ 9243130561Sobrien if (!get_sym_h (&h, &sym, &sym_sec, NULL, &local_syms, 9244130561Sobrien r_indx, input_bfd)) 9245130561Sobrien goto error_ret_free_internal; 9246130561Sobrien hash = (struct ppc_link_hash_entry *) h; 9247130561Sobrien 9248218822Sdim ok_dest = FALSE; 9249218822Sdim fdh = NULL; 9250218822Sdim sym_value = 0; 9251130561Sobrien if (hash == NULL) 9252104834Sobrien { 9253130561Sobrien sym_value = sym->st_value; 9254218822Sdim ok_dest = TRUE; 9255218822Sdim } 9256218822Sdim else if (hash->elf.root.type == bfd_link_hash_defined 9257218822Sdim || hash->elf.root.type == bfd_link_hash_defweak) 9258218822Sdim { 9259218822Sdim sym_value = hash->elf.root.u.def.value; 9260218822Sdim if (sym_sec->output_section != NULL) 9261218822Sdim ok_dest = TRUE; 9262218822Sdim } 9263218822Sdim else if (hash->elf.root.type == bfd_link_hash_undefweak 9264218822Sdim || hash->elf.root.type == bfd_link_hash_undefined) 9265218822Sdim { 9266218822Sdim /* Recognise an old ABI func code entry sym, and 9267218822Sdim use the func descriptor sym instead if it is 9268218822Sdim defined. */ 9269218822Sdim if (hash->elf.root.root.string[0] == '.' 9270218822Sdim && (fdh = get_fdh (hash, htab)) != NULL) 9271218822Sdim { 9272218822Sdim if (fdh->elf.root.type == bfd_link_hash_defined 9273218822Sdim || fdh->elf.root.type == bfd_link_hash_defweak) 9274218822Sdim { 9275218822Sdim sym_sec = fdh->elf.root.u.def.section; 9276218822Sdim sym_value = fdh->elf.root.u.def.value; 9277218822Sdim if (sym_sec->output_section != NULL) 9278218822Sdim ok_dest = TRUE; 9279218822Sdim } 9280218822Sdim else 9281218822Sdim fdh = NULL; 9282218822Sdim } 9283218822Sdim } 9284218822Sdim else 9285218822Sdim { 9286218822Sdim bfd_set_error (bfd_error_bad_value); 9287218822Sdim goto error_ret_free_internal; 9288218822Sdim } 9289218822Sdim 9290218822Sdim destination = 0; 9291218822Sdim if (ok_dest) 9292218822Sdim { 9293218822Sdim sym_value += irela->r_addend; 9294218822Sdim destination = (sym_value 9295104834Sobrien + sym_sec->output_offset 9296104834Sobrien + sym_sec->output_section->vma); 9297104834Sobrien } 9298218822Sdim 9299218822Sdim code_sec = sym_sec; 9300218822Sdim opd_adjust = get_opd_info (sym_sec); 9301218822Sdim if (opd_adjust != NULL) 9302104834Sobrien { 9303218822Sdim bfd_vma dest; 9304218822Sdim 9305218822Sdim if (hash == NULL) 9306104834Sobrien { 9307218822Sdim long adjust = opd_adjust[sym_value / 8]; 9308218822Sdim if (adjust == -1) 9309218822Sdim continue; 9310218822Sdim sym_value += adjust; 9311104834Sobrien } 9312218822Sdim dest = opd_entry_value (sym_sec, sym_value, 9313218822Sdim &code_sec, &sym_value); 9314218822Sdim if (dest != (bfd_vma) -1) 9315104834Sobrien { 9316218822Sdim destination = dest; 9317218822Sdim if (fdh != NULL) 9318218822Sdim { 9319218822Sdim /* Fixup old ABI sym to point at code 9320218822Sdim entry. */ 9321218822Sdim hash->elf.root.type = bfd_link_hash_defweak; 9322218822Sdim hash->elf.root.u.def.section = code_sec; 9323218822Sdim hash->elf.root.u.def.value = sym_value; 9324218822Sdim } 9325104834Sobrien } 9326104834Sobrien } 9327104834Sobrien 9328104834Sobrien /* Determine what (if any) linker stub is needed. */ 9329104834Sobrien stub_type = ppc_type_of_stub (section, irela, &hash, 9330104834Sobrien destination); 9331130561Sobrien 9332130561Sobrien if (stub_type != ppc_stub_plt_call) 9333130561Sobrien { 9334130561Sobrien /* Check whether we need a TOC adjusting stub. 9335130561Sobrien Since the linker pastes together pieces from 9336130561Sobrien different object files when creating the 9337130561Sobrien _init and _fini functions, it may be that a 9338130561Sobrien call to what looks like a local sym is in 9339130561Sobrien fact a call needing a TOC adjustment. */ 9340218822Sdim if (code_sec != NULL 9341218822Sdim && code_sec->output_section != NULL 9342218822Sdim && (htab->stub_group[code_sec->id].toc_off 9343130561Sobrien != htab->stub_group[section->id].toc_off) 9344218822Sdim && (code_sec->has_toc_reloc 9345218822Sdim || code_sec->makes_toc_func_call)) 9346130561Sobrien stub_type = ppc_stub_long_branch_r2off; 9347130561Sobrien } 9348130561Sobrien 9349104834Sobrien if (stub_type == ppc_stub_none) 9350104834Sobrien continue; 9351104834Sobrien 9352130561Sobrien /* __tls_get_addr calls might be eliminated. */ 9353130561Sobrien if (stub_type != ppc_stub_plt_call 9354130561Sobrien && hash != NULL 9355218822Sdim && (hash == htab->tls_get_addr 9356218822Sdim || hash == htab->tls_get_addr_fd) 9357130561Sobrien && section->has_tls_reloc 9358130561Sobrien && irela != internal_relocs) 9359130561Sobrien { 9360130561Sobrien /* Get tls info. */ 9361130561Sobrien char *tls_mask; 9362130561Sobrien 9363130561Sobrien if (!get_tls_mask (&tls_mask, NULL, &local_syms, 9364130561Sobrien irela - 1, input_bfd)) 9365130561Sobrien goto error_ret_free_internal; 9366130561Sobrien if (*tls_mask != 0) 9367130561Sobrien continue; 9368130561Sobrien } 9369130561Sobrien 9370104834Sobrien /* Support for grouping stub sections. */ 9371104834Sobrien id_sec = htab->stub_group[section->id].link_sec; 9372104834Sobrien 9373104834Sobrien /* Get the name of this stub. */ 9374104834Sobrien stub_name = ppc_stub_name (id_sec, sym_sec, hash, irela); 9375104834Sobrien if (!stub_name) 9376104834Sobrien goto error_ret_free_internal; 9377104834Sobrien 9378104834Sobrien stub_entry = ppc_stub_hash_lookup (&htab->stub_hash_table, 9379130561Sobrien stub_name, FALSE, FALSE); 9380104834Sobrien if (stub_entry != NULL) 9381104834Sobrien { 9382104834Sobrien /* The proper stub has already been created. */ 9383104834Sobrien free (stub_name); 9384104834Sobrien continue; 9385104834Sobrien } 9386104834Sobrien 9387104834Sobrien stub_entry = ppc_add_stub (stub_name, section, htab); 9388104834Sobrien if (stub_entry == NULL) 9389104834Sobrien { 9390104834Sobrien free (stub_name); 9391104834Sobrien error_ret_free_internal: 9392104834Sobrien if (elf_section_data (section)->relocs == NULL) 9393104834Sobrien free (internal_relocs); 9394104834Sobrien error_ret_free_local: 9395104834Sobrien if (local_syms != NULL 9396104834Sobrien && (symtab_hdr->contents 9397104834Sobrien != (unsigned char *) local_syms)) 9398104834Sobrien free (local_syms); 9399130561Sobrien return FALSE; 9400104834Sobrien } 9401104834Sobrien 9402130561Sobrien stub_entry->stub_type = stub_type; 9403104834Sobrien stub_entry->target_value = sym_value; 9404218822Sdim stub_entry->target_section = code_sec; 9405104834Sobrien stub_entry->h = hash; 9406130561Sobrien stub_entry->addend = irela->r_addend; 9407218822Sdim 9408218822Sdim if (stub_entry->h != NULL) 9409218822Sdim htab->stub_globals += 1; 9410104834Sobrien } 9411104834Sobrien 9412104834Sobrien /* We're done with the internal relocs, free them. */ 9413104834Sobrien if (elf_section_data (section)->relocs != internal_relocs) 9414104834Sobrien free (internal_relocs); 9415104834Sobrien } 9416104834Sobrien 9417104834Sobrien if (local_syms != NULL 9418104834Sobrien && symtab_hdr->contents != (unsigned char *) local_syms) 9419104834Sobrien { 9420104834Sobrien if (!info->keep_memory) 9421104834Sobrien free (local_syms); 9422104834Sobrien else 9423104834Sobrien symtab_hdr->contents = (unsigned char *) local_syms; 9424104834Sobrien } 9425104834Sobrien } 9426104834Sobrien 9427218822Sdim /* We may have added some stubs. Find out the new size of the 9428104834Sobrien stub sections. */ 9429104834Sobrien for (stub_sec = htab->stub_bfd->sections; 9430104834Sobrien stub_sec != NULL; 9431104834Sobrien stub_sec = stub_sec->next) 9432130561Sobrien if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) 9433130561Sobrien { 9434218822Sdim stub_sec->rawsize = stub_sec->size; 9435218822Sdim stub_sec->size = 0; 9436218822Sdim stub_sec->reloc_count = 0; 9437218822Sdim stub_sec->flags &= ~SEC_RELOC; 9438130561Sobrien } 9439104834Sobrien 9440218822Sdim htab->brlt->size = 0; 9441218822Sdim htab->brlt->reloc_count = 0; 9442218822Sdim htab->brlt->flags &= ~SEC_RELOC; 9443218822Sdim if (htab->relbrlt != NULL) 9444218822Sdim htab->relbrlt->size = 0; 9445218822Sdim 9446130561Sobrien bfd_hash_traverse (&htab->stub_hash_table, ppc_size_one_stub, info); 9447104834Sobrien 9448218822Sdim for (stub_sec = htab->stub_bfd->sections; 9449218822Sdim stub_sec != NULL; 9450218822Sdim stub_sec = stub_sec->next) 9451218822Sdim if ((stub_sec->flags & SEC_LINKER_CREATED) == 0 9452218822Sdim && stub_sec->rawsize != stub_sec->size) 9453218822Sdim break; 9454218822Sdim 9455218822Sdim /* Exit from this loop when no stubs have been added, and no stubs 9456218822Sdim have changed size. */ 9457218822Sdim if (stub_sec == NULL) 9458218822Sdim break; 9459218822Sdim 9460104834Sobrien /* Ask the linker to do its stuff. */ 9461104834Sobrien (*htab->layout_sections_again) (); 9462104834Sobrien } 9463104834Sobrien 9464218822Sdim /* It would be nice to strip htab->brlt from the output if the 9465104834Sobrien section is empty, but it's too late. If we strip sections here, 9466104834Sobrien the dynamic symbol table is corrupted since the section symbol 9467104834Sobrien for the stripped section isn't written. */ 9468104834Sobrien 9469130561Sobrien return TRUE; 947089857Sobrien} 947189857Sobrien 9472104834Sobrien/* Called after we have determined section placement. If sections 9473104834Sobrien move, we'll be called again. Provide a value for TOCstart. */ 9474104834Sobrien 9475104834Sobrienbfd_vma 9476130561Sobrienppc64_elf_toc (bfd *obfd) 9477104834Sobrien{ 9478104834Sobrien asection *s; 9479104834Sobrien bfd_vma TOCstart; 9480104834Sobrien 9481104834Sobrien /* The TOC consists of sections .got, .toc, .tocbss, .plt in that 9482104834Sobrien order. The TOC starts where the first of these sections starts. */ 9483104834Sobrien s = bfd_get_section_by_name (obfd, ".got"); 9484104834Sobrien if (s == NULL) 9485104834Sobrien s = bfd_get_section_by_name (obfd, ".toc"); 9486104834Sobrien if (s == NULL) 9487104834Sobrien s = bfd_get_section_by_name (obfd, ".tocbss"); 9488104834Sobrien if (s == NULL) 9489104834Sobrien s = bfd_get_section_by_name (obfd, ".plt"); 9490104834Sobrien if (s == NULL) 9491104834Sobrien { 9492104834Sobrien /* This may happen for 9493104834Sobrien o references to TOC base (SYM@toc / TOC[tc0]) without a 9494104834Sobrien .toc directive 9495104834Sobrien o bad linker script 9496104834Sobrien o --gc-sections and empty TOC sections 9497104834Sobrien 9498104834Sobrien FIXME: Warn user? */ 9499104834Sobrien 9500104834Sobrien /* Look for a likely section. We probably won't even be 9501104834Sobrien using TOCstart. */ 9502104834Sobrien for (s = obfd->sections; s != NULL; s = s->next) 9503104834Sobrien if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA | SEC_READONLY)) 9504104834Sobrien == (SEC_ALLOC | SEC_SMALL_DATA)) 9505104834Sobrien break; 9506104834Sobrien if (s == NULL) 9507104834Sobrien for (s = obfd->sections; s != NULL; s = s->next) 9508104834Sobrien if ((s->flags & (SEC_ALLOC | SEC_SMALL_DATA)) 9509104834Sobrien == (SEC_ALLOC | SEC_SMALL_DATA)) 9510104834Sobrien break; 9511104834Sobrien if (s == NULL) 9512104834Sobrien for (s = obfd->sections; s != NULL; s = s->next) 9513104834Sobrien if ((s->flags & (SEC_ALLOC | SEC_READONLY)) == SEC_ALLOC) 9514104834Sobrien break; 9515104834Sobrien if (s == NULL) 9516104834Sobrien for (s = obfd->sections; s != NULL; s = s->next) 9517104834Sobrien if ((s->flags & SEC_ALLOC) == SEC_ALLOC) 9518104834Sobrien break; 9519104834Sobrien } 9520104834Sobrien 9521104834Sobrien TOCstart = 0; 9522104834Sobrien if (s != NULL) 9523104834Sobrien TOCstart = s->output_section->vma + s->output_offset; 9524104834Sobrien 9525104834Sobrien return TOCstart; 9526104834Sobrien} 9527104834Sobrien 9528104834Sobrien/* Build all the stubs associated with the current output file. 9529104834Sobrien The stubs are kept in a hash table attached to the main linker 9530104834Sobrien hash table. This function is called via gldelf64ppc_finish. */ 9531104834Sobrien 9532130561Sobrienbfd_boolean 9533130561Sobrienppc64_elf_build_stubs (bfd_boolean emit_stub_syms, 9534130561Sobrien struct bfd_link_info *info, 9535130561Sobrien char **stats) 9536104834Sobrien{ 9537104834Sobrien struct ppc_link_hash_table *htab = ppc_hash_table (info); 9538104834Sobrien asection *stub_sec; 9539104834Sobrien bfd_byte *p; 9540130561Sobrien int stub_sec_count = 0; 9541104834Sobrien 9542130561Sobrien htab->emit_stub_syms = emit_stub_syms; 9543218822Sdim 9544218822Sdim /* Allocate memory to hold the linker stubs. */ 9545104834Sobrien for (stub_sec = htab->stub_bfd->sections; 9546104834Sobrien stub_sec != NULL; 9547104834Sobrien stub_sec = stub_sec->next) 9548218822Sdim if ((stub_sec->flags & SEC_LINKER_CREATED) == 0 9549218822Sdim && stub_sec->size != 0) 9550130561Sobrien { 9551218822Sdim stub_sec->contents = bfd_zalloc (htab->stub_bfd, stub_sec->size); 9552218822Sdim if (stub_sec->contents == NULL) 9553218822Sdim return FALSE; 9554218822Sdim /* We want to check that built size is the same as calculated 9555218822Sdim size. rawsize is a convenient location to use. */ 9556218822Sdim stub_sec->rawsize = stub_sec->size; 9557218822Sdim stub_sec->size = 0; 9558130561Sobrien } 9559104834Sobrien 9560218822Sdim if (htab->glink != NULL && htab->glink->size != 0) 9561104834Sobrien { 9562104834Sobrien unsigned int indx; 9563130561Sobrien bfd_vma plt0; 9564104834Sobrien 9565104834Sobrien /* Build the .glink plt call stub. */ 9566130561Sobrien if (htab->emit_stub_syms) 9567130561Sobrien { 9568130561Sobrien struct elf_link_hash_entry *h; 9569130561Sobrien h = elf_link_hash_lookup (&htab->elf, "__glink", TRUE, FALSE, FALSE); 9570130561Sobrien if (h == NULL) 9571130561Sobrien return FALSE; 9572130561Sobrien if (h->root.type == bfd_link_hash_new) 9573130561Sobrien { 9574130561Sobrien h->root.type = bfd_link_hash_defined; 9575130561Sobrien h->root.u.def.section = htab->glink; 9576218822Sdim h->root.u.def.value = 8; 9577218822Sdim h->ref_regular = 1; 9578218822Sdim h->def_regular = 1; 9579218822Sdim h->ref_regular_nonweak = 1; 9580218822Sdim h->forced_local = 1; 9581218822Sdim h->non_elf = 0; 9582130561Sobrien } 9583130561Sobrien } 9584130561Sobrien p = htab->glink->contents; 9585218822Sdim plt0 = (htab->plt->output_section->vma 9586218822Sdim + htab->plt->output_offset 9587218822Sdim - (htab->glink->output_section->vma 9588218822Sdim + htab->glink->output_offset 9589218822Sdim + 16)); 9590218822Sdim bfd_put_64 (htab->glink->owner, plt0, p); 9591218822Sdim p += 8; 9592218822Sdim bfd_put_32 (htab->glink->owner, MFLR_R12, p); 9593130561Sobrien p += 4; 9594218822Sdim bfd_put_32 (htab->glink->owner, BCL_20_31, p); 9595130561Sobrien p += 4; 9596218822Sdim bfd_put_32 (htab->glink->owner, MFLR_R11, p); 9597130561Sobrien p += 4; 9598218822Sdim bfd_put_32 (htab->glink->owner, LD_R2_M16R11, p); 9599130561Sobrien p += 4; 9600218822Sdim bfd_put_32 (htab->glink->owner, MTLR_R12, p); 9601130561Sobrien p += 4; 9602218822Sdim bfd_put_32 (htab->glink->owner, ADD_R12_R2_R11, p); 9603130561Sobrien p += 4; 9604218822Sdim bfd_put_32 (htab->glink->owner, LD_R11_0R12, p); 9605130561Sobrien p += 4; 9606130561Sobrien bfd_put_32 (htab->glink->owner, LD_R2_0R12 | 8, p); 9607130561Sobrien p += 4; 9608130561Sobrien bfd_put_32 (htab->glink->owner, MTCTR_R11, p); 9609130561Sobrien p += 4; 9610130561Sobrien bfd_put_32 (htab->glink->owner, LD_R11_0R12 | 16, p); 9611130561Sobrien p += 4; 9612130561Sobrien bfd_put_32 (htab->glink->owner, BCTR, p); 9613130561Sobrien p += 4; 9614218822Sdim while (p - htab->glink->contents < GLINK_CALL_STUB_SIZE) 9615218822Sdim { 9616218822Sdim bfd_put_32 (htab->glink->owner, NOP, p); 9617218822Sdim p += 4; 9618218822Sdim } 9619130561Sobrien 9620104834Sobrien /* Build the .glink lazy link call stubs. */ 9621104834Sobrien indx = 0; 9622218822Sdim while (p < htab->glink->contents + htab->glink->size) 9623104834Sobrien { 9624104834Sobrien if (indx < 0x8000) 9625104834Sobrien { 9626130561Sobrien bfd_put_32 (htab->glink->owner, LI_R0_0 | indx, p); 9627104834Sobrien p += 4; 9628104834Sobrien } 9629104834Sobrien else 9630104834Sobrien { 9631130561Sobrien bfd_put_32 (htab->glink->owner, LIS_R0_0 | PPC_HI (indx), p); 9632104834Sobrien p += 4; 9633130561Sobrien bfd_put_32 (htab->glink->owner, ORI_R0_R0_0 | PPC_LO (indx), p); 9634104834Sobrien p += 4; 9635104834Sobrien } 9636130561Sobrien bfd_put_32 (htab->glink->owner, 9637218822Sdim B_DOT | ((htab->glink->contents - p + 8) & 0x3fffffc), p); 9638104834Sobrien indx++; 9639104834Sobrien p += 4; 9640104834Sobrien } 9641218822Sdim htab->glink->rawsize = p - htab->glink->contents; 9642104834Sobrien } 9643104834Sobrien 9644218822Sdim if (htab->brlt->size != 0) 9645104834Sobrien { 9646130561Sobrien htab->brlt->contents = bfd_zalloc (htab->brlt->owner, 9647218822Sdim htab->brlt->size); 9648130561Sobrien if (htab->brlt->contents == NULL) 9649130561Sobrien return FALSE; 9650104834Sobrien } 9651218822Sdim if (htab->relbrlt != NULL && htab->relbrlt->size != 0) 9652130561Sobrien { 9653130561Sobrien htab->relbrlt->contents = bfd_zalloc (htab->relbrlt->owner, 9654218822Sdim htab->relbrlt->size); 9655130561Sobrien if (htab->relbrlt->contents == NULL) 9656130561Sobrien return FALSE; 9657130561Sobrien } 9658104834Sobrien 9659104834Sobrien /* Build the stubs as directed by the stub hash table. */ 9660104834Sobrien bfd_hash_traverse (&htab->stub_hash_table, ppc_build_one_stub, info); 9661104834Sobrien 9662218822Sdim if (htab->relbrlt != NULL) 9663218822Sdim htab->relbrlt->reloc_count = 0; 9664218822Sdim 9665104834Sobrien for (stub_sec = htab->stub_bfd->sections; 9666104834Sobrien stub_sec != NULL; 9667104834Sobrien stub_sec = stub_sec->next) 9668130561Sobrien if ((stub_sec->flags & SEC_LINKER_CREATED) == 0) 9669130561Sobrien { 9670130561Sobrien stub_sec_count += 1; 9671218822Sdim if (stub_sec->rawsize != stub_sec->size) 9672130561Sobrien break; 9673130561Sobrien } 9674104834Sobrien 9675104834Sobrien if (stub_sec != NULL 9676218822Sdim || htab->glink->rawsize != htab->glink->size) 9677104834Sobrien { 9678130561Sobrien htab->stub_error = TRUE; 9679104834Sobrien (*_bfd_error_handler) (_("stubs don't match calculated size")); 9680104834Sobrien } 9681104834Sobrien 9682130561Sobrien if (htab->stub_error) 9683130561Sobrien return FALSE; 9684130561Sobrien 9685130561Sobrien if (stats != NULL) 9686130561Sobrien { 9687130561Sobrien *stats = bfd_malloc (500); 9688130561Sobrien if (*stats == NULL) 9689130561Sobrien return FALSE; 9690130561Sobrien 9691218822Sdim sprintf (*stats, _("linker stubs in %u group%s\n" 9692130561Sobrien " branch %lu\n" 9693130561Sobrien " toc adjust %lu\n" 9694130561Sobrien " long branch %lu\n" 9695130561Sobrien " long toc adj %lu\n" 9696130561Sobrien " plt call %lu"), 9697130561Sobrien stub_sec_count, 9698218822Sdim stub_sec_count == 1 ? "" : "s", 9699130561Sobrien htab->stub_count[ppc_stub_long_branch - 1], 9700130561Sobrien htab->stub_count[ppc_stub_long_branch_r2off - 1], 9701130561Sobrien htab->stub_count[ppc_stub_plt_branch - 1], 9702130561Sobrien htab->stub_count[ppc_stub_plt_branch_r2off - 1], 9703130561Sobrien htab->stub_count[ppc_stub_plt_call - 1]); 9704130561Sobrien } 9705130561Sobrien return TRUE; 9706104834Sobrien} 9707104834Sobrien 9708218822Sdim/* This function undoes the changes made by add_symbol_adjust. */ 9709218822Sdim 9710218822Sdimstatic bfd_boolean 9711218822Sdimundo_symbol_twiddle (struct elf_link_hash_entry *h, void *inf ATTRIBUTE_UNUSED) 9712218822Sdim{ 9713218822Sdim struct ppc_link_hash_entry *eh; 9714218822Sdim 9715218822Sdim if (h->root.type == bfd_link_hash_indirect) 9716218822Sdim return TRUE; 9717218822Sdim 9718218822Sdim if (h->root.type == bfd_link_hash_warning) 9719218822Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 9720218822Sdim 9721218822Sdim eh = (struct ppc_link_hash_entry *) h; 9722218822Sdim if (eh->elf.root.type != bfd_link_hash_undefweak || !eh->was_undefined) 9723218822Sdim return TRUE; 9724218822Sdim 9725218822Sdim eh->elf.root.type = bfd_link_hash_undefined; 9726218822Sdim return TRUE; 9727218822Sdim} 9728218822Sdim 9729218822Sdimvoid 9730218822Sdimppc64_elf_restore_symbols (struct bfd_link_info *info) 9731218822Sdim{ 9732218822Sdim struct ppc_link_hash_table *htab = ppc_hash_table (info); 9733218822Sdim elf_link_hash_traverse (&htab->elf, undo_symbol_twiddle, info); 9734218822Sdim} 9735218822Sdim 9736218822Sdim/* What to do when ld finds relocations against symbols defined in 9737218822Sdim discarded sections. */ 9738218822Sdim 9739218822Sdimstatic unsigned int 9740218822Sdimppc64_elf_action_discarded (asection *sec) 9741218822Sdim{ 9742218822Sdim if (strcmp (".opd", sec->name) == 0) 9743218822Sdim return 0; 9744218822Sdim 9745218822Sdim if (strcmp (".toc", sec->name) == 0) 9746218822Sdim return 0; 9747218822Sdim 9748218822Sdim if (strcmp (".toc1", sec->name) == 0) 9749218822Sdim return 0; 9750218822Sdim 9751218822Sdim if (sec->flags & SEC_RELOC) 9752218822Sdim return 0; 9753218822Sdim 9754218822Sdim return _bfd_elf_default_action_discarded (sec); 9755218822Sdim} 9756218822Sdim 975789857Sobrien/* The RELOCATE_SECTION function is called by the ELF backend linker 975889857Sobrien to handle the relocations for a section. 975989857Sobrien 976089857Sobrien The relocs are always passed as Rela structures; if the section 976189857Sobrien actually uses Rel structures, the r_addend field will always be 976289857Sobrien zero. 976389857Sobrien 976489857Sobrien This function is responsible for adjust the section contents as 976589857Sobrien necessary, and (if using Rela relocs and generating a 9766130561Sobrien relocatable output file) adjusting the reloc addend as 976789857Sobrien necessary. 976889857Sobrien 976989857Sobrien This function does not have to worry about setting the reloc 977089857Sobrien address or the reloc symbol index. 977189857Sobrien 977289857Sobrien LOCAL_SYMS is a pointer to the swapped in local symbols. 977389857Sobrien 977489857Sobrien LOCAL_SECTIONS is an array giving the section in the input file 977589857Sobrien corresponding to the st_shndx field of each local symbol. 977689857Sobrien 977789857Sobrien The global hash table entry for the global symbols can be found 977889857Sobrien via elf_sym_hashes (input_bfd). 977989857Sobrien 9780130561Sobrien When generating relocatable output, this function must handle 978189857Sobrien STB_LOCAL/STT_SECTION symbols specially. The output symbol is 978289857Sobrien going to be the section symbol corresponding to the output 978389857Sobrien section, which means that the addend must be adjusted 978489857Sobrien accordingly. */ 978589857Sobrien 9786130561Sobrienstatic bfd_boolean 9787130561Sobrienppc64_elf_relocate_section (bfd *output_bfd, 9788130561Sobrien struct bfd_link_info *info, 9789130561Sobrien bfd *input_bfd, 9790130561Sobrien asection *input_section, 9791130561Sobrien bfd_byte *contents, 9792130561Sobrien Elf_Internal_Rela *relocs, 9793130561Sobrien Elf_Internal_Sym *local_syms, 9794130561Sobrien asection **local_sections) 979589857Sobrien{ 979689857Sobrien struct ppc_link_hash_table *htab; 979789857Sobrien Elf_Internal_Shdr *symtab_hdr; 979889857Sobrien struct elf_link_hash_entry **sym_hashes; 979989857Sobrien Elf_Internal_Rela *rel; 980089857Sobrien Elf_Internal_Rela *relend; 9801130561Sobrien Elf_Internal_Rela outrel; 9802130561Sobrien bfd_byte *loc; 9803130561Sobrien struct got_entry **local_got_ents; 980489857Sobrien bfd_vma TOCstart; 9805130561Sobrien bfd_boolean ret = TRUE; 9806130561Sobrien bfd_boolean is_opd; 980792828Sobrien /* Disabled until we sort out how ld should choose 'y' vs 'at'. */ 9808130561Sobrien bfd_boolean is_power4 = FALSE; 9809218822Sdim bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0); 981089857Sobrien 981189857Sobrien /* Initialize howto table if needed. */ 981289857Sobrien if (!ppc64_elf_howto_table[R_PPC64_ADDR32]) 981389857Sobrien ppc_howto_init (); 981489857Sobrien 981589857Sobrien htab = ppc_hash_table (info); 9816218822Sdim 9817218822Sdim /* Don't relocate stub sections. */ 9818218822Sdim if (input_section->owner == htab->stub_bfd) 9819218822Sdim return TRUE; 9820218822Sdim 9821130561Sobrien local_got_ents = elf_local_got_ents (input_bfd); 982289857Sobrien TOCstart = elf_gp (output_bfd); 982389857Sobrien symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; 982489857Sobrien sym_hashes = elf_sym_hashes (input_bfd); 9825218822Sdim is_opd = ppc64_elf_section_data (input_section)->sec_type == sec_opd; 982689857Sobrien 982789857Sobrien rel = relocs; 982889857Sobrien relend = relocs + input_section->reloc_count; 982989857Sobrien for (; rel < relend; rel++) 983089857Sobrien { 9831130561Sobrien enum elf_ppc64_reloc_type r_type; 9832218822Sdim bfd_vma addend, orig_addend; 983389857Sobrien bfd_reloc_status_type r; 983489857Sobrien Elf_Internal_Sym *sym; 983589857Sobrien asection *sec; 9836218822Sdim struct elf_link_hash_entry *h_elf; 9837218822Sdim struct ppc_link_hash_entry *h; 9838218822Sdim struct ppc_link_hash_entry *fdh; 983989857Sobrien const char *sym_name; 9840130561Sobrien unsigned long r_symndx, toc_symndx; 9841130561Sobrien char tls_mask, tls_gd, tls_type; 9842130561Sobrien char sym_type; 984389857Sobrien bfd_vma relocation; 9844130561Sobrien bfd_boolean unresolved_reloc; 9845130561Sobrien bfd_boolean warned; 9846130561Sobrien unsigned long insn, mask; 9847104834Sobrien struct ppc_stub_hash_entry *stub_entry; 9848104834Sobrien bfd_vma max_br_offset; 984999461Sobrien bfd_vma from; 985089857Sobrien 9851130561Sobrien r_type = ELF64_R_TYPE (rel->r_info); 985289857Sobrien r_symndx = ELF64_R_SYM (rel->r_info); 985389857Sobrien 9854130561Sobrien /* For old style R_PPC64_TOC relocs with a zero symbol, use the 9855130561Sobrien symbol of the previous ADDR64 reloc. The symbol gives us the 9856130561Sobrien proper TOC base to use. */ 9857130561Sobrien if (rel->r_info == ELF64_R_INFO (0, R_PPC64_TOC) 9858130561Sobrien && rel != relocs 9859130561Sobrien && ELF64_R_TYPE (rel[-1].r_info) == R_PPC64_ADDR64 9860130561Sobrien && is_opd) 9861130561Sobrien r_symndx = ELF64_R_SYM (rel[-1].r_info); 9862130561Sobrien 9863130561Sobrien sym = NULL; 9864130561Sobrien sec = NULL; 9865218822Sdim h_elf = NULL; 9866130561Sobrien sym_name = NULL; 9867130561Sobrien unresolved_reloc = FALSE; 9868130561Sobrien warned = FALSE; 9869218822Sdim orig_addend = rel->r_addend; 9870130561Sobrien 9871130561Sobrien if (r_symndx < symtab_hdr->sh_info) 987289857Sobrien { 987389857Sobrien /* It's a local symbol. */ 9874218822Sdim long *opd_adjust; 9875218822Sdim 987689857Sobrien sym = local_syms + r_symndx; 987789857Sobrien sec = local_sections[r_symndx]; 9878218822Sdim sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec); 9879130561Sobrien sym_type = ELF64_ST_TYPE (sym->st_info); 9880130561Sobrien relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); 9881218822Sdim opd_adjust = get_opd_info (sec); 9882218822Sdim if (opd_adjust != NULL) 9883104834Sobrien { 9884218822Sdim long adjust = opd_adjust[(sym->st_value + rel->r_addend) / 8]; 9885218822Sdim if (adjust == -1) 9886218822Sdim relocation = 0; 9887218822Sdim else 9888218822Sdim { 9889218822Sdim /* If this is a relocation against the opd section sym 9890218822Sdim and we have edited .opd, adjust the reloc addend so 9891218822Sdim that ld -r and ld --emit-relocs output is correct. 9892218822Sdim If it is a reloc against some other .opd symbol, 9893218822Sdim then the symbol value will be adjusted later. */ 9894218822Sdim if (ELF_ST_TYPE (sym->st_info) == STT_SECTION) 9895218822Sdim rel->r_addend += adjust; 9896218822Sdim else 9897218822Sdim relocation += adjust; 9898218822Sdim } 9899104834Sobrien } 990089857Sobrien } 990189857Sobrien else 990289857Sobrien { 9903130561Sobrien RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, 9904130561Sobrien r_symndx, symtab_hdr, sym_hashes, 9905218822Sdim h_elf, sec, relocation, 9906130561Sobrien unresolved_reloc, warned); 9907218822Sdim sym_name = h_elf->root.root.string; 9908218822Sdim sym_type = h_elf->type; 9909130561Sobrien } 9910218822Sdim h = (struct ppc_link_hash_entry *) h_elf; 9911130561Sobrien 9912218822Sdim if (sec != NULL && elf_discarded_section (sec)) 9913218822Sdim { 9914218822Sdim /* For relocs against symbols from removed linkonce sections, 9915218822Sdim or sections discarded by a linker script, we just want the 9916218822Sdim section contents zeroed. Avoid any special processing. */ 9917218822Sdim _bfd_clear_contents (ppc64_elf_howto_table[r_type], input_bfd, 9918218822Sdim contents + rel->r_offset); 9919218822Sdim rel->r_info = 0; 9920218822Sdim rel->r_addend = 0; 9921218822Sdim continue; 9922218822Sdim } 9923218822Sdim 9924218822Sdim if (info->relocatable) 9925218822Sdim continue; 9926218822Sdim 9927130561Sobrien /* TLS optimizations. Replace instruction sequences and relocs 9928130561Sobrien based on information we collected in tls_optimize. We edit 9929130561Sobrien RELOCS so that --emit-relocs will output something sensible 9930130561Sobrien for the final instruction stream. */ 9931130561Sobrien tls_mask = 0; 9932130561Sobrien tls_gd = 0; 9933130561Sobrien toc_symndx = 0; 9934130561Sobrien if (IS_PPC64_TLS_RELOC (r_type)) 9935130561Sobrien { 9936130561Sobrien if (h != NULL) 9937218822Sdim tls_mask = h->tls_mask; 9938130561Sobrien else if (local_got_ents != NULL) 9939130561Sobrien { 9940130561Sobrien char *lgot_masks; 9941130561Sobrien lgot_masks = (char *) (local_got_ents + symtab_hdr->sh_info); 9942130561Sobrien tls_mask = lgot_masks[r_symndx]; 9943130561Sobrien } 9944130561Sobrien if (tls_mask == 0 && r_type == R_PPC64_TLS) 9945130561Sobrien { 9946130561Sobrien /* Check for toc tls entries. */ 9947130561Sobrien char *toc_tls; 9948130561Sobrien 9949130561Sobrien if (!get_tls_mask (&toc_tls, &toc_symndx, &local_syms, 9950130561Sobrien rel, input_bfd)) 9951130561Sobrien return FALSE; 9952130561Sobrien 9953130561Sobrien if (toc_tls) 9954130561Sobrien tls_mask = *toc_tls; 9955130561Sobrien } 9956130561Sobrien } 9957130561Sobrien 9958130561Sobrien /* Check that tls relocs are used with tls syms, and non-tls 9959130561Sobrien relocs are used with non-tls syms. */ 9960130561Sobrien if (r_symndx != 0 9961130561Sobrien && r_type != R_PPC64_NONE 9962130561Sobrien && (h == NULL 9963218822Sdim || h->elf.root.type == bfd_link_hash_defined 9964218822Sdim || h->elf.root.type == bfd_link_hash_defweak) 9965130561Sobrien && IS_PPC64_TLS_RELOC (r_type) != (sym_type == STT_TLS)) 9966130561Sobrien { 9967130561Sobrien if (r_type == R_PPC64_TLS && tls_mask != 0) 9968130561Sobrien /* R_PPC64_TLS is OK against a symbol in the TOC. */ 9969130561Sobrien ; 9970130561Sobrien else 9971130561Sobrien (*_bfd_error_handler) 9972130561Sobrien (sym_type == STT_TLS 9973218822Sdim ? _("%B(%A+0x%lx): %s used with TLS symbol %s") 9974218822Sdim : _("%B(%A+0x%lx): %s used with non-TLS symbol %s"), 9975218822Sdim input_bfd, 9976218822Sdim input_section, 9977130561Sobrien (long) rel->r_offset, 9978130561Sobrien ppc64_elf_howto_table[r_type]->name, 9979130561Sobrien sym_name); 9980130561Sobrien } 9981130561Sobrien 9982130561Sobrien /* Ensure reloc mapping code below stays sane. */ 9983130561Sobrien if (R_PPC64_TOC16_LO_DS != R_PPC64_TOC16_DS + 1 9984130561Sobrien || R_PPC64_TOC16_LO != R_PPC64_TOC16 + 1 9985130561Sobrien || (R_PPC64_GOT_TLSLD16 & 3) != (R_PPC64_GOT_TLSGD16 & 3) 9986130561Sobrien || (R_PPC64_GOT_TLSLD16_LO & 3) != (R_PPC64_GOT_TLSGD16_LO & 3) 9987130561Sobrien || (R_PPC64_GOT_TLSLD16_HI & 3) != (R_PPC64_GOT_TLSGD16_HI & 3) 9988130561Sobrien || (R_PPC64_GOT_TLSLD16_HA & 3) != (R_PPC64_GOT_TLSGD16_HA & 3) 9989130561Sobrien || (R_PPC64_GOT_TLSLD16 & 3) != (R_PPC64_GOT_TPREL16_DS & 3) 9990130561Sobrien || (R_PPC64_GOT_TLSLD16_LO & 3) != (R_PPC64_GOT_TPREL16_LO_DS & 3) 9991130561Sobrien || (R_PPC64_GOT_TLSLD16_HI & 3) != (R_PPC64_GOT_TPREL16_HI & 3) 9992130561Sobrien || (R_PPC64_GOT_TLSLD16_HA & 3) != (R_PPC64_GOT_TPREL16_HA & 3)) 9993130561Sobrien abort (); 9994130561Sobrien 9995130561Sobrien switch (r_type) 9996130561Sobrien { 9997130561Sobrien default: 9998130561Sobrien break; 9999130561Sobrien 10000130561Sobrien case R_PPC64_TOC16: 10001130561Sobrien case R_PPC64_TOC16_LO: 10002130561Sobrien case R_PPC64_TOC16_DS: 10003130561Sobrien case R_PPC64_TOC16_LO_DS: 10004130561Sobrien { 10005130561Sobrien /* Check for toc tls entries. */ 10006130561Sobrien char *toc_tls; 10007130561Sobrien int retval; 10008130561Sobrien 10009130561Sobrien retval = get_tls_mask (&toc_tls, &toc_symndx, &local_syms, 10010130561Sobrien rel, input_bfd); 10011130561Sobrien if (retval == 0) 10012130561Sobrien return FALSE; 10013130561Sobrien 10014130561Sobrien if (toc_tls) 10015130561Sobrien { 10016130561Sobrien tls_mask = *toc_tls; 10017130561Sobrien if (r_type == R_PPC64_TOC16_DS 10018130561Sobrien || r_type == R_PPC64_TOC16_LO_DS) 10019130561Sobrien { 10020130561Sobrien if (tls_mask != 0 10021130561Sobrien && (tls_mask & (TLS_DTPREL | TLS_TPREL)) == 0) 10022130561Sobrien goto toctprel; 10023130561Sobrien } 10024130561Sobrien else 10025130561Sobrien { 10026130561Sobrien /* If we found a GD reloc pair, then we might be 10027130561Sobrien doing a GD->IE transition. */ 10028130561Sobrien if (retval == 2) 10029130561Sobrien { 10030130561Sobrien tls_gd = TLS_TPRELGD; 10031130561Sobrien if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) 10032130561Sobrien goto tls_get_addr_check; 10033130561Sobrien } 10034130561Sobrien else if (retval == 3) 10035130561Sobrien { 10036130561Sobrien if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) 10037130561Sobrien goto tls_get_addr_check; 10038130561Sobrien } 10039130561Sobrien } 10040130561Sobrien } 10041130561Sobrien } 10042130561Sobrien break; 10043130561Sobrien 10044130561Sobrien case R_PPC64_GOT_TPREL16_DS: 10045130561Sobrien case R_PPC64_GOT_TPREL16_LO_DS: 10046130561Sobrien if (tls_mask != 0 10047130561Sobrien && (tls_mask & TLS_TPREL) == 0) 1004889857Sobrien { 10049130561Sobrien toctprel: 10050218822Sdim insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); 10051130561Sobrien insn &= 31 << 21; 10052130561Sobrien insn |= 0x3c0d0000; /* addis 0,13,0 */ 10053218822Sdim bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset); 10054130561Sobrien r_type = R_PPC64_TPREL16_HA; 10055130561Sobrien if (toc_symndx != 0) 10056130561Sobrien { 10057130561Sobrien rel->r_info = ELF64_R_INFO (toc_symndx, r_type); 10058130561Sobrien /* We changed the symbol. Start over in order to 10059130561Sobrien get h, sym, sec etc. right. */ 10060130561Sobrien rel--; 10061130561Sobrien continue; 10062130561Sobrien } 1006389857Sobrien else 10064130561Sobrien rel->r_info = ELF64_R_INFO (r_symndx, r_type); 1006589857Sobrien } 10066130561Sobrien break; 10067130561Sobrien 10068130561Sobrien case R_PPC64_TLS: 10069130561Sobrien if (tls_mask != 0 10070130561Sobrien && (tls_mask & TLS_TPREL) == 0) 10071130561Sobrien { 10072130561Sobrien bfd_vma rtra; 10073130561Sobrien insn = bfd_get_32 (output_bfd, contents + rel->r_offset); 10074130561Sobrien if ((insn & ((0x3f << 26) | (31 << 11))) 10075130561Sobrien == ((31 << 26) | (13 << 11))) 10076130561Sobrien rtra = insn & ((1 << 26) - (1 << 16)); 10077130561Sobrien else if ((insn & ((0x3f << 26) | (31 << 16))) 10078130561Sobrien == ((31 << 26) | (13 << 16))) 10079130561Sobrien rtra = (insn & (31 << 21)) | ((insn & (31 << 11)) << 5); 10080130561Sobrien else 10081130561Sobrien abort (); 10082130561Sobrien if ((insn & ((1 << 11) - (1 << 1))) == 266 << 1) 10083130561Sobrien /* add -> addi. */ 10084130561Sobrien insn = 14 << 26; 10085130561Sobrien else if ((insn & (31 << 1)) == 23 << 1 10086130561Sobrien && ((insn & (31 << 6)) < 14 << 6 10087130561Sobrien || ((insn & (31 << 6)) >= 16 << 6 10088130561Sobrien && (insn & (31 << 6)) < 24 << 6))) 10089130561Sobrien /* load and store indexed -> dform. */ 10090130561Sobrien insn = (32 | ((insn >> 6) & 31)) << 26; 10091130561Sobrien else if ((insn & (31 << 1)) == 21 << 1 10092130561Sobrien && (insn & (0x1a << 6)) == 0) 10093130561Sobrien /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu. */ 10094130561Sobrien insn = (((58 | ((insn >> 6) & 4)) << 26) 10095130561Sobrien | ((insn >> 6) & 1)); 10096130561Sobrien else if ((insn & (31 << 1)) == 21 << 1 10097130561Sobrien && (insn & ((1 << 11) - (1 << 1))) == 341 << 1) 10098130561Sobrien /* lwax -> lwa. */ 10099130561Sobrien insn = (58 << 26) | 2; 10100130561Sobrien else 10101130561Sobrien abort (); 10102130561Sobrien insn |= rtra; 10103130561Sobrien bfd_put_32 (output_bfd, insn, contents + rel->r_offset); 10104130561Sobrien /* Was PPC64_TLS which sits on insn boundary, now 10105218822Sdim PPC64_TPREL16_LO which is at low-order half-word. */ 10106218822Sdim rel->r_offset += d_offset; 10107130561Sobrien r_type = R_PPC64_TPREL16_LO; 10108130561Sobrien if (toc_symndx != 0) 10109130561Sobrien { 10110130561Sobrien rel->r_info = ELF64_R_INFO (toc_symndx, r_type); 10111130561Sobrien /* We changed the symbol. Start over in order to 10112130561Sobrien get h, sym, sec etc. right. */ 10113130561Sobrien rel--; 10114130561Sobrien continue; 10115130561Sobrien } 10116130561Sobrien else 10117130561Sobrien rel->r_info = ELF64_R_INFO (r_symndx, r_type); 10118130561Sobrien } 10119130561Sobrien break; 10120130561Sobrien 10121130561Sobrien case R_PPC64_GOT_TLSGD16_HI: 10122130561Sobrien case R_PPC64_GOT_TLSGD16_HA: 10123130561Sobrien tls_gd = TLS_TPRELGD; 10124130561Sobrien if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) 10125130561Sobrien goto tls_gdld_hi; 10126130561Sobrien break; 10127130561Sobrien 10128130561Sobrien case R_PPC64_GOT_TLSLD16_HI: 10129130561Sobrien case R_PPC64_GOT_TLSLD16_HA: 10130130561Sobrien if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) 10131130561Sobrien { 10132130561Sobrien tls_gdld_hi: 10133130561Sobrien if ((tls_mask & tls_gd) != 0) 10134130561Sobrien r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3) 10135130561Sobrien + R_PPC64_GOT_TPREL16_DS); 10136130561Sobrien else 10137130561Sobrien { 10138130561Sobrien bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); 10139218822Sdim rel->r_offset -= d_offset; 10140130561Sobrien r_type = R_PPC64_NONE; 10141130561Sobrien } 10142130561Sobrien rel->r_info = ELF64_R_INFO (r_symndx, r_type); 10143130561Sobrien } 10144130561Sobrien break; 10145130561Sobrien 10146130561Sobrien case R_PPC64_GOT_TLSGD16: 10147130561Sobrien case R_PPC64_GOT_TLSGD16_LO: 10148130561Sobrien tls_gd = TLS_TPRELGD; 10149130561Sobrien if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) 10150130561Sobrien goto tls_get_addr_check; 10151130561Sobrien break; 10152130561Sobrien 10153130561Sobrien case R_PPC64_GOT_TLSLD16: 10154130561Sobrien case R_PPC64_GOT_TLSLD16_LO: 10155130561Sobrien if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) 10156130561Sobrien { 10157130561Sobrien tls_get_addr_check: 10158130561Sobrien if (rel + 1 < relend) 10159130561Sobrien { 10160130561Sobrien enum elf_ppc64_reloc_type r_type2; 10161130561Sobrien unsigned long r_symndx2; 10162130561Sobrien struct elf_link_hash_entry *h2; 10163130561Sobrien bfd_vma insn1, insn2, insn3; 10164130561Sobrien bfd_vma offset; 10165130561Sobrien 10166130561Sobrien /* The next instruction should be a call to 10167130561Sobrien __tls_get_addr. Peek at the reloc to be sure. */ 10168130561Sobrien r_type2 = ELF64_R_TYPE (rel[1].r_info); 10169130561Sobrien r_symndx2 = ELF64_R_SYM (rel[1].r_info); 10170130561Sobrien if (r_symndx2 < symtab_hdr->sh_info 10171130561Sobrien || (r_type2 != R_PPC64_REL14 10172130561Sobrien && r_type2 != R_PPC64_REL14_BRTAKEN 10173130561Sobrien && r_type2 != R_PPC64_REL14_BRNTAKEN 10174130561Sobrien && r_type2 != R_PPC64_REL24)) 10175130561Sobrien break; 10176130561Sobrien 10177130561Sobrien h2 = sym_hashes[r_symndx2 - symtab_hdr->sh_info]; 10178130561Sobrien while (h2->root.type == bfd_link_hash_indirect 10179130561Sobrien || h2->root.type == bfd_link_hash_warning) 10180130561Sobrien h2 = (struct elf_link_hash_entry *) h2->root.u.i.link; 10181218822Sdim if (h2 == NULL || (h2 != &htab->tls_get_addr->elf 10182218822Sdim && h2 != &htab->tls_get_addr_fd->elf)) 10183130561Sobrien break; 10184130561Sobrien 10185130561Sobrien /* OK, it checks out. Replace the call. */ 10186130561Sobrien offset = rel[1].r_offset; 10187130561Sobrien insn1 = bfd_get_32 (output_bfd, 10188218822Sdim contents + rel->r_offset - d_offset); 10189130561Sobrien insn3 = bfd_get_32 (output_bfd, 10190130561Sobrien contents + offset + 4); 10191130561Sobrien if ((tls_mask & tls_gd) != 0) 10192130561Sobrien { 10193130561Sobrien /* IE */ 10194130561Sobrien insn1 &= (1 << 26) - (1 << 2); 10195130561Sobrien insn1 |= 58 << 26; /* ld */ 10196130561Sobrien insn2 = 0x7c636a14; /* add 3,3,13 */ 10197130561Sobrien rel[1].r_info = ELF64_R_INFO (r_symndx2, R_PPC64_NONE); 10198130561Sobrien if ((tls_mask & TLS_EXPLICIT) == 0) 10199130561Sobrien r_type = (((r_type - (R_PPC64_GOT_TLSGD16 & 3)) & 3) 10200130561Sobrien + R_PPC64_GOT_TPREL16_DS); 10201130561Sobrien else 10202130561Sobrien r_type += R_PPC64_TOC16_DS - R_PPC64_TOC16; 10203130561Sobrien rel->r_info = ELF64_R_INFO (r_symndx, r_type); 10204130561Sobrien } 10205130561Sobrien else 10206130561Sobrien { 10207130561Sobrien /* LE */ 10208130561Sobrien insn1 = 0x3c6d0000; /* addis 3,13,0 */ 10209130561Sobrien insn2 = 0x38630000; /* addi 3,3,0 */ 10210130561Sobrien if (tls_gd == 0) 10211130561Sobrien { 10212130561Sobrien /* Was an LD reloc. */ 10213130561Sobrien r_symndx = 0; 10214130561Sobrien rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; 10215130561Sobrien rel[1].r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; 10216130561Sobrien } 10217130561Sobrien else if (toc_symndx != 0) 10218130561Sobrien r_symndx = toc_symndx; 10219130561Sobrien r_type = R_PPC64_TPREL16_HA; 10220130561Sobrien rel->r_info = ELF64_R_INFO (r_symndx, r_type); 10221130561Sobrien rel[1].r_info = ELF64_R_INFO (r_symndx, 10222130561Sobrien R_PPC64_TPREL16_LO); 10223218822Sdim rel[1].r_offset += d_offset; 10224130561Sobrien } 10225130561Sobrien if (insn3 == NOP 10226130561Sobrien || insn3 == CROR_151515 || insn3 == CROR_313131) 10227130561Sobrien { 10228130561Sobrien insn3 = insn2; 10229130561Sobrien insn2 = NOP; 10230130561Sobrien rel[1].r_offset += 4; 10231130561Sobrien } 10232218822Sdim bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - d_offset); 10233130561Sobrien bfd_put_32 (output_bfd, insn2, contents + offset); 10234130561Sobrien bfd_put_32 (output_bfd, insn3, contents + offset + 4); 10235130561Sobrien if (tls_gd == 0 || toc_symndx != 0) 10236130561Sobrien { 10237130561Sobrien /* We changed the symbol. Start over in order 10238130561Sobrien to get h, sym, sec etc. right. */ 10239130561Sobrien rel--; 10240130561Sobrien continue; 10241130561Sobrien } 10242130561Sobrien } 10243130561Sobrien } 10244130561Sobrien break; 10245130561Sobrien 10246130561Sobrien case R_PPC64_DTPMOD64: 10247130561Sobrien if (rel + 1 < relend 10248130561Sobrien && rel[1].r_info == ELF64_R_INFO (r_symndx, R_PPC64_DTPREL64) 10249130561Sobrien && rel[1].r_offset == rel->r_offset + 8) 10250130561Sobrien { 10251130561Sobrien if ((tls_mask & TLS_GD) == 0) 10252130561Sobrien { 10253130561Sobrien rel[1].r_info = ELF64_R_INFO (r_symndx, R_PPC64_NONE); 10254130561Sobrien if ((tls_mask & TLS_TPRELGD) != 0) 10255130561Sobrien r_type = R_PPC64_TPREL64; 10256130561Sobrien else 10257130561Sobrien { 10258130561Sobrien bfd_put_64 (output_bfd, 1, contents + rel->r_offset); 10259130561Sobrien r_type = R_PPC64_NONE; 10260130561Sobrien } 10261130561Sobrien rel->r_info = ELF64_R_INFO (r_symndx, r_type); 10262130561Sobrien } 10263130561Sobrien } 1026489857Sobrien else 1026589857Sobrien { 10266130561Sobrien if ((tls_mask & TLS_LD) == 0) 10267130561Sobrien { 10268130561Sobrien bfd_put_64 (output_bfd, 1, contents + rel->r_offset); 10269130561Sobrien r_type = R_PPC64_NONE; 10270130561Sobrien rel->r_info = ELF64_R_INFO (r_symndx, r_type); 10271130561Sobrien } 1027289857Sobrien } 10273130561Sobrien break; 10274130561Sobrien 10275130561Sobrien case R_PPC64_TPREL64: 10276130561Sobrien if ((tls_mask & TLS_TPREL) == 0) 10277130561Sobrien { 10278130561Sobrien r_type = R_PPC64_NONE; 10279130561Sobrien rel->r_info = ELF64_R_INFO (r_symndx, r_type); 10280130561Sobrien } 10281130561Sobrien break; 1028289857Sobrien } 1028389857Sobrien 10284130561Sobrien /* Handle other relocations that tweak non-addend part of insn. */ 1028589857Sobrien insn = 0; 10286218822Sdim max_br_offset = 1 << 25; 10287218822Sdim addend = rel->r_addend; 1028889857Sobrien switch (r_type) 1028989857Sobrien { 1029089857Sobrien default: 1029189857Sobrien break; 1029289857Sobrien 1029389857Sobrien /* Branch taken prediction relocations. */ 1029489857Sobrien case R_PPC64_ADDR14_BRTAKEN: 1029589857Sobrien case R_PPC64_REL14_BRTAKEN: 10296104834Sobrien insn = 0x01 << 21; /* 'y' or 't' bit, lowest bit of BO field. */ 10297104834Sobrien /* Fall thru. */ 1029889857Sobrien 1029989857Sobrien /* Branch not taken prediction relocations. */ 1030089857Sobrien case R_PPC64_ADDR14_BRNTAKEN: 1030189857Sobrien case R_PPC64_REL14_BRNTAKEN: 10302130561Sobrien insn |= bfd_get_32 (output_bfd, 10303130561Sobrien contents + rel->r_offset) & ~(0x01 << 21); 10304218822Sdim /* Fall thru. */ 1030599461Sobrien 10306218822Sdim case R_PPC64_REL14: 10307218822Sdim max_br_offset = 1 << 15; 10308218822Sdim /* Fall thru. */ 1030989857Sobrien 1031089857Sobrien case R_PPC64_REL24: 10311130561Sobrien /* Calls to functions with a different TOC, such as calls to 10312130561Sobrien shared objects, need to alter the TOC pointer. This is 10313130561Sobrien done using a linkage stub. A REL24 branching to these 10314130561Sobrien linkage stubs needs to be followed by a nop, as the nop 10315130561Sobrien will be replaced with an instruction to restore the TOC 10316130561Sobrien base pointer. */ 10317218822Sdim stub_entry = NULL; 10318218822Sdim fdh = h; 10319130561Sobrien if (((h != NULL 10320218822Sdim && (((fdh = h->oh) != NULL 10321218822Sdim && fdh->elf.plt.plist != NULL) 10322218822Sdim || (fdh = h)->elf.plt.plist != NULL)) 10323218822Sdim || (sec != NULL 10324130561Sobrien && sec->output_section != NULL 10325218822Sdim && sec->id <= htab->top_id 10326130561Sobrien && (htab->stub_group[sec->id].toc_off 10327130561Sobrien != htab->stub_group[input_section->id].toc_off))) 10328104834Sobrien && (stub_entry = ppc_get_stub_entry (input_section, sec, fdh, 10329130561Sobrien rel, htab)) != NULL 10330130561Sobrien && (stub_entry->stub_type == ppc_stub_plt_call 10331130561Sobrien || stub_entry->stub_type == ppc_stub_plt_branch_r2off 10332130561Sobrien || stub_entry->stub_type == ppc_stub_long_branch_r2off)) 1033389857Sobrien { 10334218822Sdim bfd_boolean can_plt_call = FALSE; 1033589857Sobrien 10336218822Sdim if (rel->r_offset + 8 <= input_section->size) 1033789857Sobrien { 10338218822Sdim unsigned long nop; 10339218822Sdim nop = bfd_get_32 (input_bfd, contents + rel->r_offset + 4); 10340218822Sdim if (nop == NOP 10341218822Sdim || nop == CROR_151515 || nop == CROR_313131) 1034289857Sobrien { 10343130561Sobrien bfd_put_32 (input_bfd, LD_R2_40R1, 10344130561Sobrien contents + rel->r_offset + 4); 10345218822Sdim can_plt_call = TRUE; 1034689857Sobrien } 1034789857Sobrien } 1034899461Sobrien 1034999461Sobrien if (!can_plt_call) 1035099461Sobrien { 10351130561Sobrien if (stub_entry->stub_type == ppc_stub_plt_call) 10352130561Sobrien { 10353130561Sobrien /* If this is a plain branch rather than a branch 10354218822Sdim and link, don't require a nop. However, don't 10355218822Sdim allow tail calls in a shared library as they 10356218822Sdim will result in r2 being corrupted. */ 10357218822Sdim unsigned long br; 10358218822Sdim br = bfd_get_32 (input_bfd, contents + rel->r_offset); 10359218822Sdim if (info->executable && (br & 1) == 0) 10360218822Sdim can_plt_call = TRUE; 10361218822Sdim else 10362218822Sdim stub_entry = NULL; 10363130561Sobrien } 10364130561Sobrien else if (h != NULL 10365218822Sdim && strcmp (h->elf.root.root.string, 10366130561Sobrien ".__libc_start_main") == 0) 10367130561Sobrien { 10368130561Sobrien /* Allow crt1 branch to go via a toc adjusting stub. */ 10369218822Sdim can_plt_call = TRUE; 10370130561Sobrien } 10371130561Sobrien else 10372130561Sobrien { 10373130561Sobrien if (strcmp (input_section->output_section->name, 10374130561Sobrien ".init") == 0 10375130561Sobrien || strcmp (input_section->output_section->name, 10376130561Sobrien ".fini") == 0) 10377130561Sobrien (*_bfd_error_handler) 10378218822Sdim (_("%B(%A+0x%lx): automatic multiple TOCs " 10379130561Sobrien "not supported using your crt files; " 10380130561Sobrien "recompile with -mminimal-toc or upgrade gcc"), 10381218822Sdim input_bfd, 10382218822Sdim input_section, 10383130561Sobrien (long) rel->r_offset); 10384130561Sobrien else 10385130561Sobrien (*_bfd_error_handler) 10386218822Sdim (_("%B(%A+0x%lx): sibling call optimization to `%s' " 10387130561Sobrien "does not allow automatic multiple TOCs; " 10388130561Sobrien "recompile with -mminimal-toc or " 10389130561Sobrien "-fno-optimize-sibling-calls, " 10390130561Sobrien "or make `%s' extern"), 10391218822Sdim input_bfd, 10392218822Sdim input_section, 10393130561Sobrien (long) rel->r_offset, 10394130561Sobrien sym_name, 10395130561Sobrien sym_name); 10396130561Sobrien bfd_set_error (bfd_error_bad_value); 10397130561Sobrien ret = FALSE; 10398130561Sobrien } 1039999461Sobrien } 1040099461Sobrien 10401218822Sdim if (can_plt_call 10402218822Sdim && stub_entry->stub_type == ppc_stub_plt_call) 10403218822Sdim unresolved_reloc = FALSE; 10404218822Sdim } 10405218822Sdim 10406218822Sdim if (stub_entry == NULL 10407218822Sdim && get_opd_info (sec) != NULL) 10408218822Sdim { 10409218822Sdim /* The branch destination is the value of the opd entry. */ 10410218822Sdim bfd_vma off = (relocation + addend 10411218822Sdim - sec->output_section->vma 10412218822Sdim - sec->output_offset); 10413218822Sdim bfd_vma dest = opd_entry_value (sec, off, NULL, NULL); 10414218822Sdim if (dest != (bfd_vma) -1) 1041599461Sobrien { 10416218822Sdim relocation = dest; 10417218822Sdim addend = 0; 1041899461Sobrien } 1041989857Sobrien } 1042089857Sobrien 10421218822Sdim /* If the branch is out of reach we ought to have a long 10422218822Sdim branch stub. */ 10423218822Sdim from = (rel->r_offset 10424218822Sdim + input_section->output_offset 10425218822Sdim + input_section->output_section->vma); 10426218822Sdim 10427218822Sdim if (stub_entry == NULL 10428218822Sdim && (relocation + addend - from + max_br_offset 10429218822Sdim >= 2 * max_br_offset) 10430218822Sdim && r_type != R_PPC64_ADDR14_BRTAKEN 10431218822Sdim && r_type != R_PPC64_ADDR14_BRNTAKEN) 10432218822Sdim stub_entry = ppc_get_stub_entry (input_section, sec, h, rel, 10433218822Sdim htab); 10434218822Sdim 10435218822Sdim if (stub_entry != NULL) 1043689857Sobrien { 10437218822Sdim /* Munge up the value and addend so that we call the stub 10438218822Sdim rather than the procedure directly. */ 10439218822Sdim relocation = (stub_entry->stub_offset 10440218822Sdim + stub_entry->stub_sec->output_offset 10441218822Sdim + stub_entry->stub_sec->output_section->vma); 10442218822Sdim addend = 0; 10443218822Sdim } 1044499461Sobrien 10445218822Sdim if (insn != 0) 10446218822Sdim { 10447218822Sdim if (is_power4) 10448218822Sdim { 10449218822Sdim /* Set 'a' bit. This is 0b00010 in BO field for branch 10450218822Sdim on CR(BI) insns (BO == 001at or 011at), and 0b01000 10451218822Sdim for branch on CTR insns (BO == 1a00t or 1a01t). */ 10452218822Sdim if ((insn & (0x14 << 21)) == (0x04 << 21)) 10453218822Sdim insn |= 0x02 << 21; 10454218822Sdim else if ((insn & (0x14 << 21)) == (0x10 << 21)) 10455218822Sdim insn |= 0x08 << 21; 10456218822Sdim else 10457218822Sdim break; 10458218822Sdim } 10459218822Sdim else 10460218822Sdim { 10461218822Sdim /* Invert 'y' bit if not the default. */ 10462218822Sdim if ((bfd_signed_vma) (relocation + addend - from) < 0) 10463218822Sdim insn ^= 0x01 << 21; 10464218822Sdim } 10465218822Sdim 10466218822Sdim bfd_put_32 (output_bfd, insn, contents + rel->r_offset); 1046789857Sobrien } 10468218822Sdim 10469218822Sdim /* NOP out calls to undefined weak functions. 10470218822Sdim We can thus call a weak function without first 10471218822Sdim checking whether the function is defined. */ 10472218822Sdim else if (h != NULL 10473218822Sdim && h->elf.root.type == bfd_link_hash_undefweak 10474218822Sdim && r_type == R_PPC64_REL24 10475218822Sdim && relocation == 0 10476218822Sdim && addend == 0) 10477218822Sdim { 10478218822Sdim bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); 10479218822Sdim continue; 10480218822Sdim } 1048189857Sobrien break; 1048289857Sobrien } 1048389857Sobrien 1048489857Sobrien /* Set `addend'. */ 10485130561Sobrien tls_type = 0; 1048689857Sobrien switch (r_type) 1048789857Sobrien { 1048889857Sobrien default: 1048989857Sobrien (*_bfd_error_handler) 10490218822Sdim (_("%B: unknown relocation type %d for symbol %s"), 10491218822Sdim input_bfd, (int) r_type, sym_name); 1049289857Sobrien 1049389857Sobrien bfd_set_error (bfd_error_bad_value); 10494130561Sobrien ret = FALSE; 1049589857Sobrien continue; 1049689857Sobrien 1049789857Sobrien case R_PPC64_NONE: 10498130561Sobrien case R_PPC64_TLS: 10499130561Sobrien case R_PPC64_GNU_VTINHERIT: 10500130561Sobrien case R_PPC64_GNU_VTENTRY: 1050189857Sobrien continue; 1050289857Sobrien 1050389857Sobrien /* GOT16 relocations. Like an ADDR16 using the symbol's 1050489857Sobrien address in the GOT as relocation value instead of the 10505130561Sobrien symbol's value itself. Also, create a GOT entry for the 1050689857Sobrien symbol and put the symbol value there. */ 10507130561Sobrien case R_PPC64_GOT_TLSGD16: 10508130561Sobrien case R_PPC64_GOT_TLSGD16_LO: 10509130561Sobrien case R_PPC64_GOT_TLSGD16_HI: 10510130561Sobrien case R_PPC64_GOT_TLSGD16_HA: 10511130561Sobrien tls_type = TLS_TLS | TLS_GD; 10512130561Sobrien goto dogot; 10513130561Sobrien 10514130561Sobrien case R_PPC64_GOT_TLSLD16: 10515130561Sobrien case R_PPC64_GOT_TLSLD16_LO: 10516130561Sobrien case R_PPC64_GOT_TLSLD16_HI: 10517130561Sobrien case R_PPC64_GOT_TLSLD16_HA: 10518130561Sobrien tls_type = TLS_TLS | TLS_LD; 10519130561Sobrien goto dogot; 10520130561Sobrien 10521130561Sobrien case R_PPC64_GOT_TPREL16_DS: 10522130561Sobrien case R_PPC64_GOT_TPREL16_LO_DS: 10523130561Sobrien case R_PPC64_GOT_TPREL16_HI: 10524130561Sobrien case R_PPC64_GOT_TPREL16_HA: 10525130561Sobrien tls_type = TLS_TLS | TLS_TPREL; 10526130561Sobrien goto dogot; 10527130561Sobrien 10528130561Sobrien case R_PPC64_GOT_DTPREL16_DS: 10529130561Sobrien case R_PPC64_GOT_DTPREL16_LO_DS: 10530130561Sobrien case R_PPC64_GOT_DTPREL16_HI: 10531130561Sobrien case R_PPC64_GOT_DTPREL16_HA: 10532130561Sobrien tls_type = TLS_TLS | TLS_DTPREL; 10533130561Sobrien goto dogot; 10534130561Sobrien 1053589857Sobrien case R_PPC64_GOT16: 1053689857Sobrien case R_PPC64_GOT16_LO: 1053789857Sobrien case R_PPC64_GOT16_HI: 1053889857Sobrien case R_PPC64_GOT16_HA: 1053989857Sobrien case R_PPC64_GOT16_DS: 1054089857Sobrien case R_PPC64_GOT16_LO_DS: 10541130561Sobrien dogot: 1054289857Sobrien { 1054389857Sobrien /* Relocation is to the entry for this symbol in the global 1054489857Sobrien offset table. */ 10545130561Sobrien asection *got; 10546130561Sobrien bfd_vma *offp; 1054789857Sobrien bfd_vma off; 10548130561Sobrien unsigned long indx = 0; 1054989857Sobrien 10550130561Sobrien if (tls_type == (TLS_TLS | TLS_LD) 10551130561Sobrien && (h == NULL 10552218822Sdim || !h->elf.def_dynamic)) 10553130561Sobrien offp = &ppc64_tlsld_got (input_bfd)->offset; 10554130561Sobrien else 1055589857Sobrien { 10556130561Sobrien struct got_entry *ent; 1055789857Sobrien 10558130561Sobrien if (h != NULL) 1055989857Sobrien { 10560130561Sobrien bfd_boolean dyn = htab->elf.dynamic_sections_created; 10561218822Sdim if (!WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, 10562218822Sdim &h->elf) 10563130561Sobrien || (info->shared 10564218822Sdim && SYMBOL_REFERENCES_LOCAL (info, &h->elf))) 10565130561Sobrien /* This is actually a static link, or it is a 10566130561Sobrien -Bsymbolic link and the symbol is defined 10567130561Sobrien locally, or the symbol was forced to be local 10568130561Sobrien because of a version file. */ 10569130561Sobrien ; 1057089857Sobrien else 1057189857Sobrien { 10572218822Sdim indx = h->elf.dynindx; 10573130561Sobrien unresolved_reloc = FALSE; 1057489857Sobrien } 10575218822Sdim ent = h->elf.got.glist; 1057689857Sobrien } 1057789857Sobrien else 10578130561Sobrien { 10579130561Sobrien if (local_got_ents == NULL) 10580130561Sobrien abort (); 10581130561Sobrien ent = local_got_ents[r_symndx]; 10582130561Sobrien } 10583130561Sobrien 10584130561Sobrien for (; ent != NULL; ent = ent->next) 10585218822Sdim if (ent->addend == orig_addend 10586130561Sobrien && ent->owner == input_bfd 10587130561Sobrien && ent->tls_type == tls_type) 10588130561Sobrien break; 10589130561Sobrien if (ent == NULL) 10590130561Sobrien abort (); 10591130561Sobrien offp = &ent->got.offset; 1059289857Sobrien } 10593130561Sobrien 10594130561Sobrien got = ppc64_elf_tdata (input_bfd)->got; 10595130561Sobrien if (got == NULL) 10596130561Sobrien abort (); 10597130561Sobrien 10598130561Sobrien /* The offset must always be a multiple of 8. We use the 10599130561Sobrien least significant bit to record whether we have already 10600130561Sobrien processed this entry. */ 10601130561Sobrien off = *offp; 10602130561Sobrien if ((off & 1) != 0) 10603130561Sobrien off &= ~1; 1060489857Sobrien else 1060589857Sobrien { 10606130561Sobrien /* Generate relocs for the dynamic linker, except in 10607130561Sobrien the case of TLSLD where we'll use one entry per 10608130561Sobrien module. */ 10609130561Sobrien asection *relgot = ppc64_elf_tdata (input_bfd)->relgot; 1061089857Sobrien 10611130561Sobrien *offp = off | 1; 10612130561Sobrien if ((info->shared || indx != 0) 10613130561Sobrien && (h == NULL 10614218822Sdim || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT 10615218822Sdim || h->elf.root.type != bfd_link_hash_undefweak)) 10616130561Sobrien { 10617130561Sobrien outrel.r_offset = (got->output_section->vma 10618130561Sobrien + got->output_offset 10619130561Sobrien + off); 10620218822Sdim outrel.r_addend = addend; 10621130561Sobrien if (tls_type & (TLS_LD | TLS_GD)) 10622130561Sobrien { 10623130561Sobrien outrel.r_addend = 0; 10624130561Sobrien outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPMOD64); 10625130561Sobrien if (tls_type == (TLS_TLS | TLS_GD)) 10626130561Sobrien { 10627130561Sobrien loc = relgot->contents; 10628130561Sobrien loc += (relgot->reloc_count++ 10629130561Sobrien * sizeof (Elf64_External_Rela)); 10630130561Sobrien bfd_elf64_swap_reloca_out (output_bfd, 10631130561Sobrien &outrel, loc); 10632130561Sobrien outrel.r_offset += 8; 10633218822Sdim outrel.r_addend = addend; 10634130561Sobrien outrel.r_info 10635130561Sobrien = ELF64_R_INFO (indx, R_PPC64_DTPREL64); 10636130561Sobrien } 10637130561Sobrien } 10638130561Sobrien else if (tls_type == (TLS_TLS | TLS_DTPREL)) 10639130561Sobrien outrel.r_info = ELF64_R_INFO (indx, R_PPC64_DTPREL64); 10640130561Sobrien else if (tls_type == (TLS_TLS | TLS_TPREL)) 10641130561Sobrien outrel.r_info = ELF64_R_INFO (indx, R_PPC64_TPREL64); 10642130561Sobrien else if (indx == 0) 10643130561Sobrien { 10644130561Sobrien outrel.r_info = ELF64_R_INFO (indx, R_PPC64_RELATIVE); 1064589857Sobrien 10646130561Sobrien /* Write the .got section contents for the sake 10647130561Sobrien of prelink. */ 10648130561Sobrien loc = got->contents + off; 10649130561Sobrien bfd_put_64 (output_bfd, outrel.r_addend + relocation, 10650130561Sobrien loc); 10651130561Sobrien } 10652130561Sobrien else 10653130561Sobrien outrel.r_info = ELF64_R_INFO (indx, R_PPC64_GLOB_DAT); 10654130561Sobrien 10655130561Sobrien if (indx == 0 && tls_type != (TLS_TLS | TLS_LD)) 10656130561Sobrien { 10657130561Sobrien outrel.r_addend += relocation; 10658130561Sobrien if (tls_type & (TLS_GD | TLS_DTPREL | TLS_TPREL)) 10659130561Sobrien outrel.r_addend -= htab->elf.tls_sec->vma; 10660130561Sobrien } 10661130561Sobrien loc = relgot->contents; 10662130561Sobrien loc += (relgot->reloc_count++ 10663130561Sobrien * sizeof (Elf64_External_Rela)); 10664130561Sobrien bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); 10665130561Sobrien } 10666130561Sobrien 10667130561Sobrien /* Init the .got section contents here if we're not 10668130561Sobrien emitting a reloc. */ 1066989857Sobrien else 1067089857Sobrien { 10671218822Sdim relocation += addend; 10672130561Sobrien if (tls_type == (TLS_TLS | TLS_LD)) 10673130561Sobrien relocation = 1; 10674130561Sobrien else if (tls_type != 0) 1067589857Sobrien { 10676130561Sobrien relocation -= htab->elf.tls_sec->vma + DTP_OFFSET; 10677130561Sobrien if (tls_type == (TLS_TLS | TLS_TPREL)) 10678130561Sobrien relocation += DTP_OFFSET - TP_OFFSET; 1067989857Sobrien 10680130561Sobrien if (tls_type == (TLS_TLS | TLS_GD)) 10681130561Sobrien { 10682130561Sobrien bfd_put_64 (output_bfd, relocation, 10683130561Sobrien got->contents + off + 8); 10684130561Sobrien relocation = 1; 10685130561Sobrien } 1068689857Sobrien } 1068789857Sobrien 10688130561Sobrien bfd_put_64 (output_bfd, relocation, 10689130561Sobrien got->contents + off); 1069089857Sobrien } 1069189857Sobrien } 1069289857Sobrien 1069389857Sobrien if (off >= (bfd_vma) -2) 1069489857Sobrien abort (); 1069589857Sobrien 10696130561Sobrien relocation = got->output_offset + off; 1069789857Sobrien 1069889857Sobrien /* TOC base (r2) is TOC start plus 0x8000. */ 10699130561Sobrien addend = -TOC_BASE_OFF; 1070089857Sobrien } 1070189857Sobrien break; 1070289857Sobrien 1070389857Sobrien case R_PPC64_PLT16_HA: 1070489857Sobrien case R_PPC64_PLT16_HI: 1070589857Sobrien case R_PPC64_PLT16_LO: 1070689857Sobrien case R_PPC64_PLT32: 1070789857Sobrien case R_PPC64_PLT64: 1070889857Sobrien /* Relocation is to the entry for this symbol in the 1070989857Sobrien procedure linkage table. */ 1071089857Sobrien 1071189857Sobrien /* Resolve a PLT reloc against a local symbol directly, 1071289857Sobrien without using the procedure linkage table. */ 1071389857Sobrien if (h == NULL) 1071489857Sobrien break; 1071589857Sobrien 10716130561Sobrien /* It's possible that we didn't make a PLT entry for this 10717130561Sobrien symbol. This happens when statically linking PIC code, 10718130561Sobrien or when using -Bsymbolic. Go find a match if there is a 10719130561Sobrien PLT entry. */ 10720130561Sobrien if (htab->plt != NULL) 1072189857Sobrien { 10722130561Sobrien struct plt_entry *ent; 10723218822Sdim for (ent = h->elf.plt.plist; ent != NULL; ent = ent->next) 10724218822Sdim if (ent->addend == orig_addend 10725130561Sobrien && ent->plt.offset != (bfd_vma) -1) 10726130561Sobrien { 10727130561Sobrien relocation = (htab->plt->output_section->vma 10728130561Sobrien + htab->plt->output_offset 10729130561Sobrien + ent->plt.offset); 10730130561Sobrien unresolved_reloc = FALSE; 10731130561Sobrien } 1073289857Sobrien } 1073389857Sobrien break; 1073489857Sobrien 10735130561Sobrien case R_PPC64_TOC: 10736130561Sobrien /* Relocation value is TOC base. */ 10737130561Sobrien relocation = TOCstart; 10738130561Sobrien if (r_symndx == 0) 10739130561Sobrien relocation += htab->stub_group[input_section->id].toc_off; 10740130561Sobrien else if (unresolved_reloc) 10741130561Sobrien ; 10742130561Sobrien else if (sec != NULL && sec->id <= htab->top_id) 10743130561Sobrien relocation += htab->stub_group[sec->id].toc_off; 10744130561Sobrien else 10745130561Sobrien unresolved_reloc = TRUE; 10746218822Sdim goto dodyn; 10747130561Sobrien 1074889857Sobrien /* TOC16 relocs. We want the offset relative to the TOC base, 1074989857Sobrien which is the address of the start of the TOC plus 0x8000. 1075089857Sobrien The TOC consists of sections .got, .toc, .tocbss, and .plt, 1075189857Sobrien in this order. */ 1075289857Sobrien case R_PPC64_TOC16: 1075389857Sobrien case R_PPC64_TOC16_LO: 1075489857Sobrien case R_PPC64_TOC16_HI: 1075589857Sobrien case R_PPC64_TOC16_DS: 1075689857Sobrien case R_PPC64_TOC16_LO_DS: 1075789857Sobrien case R_PPC64_TOC16_HA: 10758130561Sobrien addend -= TOCstart + htab->stub_group[input_section->id].toc_off; 1075989857Sobrien break; 1076089857Sobrien 1076189857Sobrien /* Relocate against the beginning of the section. */ 1076289857Sobrien case R_PPC64_SECTOFF: 1076389857Sobrien case R_PPC64_SECTOFF_LO: 1076489857Sobrien case R_PPC64_SECTOFF_HI: 1076589857Sobrien case R_PPC64_SECTOFF_DS: 1076689857Sobrien case R_PPC64_SECTOFF_LO_DS: 1076789857Sobrien case R_PPC64_SECTOFF_HA: 10768130561Sobrien if (sec != NULL) 1076989857Sobrien addend -= sec->output_section->vma; 1077089857Sobrien break; 1077189857Sobrien 10772104834Sobrien case R_PPC64_REL14: 10773104834Sobrien case R_PPC64_REL14_BRNTAKEN: 10774104834Sobrien case R_PPC64_REL14_BRTAKEN: 1077589857Sobrien case R_PPC64_REL24: 1077689857Sobrien break; 1077789857Sobrien 10778130561Sobrien case R_PPC64_TPREL16: 10779130561Sobrien case R_PPC64_TPREL16_LO: 10780130561Sobrien case R_PPC64_TPREL16_HI: 10781130561Sobrien case R_PPC64_TPREL16_HA: 10782130561Sobrien case R_PPC64_TPREL16_DS: 10783130561Sobrien case R_PPC64_TPREL16_LO_DS: 10784130561Sobrien case R_PPC64_TPREL16_HIGHER: 10785130561Sobrien case R_PPC64_TPREL16_HIGHERA: 10786130561Sobrien case R_PPC64_TPREL16_HIGHEST: 10787130561Sobrien case R_PPC64_TPREL16_HIGHESTA: 10788130561Sobrien addend -= htab->elf.tls_sec->vma + TP_OFFSET; 10789130561Sobrien if (info->shared) 10790130561Sobrien /* The TPREL16 relocs shouldn't really be used in shared 10791130561Sobrien libs as they will result in DT_TEXTREL being set, but 10792130561Sobrien support them anyway. */ 10793130561Sobrien goto dodyn; 10794130561Sobrien break; 10795130561Sobrien 10796130561Sobrien case R_PPC64_DTPREL16: 10797130561Sobrien case R_PPC64_DTPREL16_LO: 10798130561Sobrien case R_PPC64_DTPREL16_HI: 10799130561Sobrien case R_PPC64_DTPREL16_HA: 10800130561Sobrien case R_PPC64_DTPREL16_DS: 10801130561Sobrien case R_PPC64_DTPREL16_LO_DS: 10802130561Sobrien case R_PPC64_DTPREL16_HIGHER: 10803130561Sobrien case R_PPC64_DTPREL16_HIGHERA: 10804130561Sobrien case R_PPC64_DTPREL16_HIGHEST: 10805130561Sobrien case R_PPC64_DTPREL16_HIGHESTA: 10806130561Sobrien addend -= htab->elf.tls_sec->vma + DTP_OFFSET; 10807130561Sobrien break; 10808130561Sobrien 10809130561Sobrien case R_PPC64_DTPMOD64: 10810130561Sobrien relocation = 1; 10811130561Sobrien addend = 0; 10812130561Sobrien goto dodyn; 10813130561Sobrien 10814130561Sobrien case R_PPC64_TPREL64: 10815130561Sobrien addend -= htab->elf.tls_sec->vma + TP_OFFSET; 10816130561Sobrien goto dodyn; 10817130561Sobrien 10818130561Sobrien case R_PPC64_DTPREL64: 10819130561Sobrien addend -= htab->elf.tls_sec->vma + DTP_OFFSET; 10820130561Sobrien /* Fall thru */ 10821130561Sobrien 1082289857Sobrien /* Relocations that may need to be propagated if this is a 1082389857Sobrien dynamic object. */ 10824130561Sobrien case R_PPC64_REL30: 1082589857Sobrien case R_PPC64_REL32: 1082689857Sobrien case R_PPC64_REL64: 1082789857Sobrien case R_PPC64_ADDR14: 1082889857Sobrien case R_PPC64_ADDR14_BRNTAKEN: 1082989857Sobrien case R_PPC64_ADDR14_BRTAKEN: 1083089857Sobrien case R_PPC64_ADDR16: 1083189857Sobrien case R_PPC64_ADDR16_DS: 1083289857Sobrien case R_PPC64_ADDR16_HA: 1083389857Sobrien case R_PPC64_ADDR16_HI: 1083489857Sobrien case R_PPC64_ADDR16_HIGHER: 1083589857Sobrien case R_PPC64_ADDR16_HIGHERA: 1083689857Sobrien case R_PPC64_ADDR16_HIGHEST: 1083789857Sobrien case R_PPC64_ADDR16_HIGHESTA: 1083889857Sobrien case R_PPC64_ADDR16_LO: 1083989857Sobrien case R_PPC64_ADDR16_LO_DS: 1084089857Sobrien case R_PPC64_ADDR24: 1084189857Sobrien case R_PPC64_ADDR32: 1084289857Sobrien case R_PPC64_ADDR64: 1084389857Sobrien case R_PPC64_UADDR16: 1084489857Sobrien case R_PPC64_UADDR32: 1084589857Sobrien case R_PPC64_UADDR64: 10846130561Sobrien dodyn: 1084789857Sobrien if ((input_section->flags & SEC_ALLOC) == 0) 1084889857Sobrien break; 1084989857Sobrien 1085089857Sobrien if (NO_OPD_RELOCS && is_opd) 1085189857Sobrien break; 1085289857Sobrien 1085389857Sobrien if ((info->shared 10854130561Sobrien && (h == NULL 10855218822Sdim || ELF_ST_VISIBILITY (h->elf.other) == STV_DEFAULT 10856218822Sdim || h->elf.root.type != bfd_link_hash_undefweak) 10857130561Sobrien && (MUST_BE_DYN_RELOC (r_type) 10858218822Sdim || !SYMBOL_CALLS_LOCAL (info, &h->elf))) 10859130561Sobrien || (ELIMINATE_COPY_RELOCS 10860130561Sobrien && !info->shared 1086189857Sobrien && h != NULL 10862218822Sdim && h->elf.dynindx != -1 10863218822Sdim && !h->elf.non_got_ref 10864218822Sdim && h->elf.def_dynamic 10865218822Sdim && !h->elf.def_regular)) 1086689857Sobrien { 1086789857Sobrien Elf_Internal_Rela outrel; 10868130561Sobrien bfd_boolean skip, relocate; 1086989857Sobrien asection *sreloc; 10870130561Sobrien bfd_byte *loc; 10871130561Sobrien bfd_vma out_off; 1087289857Sobrien 1087389857Sobrien /* When generating a dynamic object, these relocations 1087489857Sobrien are copied into the output file to be resolved at run 1087589857Sobrien time. */ 1087689857Sobrien 10877130561Sobrien skip = FALSE; 10878130561Sobrien relocate = FALSE; 1087989857Sobrien 10880130561Sobrien out_off = _bfd_elf_section_offset (output_bfd, info, 10881130561Sobrien input_section, rel->r_offset); 10882130561Sobrien if (out_off == (bfd_vma) -1) 10883130561Sobrien skip = TRUE; 10884130561Sobrien else if (out_off == (bfd_vma) -2) 10885130561Sobrien skip = TRUE, relocate = TRUE; 10886130561Sobrien out_off += (input_section->output_section->vma 10887130561Sobrien + input_section->output_offset); 10888130561Sobrien outrel.r_offset = out_off; 10889130561Sobrien outrel.r_addend = rel->r_addend; 1089089857Sobrien 10891130561Sobrien /* Optimize unaligned reloc use. */ 10892130561Sobrien if ((r_type == R_PPC64_ADDR64 && (out_off & 7) != 0) 10893130561Sobrien || (r_type == R_PPC64_UADDR64 && (out_off & 7) == 0)) 10894130561Sobrien r_type ^= R_PPC64_ADDR64 ^ R_PPC64_UADDR64; 10895130561Sobrien else if ((r_type == R_PPC64_ADDR32 && (out_off & 3) != 0) 10896130561Sobrien || (r_type == R_PPC64_UADDR32 && (out_off & 3) == 0)) 10897130561Sobrien r_type ^= R_PPC64_ADDR32 ^ R_PPC64_UADDR32; 10898130561Sobrien else if ((r_type == R_PPC64_ADDR16 && (out_off & 1) != 0) 10899130561Sobrien || (r_type == R_PPC64_UADDR16 && (out_off & 1) == 0)) 10900130561Sobrien r_type ^= R_PPC64_ADDR16 ^ R_PPC64_UADDR16; 10901130561Sobrien 1090289857Sobrien if (skip) 1090391041Sobrien memset (&outrel, 0, sizeof outrel); 10904218822Sdim else if (!SYMBOL_REFERENCES_LOCAL (info, &h->elf) 1090589857Sobrien && !is_opd 10906130561Sobrien && r_type != R_PPC64_TOC) 10907218822Sdim outrel.r_info = ELF64_R_INFO (h->elf.dynindx, r_type); 1090889857Sobrien else 1090989857Sobrien { 1091089857Sobrien /* This symbol is local, or marked to become local, 1091189857Sobrien or this is an opd section reloc which must point 1091289857Sobrien at a local function. */ 1091389857Sobrien outrel.r_addend += relocation; 1091489857Sobrien if (r_type == R_PPC64_ADDR64 || r_type == R_PPC64_TOC) 1091589857Sobrien { 10916104834Sobrien if (is_opd && h != NULL) 10917104834Sobrien { 10918104834Sobrien /* Lie about opd entries. This case occurs 10919104834Sobrien when building shared libraries and we 10920104834Sobrien reference a function in another shared 10921104834Sobrien lib. The same thing happens for a weak 10922104834Sobrien definition in an application that's 10923104834Sobrien overridden by a strong definition in a 10924104834Sobrien shared lib. (I believe this is a generic 10925104834Sobrien bug in binutils handling of weak syms.) 10926104834Sobrien In these cases we won't use the opd 10927104834Sobrien entry in this lib. */ 10928130561Sobrien unresolved_reloc = FALSE; 10929104834Sobrien } 1093089857Sobrien outrel.r_info = ELF64_R_INFO (0, R_PPC64_RELATIVE); 10931130561Sobrien 10932130561Sobrien /* We need to relocate .opd contents for ld.so. 10933130561Sobrien Prelink also wants simple and consistent rules 10934130561Sobrien for relocs. This make all RELATIVE relocs have 10935130561Sobrien *r_offset equal to r_addend. */ 10936130561Sobrien relocate = TRUE; 1093789857Sobrien } 1093889857Sobrien else 1093989857Sobrien { 1094089857Sobrien long indx = 0; 1094189857Sobrien 1094289857Sobrien if (bfd_is_abs_section (sec)) 1094389857Sobrien ; 1094489857Sobrien else if (sec == NULL || sec->owner == NULL) 1094589857Sobrien { 1094689857Sobrien bfd_set_error (bfd_error_bad_value); 10947130561Sobrien return FALSE; 1094889857Sobrien } 1094989857Sobrien else 1095089857Sobrien { 1095189857Sobrien asection *osec; 1095289857Sobrien 1095389857Sobrien osec = sec->output_section; 1095489857Sobrien indx = elf_section_data (osec)->dynindx; 1095589857Sobrien 10956218822Sdim if (indx == 0) 10957218822Sdim { 10958218822Sdim if ((osec->flags & SEC_READONLY) == 0 10959218822Sdim && htab->elf.data_index_section != NULL) 10960218822Sdim osec = htab->elf.data_index_section; 10961218822Sdim else 10962218822Sdim osec = htab->elf.text_index_section; 10963218822Sdim indx = elf_section_data (osec)->dynindx; 10964218822Sdim } 10965218822Sdim BFD_ASSERT (indx != 0); 10966218822Sdim 1096789857Sobrien /* We are turning this relocation into one 1096889857Sobrien against a section symbol, so subtract out 1096989857Sobrien the output section's address but not the 1097089857Sobrien offset of the input section in the output 1097189857Sobrien section. */ 1097289857Sobrien outrel.r_addend -= osec->vma; 1097389857Sobrien } 1097489857Sobrien 1097589857Sobrien outrel.r_info = ELF64_R_INFO (indx, r_type); 1097689857Sobrien } 1097789857Sobrien } 1097889857Sobrien 1097989857Sobrien sreloc = elf_section_data (input_section)->sreloc; 1098089857Sobrien if (sreloc == NULL) 1098189857Sobrien abort (); 1098289857Sobrien 10983218822Sdim if (sreloc->reloc_count * sizeof (Elf64_External_Rela) 10984218822Sdim >= sreloc->size) 10985218822Sdim abort (); 10986130561Sobrien loc = sreloc->contents; 10987130561Sobrien loc += sreloc->reloc_count++ * sizeof (Elf64_External_Rela); 1098889857Sobrien bfd_elf64_swap_reloca_out (output_bfd, &outrel, loc); 1098989857Sobrien 1099089857Sobrien /* If this reloc is against an external symbol, it will 1099189857Sobrien be computed at runtime, so there's no need to do 10992130561Sobrien anything now. However, for the sake of prelink ensure 10993130561Sobrien that the section contents are a known value. */ 1099489857Sobrien if (! relocate) 10995130561Sobrien { 10996130561Sobrien unresolved_reloc = FALSE; 10997130561Sobrien /* The value chosen here is quite arbitrary as ld.so 10998130561Sobrien ignores section contents except for the special 10999130561Sobrien case of .opd where the contents might be accessed 11000130561Sobrien before relocation. Choose zero, as that won't 11001130561Sobrien cause reloc overflow. */ 11002130561Sobrien relocation = 0; 11003130561Sobrien addend = 0; 11004130561Sobrien /* Use *r_offset == r_addend for R_PPC64_ADDR64 relocs 11005130561Sobrien to improve backward compatibility with older 11006130561Sobrien versions of ld. */ 11007130561Sobrien if (r_type == R_PPC64_ADDR64) 11008130561Sobrien addend = outrel.r_addend; 11009130561Sobrien /* Adjust pc_relative relocs to have zero in *r_offset. */ 11010130561Sobrien else if (ppc64_elf_howto_table[r_type]->pc_relative) 11011130561Sobrien addend = (input_section->output_section->vma 11012130561Sobrien + input_section->output_offset 11013130561Sobrien + rel->r_offset); 11014130561Sobrien } 1101589857Sobrien } 1101689857Sobrien break; 1101789857Sobrien 1101889857Sobrien case R_PPC64_COPY: 1101989857Sobrien case R_PPC64_GLOB_DAT: 1102089857Sobrien case R_PPC64_JMP_SLOT: 1102189857Sobrien case R_PPC64_RELATIVE: 1102289857Sobrien /* We shouldn't ever see these dynamic relocs in relocatable 1102389857Sobrien files. */ 11024130561Sobrien /* Fall through. */ 1102589857Sobrien 1102689857Sobrien case R_PPC64_PLTGOT16: 1102789857Sobrien case R_PPC64_PLTGOT16_DS: 1102889857Sobrien case R_PPC64_PLTGOT16_HA: 1102989857Sobrien case R_PPC64_PLTGOT16_HI: 1103089857Sobrien case R_PPC64_PLTGOT16_LO: 1103189857Sobrien case R_PPC64_PLTGOT16_LO_DS: 1103289857Sobrien case R_PPC64_PLTREL32: 1103389857Sobrien case R_PPC64_PLTREL64: 1103489857Sobrien /* These ones haven't been implemented yet. */ 1103589857Sobrien 1103689857Sobrien (*_bfd_error_handler) 11037218822Sdim (_("%B: relocation %s is not supported for symbol %s."), 11038218822Sdim input_bfd, 11039130561Sobrien ppc64_elf_howto_table[r_type]->name, sym_name); 1104089857Sobrien 1104189857Sobrien bfd_set_error (bfd_error_invalid_operation); 11042130561Sobrien ret = FALSE; 1104389857Sobrien continue; 1104489857Sobrien } 1104589857Sobrien 1104689857Sobrien /* Do any further special processing. */ 1104789857Sobrien switch (r_type) 1104889857Sobrien { 1104989857Sobrien default: 1105089857Sobrien break; 1105189857Sobrien 1105289857Sobrien case R_PPC64_ADDR16_HA: 1105389857Sobrien case R_PPC64_ADDR16_HIGHERA: 1105489857Sobrien case R_PPC64_ADDR16_HIGHESTA: 1105589857Sobrien case R_PPC64_TOC16_HA: 1105689857Sobrien case R_PPC64_SECTOFF_HA: 11057130561Sobrien case R_PPC64_TPREL16_HA: 11058130561Sobrien case R_PPC64_DTPREL16_HA: 11059130561Sobrien case R_PPC64_TPREL16_HIGHER: 11060130561Sobrien case R_PPC64_TPREL16_HIGHERA: 11061130561Sobrien case R_PPC64_TPREL16_HIGHEST: 11062130561Sobrien case R_PPC64_TPREL16_HIGHESTA: 11063130561Sobrien case R_PPC64_DTPREL16_HIGHER: 11064130561Sobrien case R_PPC64_DTPREL16_HIGHERA: 11065130561Sobrien case R_PPC64_DTPREL16_HIGHEST: 11066130561Sobrien case R_PPC64_DTPREL16_HIGHESTA: 1106789857Sobrien /* It's just possible that this symbol is a weak symbol 1106889857Sobrien that's not actually defined anywhere. In that case, 1106989857Sobrien 'sec' would be NULL, and we should leave the symbol 1107089857Sobrien alone (it will be set to zero elsewhere in the link). */ 11071218822Sdim if (sec == NULL) 11072218822Sdim break; 11073218822Sdim /* Fall thru */ 11074218822Sdim 11075218822Sdim case R_PPC64_GOT16_HA: 11076218822Sdim case R_PPC64_PLTGOT16_HA: 11077218822Sdim case R_PPC64_PLT16_HA: 11078218822Sdim case R_PPC64_GOT_TLSGD16_HA: 11079218822Sdim case R_PPC64_GOT_TLSLD16_HA: 11080218822Sdim case R_PPC64_GOT_TPREL16_HA: 11081218822Sdim case R_PPC64_GOT_DTPREL16_HA: 11082218822Sdim /* Add 0x10000 if sign bit in 0:15 is set. 11083218822Sdim Bits 0:15 are not used. */ 11084218822Sdim addend += 0x8000; 1108589857Sobrien break; 1108689857Sobrien 1108789857Sobrien case R_PPC64_ADDR16_DS: 1108889857Sobrien case R_PPC64_ADDR16_LO_DS: 1108989857Sobrien case R_PPC64_GOT16_DS: 1109089857Sobrien case R_PPC64_GOT16_LO_DS: 1109189857Sobrien case R_PPC64_PLT16_LO_DS: 1109289857Sobrien case R_PPC64_SECTOFF_DS: 1109389857Sobrien case R_PPC64_SECTOFF_LO_DS: 1109489857Sobrien case R_PPC64_TOC16_DS: 1109589857Sobrien case R_PPC64_TOC16_LO_DS: 1109689857Sobrien case R_PPC64_PLTGOT16_DS: 1109789857Sobrien case R_PPC64_PLTGOT16_LO_DS: 11098130561Sobrien case R_PPC64_GOT_TPREL16_DS: 11099130561Sobrien case R_PPC64_GOT_TPREL16_LO_DS: 11100130561Sobrien case R_PPC64_GOT_DTPREL16_DS: 11101130561Sobrien case R_PPC64_GOT_DTPREL16_LO_DS: 11102130561Sobrien case R_PPC64_TPREL16_DS: 11103130561Sobrien case R_PPC64_TPREL16_LO_DS: 11104130561Sobrien case R_PPC64_DTPREL16_DS: 11105130561Sobrien case R_PPC64_DTPREL16_LO_DS: 11106130561Sobrien insn = bfd_get_32 (input_bfd, contents + (rel->r_offset & ~3)); 11107130561Sobrien mask = 3; 11108130561Sobrien /* If this reloc is against an lq insn, then the value must be 11109130561Sobrien a multiple of 16. This is somewhat of a hack, but the 11110130561Sobrien "correct" way to do this by defining _DQ forms of all the 11111130561Sobrien _DS relocs bloats all reloc switches in this file. It 11112130561Sobrien doesn't seem to make much sense to use any of these relocs 11113130561Sobrien in data, so testing the insn should be safe. */ 11114130561Sobrien if ((insn & (0x3f << 26)) == (56u << 26)) 11115130561Sobrien mask = 15; 11116130561Sobrien if (((relocation + addend) & mask) != 0) 1111789857Sobrien { 1111889857Sobrien (*_bfd_error_handler) 11119218822Sdim (_("%B: error: relocation %s not a multiple of %d"), 11120218822Sdim input_bfd, 11121130561Sobrien ppc64_elf_howto_table[r_type]->name, 11122130561Sobrien mask + 1); 1112389857Sobrien bfd_set_error (bfd_error_bad_value); 11124130561Sobrien ret = FALSE; 1112589857Sobrien continue; 1112689857Sobrien } 1112789857Sobrien break; 1112889857Sobrien } 1112989857Sobrien 11130104834Sobrien /* Dynamic relocs are not propagated for SEC_DEBUGGING sections 11131104834Sobrien because such sections are not SEC_ALLOC and thus ld.so will 11132104834Sobrien not process them. */ 1113389857Sobrien if (unresolved_reloc 11134104834Sobrien && !((input_section->flags & SEC_DEBUGGING) != 0 11135218822Sdim && h->elf.def_dynamic)) 11136104834Sobrien { 11137104834Sobrien (*_bfd_error_handler) 11138218822Sdim (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), 11139218822Sdim input_bfd, 11140218822Sdim input_section, 11141104834Sobrien (long) rel->r_offset, 11142130561Sobrien ppc64_elf_howto_table[(int) r_type]->name, 11143218822Sdim h->elf.root.root.string); 11144130561Sobrien ret = FALSE; 11145104834Sobrien } 1114689857Sobrien 1114789857Sobrien r = _bfd_final_link_relocate (ppc64_elf_howto_table[(int) r_type], 1114889857Sobrien input_bfd, 1114989857Sobrien input_section, 1115089857Sobrien contents, 11151130561Sobrien rel->r_offset, 1115289857Sobrien relocation, 1115389857Sobrien addend); 1115489857Sobrien 11155104834Sobrien if (r != bfd_reloc_ok) 1115689857Sobrien { 11157130561Sobrien if (sym_name == NULL) 11158130561Sobrien sym_name = "(null)"; 11159130561Sobrien if (r == bfd_reloc_overflow) 1116089857Sobrien { 11161130561Sobrien if (warned) 11162130561Sobrien continue; 11163130561Sobrien if (h != NULL 11164218822Sdim && h->elf.root.type == bfd_link_hash_undefweak 11165130561Sobrien && ppc64_elf_howto_table[r_type]->pc_relative) 1116689857Sobrien { 1116789857Sobrien /* Assume this is a call protected by other code that 1116889857Sobrien detects the symbol is undefined. If this is the case, 1116989857Sobrien we can safely ignore the overflow. If not, the 1117089857Sobrien program is hosed anyway, and a little warning isn't 1117189857Sobrien going to help. */ 1117289857Sobrien 1117389857Sobrien continue; 1117489857Sobrien } 1117589857Sobrien 11176104834Sobrien if (!((*info->callbacks->reloc_overflow) 11177218822Sdim (info, (h ? &h->elf.root : NULL), sym_name, 11178218822Sdim ppc64_elf_howto_table[r_type]->name, 11179218822Sdim orig_addend, input_bfd, input_section, rel->r_offset))) 11180130561Sobrien return FALSE; 11181104834Sobrien } 11182104834Sobrien else 11183104834Sobrien { 11184104834Sobrien (*_bfd_error_handler) 11185218822Sdim (_("%B(%A+0x%lx): %s reloc against `%s': error %d"), 11186218822Sdim input_bfd, 11187218822Sdim input_section, 11188130561Sobrien (long) rel->r_offset, 11189130561Sobrien ppc64_elf_howto_table[r_type]->name, 11190130561Sobrien sym_name, 11191130561Sobrien (int) r); 11192130561Sobrien ret = FALSE; 11193104834Sobrien } 1119489857Sobrien } 1119589857Sobrien } 1119689857Sobrien 11197218822Sdim /* If we're emitting relocations, then shortly after this function 11198218822Sdim returns, reloc offsets and addends for this section will be 11199218822Sdim adjusted. Worse, reloc symbol indices will be for the output 11200218822Sdim file rather than the input. Save a copy of the relocs for 11201218822Sdim opd_entry_value. */ 11202218822Sdim if (is_opd && (info->emitrelocations || info->relocatable)) 11203218822Sdim { 11204218822Sdim bfd_size_type amt; 11205218822Sdim amt = input_section->reloc_count * sizeof (Elf_Internal_Rela); 11206218822Sdim rel = bfd_alloc (input_bfd, amt); 11207218822Sdim BFD_ASSERT (ppc64_elf_tdata (input_bfd)->opd_relocs == NULL); 11208218822Sdim ppc64_elf_tdata (input_bfd)->opd_relocs = rel; 11209218822Sdim if (rel == NULL) 11210218822Sdim return FALSE; 11211218822Sdim memcpy (rel, relocs, amt); 11212218822Sdim } 1121389857Sobrien return ret; 1121489857Sobrien} 1121589857Sobrien 11216130561Sobrien/* Adjust the value of any local symbols in opd sections. */ 11217130561Sobrien 11218130561Sobrienstatic bfd_boolean 11219130561Sobrienppc64_elf_output_symbol_hook (struct bfd_link_info *info, 11220130561Sobrien const char *name ATTRIBUTE_UNUSED, 11221130561Sobrien Elf_Internal_Sym *elfsym, 11222130561Sobrien asection *input_sec, 11223130561Sobrien struct elf_link_hash_entry *h) 11224130561Sobrien{ 11225218822Sdim long *opd_adjust, adjust; 11226130561Sobrien bfd_vma value; 11227130561Sobrien 11228218822Sdim if (h != NULL) 11229130561Sobrien return TRUE; 11230130561Sobrien 11231218822Sdim opd_adjust = get_opd_info (input_sec); 11232218822Sdim if (opd_adjust == NULL) 11233218822Sdim return TRUE; 11234218822Sdim 11235130561Sobrien value = elfsym->st_value - input_sec->output_offset; 11236130561Sobrien if (!info->relocatable) 11237130561Sobrien value -= input_sec->output_section->vma; 11238130561Sobrien 11239218822Sdim adjust = opd_adjust[value / 8]; 11240218822Sdim if (adjust == -1) 11241218822Sdim elfsym->st_value = 0; 11242218822Sdim else 11243218822Sdim elfsym->st_value += adjust; 11244130561Sobrien return TRUE; 11245130561Sobrien} 11246130561Sobrien 1124789857Sobrien/* Finish up dynamic symbol handling. We set the contents of various 1124889857Sobrien dynamic sections here. */ 1124989857Sobrien 11250130561Sobrienstatic bfd_boolean 11251130561Sobrienppc64_elf_finish_dynamic_symbol (bfd *output_bfd, 11252130561Sobrien struct bfd_link_info *info, 11253130561Sobrien struct elf_link_hash_entry *h, 11254130561Sobrien Elf_Internal_Sym *sym) 1125589857Sobrien{ 1125689857Sobrien struct ppc_link_hash_table *htab; 11257218822Sdim struct plt_entry *ent; 11258218822Sdim Elf_Internal_Rela rela; 11259218822Sdim bfd_byte *loc; 1126089857Sobrien 1126189857Sobrien htab = ppc_hash_table (info); 1126289857Sobrien 11263218822Sdim for (ent = h->plt.plist; ent != NULL; ent = ent->next) 11264218822Sdim if (ent->plt.offset != (bfd_vma) -1) 11265218822Sdim { 11266218822Sdim /* This symbol has an entry in the procedure linkage 11267218822Sdim table. Set it up. */ 1126889857Sobrien 11269218822Sdim if (htab->plt == NULL 11270218822Sdim || htab->relplt == NULL 11271218822Sdim || htab->glink == NULL) 11272218822Sdim abort (); 1127389857Sobrien 11274218822Sdim /* Create a JMP_SLOT reloc to inform the dynamic linker to 11275218822Sdim fill in the PLT entry. */ 11276218822Sdim rela.r_offset = (htab->plt->output_section->vma 11277218822Sdim + htab->plt->output_offset 11278218822Sdim + ent->plt.offset); 11279218822Sdim rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_JMP_SLOT); 11280218822Sdim rela.r_addend = ent->addend; 1128189857Sobrien 11282218822Sdim loc = htab->relplt->contents; 11283218822Sdim loc += ((ent->plt.offset - PLT_INITIAL_ENTRY_SIZE) / PLT_ENTRY_SIZE 11284218822Sdim * sizeof (Elf64_External_Rela)); 11285218822Sdim bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); 11286218822Sdim } 1128789857Sobrien 11288218822Sdim if (h->needs_copy) 1128989857Sobrien { 1129089857Sobrien Elf_Internal_Rela rela; 11291130561Sobrien bfd_byte *loc; 1129289857Sobrien 1129389857Sobrien /* This symbol needs a copy reloc. Set it up. */ 1129489857Sobrien 1129589857Sobrien if (h->dynindx == -1 1129689857Sobrien || (h->root.type != bfd_link_hash_defined 1129789857Sobrien && h->root.type != bfd_link_hash_defweak) 11298130561Sobrien || htab->relbss == NULL) 1129989857Sobrien abort (); 1130089857Sobrien 1130189857Sobrien rela.r_offset = (h->root.u.def.value 1130289857Sobrien + h->root.u.def.section->output_section->vma 1130389857Sobrien + h->root.u.def.section->output_offset); 1130489857Sobrien rela.r_info = ELF64_R_INFO (h->dynindx, R_PPC64_COPY); 1130589857Sobrien rela.r_addend = 0; 11306130561Sobrien loc = htab->relbss->contents; 11307130561Sobrien loc += htab->relbss->reloc_count++ * sizeof (Elf64_External_Rela); 1130889857Sobrien bfd_elf64_swap_reloca_out (output_bfd, &rela, loc); 1130989857Sobrien } 1131089857Sobrien 1131189857Sobrien /* Mark some specially defined symbols as absolute. */ 1131289857Sobrien if (strcmp (h->root.root.string, "_DYNAMIC") == 0) 1131389857Sobrien sym->st_shndx = SHN_ABS; 1131489857Sobrien 11315130561Sobrien return TRUE; 1131689857Sobrien} 1131789857Sobrien 1131889857Sobrien/* Used to decide how to sort relocs in an optimal manner for the 1131989857Sobrien dynamic linker, before writing them out. */ 1132089857Sobrien 1132189857Sobrienstatic enum elf_reloc_type_class 11322130561Sobrienppc64_elf_reloc_type_class (const Elf_Internal_Rela *rela) 1132389857Sobrien{ 11324130561Sobrien enum elf_ppc64_reloc_type r_type; 1132589857Sobrien 11326130561Sobrien r_type = ELF64_R_TYPE (rela->r_info); 1132789857Sobrien switch (r_type) 1132889857Sobrien { 1132989857Sobrien case R_PPC64_RELATIVE: 1133089857Sobrien return reloc_class_relative; 1133189857Sobrien case R_PPC64_JMP_SLOT: 1133289857Sobrien return reloc_class_plt; 1133389857Sobrien case R_PPC64_COPY: 1133489857Sobrien return reloc_class_copy; 1133589857Sobrien default: 1133689857Sobrien return reloc_class_normal; 1133789857Sobrien } 1133889857Sobrien} 1133989857Sobrien 1134089857Sobrien/* Finish up the dynamic sections. */ 1134189857Sobrien 11342130561Sobrienstatic bfd_boolean 11343130561Sobrienppc64_elf_finish_dynamic_sections (bfd *output_bfd, 11344130561Sobrien struct bfd_link_info *info) 1134589857Sobrien{ 1134689857Sobrien struct ppc_link_hash_table *htab; 1134789857Sobrien bfd *dynobj; 1134889857Sobrien asection *sdyn; 1134989857Sobrien 1135089857Sobrien htab = ppc_hash_table (info); 1135189857Sobrien dynobj = htab->elf.dynobj; 1135289857Sobrien sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); 1135389857Sobrien 1135489857Sobrien if (htab->elf.dynamic_sections_created) 1135589857Sobrien { 1135689857Sobrien Elf64_External_Dyn *dyncon, *dynconend; 1135789857Sobrien 11358130561Sobrien if (sdyn == NULL || htab->got == NULL) 1135989857Sobrien abort (); 1136089857Sobrien 1136189857Sobrien dyncon = (Elf64_External_Dyn *) sdyn->contents; 11362218822Sdim dynconend = (Elf64_External_Dyn *) (sdyn->contents + sdyn->size); 1136389857Sobrien for (; dyncon < dynconend; dyncon++) 1136489857Sobrien { 1136589857Sobrien Elf_Internal_Dyn dyn; 1136691041Sobrien asection *s; 1136789857Sobrien 1136889857Sobrien bfd_elf64_swap_dyn_in (dynobj, dyncon, &dyn); 1136989857Sobrien 1137089857Sobrien switch (dyn.d_tag) 1137189857Sobrien { 1137289857Sobrien default: 1137389857Sobrien continue; 1137489857Sobrien 1137589857Sobrien case DT_PPC64_GLINK: 11376130561Sobrien s = htab->glink; 11377130561Sobrien dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; 11378130561Sobrien /* We stupidly defined DT_PPC64_GLINK to be the start 11379130561Sobrien of glink rather than the first entry point, which is 11380130561Sobrien what ld.so needs, and now have a bigger stub to 11381130561Sobrien support automatic multiple TOCs. */ 11382130561Sobrien dyn.d_un.d_ptr += GLINK_CALL_STUB_SIZE - 32; 1138389857Sobrien break; 1138489857Sobrien 1138591041Sobrien case DT_PPC64_OPD: 1138691041Sobrien s = bfd_get_section_by_name (output_bfd, ".opd"); 11387130561Sobrien if (s == NULL) 11388130561Sobrien continue; 11389130561Sobrien dyn.d_un.d_ptr = s->vma; 1139091041Sobrien break; 1139191041Sobrien 1139291041Sobrien case DT_PPC64_OPDSZ: 1139391041Sobrien s = bfd_get_section_by_name (output_bfd, ".opd"); 11394130561Sobrien if (s == NULL) 11395130561Sobrien continue; 11396218822Sdim dyn.d_un.d_val = s->size; 1139791041Sobrien break; 1139891041Sobrien 1139989857Sobrien case DT_PLTGOT: 11400130561Sobrien s = htab->plt; 11401130561Sobrien dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; 1140289857Sobrien break; 1140389857Sobrien 1140489857Sobrien case DT_JMPREL: 11405130561Sobrien s = htab->relplt; 11406130561Sobrien dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; 1140789857Sobrien break; 1140889857Sobrien 1140989857Sobrien case DT_PLTRELSZ: 11410218822Sdim dyn.d_un.d_val = htab->relplt->size; 1141189857Sobrien break; 1141289857Sobrien 1141389857Sobrien case DT_RELASZ: 1141489857Sobrien /* Don't count procedure linkage table relocs in the 1141589857Sobrien overall reloc count. */ 11416130561Sobrien s = htab->relplt; 11417130561Sobrien if (s == NULL) 11418130561Sobrien continue; 11419218822Sdim dyn.d_un.d_val -= s->size; 1142089857Sobrien break; 11421130561Sobrien 11422130561Sobrien case DT_RELA: 11423130561Sobrien /* We may not be using the standard ELF linker script. 11424130561Sobrien If .rela.plt is the first .rela section, we adjust 11425130561Sobrien DT_RELA to not include it. */ 11426130561Sobrien s = htab->relplt; 11427130561Sobrien if (s == NULL) 11428130561Sobrien continue; 11429130561Sobrien if (dyn.d_un.d_ptr != s->output_section->vma + s->output_offset) 11430130561Sobrien continue; 11431218822Sdim dyn.d_un.d_ptr += s->size; 11432130561Sobrien break; 1143389857Sobrien } 1143489857Sobrien 1143589857Sobrien bfd_elf64_swap_dyn_out (output_bfd, &dyn, dyncon); 1143689857Sobrien } 1143789857Sobrien } 1143889857Sobrien 11439218822Sdim if (htab->got != NULL && htab->got->size != 0) 1144089857Sobrien { 1144189857Sobrien /* Fill in the first entry in the global offset table. 1144289857Sobrien We use it to hold the link-time TOCbase. */ 1144389857Sobrien bfd_put_64 (output_bfd, 1144489857Sobrien elf_gp (output_bfd) + TOC_BASE_OFF, 11445130561Sobrien htab->got->contents); 1144689857Sobrien 1144789857Sobrien /* Set .got entry size. */ 11448130561Sobrien elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 8; 1144989857Sobrien } 1145089857Sobrien 11451218822Sdim if (htab->plt != NULL && htab->plt->size != 0) 1145289857Sobrien { 1145389857Sobrien /* Set .plt entry size. */ 11454130561Sobrien elf_section_data (htab->plt->output_section)->this_hdr.sh_entsize 1145589857Sobrien = PLT_ENTRY_SIZE; 1145689857Sobrien } 1145789857Sobrien 11458218822Sdim /* brlt is SEC_LINKER_CREATED, so we need to write out relocs for 11459218822Sdim brlt ourselves if emitrelocations. */ 11460218822Sdim if (htab->brlt != NULL 11461218822Sdim && htab->brlt->reloc_count != 0 11462218822Sdim && !_bfd_elf_link_output_relocs (output_bfd, 11463218822Sdim htab->brlt, 11464218822Sdim &elf_section_data (htab->brlt)->rel_hdr, 11465218822Sdim elf_section_data (htab->brlt)->relocs, 11466218822Sdim NULL)) 11467218822Sdim return FALSE; 11468218822Sdim 11469130561Sobrien /* We need to handle writing out multiple GOT sections ourselves, 11470218822Sdim since we didn't add them to DYNOBJ. We know dynobj is the first 11471218822Sdim bfd. */ 11472130561Sobrien while ((dynobj = dynobj->link_next) != NULL) 11473130561Sobrien { 11474130561Sobrien asection *s; 11475209867Snwhitehorn 11476218822Sdim if (!is_ppc64_elf_target (dynobj->xvec)) 11477209867Snwhitehorn continue; 11478209867Snwhitehorn 11479130561Sobrien s = ppc64_elf_tdata (dynobj)->got; 11480130561Sobrien if (s != NULL 11481218822Sdim && s->size != 0 11482130561Sobrien && s->output_section != bfd_abs_section_ptr 11483130561Sobrien && !bfd_set_section_contents (output_bfd, s->output_section, 11484130561Sobrien s->contents, s->output_offset, 11485218822Sdim s->size)) 11486130561Sobrien return FALSE; 11487130561Sobrien s = ppc64_elf_tdata (dynobj)->relgot; 11488130561Sobrien if (s != NULL 11489218822Sdim && s->size != 0 11490130561Sobrien && s->output_section != bfd_abs_section_ptr 11491130561Sobrien && !bfd_set_section_contents (output_bfd, s->output_section, 11492130561Sobrien s->contents, s->output_offset, 11493218822Sdim s->size)) 11494130561Sobrien return FALSE; 11495130561Sobrien } 11496130561Sobrien 11497130561Sobrien return TRUE; 1149889857Sobrien} 1149989857Sobrien 1150089857Sobrien#include "elf64-target.h" 11501