160484Sobrien/* PowerPC-specific support for 32-bit ELF 2130561Sobrien Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 3218822Sdim 2004, 2005, 2006, 2007 Free Software Foundation, Inc. 460484Sobrien Written by Ian Lance Taylor, Cygnus Support. 560484Sobrien 6130561Sobrien This file is part of BFD, the Binary File Descriptor library. 760484Sobrien 8130561Sobrien This program is free software; you can redistribute it and/or modify 9130561Sobrien it under the terms of the GNU General Public License as published by 10130561Sobrien the Free Software Foundation; either version 2 of the License, or 11130561Sobrien (at your option) any later version. 1260484Sobrien 13130561Sobrien This program is distributed in the hope that it will be useful, 14130561Sobrien but WITHOUT ANY WARRANTY; without even the implied warranty of 15130561Sobrien MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16130561Sobrien GNU General Public License for more details. 1760484Sobrien 18130561Sobrien You should have received a copy of the GNU General Public License 19130561Sobrien along with this program; if not, write to the 20218822Sdim Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 21218822Sdim Boston, MA 02110-1301, USA. */ 2260484Sobrien 2360484Sobrien/* This file is based on a preliminary PowerPC ELF ABI. The 2460484Sobrien information may not match the final PowerPC ELF ABI. It includes 2560484Sobrien suggestions from the in-progress Embedded PowerPC ABI, and that 2660484Sobrien information may also not match. */ 2760484Sobrien 28218822Sdim#include "sysdep.h" 29218822Sdim#include <stdarg.h> 3060484Sobrien#include "bfd.h" 3160484Sobrien#include "bfdlink.h" 3260484Sobrien#include "libbfd.h" 3360484Sobrien#include "elf-bfd.h" 3460484Sobrien#include "elf/ppc.h" 35130561Sobrien#include "elf32-ppc.h" 36218822Sdim#include "elf-vxworks.h" 3760484Sobrien 38130561Sobrien/* RELA relocations are used here. */ 3960484Sobrien 4060484Sobrienstatic bfd_reloc_status_type ppc_elf_addr16_ha_reloc 41130561Sobrien (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 42130561Sobrienstatic bfd_reloc_status_type ppc_elf_unhandled_reloc 43130561Sobrien (bfd *, arelent *, asymbol *, void *, asection *, bfd *, char **); 4460484Sobrien 45130561Sobrien/* Branch prediction bit for branch taken relocs. */ 46130561Sobrien#define BRANCH_PREDICT_BIT 0x200000 47130561Sobrien/* Mask to set RA in memory instructions. */ 48130561Sobrien#define RA_REGISTER_MASK 0x001f0000 49130561Sobrien/* Value to shift register by to insert RA. */ 50130561Sobrien#define RA_REGISTER_SHIFT 16 5160484Sobrien 52130561Sobrien/* The name of the dynamic interpreter. This is put in the .interp 53130561Sobrien section. */ 54130561Sobrien#define ELF_DYNAMIC_INTERPRETER "/usr/lib/ld.so.1" 5560484Sobrien 56218822Sdim/* For old-style PLT. */ 57130561Sobrien/* The number of single-slot PLT entries (the rest use two slots). */ 58130561Sobrien#define PLT_NUM_SINGLE_ENTRIES 8192 5960484Sobrien 60218822Sdim/* For new-style .glink and .plt. */ 61218822Sdim#define GLINK_PLTRESOLVE 16*4 62218822Sdim#define GLINK_ENTRY_SIZE 4*4 6360484Sobrien 64218822Sdim/* VxWorks uses its own plt layout, filled in by the static linker. */ 6560484Sobrien 66218822Sdim/* The standard VxWorks PLT entry. */ 67218822Sdim#define VXWORKS_PLT_ENTRY_SIZE 32 68218822Sdimstatic const bfd_vma ppc_elf_vxworks_plt_entry 69218822Sdim [VXWORKS_PLT_ENTRY_SIZE / 4] = 70218822Sdim { 71218822Sdim 0x3d800000, /* lis r12,0 */ 72218822Sdim 0x818c0000, /* lwz r12,0(r12) */ 73218822Sdim 0x7d8903a6, /* mtctr r12 */ 74218822Sdim 0x4e800420, /* bctr */ 75218822Sdim 0x39600000, /* li r11,0 */ 76218822Sdim 0x48000000, /* b 14 <.PLT0resolve+0x4> */ 77218822Sdim 0x60000000, /* nop */ 78218822Sdim 0x60000000, /* nop */ 79218822Sdim }; 80218822Sdimstatic const bfd_vma ppc_elf_vxworks_pic_plt_entry 81218822Sdim [VXWORKS_PLT_ENTRY_SIZE / 4] = 82218822Sdim { 83218822Sdim 0x3d9e0000, /* addis r12,r30,0 */ 84218822Sdim 0x818c0000, /* lwz r12,0(r12) */ 85218822Sdim 0x7d8903a6, /* mtctr r12 */ 86218822Sdim 0x4e800420, /* bctr */ 87218822Sdim 0x39600000, /* li r11,0 */ 88218822Sdim 0x48000000, /* b 14 <.PLT0resolve+0x4> 14: R_PPC_REL24 .PLTresolve */ 89218822Sdim 0x60000000, /* nop */ 90218822Sdim 0x60000000, /* nop */ 91218822Sdim }; 9260484Sobrien 93218822Sdim/* The initial VxWorks PLT entry. */ 94218822Sdim#define VXWORKS_PLT_INITIAL_ENTRY_SIZE 32 95218822Sdimstatic const bfd_vma ppc_elf_vxworks_plt0_entry 96218822Sdim [VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] = 97218822Sdim { 98218822Sdim 0x3d800000, /* lis r12,0 */ 99218822Sdim 0x398c0000, /* addi r12,r12,0 */ 100218822Sdim 0x800c0008, /* lwz r0,8(r12) */ 101218822Sdim 0x7c0903a6, /* mtctr r0 */ 102218822Sdim 0x818c0004, /* lwz r12,4(r12) */ 103218822Sdim 0x4e800420, /* bctr */ 104218822Sdim 0x60000000, /* nop */ 105218822Sdim 0x60000000, /* nop */ 106218822Sdim }; 107218822Sdimstatic const bfd_vma ppc_elf_vxworks_pic_plt0_entry 108218822Sdim [VXWORKS_PLT_INITIAL_ENTRY_SIZE / 4] = 109218822Sdim { 110218822Sdim 0x819e0008, /* lwz r12,8(r30) */ 111218822Sdim 0x7d8903a6, /* mtctr r12 */ 112218822Sdim 0x819e0004, /* lwz r12,4(r30) */ 113218822Sdim 0x4e800420, /* bctr */ 114218822Sdim 0x60000000, /* nop */ 115218822Sdim 0x60000000, /* nop */ 116218822Sdim 0x60000000, /* nop */ 117218822Sdim 0x60000000, /* nop */ 118218822Sdim }; 11960484Sobrien 120218822Sdim/* For executables, we have some additional relocations in 121218822Sdim .rela.plt.unloaded, for the kernel loader. */ 12260484Sobrien 123218822Sdim/* The number of non-JMP_SLOT relocations per PLT0 slot. */ 124218822Sdim#define VXWORKS_PLT_NON_JMP_SLOT_RELOCS 3 125218822Sdim/* The number of relocations in the PLTResolve slot. */ 126218822Sdim#define VXWORKS_PLTRESOLVE_RELOCS 2 127218822Sdim/* The number of relocations in the PLTResolve slot when when creating 128218822Sdim a shared library. */ 129218822Sdim#define VXWORKS_PLTRESOLVE_RELOCS_SHLIB 0 13060484Sobrien 131218822Sdim/* Some instructions. */ 132218822Sdim#define ADDIS_11_11 0x3d6b0000 133218822Sdim#define ADDIS_11_30 0x3d7e0000 134218822Sdim#define ADDIS_12_12 0x3d8c0000 135218822Sdim#define ADDI_11_11 0x396b0000 136218822Sdim#define ADD_0_11_11 0x7c0b5a14 137218822Sdim#define ADD_11_0_11 0x7d605a14 138218822Sdim#define B 0x48000000 139218822Sdim#define BCL_20_31 0x429f0005 140218822Sdim#define BCTR 0x4e800420 141218822Sdim#define LIS_11 0x3d600000 142218822Sdim#define LIS_12 0x3d800000 143218822Sdim#define LWZU_0_12 0x840c0000 144218822Sdim#define LWZ_0_12 0x800c0000 145218822Sdim#define LWZ_11_11 0x816b0000 146218822Sdim#define LWZ_11_30 0x817e0000 147218822Sdim#define LWZ_12_12 0x818c0000 148218822Sdim#define MFLR_0 0x7c0802a6 149218822Sdim#define MFLR_12 0x7d8802a6 150218822Sdim#define MTCTR_0 0x7c0903a6 151218822Sdim#define MTCTR_11 0x7d6903a6 152218822Sdim#define MTLR_0 0x7c0803a6 153218822Sdim#define NOP 0x60000000 154218822Sdim#define SUB_11_11_12 0x7d6c5850 15560484Sobrien 156218822Sdim/* Offset of tp and dtp pointers from start of TLS block. */ 157218822Sdim#define TP_OFFSET 0x7000 158218822Sdim#define DTP_OFFSET 0x8000 15960484Sobrien 160130561Sobrienstatic reloc_howto_type *ppc_elf_howto_table[R_PPC_max]; 16160484Sobrien 16277298Sobrienstatic reloc_howto_type ppc_elf_howto_raw[] = { 16360484Sobrien /* This reloc does nothing. */ 16460484Sobrien HOWTO (R_PPC_NONE, /* type */ 16560484Sobrien 0, /* rightshift */ 16660484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 16760484Sobrien 32, /* bitsize */ 168130561Sobrien FALSE, /* pc_relative */ 16960484Sobrien 0, /* bitpos */ 17060484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 17160484Sobrien bfd_elf_generic_reloc, /* special_function */ 17260484Sobrien "R_PPC_NONE", /* name */ 173130561Sobrien FALSE, /* partial_inplace */ 17460484Sobrien 0, /* src_mask */ 17560484Sobrien 0, /* dst_mask */ 176130561Sobrien FALSE), /* pcrel_offset */ 17760484Sobrien 17860484Sobrien /* A standard 32 bit relocation. */ 17960484Sobrien HOWTO (R_PPC_ADDR32, /* type */ 18060484Sobrien 0, /* rightshift */ 18160484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 18260484Sobrien 32, /* bitsize */ 183130561Sobrien FALSE, /* pc_relative */ 18460484Sobrien 0, /* bitpos */ 18560484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 18660484Sobrien bfd_elf_generic_reloc, /* special_function */ 18760484Sobrien "R_PPC_ADDR32", /* name */ 188130561Sobrien FALSE, /* partial_inplace */ 18960484Sobrien 0, /* src_mask */ 19060484Sobrien 0xffffffff, /* dst_mask */ 191130561Sobrien FALSE), /* pcrel_offset */ 19260484Sobrien 19360484Sobrien /* An absolute 26 bit branch; the lower two bits must be zero. 19460484Sobrien FIXME: we don't check that, we just clear them. */ 19560484Sobrien HOWTO (R_PPC_ADDR24, /* type */ 19660484Sobrien 0, /* rightshift */ 19760484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 19860484Sobrien 26, /* bitsize */ 199130561Sobrien FALSE, /* pc_relative */ 20060484Sobrien 0, /* bitpos */ 20160484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 20260484Sobrien bfd_elf_generic_reloc, /* special_function */ 20360484Sobrien "R_PPC_ADDR24", /* name */ 204130561Sobrien FALSE, /* partial_inplace */ 20560484Sobrien 0, /* src_mask */ 20660484Sobrien 0x3fffffc, /* dst_mask */ 207130561Sobrien FALSE), /* pcrel_offset */ 20860484Sobrien 20960484Sobrien /* A standard 16 bit relocation. */ 21060484Sobrien HOWTO (R_PPC_ADDR16, /* type */ 21160484Sobrien 0, /* rightshift */ 21260484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 21360484Sobrien 16, /* bitsize */ 214130561Sobrien FALSE, /* pc_relative */ 21560484Sobrien 0, /* bitpos */ 21660484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 21760484Sobrien bfd_elf_generic_reloc, /* special_function */ 21860484Sobrien "R_PPC_ADDR16", /* name */ 219130561Sobrien FALSE, /* partial_inplace */ 22060484Sobrien 0, /* src_mask */ 22160484Sobrien 0xffff, /* dst_mask */ 222130561Sobrien FALSE), /* pcrel_offset */ 22360484Sobrien 22460484Sobrien /* A 16 bit relocation without overflow. */ 22560484Sobrien HOWTO (R_PPC_ADDR16_LO, /* type */ 22660484Sobrien 0, /* rightshift */ 22760484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 22860484Sobrien 16, /* bitsize */ 229130561Sobrien FALSE, /* pc_relative */ 23060484Sobrien 0, /* bitpos */ 23160484Sobrien complain_overflow_dont,/* complain_on_overflow */ 23260484Sobrien bfd_elf_generic_reloc, /* special_function */ 23360484Sobrien "R_PPC_ADDR16_LO", /* name */ 234130561Sobrien FALSE, /* partial_inplace */ 23560484Sobrien 0, /* src_mask */ 23660484Sobrien 0xffff, /* dst_mask */ 237130561Sobrien FALSE), /* pcrel_offset */ 23860484Sobrien 23960484Sobrien /* The high order 16 bits of an address. */ 24060484Sobrien HOWTO (R_PPC_ADDR16_HI, /* type */ 24160484Sobrien 16, /* rightshift */ 24260484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 24360484Sobrien 16, /* bitsize */ 244130561Sobrien FALSE, /* pc_relative */ 24560484Sobrien 0, /* bitpos */ 24660484Sobrien complain_overflow_dont, /* complain_on_overflow */ 24760484Sobrien bfd_elf_generic_reloc, /* special_function */ 24860484Sobrien "R_PPC_ADDR16_HI", /* name */ 249130561Sobrien FALSE, /* partial_inplace */ 25060484Sobrien 0, /* src_mask */ 25160484Sobrien 0xffff, /* dst_mask */ 252130561Sobrien FALSE), /* pcrel_offset */ 25360484Sobrien 25460484Sobrien /* The high order 16 bits of an address, plus 1 if the contents of 25577298Sobrien the low 16 bits, treated as a signed number, is negative. */ 25660484Sobrien HOWTO (R_PPC_ADDR16_HA, /* type */ 25760484Sobrien 16, /* rightshift */ 25860484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 25960484Sobrien 16, /* bitsize */ 260130561Sobrien FALSE, /* pc_relative */ 26160484Sobrien 0, /* bitpos */ 26260484Sobrien complain_overflow_dont, /* complain_on_overflow */ 26360484Sobrien ppc_elf_addr16_ha_reloc, /* special_function */ 26460484Sobrien "R_PPC_ADDR16_HA", /* name */ 265130561Sobrien FALSE, /* partial_inplace */ 26660484Sobrien 0, /* src_mask */ 26760484Sobrien 0xffff, /* dst_mask */ 268130561Sobrien FALSE), /* pcrel_offset */ 26960484Sobrien 27060484Sobrien /* An absolute 16 bit branch; the lower two bits must be zero. 27160484Sobrien FIXME: we don't check that, we just clear them. */ 27260484Sobrien HOWTO (R_PPC_ADDR14, /* type */ 27360484Sobrien 0, /* rightshift */ 27460484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 27560484Sobrien 16, /* bitsize */ 276130561Sobrien FALSE, /* pc_relative */ 27760484Sobrien 0, /* bitpos */ 27860484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 27960484Sobrien bfd_elf_generic_reloc, /* special_function */ 28060484Sobrien "R_PPC_ADDR14", /* name */ 281130561Sobrien FALSE, /* partial_inplace */ 28260484Sobrien 0, /* src_mask */ 28360484Sobrien 0xfffc, /* dst_mask */ 284130561Sobrien FALSE), /* pcrel_offset */ 28560484Sobrien 28660484Sobrien /* An absolute 16 bit branch, for which bit 10 should be set to 28760484Sobrien indicate that the branch is expected to be taken. The lower two 28877298Sobrien bits must be zero. */ 28960484Sobrien HOWTO (R_PPC_ADDR14_BRTAKEN, /* type */ 29060484Sobrien 0, /* rightshift */ 29160484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 29260484Sobrien 16, /* bitsize */ 293130561Sobrien FALSE, /* pc_relative */ 29460484Sobrien 0, /* bitpos */ 29560484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 29660484Sobrien bfd_elf_generic_reloc, /* special_function */ 29760484Sobrien "R_PPC_ADDR14_BRTAKEN",/* name */ 298130561Sobrien FALSE, /* partial_inplace */ 29960484Sobrien 0, /* src_mask */ 30060484Sobrien 0xfffc, /* dst_mask */ 301130561Sobrien FALSE), /* pcrel_offset */ 30260484Sobrien 30360484Sobrien /* An absolute 16 bit branch, for which bit 10 should be set to 30460484Sobrien indicate that the branch is not expected to be taken. The lower 30560484Sobrien two bits must be zero. */ 30660484Sobrien HOWTO (R_PPC_ADDR14_BRNTAKEN, /* type */ 30760484Sobrien 0, /* rightshift */ 30860484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 30960484Sobrien 16, /* bitsize */ 310130561Sobrien FALSE, /* pc_relative */ 31160484Sobrien 0, /* bitpos */ 31260484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 31360484Sobrien bfd_elf_generic_reloc, /* special_function */ 31460484Sobrien "R_PPC_ADDR14_BRNTAKEN",/* name */ 315130561Sobrien FALSE, /* partial_inplace */ 31660484Sobrien 0, /* src_mask */ 31760484Sobrien 0xfffc, /* dst_mask */ 318130561Sobrien FALSE), /* pcrel_offset */ 31960484Sobrien 32077298Sobrien /* A relative 26 bit branch; the lower two bits must be zero. */ 32160484Sobrien HOWTO (R_PPC_REL24, /* type */ 32260484Sobrien 0, /* rightshift */ 32360484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 32460484Sobrien 26, /* bitsize */ 325130561Sobrien TRUE, /* pc_relative */ 32660484Sobrien 0, /* bitpos */ 32760484Sobrien complain_overflow_signed, /* complain_on_overflow */ 32860484Sobrien bfd_elf_generic_reloc, /* special_function */ 32960484Sobrien "R_PPC_REL24", /* name */ 330130561Sobrien FALSE, /* partial_inplace */ 33160484Sobrien 0, /* src_mask */ 33260484Sobrien 0x3fffffc, /* dst_mask */ 333130561Sobrien TRUE), /* pcrel_offset */ 33460484Sobrien 33577298Sobrien /* A relative 16 bit branch; the lower two bits must be zero. */ 33660484Sobrien HOWTO (R_PPC_REL14, /* type */ 33760484Sobrien 0, /* rightshift */ 33860484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 33960484Sobrien 16, /* bitsize */ 340130561Sobrien TRUE, /* pc_relative */ 34160484Sobrien 0, /* bitpos */ 34260484Sobrien complain_overflow_signed, /* complain_on_overflow */ 34360484Sobrien bfd_elf_generic_reloc, /* special_function */ 34460484Sobrien "R_PPC_REL14", /* name */ 345130561Sobrien FALSE, /* partial_inplace */ 34660484Sobrien 0, /* src_mask */ 34760484Sobrien 0xfffc, /* dst_mask */ 348130561Sobrien TRUE), /* pcrel_offset */ 34960484Sobrien 35077298Sobrien /* A relative 16 bit branch. Bit 10 should be set to indicate that 35160484Sobrien the branch is expected to be taken. The lower two bits must be 35260484Sobrien zero. */ 35360484Sobrien HOWTO (R_PPC_REL14_BRTAKEN, /* type */ 35460484Sobrien 0, /* rightshift */ 35560484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 35660484Sobrien 16, /* bitsize */ 357130561Sobrien TRUE, /* pc_relative */ 35860484Sobrien 0, /* bitpos */ 35960484Sobrien complain_overflow_signed, /* complain_on_overflow */ 36060484Sobrien bfd_elf_generic_reloc, /* special_function */ 36160484Sobrien "R_PPC_REL14_BRTAKEN", /* name */ 362130561Sobrien FALSE, /* partial_inplace */ 36360484Sobrien 0, /* src_mask */ 36460484Sobrien 0xfffc, /* dst_mask */ 365130561Sobrien TRUE), /* pcrel_offset */ 36660484Sobrien 36777298Sobrien /* A relative 16 bit branch. Bit 10 should be set to indicate that 36860484Sobrien the branch is not expected to be taken. The lower two bits must 36960484Sobrien be zero. */ 37060484Sobrien HOWTO (R_PPC_REL14_BRNTAKEN, /* type */ 37160484Sobrien 0, /* rightshift */ 37260484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 37360484Sobrien 16, /* bitsize */ 374130561Sobrien TRUE, /* pc_relative */ 37560484Sobrien 0, /* bitpos */ 37660484Sobrien complain_overflow_signed, /* complain_on_overflow */ 37760484Sobrien bfd_elf_generic_reloc, /* special_function */ 37860484Sobrien "R_PPC_REL14_BRNTAKEN",/* name */ 379130561Sobrien FALSE, /* partial_inplace */ 38060484Sobrien 0, /* src_mask */ 38160484Sobrien 0xfffc, /* dst_mask */ 382130561Sobrien TRUE), /* pcrel_offset */ 38360484Sobrien 38460484Sobrien /* Like R_PPC_ADDR16, but referring to the GOT table entry for the 38560484Sobrien symbol. */ 38660484Sobrien HOWTO (R_PPC_GOT16, /* type */ 38760484Sobrien 0, /* rightshift */ 38860484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 38960484Sobrien 16, /* bitsize */ 390130561Sobrien FALSE, /* pc_relative */ 39160484Sobrien 0, /* bitpos */ 39260484Sobrien complain_overflow_signed, /* complain_on_overflow */ 39360484Sobrien bfd_elf_generic_reloc, /* special_function */ 39460484Sobrien "R_PPC_GOT16", /* name */ 395130561Sobrien FALSE, /* partial_inplace */ 39660484Sobrien 0, /* src_mask */ 39760484Sobrien 0xffff, /* dst_mask */ 398130561Sobrien FALSE), /* pcrel_offset */ 39960484Sobrien 40060484Sobrien /* Like R_PPC_ADDR16_LO, but referring to the GOT table entry for 40160484Sobrien the symbol. */ 40260484Sobrien HOWTO (R_PPC_GOT16_LO, /* type */ 40360484Sobrien 0, /* rightshift */ 40460484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 40560484Sobrien 16, /* bitsize */ 406130561Sobrien FALSE, /* pc_relative */ 40760484Sobrien 0, /* bitpos */ 40860484Sobrien complain_overflow_dont, /* complain_on_overflow */ 40960484Sobrien bfd_elf_generic_reloc, /* special_function */ 41060484Sobrien "R_PPC_GOT16_LO", /* name */ 411130561Sobrien FALSE, /* partial_inplace */ 41260484Sobrien 0, /* src_mask */ 41360484Sobrien 0xffff, /* dst_mask */ 414130561Sobrien FALSE), /* pcrel_offset */ 41560484Sobrien 41660484Sobrien /* Like R_PPC_ADDR16_HI, but referring to the GOT table entry for 41760484Sobrien the symbol. */ 41860484Sobrien HOWTO (R_PPC_GOT16_HI, /* type */ 41960484Sobrien 16, /* rightshift */ 42060484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 42160484Sobrien 16, /* bitsize */ 422130561Sobrien FALSE, /* pc_relative */ 42360484Sobrien 0, /* bitpos */ 42460484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 42560484Sobrien bfd_elf_generic_reloc, /* special_function */ 42660484Sobrien "R_PPC_GOT16_HI", /* name */ 427130561Sobrien FALSE, /* partial_inplace */ 42860484Sobrien 0, /* src_mask */ 42960484Sobrien 0xffff, /* dst_mask */ 430130561Sobrien FALSE), /* pcrel_offset */ 43160484Sobrien 43260484Sobrien /* Like R_PPC_ADDR16_HA, but referring to the GOT table entry for 43360484Sobrien the symbol. */ 43460484Sobrien HOWTO (R_PPC_GOT16_HA, /* type */ 43560484Sobrien 16, /* rightshift */ 43660484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 43760484Sobrien 16, /* bitsize */ 438130561Sobrien FALSE, /* pc_relative */ 43960484Sobrien 0, /* bitpos */ 44060484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 44160484Sobrien ppc_elf_addr16_ha_reloc, /* special_function */ 44260484Sobrien "R_PPC_GOT16_HA", /* name */ 443130561Sobrien FALSE, /* partial_inplace */ 44460484Sobrien 0, /* src_mask */ 44560484Sobrien 0xffff, /* dst_mask */ 446130561Sobrien FALSE), /* pcrel_offset */ 44760484Sobrien 44860484Sobrien /* Like R_PPC_REL24, but referring to the procedure linkage table 44960484Sobrien entry for the symbol. */ 45060484Sobrien HOWTO (R_PPC_PLTREL24, /* type */ 45160484Sobrien 0, /* rightshift */ 45260484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 45360484Sobrien 26, /* bitsize */ 454130561Sobrien TRUE, /* pc_relative */ 45560484Sobrien 0, /* bitpos */ 45660484Sobrien complain_overflow_signed, /* complain_on_overflow */ 45760484Sobrien bfd_elf_generic_reloc, /* special_function */ 45860484Sobrien "R_PPC_PLTREL24", /* name */ 459130561Sobrien FALSE, /* partial_inplace */ 46060484Sobrien 0, /* src_mask */ 46160484Sobrien 0x3fffffc, /* dst_mask */ 462130561Sobrien TRUE), /* pcrel_offset */ 46360484Sobrien 46460484Sobrien /* This is used only by the dynamic linker. The symbol should exist 46560484Sobrien both in the object being run and in some shared library. The 46660484Sobrien dynamic linker copies the data addressed by the symbol from the 46760484Sobrien shared library into the object, because the object being 46860484Sobrien run has to have the data at some particular address. */ 46960484Sobrien HOWTO (R_PPC_COPY, /* type */ 47060484Sobrien 0, /* rightshift */ 47160484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 47260484Sobrien 32, /* bitsize */ 473130561Sobrien FALSE, /* pc_relative */ 47460484Sobrien 0, /* bitpos */ 47560484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 47660484Sobrien bfd_elf_generic_reloc, /* special_function */ 47760484Sobrien "R_PPC_COPY", /* name */ 478130561Sobrien FALSE, /* partial_inplace */ 47960484Sobrien 0, /* src_mask */ 48060484Sobrien 0, /* dst_mask */ 481130561Sobrien FALSE), /* pcrel_offset */ 48260484Sobrien 48360484Sobrien /* Like R_PPC_ADDR32, but used when setting global offset table 48460484Sobrien entries. */ 48560484Sobrien HOWTO (R_PPC_GLOB_DAT, /* type */ 48660484Sobrien 0, /* rightshift */ 48760484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 48860484Sobrien 32, /* bitsize */ 489130561Sobrien FALSE, /* pc_relative */ 49060484Sobrien 0, /* bitpos */ 49160484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 49260484Sobrien bfd_elf_generic_reloc, /* special_function */ 49360484Sobrien "R_PPC_GLOB_DAT", /* name */ 494130561Sobrien FALSE, /* partial_inplace */ 49560484Sobrien 0, /* src_mask */ 49660484Sobrien 0xffffffff, /* dst_mask */ 497130561Sobrien FALSE), /* pcrel_offset */ 49860484Sobrien 49960484Sobrien /* Marks a procedure linkage table entry for a symbol. */ 50060484Sobrien HOWTO (R_PPC_JMP_SLOT, /* type */ 50160484Sobrien 0, /* rightshift */ 50260484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 50360484Sobrien 32, /* bitsize */ 504130561Sobrien FALSE, /* pc_relative */ 50560484Sobrien 0, /* bitpos */ 50660484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 50760484Sobrien bfd_elf_generic_reloc, /* special_function */ 50860484Sobrien "R_PPC_JMP_SLOT", /* name */ 509130561Sobrien FALSE, /* partial_inplace */ 51060484Sobrien 0, /* src_mask */ 51160484Sobrien 0, /* dst_mask */ 512130561Sobrien FALSE), /* pcrel_offset */ 51360484Sobrien 51460484Sobrien /* Used only by the dynamic linker. When the object is run, this 51560484Sobrien longword is set to the load address of the object, plus the 51660484Sobrien addend. */ 51760484Sobrien HOWTO (R_PPC_RELATIVE, /* type */ 51860484Sobrien 0, /* rightshift */ 51960484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 52060484Sobrien 32, /* bitsize */ 521130561Sobrien FALSE, /* pc_relative */ 52260484Sobrien 0, /* bitpos */ 52360484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 52460484Sobrien bfd_elf_generic_reloc, /* special_function */ 52560484Sobrien "R_PPC_RELATIVE", /* name */ 526130561Sobrien FALSE, /* partial_inplace */ 52760484Sobrien 0, /* src_mask */ 52860484Sobrien 0xffffffff, /* dst_mask */ 529130561Sobrien FALSE), /* pcrel_offset */ 53060484Sobrien 53160484Sobrien /* Like R_PPC_REL24, but uses the value of the symbol within the 53260484Sobrien object rather than the final value. Normally used for 53360484Sobrien _GLOBAL_OFFSET_TABLE_. */ 53460484Sobrien HOWTO (R_PPC_LOCAL24PC, /* type */ 53560484Sobrien 0, /* rightshift */ 53660484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 53760484Sobrien 26, /* bitsize */ 538130561Sobrien TRUE, /* pc_relative */ 53960484Sobrien 0, /* bitpos */ 54060484Sobrien complain_overflow_signed, /* complain_on_overflow */ 54160484Sobrien bfd_elf_generic_reloc, /* special_function */ 54260484Sobrien "R_PPC_LOCAL24PC", /* name */ 543130561Sobrien FALSE, /* partial_inplace */ 54460484Sobrien 0, /* src_mask */ 54560484Sobrien 0x3fffffc, /* dst_mask */ 546130561Sobrien TRUE), /* pcrel_offset */ 54760484Sobrien 54860484Sobrien /* Like R_PPC_ADDR32, but may be unaligned. */ 54960484Sobrien HOWTO (R_PPC_UADDR32, /* type */ 55060484Sobrien 0, /* rightshift */ 55160484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 55260484Sobrien 32, /* bitsize */ 553130561Sobrien FALSE, /* pc_relative */ 55460484Sobrien 0, /* bitpos */ 55560484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 55660484Sobrien bfd_elf_generic_reloc, /* special_function */ 55760484Sobrien "R_PPC_UADDR32", /* name */ 558130561Sobrien FALSE, /* partial_inplace */ 55960484Sobrien 0, /* src_mask */ 56060484Sobrien 0xffffffff, /* dst_mask */ 561130561Sobrien FALSE), /* pcrel_offset */ 56260484Sobrien 56360484Sobrien /* Like R_PPC_ADDR16, but may be unaligned. */ 56460484Sobrien HOWTO (R_PPC_UADDR16, /* type */ 56560484Sobrien 0, /* rightshift */ 56660484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 56760484Sobrien 16, /* bitsize */ 568130561Sobrien FALSE, /* pc_relative */ 56960484Sobrien 0, /* bitpos */ 57060484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 57160484Sobrien bfd_elf_generic_reloc, /* special_function */ 57260484Sobrien "R_PPC_UADDR16", /* name */ 573130561Sobrien FALSE, /* partial_inplace */ 57460484Sobrien 0, /* src_mask */ 57560484Sobrien 0xffff, /* dst_mask */ 576130561Sobrien FALSE), /* pcrel_offset */ 57760484Sobrien 57860484Sobrien /* 32-bit PC relative */ 57960484Sobrien HOWTO (R_PPC_REL32, /* type */ 58060484Sobrien 0, /* rightshift */ 58160484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 58260484Sobrien 32, /* bitsize */ 583130561Sobrien TRUE, /* pc_relative */ 58460484Sobrien 0, /* bitpos */ 58560484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 58660484Sobrien bfd_elf_generic_reloc, /* special_function */ 58760484Sobrien "R_PPC_REL32", /* name */ 588130561Sobrien FALSE, /* partial_inplace */ 58960484Sobrien 0, /* src_mask */ 59060484Sobrien 0xffffffff, /* dst_mask */ 591130561Sobrien TRUE), /* pcrel_offset */ 59260484Sobrien 59360484Sobrien /* 32-bit relocation to the symbol's procedure linkage table. 59477298Sobrien FIXME: not supported. */ 59560484Sobrien HOWTO (R_PPC_PLT32, /* type */ 59660484Sobrien 0, /* rightshift */ 59760484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 59860484Sobrien 32, /* bitsize */ 599130561Sobrien FALSE, /* pc_relative */ 60060484Sobrien 0, /* bitpos */ 60160484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 60260484Sobrien bfd_elf_generic_reloc, /* special_function */ 60360484Sobrien "R_PPC_PLT32", /* name */ 604130561Sobrien FALSE, /* partial_inplace */ 60560484Sobrien 0, /* src_mask */ 60660484Sobrien 0, /* dst_mask */ 607130561Sobrien FALSE), /* pcrel_offset */ 60860484Sobrien 60960484Sobrien /* 32-bit PC relative relocation to the symbol's procedure linkage table. 61077298Sobrien FIXME: not supported. */ 61160484Sobrien HOWTO (R_PPC_PLTREL32, /* type */ 61260484Sobrien 0, /* rightshift */ 61360484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 61460484Sobrien 32, /* bitsize */ 615130561Sobrien TRUE, /* pc_relative */ 61660484Sobrien 0, /* bitpos */ 61760484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 61860484Sobrien bfd_elf_generic_reloc, /* special_function */ 61960484Sobrien "R_PPC_PLTREL32", /* name */ 620130561Sobrien FALSE, /* partial_inplace */ 62160484Sobrien 0, /* src_mask */ 62260484Sobrien 0, /* dst_mask */ 623130561Sobrien TRUE), /* pcrel_offset */ 62460484Sobrien 62560484Sobrien /* Like R_PPC_ADDR16_LO, but referring to the PLT table entry for 62660484Sobrien the symbol. */ 62760484Sobrien HOWTO (R_PPC_PLT16_LO, /* type */ 62860484Sobrien 0, /* rightshift */ 62960484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 63060484Sobrien 16, /* bitsize */ 631130561Sobrien FALSE, /* pc_relative */ 63260484Sobrien 0, /* bitpos */ 63360484Sobrien complain_overflow_dont, /* complain_on_overflow */ 63460484Sobrien bfd_elf_generic_reloc, /* special_function */ 63560484Sobrien "R_PPC_PLT16_LO", /* name */ 636130561Sobrien FALSE, /* partial_inplace */ 63760484Sobrien 0, /* src_mask */ 63860484Sobrien 0xffff, /* dst_mask */ 639130561Sobrien FALSE), /* pcrel_offset */ 64060484Sobrien 64160484Sobrien /* Like R_PPC_ADDR16_HI, but referring to the PLT table entry for 64260484Sobrien the symbol. */ 64360484Sobrien HOWTO (R_PPC_PLT16_HI, /* type */ 64460484Sobrien 16, /* rightshift */ 64560484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 64660484Sobrien 16, /* bitsize */ 647130561Sobrien FALSE, /* pc_relative */ 64860484Sobrien 0, /* bitpos */ 64960484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 65060484Sobrien bfd_elf_generic_reloc, /* special_function */ 65160484Sobrien "R_PPC_PLT16_HI", /* name */ 652130561Sobrien FALSE, /* partial_inplace */ 65360484Sobrien 0, /* src_mask */ 65460484Sobrien 0xffff, /* dst_mask */ 655130561Sobrien FALSE), /* pcrel_offset */ 65660484Sobrien 65760484Sobrien /* Like R_PPC_ADDR16_HA, but referring to the PLT table entry for 65860484Sobrien the symbol. */ 65960484Sobrien HOWTO (R_PPC_PLT16_HA, /* type */ 66060484Sobrien 16, /* rightshift */ 66160484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 66260484Sobrien 16, /* bitsize */ 663130561Sobrien FALSE, /* pc_relative */ 66460484Sobrien 0, /* bitpos */ 66560484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 66660484Sobrien ppc_elf_addr16_ha_reloc, /* special_function */ 66760484Sobrien "R_PPC_PLT16_HA", /* name */ 668130561Sobrien FALSE, /* partial_inplace */ 66960484Sobrien 0, /* src_mask */ 67060484Sobrien 0xffff, /* dst_mask */ 671130561Sobrien FALSE), /* pcrel_offset */ 67260484Sobrien 67360484Sobrien /* A sign-extended 16 bit value relative to _SDA_BASE_, for use with 67460484Sobrien small data items. */ 67560484Sobrien HOWTO (R_PPC_SDAREL16, /* type */ 67660484Sobrien 0, /* rightshift */ 67760484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 67860484Sobrien 16, /* bitsize */ 679130561Sobrien FALSE, /* pc_relative */ 68060484Sobrien 0, /* bitpos */ 68160484Sobrien complain_overflow_signed, /* complain_on_overflow */ 68260484Sobrien bfd_elf_generic_reloc, /* special_function */ 68360484Sobrien "R_PPC_SDAREL16", /* name */ 684130561Sobrien FALSE, /* partial_inplace */ 68560484Sobrien 0, /* src_mask */ 68660484Sobrien 0xffff, /* dst_mask */ 687130561Sobrien FALSE), /* pcrel_offset */ 68860484Sobrien 68999461Sobrien /* 16-bit section relative relocation. */ 69060484Sobrien HOWTO (R_PPC_SECTOFF, /* type */ 69160484Sobrien 0, /* rightshift */ 69299461Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 69399461Sobrien 16, /* bitsize */ 694130561Sobrien FALSE, /* pc_relative */ 69560484Sobrien 0, /* bitpos */ 69660484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 69760484Sobrien bfd_elf_generic_reloc, /* special_function */ 69860484Sobrien "R_PPC_SECTOFF", /* name */ 699130561Sobrien FALSE, /* partial_inplace */ 70060484Sobrien 0, /* src_mask */ 70199461Sobrien 0xffff, /* dst_mask */ 702130561Sobrien FALSE), /* pcrel_offset */ 70360484Sobrien 70477298Sobrien /* 16-bit lower half section relative relocation. */ 70560484Sobrien HOWTO (R_PPC_SECTOFF_LO, /* type */ 70660484Sobrien 0, /* rightshift */ 70760484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 70860484Sobrien 16, /* bitsize */ 709130561Sobrien FALSE, /* pc_relative */ 71060484Sobrien 0, /* bitpos */ 71160484Sobrien complain_overflow_dont, /* complain_on_overflow */ 71260484Sobrien bfd_elf_generic_reloc, /* special_function */ 71360484Sobrien "R_PPC_SECTOFF_LO", /* name */ 714130561Sobrien FALSE, /* partial_inplace */ 71560484Sobrien 0, /* src_mask */ 71660484Sobrien 0xffff, /* dst_mask */ 717130561Sobrien FALSE), /* pcrel_offset */ 71860484Sobrien 71977298Sobrien /* 16-bit upper half section relative relocation. */ 72060484Sobrien HOWTO (R_PPC_SECTOFF_HI, /* type */ 72160484Sobrien 16, /* rightshift */ 72260484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 72360484Sobrien 16, /* bitsize */ 724130561Sobrien FALSE, /* pc_relative */ 72560484Sobrien 0, /* bitpos */ 72660484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 72760484Sobrien bfd_elf_generic_reloc, /* special_function */ 72860484Sobrien "R_PPC_SECTOFF_HI", /* name */ 729130561Sobrien FALSE, /* partial_inplace */ 73060484Sobrien 0, /* src_mask */ 73160484Sobrien 0xffff, /* dst_mask */ 732130561Sobrien FALSE), /* pcrel_offset */ 73360484Sobrien 73477298Sobrien /* 16-bit upper half adjusted section relative relocation. */ 73560484Sobrien HOWTO (R_PPC_SECTOFF_HA, /* type */ 73660484Sobrien 16, /* rightshift */ 73760484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 73860484Sobrien 16, /* bitsize */ 739130561Sobrien FALSE, /* pc_relative */ 74060484Sobrien 0, /* bitpos */ 74160484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 74260484Sobrien ppc_elf_addr16_ha_reloc, /* special_function */ 74360484Sobrien "R_PPC_SECTOFF_HA", /* name */ 744130561Sobrien FALSE, /* partial_inplace */ 74560484Sobrien 0, /* src_mask */ 74660484Sobrien 0xffff, /* dst_mask */ 747130561Sobrien FALSE), /* pcrel_offset */ 74860484Sobrien 749130561Sobrien /* Marker reloc for TLS. */ 750130561Sobrien HOWTO (R_PPC_TLS, 751130561Sobrien 0, /* rightshift */ 752130561Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 753130561Sobrien 32, /* bitsize */ 754130561Sobrien FALSE, /* pc_relative */ 755130561Sobrien 0, /* bitpos */ 756130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 757130561Sobrien bfd_elf_generic_reloc, /* special_function */ 758130561Sobrien "R_PPC_TLS", /* name */ 759130561Sobrien FALSE, /* partial_inplace */ 760130561Sobrien 0, /* src_mask */ 761130561Sobrien 0, /* dst_mask */ 762130561Sobrien FALSE), /* pcrel_offset */ 763130561Sobrien 764130561Sobrien /* Computes the load module index of the load module that contains the 765130561Sobrien definition of its TLS sym. */ 766130561Sobrien HOWTO (R_PPC_DTPMOD32, 767130561Sobrien 0, /* rightshift */ 768130561Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 769130561Sobrien 32, /* bitsize */ 770130561Sobrien FALSE, /* pc_relative */ 771130561Sobrien 0, /* bitpos */ 772130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 773130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 774130561Sobrien "R_PPC_DTPMOD32", /* name */ 775130561Sobrien FALSE, /* partial_inplace */ 776130561Sobrien 0, /* src_mask */ 777130561Sobrien 0xffffffff, /* dst_mask */ 778130561Sobrien FALSE), /* pcrel_offset */ 779130561Sobrien 780130561Sobrien /* Computes a dtv-relative displacement, the difference between the value 781130561Sobrien of sym+add and the base address of the thread-local storage block that 782130561Sobrien contains the definition of sym, minus 0x8000. */ 783130561Sobrien HOWTO (R_PPC_DTPREL32, 784130561Sobrien 0, /* rightshift */ 785130561Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 786130561Sobrien 32, /* bitsize */ 787130561Sobrien FALSE, /* pc_relative */ 788130561Sobrien 0, /* bitpos */ 789130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 790130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 791130561Sobrien "R_PPC_DTPREL32", /* name */ 792130561Sobrien FALSE, /* partial_inplace */ 793130561Sobrien 0, /* src_mask */ 794130561Sobrien 0xffffffff, /* dst_mask */ 795130561Sobrien FALSE), /* pcrel_offset */ 796130561Sobrien 797130561Sobrien /* A 16 bit dtprel reloc. */ 798130561Sobrien HOWTO (R_PPC_DTPREL16, 799130561Sobrien 0, /* rightshift */ 800130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 801130561Sobrien 16, /* bitsize */ 802130561Sobrien FALSE, /* pc_relative */ 803130561Sobrien 0, /* bitpos */ 804130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 805130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 806130561Sobrien "R_PPC_DTPREL16", /* name */ 807130561Sobrien FALSE, /* partial_inplace */ 808130561Sobrien 0, /* src_mask */ 809130561Sobrien 0xffff, /* dst_mask */ 810130561Sobrien FALSE), /* pcrel_offset */ 811130561Sobrien 812130561Sobrien /* Like DTPREL16, but no overflow. */ 813130561Sobrien HOWTO (R_PPC_DTPREL16_LO, 814130561Sobrien 0, /* rightshift */ 815130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 816130561Sobrien 16, /* bitsize */ 817130561Sobrien FALSE, /* pc_relative */ 818130561Sobrien 0, /* bitpos */ 819130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 820130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 821130561Sobrien "R_PPC_DTPREL16_LO", /* name */ 822130561Sobrien FALSE, /* partial_inplace */ 823130561Sobrien 0, /* src_mask */ 824130561Sobrien 0xffff, /* dst_mask */ 825130561Sobrien FALSE), /* pcrel_offset */ 826130561Sobrien 827130561Sobrien /* Like DTPREL16_LO, but next higher group of 16 bits. */ 828130561Sobrien HOWTO (R_PPC_DTPREL16_HI, 829130561Sobrien 16, /* rightshift */ 830130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 831130561Sobrien 16, /* bitsize */ 832130561Sobrien FALSE, /* pc_relative */ 833130561Sobrien 0, /* bitpos */ 834130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 835130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 836130561Sobrien "R_PPC_DTPREL16_HI", /* name */ 837130561Sobrien FALSE, /* partial_inplace */ 838130561Sobrien 0, /* src_mask */ 839130561Sobrien 0xffff, /* dst_mask */ 840130561Sobrien FALSE), /* pcrel_offset */ 841130561Sobrien 842130561Sobrien /* Like DTPREL16_HI, but adjust for low 16 bits. */ 843130561Sobrien HOWTO (R_PPC_DTPREL16_HA, 844130561Sobrien 16, /* rightshift */ 845130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 846130561Sobrien 16, /* bitsize */ 847130561Sobrien FALSE, /* pc_relative */ 848130561Sobrien 0, /* bitpos */ 849130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 850130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 851130561Sobrien "R_PPC_DTPREL16_HA", /* name */ 852130561Sobrien FALSE, /* partial_inplace */ 853130561Sobrien 0, /* src_mask */ 854130561Sobrien 0xffff, /* dst_mask */ 855130561Sobrien FALSE), /* pcrel_offset */ 856130561Sobrien 857130561Sobrien /* Computes a tp-relative displacement, the difference between the value of 858130561Sobrien sym+add and the value of the thread pointer (r13). */ 859130561Sobrien HOWTO (R_PPC_TPREL32, 860130561Sobrien 0, /* rightshift */ 861130561Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 862130561Sobrien 32, /* bitsize */ 863130561Sobrien FALSE, /* pc_relative */ 864130561Sobrien 0, /* bitpos */ 865130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 866130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 867130561Sobrien "R_PPC_TPREL32", /* name */ 868130561Sobrien FALSE, /* partial_inplace */ 869130561Sobrien 0, /* src_mask */ 870130561Sobrien 0xffffffff, /* dst_mask */ 871130561Sobrien FALSE), /* pcrel_offset */ 872130561Sobrien 873130561Sobrien /* A 16 bit tprel reloc. */ 874130561Sobrien HOWTO (R_PPC_TPREL16, 875130561Sobrien 0, /* rightshift */ 876130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 877130561Sobrien 16, /* bitsize */ 878130561Sobrien FALSE, /* pc_relative */ 879130561Sobrien 0, /* bitpos */ 880130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 881130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 882130561Sobrien "R_PPC_TPREL16", /* name */ 883130561Sobrien FALSE, /* partial_inplace */ 884130561Sobrien 0, /* src_mask */ 885130561Sobrien 0xffff, /* dst_mask */ 886130561Sobrien FALSE), /* pcrel_offset */ 887130561Sobrien 888130561Sobrien /* Like TPREL16, but no overflow. */ 889130561Sobrien HOWTO (R_PPC_TPREL16_LO, 890130561Sobrien 0, /* rightshift */ 891130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 892130561Sobrien 16, /* bitsize */ 893130561Sobrien FALSE, /* pc_relative */ 894130561Sobrien 0, /* bitpos */ 895130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 896130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 897130561Sobrien "R_PPC_TPREL16_LO", /* name */ 898130561Sobrien FALSE, /* partial_inplace */ 899130561Sobrien 0, /* src_mask */ 900130561Sobrien 0xffff, /* dst_mask */ 901130561Sobrien FALSE), /* pcrel_offset */ 902130561Sobrien 903130561Sobrien /* Like TPREL16_LO, but next higher group of 16 bits. */ 904130561Sobrien HOWTO (R_PPC_TPREL16_HI, 905130561Sobrien 16, /* rightshift */ 906130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 907130561Sobrien 16, /* bitsize */ 908130561Sobrien FALSE, /* pc_relative */ 909130561Sobrien 0, /* bitpos */ 910130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 911130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 912130561Sobrien "R_PPC_TPREL16_HI", /* name */ 913130561Sobrien FALSE, /* partial_inplace */ 914130561Sobrien 0, /* src_mask */ 915130561Sobrien 0xffff, /* dst_mask */ 916130561Sobrien FALSE), /* pcrel_offset */ 917130561Sobrien 918130561Sobrien /* Like TPREL16_HI, but adjust for low 16 bits. */ 919130561Sobrien HOWTO (R_PPC_TPREL16_HA, 920130561Sobrien 16, /* rightshift */ 921130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 922130561Sobrien 16, /* bitsize */ 923130561Sobrien FALSE, /* pc_relative */ 924130561Sobrien 0, /* bitpos */ 925130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 926130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 927130561Sobrien "R_PPC_TPREL16_HA", /* name */ 928130561Sobrien FALSE, /* partial_inplace */ 929130561Sobrien 0, /* src_mask */ 930130561Sobrien 0xffff, /* dst_mask */ 931130561Sobrien FALSE), /* pcrel_offset */ 932130561Sobrien 933130561Sobrien /* Allocates two contiguous entries in the GOT to hold a tls_index structure, 934130561Sobrien with values (sym+add)@dtpmod and (sym+add)@dtprel, and computes the offset 935130561Sobrien to the first entry. */ 936130561Sobrien HOWTO (R_PPC_GOT_TLSGD16, 937130561Sobrien 0, /* rightshift */ 938130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 939130561Sobrien 16, /* bitsize */ 940130561Sobrien FALSE, /* pc_relative */ 941130561Sobrien 0, /* bitpos */ 942130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 943130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 944130561Sobrien "R_PPC_GOT_TLSGD16", /* name */ 945130561Sobrien FALSE, /* partial_inplace */ 946130561Sobrien 0, /* src_mask */ 947130561Sobrien 0xffff, /* dst_mask */ 948130561Sobrien FALSE), /* pcrel_offset */ 949130561Sobrien 950130561Sobrien /* Like GOT_TLSGD16, but no overflow. */ 951130561Sobrien HOWTO (R_PPC_GOT_TLSGD16_LO, 952130561Sobrien 0, /* rightshift */ 953130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 954130561Sobrien 16, /* bitsize */ 955130561Sobrien FALSE, /* pc_relative */ 956130561Sobrien 0, /* bitpos */ 957130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 958130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 959130561Sobrien "R_PPC_GOT_TLSGD16_LO", /* name */ 960130561Sobrien FALSE, /* partial_inplace */ 961130561Sobrien 0, /* src_mask */ 962130561Sobrien 0xffff, /* dst_mask */ 963130561Sobrien FALSE), /* pcrel_offset */ 964130561Sobrien 965130561Sobrien /* Like GOT_TLSGD16_LO, but next higher group of 16 bits. */ 966130561Sobrien HOWTO (R_PPC_GOT_TLSGD16_HI, 967130561Sobrien 16, /* rightshift */ 968130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 969130561Sobrien 16, /* bitsize */ 970130561Sobrien FALSE, /* pc_relative */ 971130561Sobrien 0, /* bitpos */ 972130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 973130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 974130561Sobrien "R_PPC_GOT_TLSGD16_HI", /* name */ 975130561Sobrien FALSE, /* partial_inplace */ 976130561Sobrien 0, /* src_mask */ 977130561Sobrien 0xffff, /* dst_mask */ 978130561Sobrien FALSE), /* pcrel_offset */ 979130561Sobrien 980130561Sobrien /* Like GOT_TLSGD16_HI, but adjust for low 16 bits. */ 981130561Sobrien HOWTO (R_PPC_GOT_TLSGD16_HA, 982130561Sobrien 16, /* rightshift */ 983130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 984130561Sobrien 16, /* bitsize */ 985130561Sobrien FALSE, /* pc_relative */ 986130561Sobrien 0, /* bitpos */ 987130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 988130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 989130561Sobrien "R_PPC_GOT_TLSGD16_HA", /* name */ 990130561Sobrien FALSE, /* partial_inplace */ 991130561Sobrien 0, /* src_mask */ 992130561Sobrien 0xffff, /* dst_mask */ 993130561Sobrien FALSE), /* pcrel_offset */ 994130561Sobrien 995130561Sobrien /* Allocates two contiguous entries in the GOT to hold a tls_index structure, 996130561Sobrien with values (sym+add)@dtpmod and zero, and computes the offset to the 997130561Sobrien first entry. */ 998130561Sobrien HOWTO (R_PPC_GOT_TLSLD16, 999130561Sobrien 0, /* rightshift */ 1000130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1001130561Sobrien 16, /* bitsize */ 1002130561Sobrien FALSE, /* pc_relative */ 1003130561Sobrien 0, /* bitpos */ 1004130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 1005130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 1006130561Sobrien "R_PPC_GOT_TLSLD16", /* name */ 1007130561Sobrien FALSE, /* partial_inplace */ 1008130561Sobrien 0, /* src_mask */ 1009130561Sobrien 0xffff, /* dst_mask */ 1010130561Sobrien FALSE), /* pcrel_offset */ 1011130561Sobrien 1012130561Sobrien /* Like GOT_TLSLD16, but no overflow. */ 1013130561Sobrien HOWTO (R_PPC_GOT_TLSLD16_LO, 1014130561Sobrien 0, /* rightshift */ 1015130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1016130561Sobrien 16, /* bitsize */ 1017130561Sobrien FALSE, /* pc_relative */ 1018130561Sobrien 0, /* bitpos */ 1019130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1020130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 1021130561Sobrien "R_PPC_GOT_TLSLD16_LO", /* name */ 1022130561Sobrien FALSE, /* partial_inplace */ 1023130561Sobrien 0, /* src_mask */ 1024130561Sobrien 0xffff, /* dst_mask */ 1025130561Sobrien FALSE), /* pcrel_offset */ 1026130561Sobrien 1027130561Sobrien /* Like GOT_TLSLD16_LO, but next higher group of 16 bits. */ 1028130561Sobrien HOWTO (R_PPC_GOT_TLSLD16_HI, 1029130561Sobrien 16, /* rightshift */ 1030130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1031130561Sobrien 16, /* bitsize */ 1032130561Sobrien FALSE, /* pc_relative */ 1033130561Sobrien 0, /* bitpos */ 1034130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1035130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 1036130561Sobrien "R_PPC_GOT_TLSLD16_HI", /* name */ 1037130561Sobrien FALSE, /* partial_inplace */ 1038130561Sobrien 0, /* src_mask */ 1039130561Sobrien 0xffff, /* dst_mask */ 1040130561Sobrien FALSE), /* pcrel_offset */ 1041130561Sobrien 1042130561Sobrien /* Like GOT_TLSLD16_HI, but adjust for low 16 bits. */ 1043130561Sobrien HOWTO (R_PPC_GOT_TLSLD16_HA, 1044130561Sobrien 16, /* rightshift */ 1045130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1046130561Sobrien 16, /* bitsize */ 1047130561Sobrien FALSE, /* pc_relative */ 1048130561Sobrien 0, /* bitpos */ 1049130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1050130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 1051130561Sobrien "R_PPC_GOT_TLSLD16_HA", /* name */ 1052130561Sobrien FALSE, /* partial_inplace */ 1053130561Sobrien 0, /* src_mask */ 1054130561Sobrien 0xffff, /* dst_mask */ 1055130561Sobrien FALSE), /* pcrel_offset */ 1056130561Sobrien 1057130561Sobrien /* Allocates an entry in the GOT with value (sym+add)@dtprel, and computes 1058130561Sobrien the offset to the entry. */ 1059130561Sobrien HOWTO (R_PPC_GOT_DTPREL16, 1060130561Sobrien 0, /* rightshift */ 1061130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1062130561Sobrien 16, /* bitsize */ 1063130561Sobrien FALSE, /* pc_relative */ 1064130561Sobrien 0, /* bitpos */ 1065130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 1066130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 1067130561Sobrien "R_PPC_GOT_DTPREL16", /* name */ 1068130561Sobrien FALSE, /* partial_inplace */ 1069130561Sobrien 0, /* src_mask */ 1070130561Sobrien 0xffff, /* dst_mask */ 1071130561Sobrien FALSE), /* pcrel_offset */ 1072130561Sobrien 1073130561Sobrien /* Like GOT_DTPREL16, but no overflow. */ 1074130561Sobrien HOWTO (R_PPC_GOT_DTPREL16_LO, 1075130561Sobrien 0, /* rightshift */ 1076130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1077130561Sobrien 16, /* bitsize */ 1078130561Sobrien FALSE, /* pc_relative */ 1079130561Sobrien 0, /* bitpos */ 1080130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1081130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 1082130561Sobrien "R_PPC_GOT_DTPREL16_LO", /* name */ 1083130561Sobrien FALSE, /* partial_inplace */ 1084130561Sobrien 0, /* src_mask */ 1085130561Sobrien 0xffff, /* dst_mask */ 1086130561Sobrien FALSE), /* pcrel_offset */ 1087130561Sobrien 1088130561Sobrien /* Like GOT_DTPREL16_LO, but next higher group of 16 bits. */ 1089130561Sobrien HOWTO (R_PPC_GOT_DTPREL16_HI, 1090130561Sobrien 16, /* rightshift */ 1091130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1092130561Sobrien 16, /* bitsize */ 1093130561Sobrien FALSE, /* pc_relative */ 1094130561Sobrien 0, /* bitpos */ 1095130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1096130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 1097130561Sobrien "R_PPC_GOT_DTPREL16_HI", /* name */ 1098130561Sobrien FALSE, /* partial_inplace */ 1099130561Sobrien 0, /* src_mask */ 1100130561Sobrien 0xffff, /* dst_mask */ 1101130561Sobrien FALSE), /* pcrel_offset */ 1102130561Sobrien 1103130561Sobrien /* Like GOT_DTPREL16_HI, but adjust for low 16 bits. */ 1104130561Sobrien HOWTO (R_PPC_GOT_DTPREL16_HA, 1105130561Sobrien 16, /* rightshift */ 1106130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1107130561Sobrien 16, /* bitsize */ 1108130561Sobrien FALSE, /* pc_relative */ 1109130561Sobrien 0, /* bitpos */ 1110130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1111130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 1112130561Sobrien "R_PPC_GOT_DTPREL16_HA", /* name */ 1113130561Sobrien FALSE, /* partial_inplace */ 1114130561Sobrien 0, /* src_mask */ 1115130561Sobrien 0xffff, /* dst_mask */ 1116130561Sobrien FALSE), /* pcrel_offset */ 1117130561Sobrien 1118130561Sobrien /* Allocates an entry in the GOT with value (sym+add)@tprel, and computes the 1119130561Sobrien offset to the entry. */ 1120130561Sobrien HOWTO (R_PPC_GOT_TPREL16, 1121130561Sobrien 0, /* rightshift */ 1122130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1123130561Sobrien 16, /* bitsize */ 1124130561Sobrien FALSE, /* pc_relative */ 1125130561Sobrien 0, /* bitpos */ 1126130561Sobrien complain_overflow_signed, /* complain_on_overflow */ 1127130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 1128130561Sobrien "R_PPC_GOT_TPREL16", /* name */ 1129130561Sobrien FALSE, /* partial_inplace */ 1130130561Sobrien 0, /* src_mask */ 1131130561Sobrien 0xffff, /* dst_mask */ 1132130561Sobrien FALSE), /* pcrel_offset */ 1133130561Sobrien 1134130561Sobrien /* Like GOT_TPREL16, but no overflow. */ 1135130561Sobrien HOWTO (R_PPC_GOT_TPREL16_LO, 1136130561Sobrien 0, /* rightshift */ 1137130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1138130561Sobrien 16, /* bitsize */ 1139130561Sobrien FALSE, /* pc_relative */ 1140130561Sobrien 0, /* bitpos */ 1141130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1142130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 1143130561Sobrien "R_PPC_GOT_TPREL16_LO", /* name */ 1144130561Sobrien FALSE, /* partial_inplace */ 1145130561Sobrien 0, /* src_mask */ 1146130561Sobrien 0xffff, /* dst_mask */ 1147130561Sobrien FALSE), /* pcrel_offset */ 1148130561Sobrien 1149130561Sobrien /* Like GOT_TPREL16_LO, but next higher group of 16 bits. */ 1150130561Sobrien HOWTO (R_PPC_GOT_TPREL16_HI, 1151130561Sobrien 16, /* rightshift */ 1152130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1153130561Sobrien 16, /* bitsize */ 1154130561Sobrien FALSE, /* pc_relative */ 1155130561Sobrien 0, /* bitpos */ 1156130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1157130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 1158130561Sobrien "R_PPC_GOT_TPREL16_HI", /* name */ 1159130561Sobrien FALSE, /* partial_inplace */ 1160130561Sobrien 0, /* src_mask */ 1161130561Sobrien 0xffff, /* dst_mask */ 1162130561Sobrien FALSE), /* pcrel_offset */ 1163130561Sobrien 1164130561Sobrien /* Like GOT_TPREL16_HI, but adjust for low 16 bits. */ 1165130561Sobrien HOWTO (R_PPC_GOT_TPREL16_HA, 1166130561Sobrien 16, /* rightshift */ 1167130561Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 1168130561Sobrien 16, /* bitsize */ 1169130561Sobrien FALSE, /* pc_relative */ 1170130561Sobrien 0, /* bitpos */ 1171130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1172130561Sobrien ppc_elf_unhandled_reloc, /* special_function */ 1173130561Sobrien "R_PPC_GOT_TPREL16_HA", /* name */ 1174130561Sobrien FALSE, /* partial_inplace */ 1175130561Sobrien 0, /* src_mask */ 1176130561Sobrien 0xffff, /* dst_mask */ 1177130561Sobrien FALSE), /* pcrel_offset */ 1178130561Sobrien 117960484Sobrien /* The remaining relocs are from the Embedded ELF ABI, and are not 118060484Sobrien in the SVR4 ELF ABI. */ 118160484Sobrien 1182130561Sobrien /* 32 bit value resulting from the addend minus the symbol. */ 118360484Sobrien HOWTO (R_PPC_EMB_NADDR32, /* type */ 118460484Sobrien 0, /* rightshift */ 118560484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 118660484Sobrien 32, /* bitsize */ 1187130561Sobrien FALSE, /* pc_relative */ 118860484Sobrien 0, /* bitpos */ 118960484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 119060484Sobrien bfd_elf_generic_reloc, /* special_function */ 119160484Sobrien "R_PPC_EMB_NADDR32", /* name */ 1192130561Sobrien FALSE, /* partial_inplace */ 119360484Sobrien 0, /* src_mask */ 119460484Sobrien 0xffffffff, /* dst_mask */ 1195130561Sobrien FALSE), /* pcrel_offset */ 119660484Sobrien 1197130561Sobrien /* 16 bit value resulting from the addend minus the symbol. */ 119860484Sobrien HOWTO (R_PPC_EMB_NADDR16, /* type */ 119960484Sobrien 0, /* rightshift */ 120060484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 120160484Sobrien 16, /* bitsize */ 1202130561Sobrien FALSE, /* pc_relative */ 120360484Sobrien 0, /* bitpos */ 120460484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 120560484Sobrien bfd_elf_generic_reloc, /* special_function */ 120660484Sobrien "R_PPC_EMB_NADDR16", /* name */ 1207130561Sobrien FALSE, /* partial_inplace */ 120860484Sobrien 0, /* src_mask */ 120960484Sobrien 0xffff, /* dst_mask */ 1210130561Sobrien FALSE), /* pcrel_offset */ 121160484Sobrien 1212130561Sobrien /* 16 bit value resulting from the addend minus the symbol. */ 121360484Sobrien HOWTO (R_PPC_EMB_NADDR16_LO, /* type */ 121460484Sobrien 0, /* rightshift */ 121560484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 121660484Sobrien 16, /* bitsize */ 1217130561Sobrien FALSE, /* pc_relative */ 121860484Sobrien 0, /* bitpos */ 121960484Sobrien complain_overflow_dont,/* complain_on_overflow */ 122060484Sobrien bfd_elf_generic_reloc, /* special_function */ 122160484Sobrien "R_PPC_EMB_ADDR16_LO", /* name */ 1222130561Sobrien FALSE, /* partial_inplace */ 122360484Sobrien 0, /* src_mask */ 122460484Sobrien 0xffff, /* dst_mask */ 1225130561Sobrien FALSE), /* pcrel_offset */ 122660484Sobrien 1227130561Sobrien /* The high order 16 bits of the addend minus the symbol. */ 122860484Sobrien HOWTO (R_PPC_EMB_NADDR16_HI, /* type */ 122960484Sobrien 16, /* rightshift */ 123060484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 123160484Sobrien 16, /* bitsize */ 1232130561Sobrien FALSE, /* pc_relative */ 123360484Sobrien 0, /* bitpos */ 123460484Sobrien complain_overflow_dont, /* complain_on_overflow */ 123560484Sobrien bfd_elf_generic_reloc, /* special_function */ 123660484Sobrien "R_PPC_EMB_NADDR16_HI", /* name */ 1237130561Sobrien FALSE, /* partial_inplace */ 123860484Sobrien 0, /* src_mask */ 123960484Sobrien 0xffff, /* dst_mask */ 1240130561Sobrien FALSE), /* pcrel_offset */ 124160484Sobrien 124260484Sobrien /* The high order 16 bits of the result of the addend minus the address, 124360484Sobrien plus 1 if the contents of the low 16 bits, treated as a signed number, 124460484Sobrien is negative. */ 124560484Sobrien HOWTO (R_PPC_EMB_NADDR16_HA, /* type */ 124660484Sobrien 16, /* rightshift */ 124760484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 124860484Sobrien 16, /* bitsize */ 1249130561Sobrien FALSE, /* pc_relative */ 125060484Sobrien 0, /* bitpos */ 125160484Sobrien complain_overflow_dont, /* complain_on_overflow */ 125260484Sobrien ppc_elf_addr16_ha_reloc, /* special_function */ 125360484Sobrien "R_PPC_EMB_NADDR16_HA", /* name */ 1254130561Sobrien FALSE, /* partial_inplace */ 125560484Sobrien 0, /* src_mask */ 125660484Sobrien 0xffff, /* dst_mask */ 1257130561Sobrien FALSE), /* pcrel_offset */ 125860484Sobrien 125960484Sobrien /* 16 bit value resulting from allocating a 4 byte word to hold an 126060484Sobrien address in the .sdata section, and returning the offset from 1261130561Sobrien _SDA_BASE_ for that relocation. */ 126260484Sobrien HOWTO (R_PPC_EMB_SDAI16, /* type */ 126360484Sobrien 0, /* rightshift */ 126460484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 126560484Sobrien 16, /* bitsize */ 1266130561Sobrien FALSE, /* pc_relative */ 126760484Sobrien 0, /* bitpos */ 126860484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 126960484Sobrien bfd_elf_generic_reloc, /* special_function */ 127060484Sobrien "R_PPC_EMB_SDAI16", /* name */ 1271130561Sobrien FALSE, /* partial_inplace */ 127260484Sobrien 0, /* src_mask */ 127360484Sobrien 0xffff, /* dst_mask */ 1274130561Sobrien FALSE), /* pcrel_offset */ 127560484Sobrien 127660484Sobrien /* 16 bit value resulting from allocating a 4 byte word to hold an 127760484Sobrien address in the .sdata2 section, and returning the offset from 1278130561Sobrien _SDA2_BASE_ for that relocation. */ 127960484Sobrien HOWTO (R_PPC_EMB_SDA2I16, /* type */ 128060484Sobrien 0, /* rightshift */ 128160484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 128260484Sobrien 16, /* bitsize */ 1283130561Sobrien FALSE, /* pc_relative */ 128460484Sobrien 0, /* bitpos */ 128560484Sobrien complain_overflow_bitfield, /* complain_on_overflow */ 128660484Sobrien bfd_elf_generic_reloc, /* special_function */ 128760484Sobrien "R_PPC_EMB_SDA2I16", /* name */ 1288130561Sobrien FALSE, /* partial_inplace */ 128960484Sobrien 0, /* src_mask */ 129060484Sobrien 0xffff, /* dst_mask */ 1291130561Sobrien FALSE), /* pcrel_offset */ 129260484Sobrien 129360484Sobrien /* A sign-extended 16 bit value relative to _SDA2_BASE_, for use with 129460484Sobrien small data items. */ 129560484Sobrien HOWTO (R_PPC_EMB_SDA2REL, /* type */ 129660484Sobrien 0, /* rightshift */ 129760484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 129860484Sobrien 16, /* bitsize */ 1299130561Sobrien FALSE, /* pc_relative */ 130060484Sobrien 0, /* bitpos */ 130160484Sobrien complain_overflow_signed, /* complain_on_overflow */ 130260484Sobrien bfd_elf_generic_reloc, /* special_function */ 130360484Sobrien "R_PPC_EMB_SDA2REL", /* name */ 1304130561Sobrien FALSE, /* partial_inplace */ 130560484Sobrien 0, /* src_mask */ 130660484Sobrien 0xffff, /* dst_mask */ 1307130561Sobrien FALSE), /* pcrel_offset */ 130860484Sobrien 130960484Sobrien /* Relocate against either _SDA_BASE_ or _SDA2_BASE_, filling in the 16 bit 131060484Sobrien signed offset from the appropriate base, and filling in the register 131160484Sobrien field with the appropriate register (0, 2, or 13). */ 131260484Sobrien HOWTO (R_PPC_EMB_SDA21, /* type */ 131360484Sobrien 0, /* rightshift */ 131460484Sobrien 2, /* size (0 = byte, 1 = short, 2 = long) */ 131560484Sobrien 16, /* bitsize */ 1316130561Sobrien FALSE, /* pc_relative */ 131760484Sobrien 0, /* bitpos */ 131860484Sobrien complain_overflow_signed, /* complain_on_overflow */ 131960484Sobrien bfd_elf_generic_reloc, /* special_function */ 132060484Sobrien "R_PPC_EMB_SDA21", /* name */ 1321130561Sobrien FALSE, /* partial_inplace */ 132260484Sobrien 0, /* src_mask */ 132360484Sobrien 0xffff, /* dst_mask */ 1324130561Sobrien FALSE), /* pcrel_offset */ 132560484Sobrien 132660484Sobrien /* Relocation not handled: R_PPC_EMB_MRKREF */ 132760484Sobrien /* Relocation not handled: R_PPC_EMB_RELSEC16 */ 132860484Sobrien /* Relocation not handled: R_PPC_EMB_RELST_LO */ 132960484Sobrien /* Relocation not handled: R_PPC_EMB_RELST_HI */ 133060484Sobrien /* Relocation not handled: R_PPC_EMB_RELST_HA */ 133160484Sobrien /* Relocation not handled: R_PPC_EMB_BIT_FLD */ 133260484Sobrien 133360484Sobrien /* PC relative relocation against either _SDA_BASE_ or _SDA2_BASE_, filling 133460484Sobrien in the 16 bit signed offset from the appropriate base, and filling in the 133560484Sobrien register field with the appropriate register (0, 2, or 13). */ 133660484Sobrien HOWTO (R_PPC_EMB_RELSDA, /* type */ 133760484Sobrien 0, /* rightshift */ 133860484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 133960484Sobrien 16, /* bitsize */ 1340130561Sobrien TRUE, /* pc_relative */ 134160484Sobrien 0, /* bitpos */ 134260484Sobrien complain_overflow_signed, /* complain_on_overflow */ 134360484Sobrien bfd_elf_generic_reloc, /* special_function */ 134460484Sobrien "R_PPC_EMB_RELSDA", /* name */ 1345130561Sobrien FALSE, /* partial_inplace */ 134660484Sobrien 0, /* src_mask */ 134760484Sobrien 0xffff, /* dst_mask */ 1348130561Sobrien FALSE), /* pcrel_offset */ 134960484Sobrien 1350218822Sdim /* A 16 bit relative relocation. */ 1351218822Sdim HOWTO (R_PPC_REL16, /* type */ 1352130561Sobrien 0, /* rightshift */ 1353218822Sdim 1, /* size (0 = byte, 1 = short, 2 = long) */ 1354218822Sdim 16, /* bitsize */ 1355218822Sdim TRUE, /* pc_relative */ 1356130561Sobrien 0, /* bitpos */ 1357218822Sdim complain_overflow_bitfield, /* complain_on_overflow */ 1358130561Sobrien bfd_elf_generic_reloc, /* special_function */ 1359218822Sdim "R_PPC_REL16", /* name */ 1360130561Sobrien FALSE, /* partial_inplace */ 1361130561Sobrien 0, /* src_mask */ 1362218822Sdim 0xffff, /* dst_mask */ 1363218822Sdim TRUE), /* pcrel_offset */ 1364130561Sobrien 1365218822Sdim /* A 16 bit relative relocation without overflow. */ 1366218822Sdim HOWTO (R_PPC_REL16_LO, /* type */ 1367130561Sobrien 0, /* rightshift */ 1368218822Sdim 1, /* size (0 = byte, 1 = short, 2 = long) */ 1369218822Sdim 16, /* bitsize */ 1370218822Sdim TRUE, /* pc_relative */ 1371130561Sobrien 0, /* bitpos */ 1372218822Sdim complain_overflow_dont,/* complain_on_overflow */ 1373218822Sdim bfd_elf_generic_reloc, /* special_function */ 1374218822Sdim "R_PPC_REL16_LO", /* name */ 1375218822Sdim FALSE, /* partial_inplace */ 1376218822Sdim 0, /* src_mask */ 1377218822Sdim 0xffff, /* dst_mask */ 1378218822Sdim TRUE), /* pcrel_offset */ 1379218822Sdim 1380218822Sdim /* The high order 16 bits of a relative address. */ 1381218822Sdim HOWTO (R_PPC_REL16_HI, /* type */ 1382218822Sdim 16, /* rightshift */ 1383218822Sdim 1, /* size (0 = byte, 1 = short, 2 = long) */ 1384218822Sdim 16, /* bitsize */ 1385218822Sdim TRUE, /* pc_relative */ 1386218822Sdim 0, /* bitpos */ 1387130561Sobrien complain_overflow_dont, /* complain_on_overflow */ 1388130561Sobrien bfd_elf_generic_reloc, /* special_function */ 1389218822Sdim "R_PPC_REL16_HI", /* name */ 1390130561Sobrien FALSE, /* partial_inplace */ 1391130561Sobrien 0, /* src_mask */ 1392218822Sdim 0xffff, /* dst_mask */ 1393218822Sdim TRUE), /* pcrel_offset */ 1394130561Sobrien 1395218822Sdim /* The high order 16 bits of a relative address, plus 1 if the contents of 1396218822Sdim the low 16 bits, treated as a signed number, is negative. */ 1397218822Sdim HOWTO (R_PPC_REL16_HA, /* type */ 1398218822Sdim 16, /* rightshift */ 1399218822Sdim 1, /* size (0 = byte, 1 = short, 2 = long) */ 1400218822Sdim 16, /* bitsize */ 1401218822Sdim TRUE, /* pc_relative */ 1402218822Sdim 0, /* bitpos */ 1403218822Sdim complain_overflow_dont, /* complain_on_overflow */ 1404218822Sdim ppc_elf_addr16_ha_reloc, /* special_function */ 1405218822Sdim "R_PPC_REL16_HA", /* name */ 1406218822Sdim FALSE, /* partial_inplace */ 1407218822Sdim 0, /* src_mask */ 1408218822Sdim 0xffff, /* dst_mask */ 1409218822Sdim TRUE), /* pcrel_offset */ 1410218822Sdim 1411130561Sobrien /* GNU extension to record C++ vtable hierarchy. */ 141260484Sobrien HOWTO (R_PPC_GNU_VTINHERIT, /* type */ 141360484Sobrien 0, /* rightshift */ 141460484Sobrien 0, /* size (0 = byte, 1 = short, 2 = long) */ 141560484Sobrien 0, /* bitsize */ 1416130561Sobrien FALSE, /* pc_relative */ 141760484Sobrien 0, /* bitpos */ 141860484Sobrien complain_overflow_dont, /* complain_on_overflow */ 141960484Sobrien NULL, /* special_function */ 142060484Sobrien "R_PPC_GNU_VTINHERIT", /* name */ 1421130561Sobrien FALSE, /* partial_inplace */ 142260484Sobrien 0, /* src_mask */ 142360484Sobrien 0, /* dst_mask */ 1424130561Sobrien FALSE), /* pcrel_offset */ 142560484Sobrien 1426130561Sobrien /* GNU extension to record C++ vtable member usage. */ 142760484Sobrien HOWTO (R_PPC_GNU_VTENTRY, /* type */ 142860484Sobrien 0, /* rightshift */ 142960484Sobrien 0, /* size (0 = byte, 1 = short, 2 = long) */ 143060484Sobrien 0, /* bitsize */ 1431130561Sobrien FALSE, /* pc_relative */ 143260484Sobrien 0, /* bitpos */ 143360484Sobrien complain_overflow_dont, /* complain_on_overflow */ 143460484Sobrien NULL, /* special_function */ 143560484Sobrien "R_PPC_GNU_VTENTRY", /* name */ 1436130561Sobrien FALSE, /* partial_inplace */ 143760484Sobrien 0, /* src_mask */ 143860484Sobrien 0, /* dst_mask */ 1439130561Sobrien FALSE), /* pcrel_offset */ 144060484Sobrien 1441130561Sobrien /* Phony reloc to handle AIX style TOC entries. */ 144260484Sobrien HOWTO (R_PPC_TOC16, /* type */ 144360484Sobrien 0, /* rightshift */ 144460484Sobrien 1, /* size (0 = byte, 1 = short, 2 = long) */ 144560484Sobrien 16, /* bitsize */ 1446130561Sobrien FALSE, /* pc_relative */ 144760484Sobrien 0, /* bitpos */ 144860484Sobrien complain_overflow_signed, /* complain_on_overflow */ 144960484Sobrien bfd_elf_generic_reloc, /* special_function */ 145060484Sobrien "R_PPC_TOC16", /* name */ 1451130561Sobrien FALSE, /* partial_inplace */ 145260484Sobrien 0, /* src_mask */ 145360484Sobrien 0xffff, /* dst_mask */ 1454130561Sobrien FALSE), /* pcrel_offset */ 145560484Sobrien}; 145660484Sobrien 145760484Sobrien/* Initialize the ppc_elf_howto_table, so that linear accesses can be done. */ 145860484Sobrien 145960484Sobrienstatic void 1460130561Sobrienppc_elf_howto_init (void) 146160484Sobrien{ 146260484Sobrien unsigned int i, type; 146360484Sobrien 1464130561Sobrien for (i = 0; 1465130561Sobrien i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); 1466130561Sobrien i++) 146760484Sobrien { 146860484Sobrien type = ppc_elf_howto_raw[i].type; 1469130561Sobrien if (type >= (sizeof (ppc_elf_howto_table) 1470130561Sobrien / sizeof (ppc_elf_howto_table[0]))) 1471130561Sobrien abort (); 147260484Sobrien ppc_elf_howto_table[type] = &ppc_elf_howto_raw[i]; 147360484Sobrien } 147460484Sobrien} 147560484Sobrien 147660484Sobrienstatic reloc_howto_type * 1477130561Sobrienppc_elf_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED, 1478130561Sobrien bfd_reloc_code_real_type code) 147960484Sobrien{ 1480130561Sobrien enum elf_ppc_reloc_type r; 148160484Sobrien 1482130561Sobrien /* Initialize howto table if not already done. */ 148360484Sobrien if (!ppc_elf_howto_table[R_PPC_ADDR32]) 148460484Sobrien ppc_elf_howto_init (); 148560484Sobrien 1486130561Sobrien switch (code) 148760484Sobrien { 148860484Sobrien default: 1489130561Sobrien return NULL; 149060484Sobrien 1491130561Sobrien case BFD_RELOC_NONE: r = R_PPC_NONE; break; 1492130561Sobrien case BFD_RELOC_32: r = R_PPC_ADDR32; break; 1493130561Sobrien case BFD_RELOC_PPC_BA26: r = R_PPC_ADDR24; break; 1494130561Sobrien case BFD_RELOC_16: r = R_PPC_ADDR16; break; 1495130561Sobrien case BFD_RELOC_LO16: r = R_PPC_ADDR16_LO; break; 1496130561Sobrien case BFD_RELOC_HI16: r = R_PPC_ADDR16_HI; break; 1497130561Sobrien case BFD_RELOC_HI16_S: r = R_PPC_ADDR16_HA; break; 1498130561Sobrien case BFD_RELOC_PPC_BA16: r = R_PPC_ADDR14; break; 1499130561Sobrien case BFD_RELOC_PPC_BA16_BRTAKEN: r = R_PPC_ADDR14_BRTAKEN; break; 1500130561Sobrien case BFD_RELOC_PPC_BA16_BRNTAKEN: r = R_PPC_ADDR14_BRNTAKEN; break; 1501130561Sobrien case BFD_RELOC_PPC_B26: r = R_PPC_REL24; break; 1502130561Sobrien case BFD_RELOC_PPC_B16: r = R_PPC_REL14; break; 1503130561Sobrien case BFD_RELOC_PPC_B16_BRTAKEN: r = R_PPC_REL14_BRTAKEN; break; 1504130561Sobrien case BFD_RELOC_PPC_B16_BRNTAKEN: r = R_PPC_REL14_BRNTAKEN; break; 1505130561Sobrien case BFD_RELOC_16_GOTOFF: r = R_PPC_GOT16; break; 1506130561Sobrien case BFD_RELOC_LO16_GOTOFF: r = R_PPC_GOT16_LO; break; 1507130561Sobrien case BFD_RELOC_HI16_GOTOFF: r = R_PPC_GOT16_HI; break; 1508130561Sobrien case BFD_RELOC_HI16_S_GOTOFF: r = R_PPC_GOT16_HA; break; 1509130561Sobrien case BFD_RELOC_24_PLT_PCREL: r = R_PPC_PLTREL24; break; 1510130561Sobrien case BFD_RELOC_PPC_COPY: r = R_PPC_COPY; break; 1511130561Sobrien case BFD_RELOC_PPC_GLOB_DAT: r = R_PPC_GLOB_DAT; break; 1512130561Sobrien case BFD_RELOC_PPC_LOCAL24PC: r = R_PPC_LOCAL24PC; break; 1513130561Sobrien case BFD_RELOC_32_PCREL: r = R_PPC_REL32; break; 1514130561Sobrien case BFD_RELOC_32_PLTOFF: r = R_PPC_PLT32; break; 1515130561Sobrien case BFD_RELOC_32_PLT_PCREL: r = R_PPC_PLTREL32; break; 1516130561Sobrien case BFD_RELOC_LO16_PLTOFF: r = R_PPC_PLT16_LO; break; 1517130561Sobrien case BFD_RELOC_HI16_PLTOFF: r = R_PPC_PLT16_HI; break; 1518130561Sobrien case BFD_RELOC_HI16_S_PLTOFF: r = R_PPC_PLT16_HA; break; 1519130561Sobrien case BFD_RELOC_GPREL16: r = R_PPC_SDAREL16; break; 1520130561Sobrien case BFD_RELOC_16_BASEREL: r = R_PPC_SECTOFF; break; 1521130561Sobrien case BFD_RELOC_LO16_BASEREL: r = R_PPC_SECTOFF_LO; break; 1522130561Sobrien case BFD_RELOC_HI16_BASEREL: r = R_PPC_SECTOFF_HI; break; 1523130561Sobrien case BFD_RELOC_HI16_S_BASEREL: r = R_PPC_SECTOFF_HA; break; 1524130561Sobrien case BFD_RELOC_CTOR: r = R_PPC_ADDR32; break; 1525130561Sobrien case BFD_RELOC_PPC_TOC16: r = R_PPC_TOC16; break; 1526130561Sobrien case BFD_RELOC_PPC_TLS: r = R_PPC_TLS; break; 1527130561Sobrien case BFD_RELOC_PPC_DTPMOD: r = R_PPC_DTPMOD32; break; 1528130561Sobrien case BFD_RELOC_PPC_TPREL16: r = R_PPC_TPREL16; break; 1529130561Sobrien case BFD_RELOC_PPC_TPREL16_LO: r = R_PPC_TPREL16_LO; break; 1530130561Sobrien case BFD_RELOC_PPC_TPREL16_HI: r = R_PPC_TPREL16_HI; break; 1531130561Sobrien case BFD_RELOC_PPC_TPREL16_HA: r = R_PPC_TPREL16_HA; break; 1532130561Sobrien case BFD_RELOC_PPC_TPREL: r = R_PPC_TPREL32; break; 1533130561Sobrien case BFD_RELOC_PPC_DTPREL16: r = R_PPC_DTPREL16; break; 1534130561Sobrien case BFD_RELOC_PPC_DTPREL16_LO: r = R_PPC_DTPREL16_LO; break; 1535130561Sobrien case BFD_RELOC_PPC_DTPREL16_HI: r = R_PPC_DTPREL16_HI; break; 1536130561Sobrien case BFD_RELOC_PPC_DTPREL16_HA: r = R_PPC_DTPREL16_HA; break; 1537130561Sobrien case BFD_RELOC_PPC_DTPREL: r = R_PPC_DTPREL32; break; 1538130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16: r = R_PPC_GOT_TLSGD16; break; 1539130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16_LO: r = R_PPC_GOT_TLSGD16_LO; break; 1540130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16_HI: r = R_PPC_GOT_TLSGD16_HI; break; 1541130561Sobrien case BFD_RELOC_PPC_GOT_TLSGD16_HA: r = R_PPC_GOT_TLSGD16_HA; break; 1542130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16: r = R_PPC_GOT_TLSLD16; break; 1543130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16_LO: r = R_PPC_GOT_TLSLD16_LO; break; 1544130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16_HI: r = R_PPC_GOT_TLSLD16_HI; break; 1545130561Sobrien case BFD_RELOC_PPC_GOT_TLSLD16_HA: r = R_PPC_GOT_TLSLD16_HA; break; 1546130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16: r = R_PPC_GOT_TPREL16; break; 1547130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16_LO: r = R_PPC_GOT_TPREL16_LO; break; 1548130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16_HI: r = R_PPC_GOT_TPREL16_HI; break; 1549130561Sobrien case BFD_RELOC_PPC_GOT_TPREL16_HA: r = R_PPC_GOT_TPREL16_HA; break; 1550130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16: r = R_PPC_GOT_DTPREL16; break; 1551130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16_LO: r = R_PPC_GOT_DTPREL16_LO; break; 1552130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16_HI: r = R_PPC_GOT_DTPREL16_HI; break; 1553130561Sobrien case BFD_RELOC_PPC_GOT_DTPREL16_HA: r = R_PPC_GOT_DTPREL16_HA; break; 1554130561Sobrien case BFD_RELOC_PPC_EMB_NADDR32: r = R_PPC_EMB_NADDR32; break; 1555130561Sobrien case BFD_RELOC_PPC_EMB_NADDR16: r = R_PPC_EMB_NADDR16; break; 1556130561Sobrien case BFD_RELOC_PPC_EMB_NADDR16_LO: r = R_PPC_EMB_NADDR16_LO; break; 1557130561Sobrien case BFD_RELOC_PPC_EMB_NADDR16_HI: r = R_PPC_EMB_NADDR16_HI; break; 1558130561Sobrien case BFD_RELOC_PPC_EMB_NADDR16_HA: r = R_PPC_EMB_NADDR16_HA; break; 1559130561Sobrien case BFD_RELOC_PPC_EMB_SDAI16: r = R_PPC_EMB_SDAI16; break; 1560130561Sobrien case BFD_RELOC_PPC_EMB_SDA2I16: r = R_PPC_EMB_SDA2I16; break; 1561130561Sobrien case BFD_RELOC_PPC_EMB_SDA2REL: r = R_PPC_EMB_SDA2REL; break; 1562130561Sobrien case BFD_RELOC_PPC_EMB_SDA21: r = R_PPC_EMB_SDA21; break; 1563130561Sobrien case BFD_RELOC_PPC_EMB_MRKREF: r = R_PPC_EMB_MRKREF; break; 1564130561Sobrien case BFD_RELOC_PPC_EMB_RELSEC16: r = R_PPC_EMB_RELSEC16; break; 1565130561Sobrien case BFD_RELOC_PPC_EMB_RELST_LO: r = R_PPC_EMB_RELST_LO; break; 1566130561Sobrien case BFD_RELOC_PPC_EMB_RELST_HI: r = R_PPC_EMB_RELST_HI; break; 1567130561Sobrien case BFD_RELOC_PPC_EMB_RELST_HA: r = R_PPC_EMB_RELST_HA; break; 1568130561Sobrien case BFD_RELOC_PPC_EMB_BIT_FLD: r = R_PPC_EMB_BIT_FLD; break; 1569130561Sobrien case BFD_RELOC_PPC_EMB_RELSDA: r = R_PPC_EMB_RELSDA; break; 1570218822Sdim case BFD_RELOC_16_PCREL: r = R_PPC_REL16; break; 1571218822Sdim case BFD_RELOC_LO16_PCREL: r = R_PPC_REL16_LO; break; 1572218822Sdim case BFD_RELOC_HI16_PCREL: r = R_PPC_REL16_HI; break; 1573218822Sdim case BFD_RELOC_HI16_S_PCREL: r = R_PPC_REL16_HA; break; 1574130561Sobrien case BFD_RELOC_VTABLE_INHERIT: r = R_PPC_GNU_VTINHERIT; break; 1575130561Sobrien case BFD_RELOC_VTABLE_ENTRY: r = R_PPC_GNU_VTENTRY; break; 157660484Sobrien } 157760484Sobrien 1578130561Sobrien return ppc_elf_howto_table[r]; 157960484Sobrien}; 158060484Sobrien 1581218822Sdimstatic reloc_howto_type * 1582218822Sdimppc_elf_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, 1583218822Sdim const char *r_name) 1584218822Sdim{ 1585218822Sdim unsigned int i; 1586218822Sdim 1587218822Sdim for (i = 0; 1588218822Sdim i < sizeof (ppc_elf_howto_raw) / sizeof (ppc_elf_howto_raw[0]); 1589218822Sdim i++) 1590218822Sdim if (ppc_elf_howto_raw[i].name != NULL 1591218822Sdim && strcasecmp (ppc_elf_howto_raw[i].name, r_name) == 0) 1592218822Sdim return &ppc_elf_howto_raw[i]; 1593218822Sdim 1594218822Sdim return NULL; 1595218822Sdim} 1596218822Sdim 159760484Sobrien/* Set the howto pointer for a PowerPC ELF reloc. */ 159860484Sobrien 159960484Sobrienstatic void 1600130561Sobrienppc_elf_info_to_howto (bfd *abfd ATTRIBUTE_UNUSED, 1601130561Sobrien arelent *cache_ptr, 1602130561Sobrien Elf_Internal_Rela *dst) 160360484Sobrien{ 1604130561Sobrien /* Initialize howto table if not already done. */ 160577298Sobrien if (!ppc_elf_howto_table[R_PPC_ADDR32]) 160660484Sobrien ppc_elf_howto_init (); 160760484Sobrien 160860484Sobrien BFD_ASSERT (ELF32_R_TYPE (dst->r_info) < (unsigned int) R_PPC_max); 160960484Sobrien cache_ptr->howto = ppc_elf_howto_table[ELF32_R_TYPE (dst->r_info)]; 1610218822Sdim 1611218822Sdim /* Just because the above assert didn't trigger doesn't mean that 1612218822Sdim ELF32_R_TYPE (dst->r_info) is necessarily a valid relocation. */ 1613218822Sdim if (!cache_ptr->howto) 1614218822Sdim { 1615218822Sdim (*_bfd_error_handler) (_("%B: invalid relocation type %d"), 1616218822Sdim abfd, ELF32_R_TYPE (dst->r_info)); 1617218822Sdim bfd_set_error (bfd_error_bad_value); 1618218822Sdim 1619218822Sdim cache_ptr->howto = ppc_elf_howto_table[R_PPC_NONE]; 1620218822Sdim } 162160484Sobrien} 162260484Sobrien 1623218822Sdim/* Handle the R_PPC_ADDR16_HA and R_PPC_REL16_HA relocs. */ 162460484Sobrien 162560484Sobrienstatic bfd_reloc_status_type 1626130561Sobrienppc_elf_addr16_ha_reloc (bfd *abfd ATTRIBUTE_UNUSED, 1627130561Sobrien arelent *reloc_entry, 1628130561Sobrien asymbol *symbol, 1629130561Sobrien void *data ATTRIBUTE_UNUSED, 1630130561Sobrien asection *input_section, 1631130561Sobrien bfd *output_bfd, 1632130561Sobrien char **error_message ATTRIBUTE_UNUSED) 163360484Sobrien{ 163460484Sobrien bfd_vma relocation; 163560484Sobrien 163660484Sobrien if (output_bfd != NULL) 163760484Sobrien { 163860484Sobrien reloc_entry->address += input_section->output_offset; 163960484Sobrien return bfd_reloc_ok; 164060484Sobrien } 164160484Sobrien 1642218822Sdim if (reloc_entry->address > bfd_get_section_limit (abfd, input_section)) 164360484Sobrien return bfd_reloc_outofrange; 164460484Sobrien 164560484Sobrien if (bfd_is_com_section (symbol->section)) 164660484Sobrien relocation = 0; 164760484Sobrien else 164860484Sobrien relocation = symbol->value; 164960484Sobrien 165060484Sobrien relocation += symbol->section->output_section->vma; 165160484Sobrien relocation += symbol->section->output_offset; 165260484Sobrien relocation += reloc_entry->addend; 1653218822Sdim if (reloc_entry->howto->pc_relative) 1654218822Sdim relocation -= reloc_entry->address; 165560484Sobrien 165660484Sobrien reloc_entry->addend += (relocation & 0x8000) << 1; 165760484Sobrien 165860484Sobrien return bfd_reloc_continue; 165960484Sobrien} 166060484Sobrien 1661130561Sobrienstatic bfd_reloc_status_type 1662130561Sobrienppc_elf_unhandled_reloc (bfd *abfd, 1663130561Sobrien arelent *reloc_entry, 1664130561Sobrien asymbol *symbol, 1665130561Sobrien void *data, 1666130561Sobrien asection *input_section, 1667130561Sobrien bfd *output_bfd, 1668130561Sobrien char **error_message) 1669130561Sobrien{ 1670130561Sobrien /* If this is a relocatable link (output_bfd test tells us), just 1671130561Sobrien call the generic function. Any adjustment will be done at final 1672130561Sobrien link time. */ 1673130561Sobrien if (output_bfd != NULL) 1674130561Sobrien return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data, 1675130561Sobrien input_section, output_bfd, error_message); 1676130561Sobrien 1677130561Sobrien if (error_message != NULL) 1678130561Sobrien { 1679130561Sobrien static char buf[60]; 1680130561Sobrien sprintf (buf, _("generic linker can't handle %s"), 1681130561Sobrien reloc_entry->howto->name); 1682130561Sobrien *error_message = buf; 1683130561Sobrien } 1684130561Sobrien return bfd_reloc_dangerous; 1685130561Sobrien} 1686218822Sdim 1687218822Sdim/* Sections created by the linker. */ 1688130561Sobrien 1689218822Sdimtypedef struct elf_linker_section 1690218822Sdim{ 1691218822Sdim /* Pointer to the bfd section. */ 1692218822Sdim asection *section; 1693218822Sdim /* Section name. */ 1694218822Sdim const char *name; 1695218822Sdim /* Associated bss section name. */ 1696218822Sdim const char *bss_name; 1697218822Sdim /* Associated symbol name. */ 1698218822Sdim const char *sym_name; 1699218822Sdim /* Associated symbol. */ 1700218822Sdim struct elf_link_hash_entry *sym; 1701218822Sdim} elf_linker_section_t; 1702218822Sdim 1703218822Sdim/* Linked list of allocated pointer entries. This hangs off of the 1704218822Sdim symbol lists, and provides allows us to return different pointers, 1705218822Sdim based on different addend's. */ 1706218822Sdim 1707218822Sdimtypedef struct elf_linker_section_pointers 1708218822Sdim{ 1709218822Sdim /* next allocated pointer for this symbol */ 1710218822Sdim struct elf_linker_section_pointers *next; 1711218822Sdim /* offset of pointer from beginning of section */ 1712218822Sdim bfd_vma offset; 1713218822Sdim /* addend used */ 1714218822Sdim bfd_vma addend; 1715218822Sdim /* which linker section this is */ 1716218822Sdim elf_linker_section_t *lsect; 1717218822Sdim} elf_linker_section_pointers_t; 1718218822Sdim 1719218822Sdimstruct ppc_elf_obj_tdata 1720218822Sdim{ 1721218822Sdim struct elf_obj_tdata elf; 1722218822Sdim 1723218822Sdim /* A mapping from local symbols to offsets into the various linker 1724218822Sdim sections added. This is index by the symbol index. */ 1725218822Sdim elf_linker_section_pointers_t **linker_section_pointers; 1726218822Sdim 1727218822Sdim /* Flags used to auto-detect plt type. */ 1728218822Sdim unsigned int makes_plt_call : 1; 1729218822Sdim unsigned int has_rel16 : 1; 1730218822Sdim}; 1731218822Sdim 1732218822Sdim#define ppc_elf_tdata(bfd) \ 1733218822Sdim ((struct ppc_elf_obj_tdata *) (bfd)->tdata.any) 1734218822Sdim 1735218822Sdim#define elf_local_ptr_offsets(bfd) \ 1736218822Sdim (ppc_elf_tdata (bfd)->linker_section_pointers) 1737218822Sdim 1738218822Sdim/* Override the generic function because we store some extras. */ 1739218822Sdim 1740218822Sdimstatic bfd_boolean 1741218822Sdimppc_elf_mkobject (bfd *abfd) 1742218822Sdim{ 1743218822Sdim if (abfd->tdata.any == NULL) 1744218822Sdim { 1745218822Sdim bfd_size_type amt = sizeof (struct ppc_elf_obj_tdata); 1746218822Sdim abfd->tdata.any = bfd_zalloc (abfd, amt); 1747218822Sdim if (abfd->tdata.any == NULL) 1748218822Sdim return FALSE; 1749218822Sdim } 1750218822Sdim return bfd_elf_mkobject (abfd); 1751218822Sdim} 1752218822Sdim 1753104834Sobrien/* Fix bad default arch selected for a 32 bit input bfd when the 1754104834Sobrien default is 64 bit. */ 1755104834Sobrien 1756130561Sobrienstatic bfd_boolean 1757130561Sobrienppc_elf_object_p (bfd *abfd) 1758104834Sobrien{ 1759104834Sobrien if (abfd->arch_info->the_default && abfd->arch_info->bits_per_word == 64) 1760104834Sobrien { 1761104834Sobrien Elf_Internal_Ehdr *i_ehdr = elf_elfheader (abfd); 1762104834Sobrien 1763104834Sobrien if (i_ehdr->e_ident[EI_CLASS] == ELFCLASS32) 1764104834Sobrien { 1765104834Sobrien /* Relies on arch after 64 bit default being 32 bit default. */ 1766104834Sobrien abfd->arch_info = abfd->arch_info->next; 1767104834Sobrien BFD_ASSERT (abfd->arch_info->bits_per_word == 32); 1768104834Sobrien } 1769104834Sobrien } 1770130561Sobrien return TRUE; 1771104834Sobrien} 1772104834Sobrien 177377298Sobrien/* Function to set whether a module needs the -mrelocatable bit set. */ 177460484Sobrien 1775130561Sobrienstatic bfd_boolean 1776130561Sobrienppc_elf_set_private_flags (bfd *abfd, flagword flags) 177760484Sobrien{ 177860484Sobrien BFD_ASSERT (!elf_flags_init (abfd) 177960484Sobrien || elf_elfheader (abfd)->e_flags == flags); 178060484Sobrien 178160484Sobrien elf_elfheader (abfd)->e_flags = flags; 1782130561Sobrien elf_flags_init (abfd) = TRUE; 1783130561Sobrien return TRUE; 178460484Sobrien} 178560484Sobrien 1786218822Sdim/* Support for core dump NOTE sections. */ 1787130561Sobrien 1788130561Sobrienstatic bfd_boolean 1789218822Sdimppc_elf_grok_prstatus (bfd *abfd, Elf_Internal_Note *note) 179060484Sobrien{ 1791218822Sdim int offset; 1792218822Sdim unsigned int size; 179360484Sobrien 1794218822Sdim switch (note->descsz) 1795218822Sdim { 1796218822Sdim default: 1797218822Sdim return FALSE; 179860484Sobrien 1799218822Sdim case 268: /* Linux/PPC. */ 1800218822Sdim /* pr_cursig */ 1801218822Sdim elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12); 180260484Sobrien 1803218822Sdim /* pr_pid */ 1804218822Sdim elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24); 1805218822Sdim 1806218822Sdim /* pr_reg */ 1807218822Sdim offset = 72; 1808218822Sdim size = 192; 1809218822Sdim 1810218822Sdim break; 181160484Sobrien } 181260484Sobrien 1813218822Sdim /* Make a ".reg/999" section. */ 1814218822Sdim return _bfd_elfcore_make_pseudosection (abfd, ".reg", 1815218822Sdim size, note->descpos + offset); 1816218822Sdim} 181760484Sobrien 1818218822Sdimstatic bfd_boolean 1819218822Sdimppc_elf_grok_psinfo (bfd *abfd, Elf_Internal_Note *note) 1820218822Sdim{ 1821218822Sdim switch (note->descsz) 182260484Sobrien { 1823218822Sdim default: 1824218822Sdim return FALSE; 182560484Sobrien 1826218822Sdim case 128: /* Linux/PPC elf_prpsinfo. */ 1827218822Sdim elf_tdata (abfd)->core_program 1828218822Sdim = _bfd_elfcore_strndup (abfd, note->descdata + 32, 16); 1829218822Sdim elf_tdata (abfd)->core_command 1830218822Sdim = _bfd_elfcore_strndup (abfd, note->descdata + 48, 80); 1831218822Sdim } 183260484Sobrien 1833218822Sdim /* Note that for some reason, a spurious space is tacked 1834218822Sdim onto the end of the args in some (at least one anyway) 1835218822Sdim implementations, so strip it off if it exists. */ 183660484Sobrien 1837218822Sdim { 1838218822Sdim char *command = elf_tdata (abfd)->core_command; 1839218822Sdim int n = strlen (command); 184060484Sobrien 1841218822Sdim if (0 < n && command[n - 1] == ' ') 1842218822Sdim command[n - 1] = '\0'; 1843218822Sdim } 184460484Sobrien 1845218822Sdim return TRUE; 1846218822Sdim} 184760484Sobrien 1848218822Sdimstatic char * 1849218822Sdimppc_elf_write_core_note (bfd *abfd, char *buf, int *bufsiz, int note_type, ...) 1850218822Sdim{ 1851218822Sdim switch (note_type) 1852218822Sdim { 1853218822Sdim default: 1854218822Sdim return NULL; 1855218822Sdim 1856218822Sdim case NT_PRPSINFO: 1857218822Sdim { 1858218822Sdim char data[128]; 1859218822Sdim va_list ap; 1860218822Sdim 1861218822Sdim va_start (ap, note_type); 1862218822Sdim memset (data, 0, 32); 1863218822Sdim strncpy (data + 32, va_arg (ap, const char *), 16); 1864218822Sdim strncpy (data + 48, va_arg (ap, const char *), 80); 1865218822Sdim va_end (ap); 1866218822Sdim return elfcore_write_note (abfd, buf, bufsiz, 1867218822Sdim "CORE", note_type, data, sizeof (data)); 1868218822Sdim } 1869218822Sdim 1870218822Sdim case NT_PRSTATUS: 1871218822Sdim { 1872218822Sdim char data[268]; 1873218822Sdim va_list ap; 1874218822Sdim long pid; 1875218822Sdim int cursig; 1876218822Sdim const void *greg; 1877218822Sdim 1878218822Sdim va_start (ap, note_type); 1879218822Sdim memset (data, 0, 72); 1880218822Sdim pid = va_arg (ap, long); 1881218822Sdim bfd_put_32 (abfd, pid, data + 24); 1882218822Sdim cursig = va_arg (ap, int); 1883218822Sdim bfd_put_16 (abfd, cursig, data + 12); 1884218822Sdim greg = va_arg (ap, const void *); 1885218822Sdim memcpy (data + 72, greg, 192); 1886218822Sdim memset (data + 264, 0, 4); 1887218822Sdim va_end (ap); 1888218822Sdim return elfcore_write_note (abfd, buf, bufsiz, 1889218822Sdim "CORE", note_type, data, sizeof (data)); 1890218822Sdim } 189160484Sobrien } 1892218822Sdim} 189360484Sobrien 1894218822Sdim/* Return address for Ith PLT stub in section PLT, for relocation REL 1895218822Sdim or (bfd_vma) -1 if it should not be included. */ 1896218822Sdim 1897218822Sdimstatic bfd_vma 1898218822Sdimppc_elf_plt_sym_val (bfd_vma i ATTRIBUTE_UNUSED, 1899218822Sdim const asection *plt ATTRIBUTE_UNUSED, 1900218822Sdim const arelent *rel) 1901218822Sdim{ 1902218822Sdim return rel->address; 190360484Sobrien} 1904218822Sdim 190560484Sobrien/* Handle a PowerPC specific section when reading an object file. This 1906218822Sdim is called when bfd_section_from_shdr finds a section with an unknown 1907218822Sdim type. */ 190860484Sobrien 1909130561Sobrienstatic bfd_boolean 1910218822Sdimppc_elf_section_from_shdr (bfd *abfd, 1911218822Sdim Elf_Internal_Shdr *hdr, 1912218822Sdim const char *name, 1913218822Sdim int shindex) 191460484Sobrien{ 191560484Sobrien asection *newsect; 191660484Sobrien flagword flags; 191760484Sobrien 1918218822Sdim if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex)) 1919130561Sobrien return FALSE; 192060484Sobrien 192160484Sobrien newsect = hdr->bfd_section; 192260484Sobrien flags = bfd_get_section_flags (abfd, newsect); 192360484Sobrien if (hdr->sh_flags & SHF_EXCLUDE) 192460484Sobrien flags |= SEC_EXCLUDE; 192560484Sobrien 192660484Sobrien if (hdr->sh_type == SHT_ORDERED) 192760484Sobrien flags |= SEC_SORT_ENTRIES; 192860484Sobrien 192960484Sobrien bfd_set_section_flags (abfd, newsect, flags); 1930130561Sobrien return TRUE; 193160484Sobrien} 1932218822Sdim 193360484Sobrien/* Set up any other section flags and such that may be necessary. */ 193460484Sobrien 1935130561Sobrienstatic bfd_boolean 1936130561Sobrienppc_elf_fake_sections (bfd *abfd ATTRIBUTE_UNUSED, 1937130561Sobrien Elf_Internal_Shdr *shdr, 1938130561Sobrien asection *asect) 193960484Sobrien{ 1940218822Sdim if ((asect->flags & (SEC_GROUP | SEC_EXCLUDE)) == SEC_EXCLUDE) 194160484Sobrien shdr->sh_flags |= SHF_EXCLUDE; 194260484Sobrien 194360484Sobrien if ((asect->flags & SEC_SORT_ENTRIES) != 0) 194460484Sobrien shdr->sh_type = SHT_ORDERED; 194560484Sobrien 1946130561Sobrien return TRUE; 194760484Sobrien} 1948130561Sobrien 1949218822Sdim/* If we have .sbss2 or .PPC.EMB.sbss0 output sections, we 1950218822Sdim need to bump up the number of section headers. */ 1951218822Sdim 1952218822Sdimstatic int 1953218822Sdimppc_elf_additional_program_headers (bfd *abfd, 1954218822Sdim struct bfd_link_info *info ATTRIBUTE_UNUSED) 1955130561Sobrien{ 1956218822Sdim asection *s; 1957218822Sdim int ret = 0; 1958130561Sobrien 1959218822Sdim s = bfd_get_section_by_name (abfd, ".sbss2"); 1960218822Sdim if (s != NULL && (s->flags & SEC_ALLOC) != 0) 1961218822Sdim ++ret; 1962218822Sdim 1963218822Sdim s = bfd_get_section_by_name (abfd, ".PPC.EMB.sbss0"); 1964218822Sdim if (s != NULL && (s->flags & SEC_ALLOC) != 0) 1965218822Sdim ++ret; 1966218822Sdim 1967218822Sdim return ret; 1968130561Sobrien} 1969218822Sdim 1970218822Sdim/* Add extra PPC sections -- Note, for now, make .sbss2 and 1971218822Sdim .PPC.EMB.sbss0 a normal section, and not a bss section so 1972218822Sdim that the linker doesn't crater when trying to make more than 1973218822Sdim 2 sections. */ 1974218822Sdim 1975218822Sdimstatic const struct bfd_elf_special_section ppc_elf_special_sections[] = 1976218822Sdim{ 1977218822Sdim { STRING_COMMA_LEN (".plt"), 0, SHT_NOBITS, SHF_ALLOC + SHF_EXECINSTR }, 1978218822Sdim { STRING_COMMA_LEN (".sbss"), -2, SHT_NOBITS, SHF_ALLOC + SHF_WRITE }, 1979218822Sdim { STRING_COMMA_LEN (".sbss2"), -2, SHT_PROGBITS, SHF_ALLOC }, 1980218822Sdim { STRING_COMMA_LEN (".sdata"), -2, SHT_PROGBITS, SHF_ALLOC + SHF_WRITE }, 1981218822Sdim { STRING_COMMA_LEN (".sdata2"), -2, SHT_PROGBITS, SHF_ALLOC }, 1982218822Sdim { STRING_COMMA_LEN (".tags"), 0, SHT_ORDERED, SHF_ALLOC }, 1983218822Sdim { STRING_COMMA_LEN (".PPC.EMB.apuinfo"), 0, SHT_NOTE, 0 }, 1984218822Sdim { STRING_COMMA_LEN (".PPC.EMB.sbss0"), 0, SHT_PROGBITS, SHF_ALLOC }, 1985218822Sdim { STRING_COMMA_LEN (".PPC.EMB.sdata0"), 0, SHT_PROGBITS, SHF_ALLOC }, 1986218822Sdim { NULL, 0, 0, 0, 0 } 1987218822Sdim}; 1988218822Sdim 1989218822Sdim/* This is what we want for new plt/got. */ 1990218822Sdimstatic struct bfd_elf_special_section ppc_alt_plt = 1991218822Sdim { STRING_COMMA_LEN (".plt"), 0, SHT_PROGBITS, SHF_ALLOC }; 1992218822Sdim 1993218822Sdimstatic const struct bfd_elf_special_section * 1994218822Sdimppc_elf_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) 1995218822Sdim{ 1996218822Sdim const struct bfd_elf_special_section *ssect; 1997218822Sdim 1998218822Sdim /* See if this is one of the special sections. */ 1999218822Sdim if (sec->name == NULL) 2000218822Sdim return NULL; 2001218822Sdim 2002218822Sdim ssect = _bfd_elf_get_special_section (sec->name, ppc_elf_special_sections, 2003218822Sdim sec->use_rela_p); 2004218822Sdim if (ssect != NULL) 2005218822Sdim { 2006218822Sdim if (ssect == ppc_elf_special_sections && (sec->flags & SEC_LOAD) != 0) 2007218822Sdim ssect = &ppc_alt_plt; 2008218822Sdim return ssect; 2009218822Sdim } 2010218822Sdim 2011218822Sdim return _bfd_elf_get_sec_type_attr (abfd, sec); 2012218822Sdim} 2013130561Sobrien 2014218822Sdim/* Very simple linked list structure for recording apuinfo values. */ 2015218822Sdimtypedef struct apuinfo_list 2016218822Sdim{ 2017218822Sdim struct apuinfo_list *next; 2018218822Sdim unsigned long value; 2019218822Sdim} 2020218822Sdimapuinfo_list; 2021130561Sobrien 2022218822Sdimstatic apuinfo_list *head; 2023218822Sdim 2024218822Sdim 2025218822Sdimstatic void 2026218822Sdimapuinfo_list_init (void) 2027130561Sobrien{ 2028218822Sdim head = NULL; 2029218822Sdim} 2030130561Sobrien 2031218822Sdimstatic void 2032218822Sdimapuinfo_list_add (unsigned long value) 2033218822Sdim{ 2034218822Sdim apuinfo_list *entry = head; 2035130561Sobrien 2036218822Sdim while (entry != NULL) 2037130561Sobrien { 2038218822Sdim if (entry->value == value) 2039218822Sdim return; 2040218822Sdim entry = entry->next; 2041218822Sdim } 2042130561Sobrien 2043218822Sdim entry = bfd_malloc (sizeof (* entry)); 2044218822Sdim if (entry == NULL) 2045218822Sdim return; 2046130561Sobrien 2047218822Sdim entry->value = value; 2048218822Sdim entry->next = head; 2049218822Sdim head = entry; 2050218822Sdim} 2051218822Sdim 2052218822Sdimstatic unsigned 2053218822Sdimapuinfo_list_length (void) 2054218822Sdim{ 2055218822Sdim apuinfo_list *entry; 2056218822Sdim unsigned long count; 2057218822Sdim 2058218822Sdim for (entry = head, count = 0; 2059218822Sdim entry; 2060218822Sdim entry = entry->next) 2061218822Sdim ++ count; 2062218822Sdim 2063218822Sdim return count; 2064218822Sdim} 2065218822Sdim 2066218822Sdimstatic inline unsigned long 2067218822Sdimapuinfo_list_element (unsigned long number) 2068218822Sdim{ 2069218822Sdim apuinfo_list * entry; 2070218822Sdim 2071218822Sdim for (entry = head; 2072218822Sdim entry && number --; 2073218822Sdim entry = entry->next) 2074218822Sdim ; 2075218822Sdim 2076218822Sdim return entry ? entry->value : 0; 2077218822Sdim} 2078218822Sdim 2079218822Sdimstatic void 2080218822Sdimapuinfo_list_finish (void) 2081218822Sdim{ 2082218822Sdim apuinfo_list *entry; 2083218822Sdim 2084218822Sdim for (entry = head; entry;) 2085218822Sdim { 2086218822Sdim apuinfo_list *next = entry->next; 2087218822Sdim free (entry); 2088218822Sdim entry = next; 2089218822Sdim } 2090218822Sdim 2091218822Sdim head = NULL; 2092218822Sdim} 2093218822Sdim 2094218822Sdim#define APUINFO_SECTION_NAME ".PPC.EMB.apuinfo" 2095218822Sdim#define APUINFO_LABEL "APUinfo" 2096218822Sdim 2097218822Sdim/* Scan the input BFDs and create a linked list of 2098218822Sdim the APUinfo values that will need to be emitted. */ 2099218822Sdim 2100218822Sdimstatic void 2101218822Sdimppc_elf_begin_write_processing (bfd *abfd, struct bfd_link_info *link_info) 2102218822Sdim{ 2103218822Sdim bfd *ibfd; 2104218822Sdim asection *asec; 2105218822Sdim char *buffer; 2106218822Sdim unsigned num_input_sections; 2107218822Sdim bfd_size_type output_section_size; 2108218822Sdim unsigned i; 2109218822Sdim unsigned num_entries; 2110218822Sdim unsigned long offset; 2111218822Sdim unsigned long length; 2112218822Sdim const char *error_message = NULL; 2113218822Sdim 2114218822Sdim if (link_info == NULL) 2115218822Sdim return; 2116218822Sdim 2117218822Sdim /* Scan the input bfds, looking for apuinfo sections. */ 2118218822Sdim num_input_sections = 0; 2119218822Sdim output_section_size = 0; 2120218822Sdim 2121218822Sdim for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next) 2122218822Sdim { 2123218822Sdim asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME); 2124218822Sdim if (asec) 2125130561Sobrien { 2126218822Sdim ++ num_input_sections; 2127218822Sdim output_section_size += asec->size; 2128130561Sobrien } 2129218822Sdim } 2130130561Sobrien 2131218822Sdim /* We need at least one input sections 2132218822Sdim in order to make merging worthwhile. */ 2133218822Sdim if (num_input_sections < 1) 2134218822Sdim return; 2135218822Sdim 2136218822Sdim /* Just make sure that the output section exists as well. */ 2137218822Sdim asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); 2138218822Sdim if (asec == NULL) 2139218822Sdim return; 2140218822Sdim 2141218822Sdim /* Allocate a buffer for the contents of the input sections. */ 2142218822Sdim buffer = bfd_malloc (output_section_size); 2143218822Sdim if (buffer == NULL) 2144218822Sdim return; 2145218822Sdim 2146218822Sdim offset = 0; 2147218822Sdim apuinfo_list_init (); 2148218822Sdim 2149218822Sdim /* Read in the input sections contents. */ 2150218822Sdim for (ibfd = link_info->input_bfds; ibfd; ibfd = ibfd->link_next) 2151130561Sobrien { 2152218822Sdim unsigned long datum; 2153218822Sdim char *ptr; 2154130561Sobrien 2155218822Sdim asec = bfd_get_section_by_name (ibfd, APUINFO_SECTION_NAME); 2156218822Sdim if (asec == NULL) 2157218822Sdim continue; 2158218822Sdim 2159218822Sdim length = asec->size; 2160218822Sdim if (length < 24) 2161130561Sobrien { 2162218822Sdim error_message = _("corrupt or empty %s section in %B"); 2163218822Sdim goto fail; 2164218822Sdim } 2165130561Sobrien 2166218822Sdim if (bfd_seek (ibfd, asec->filepos, SEEK_SET) != 0 2167218822Sdim || (bfd_bread (buffer + offset, length, ibfd) != length)) 2168218822Sdim { 2169218822Sdim error_message = _("unable to read in %s section from %B"); 2170218822Sdim goto fail; 2171218822Sdim } 2172130561Sobrien 2173218822Sdim /* Process the contents of the section. */ 2174218822Sdim ptr = buffer + offset; 2175218822Sdim error_message = _("corrupt %s section in %B"); 2176130561Sobrien 2177218822Sdim /* Verify the contents of the header. Note - we have to 2178218822Sdim extract the values this way in order to allow for a 2179218822Sdim host whose endian-ness is different from the target. */ 2180218822Sdim datum = bfd_get_32 (ibfd, ptr); 2181218822Sdim if (datum != sizeof APUINFO_LABEL) 2182218822Sdim goto fail; 2183130561Sobrien 2184218822Sdim datum = bfd_get_32 (ibfd, ptr + 8); 2185218822Sdim if (datum != 0x2) 2186218822Sdim goto fail; 2187130561Sobrien 2188218822Sdim if (strcmp (ptr + 12, APUINFO_LABEL) != 0) 2189218822Sdim goto fail; 2190130561Sobrien 2191218822Sdim /* Get the number of bytes used for apuinfo entries. */ 2192218822Sdim datum = bfd_get_32 (ibfd, ptr + 4); 2193218822Sdim if (datum + 20 != length) 2194218822Sdim goto fail; 2195218822Sdim 2196218822Sdim /* Make sure that we do not run off the end of the section. */ 2197218822Sdim if (offset + length > output_section_size) 2198218822Sdim goto fail; 2199218822Sdim 2200218822Sdim /* Scan the apuinfo section, building a list of apuinfo numbers. */ 2201218822Sdim for (i = 0; i < datum; i += 4) 2202218822Sdim apuinfo_list_add (bfd_get_32 (ibfd, ptr + 20 + i)); 2203218822Sdim 2204218822Sdim /* Update the offset. */ 2205218822Sdim offset += length; 2206130561Sobrien } 2207130561Sobrien 2208218822Sdim error_message = NULL; 2209130561Sobrien 2210218822Sdim /* Compute the size of the output section. */ 2211218822Sdim num_entries = apuinfo_list_length (); 2212218822Sdim output_section_size = 20 + num_entries * 4; 2213130561Sobrien 2214218822Sdim asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); 2215130561Sobrien 2216218822Sdim if (! bfd_set_section_size (abfd, asec, output_section_size)) 2217218822Sdim ibfd = abfd, 2218218822Sdim error_message = _("warning: unable to set size of %s section in %B"); 2219130561Sobrien 2220218822Sdim fail: 2221218822Sdim free (buffer); 2222130561Sobrien 2223218822Sdim if (error_message) 2224218822Sdim (*_bfd_error_handler) (error_message, ibfd, APUINFO_SECTION_NAME); 2225130561Sobrien} 2226130561Sobrien 2227218822Sdim/* Prevent the output section from accumulating the input sections' 2228218822Sdim contents. We have already stored this in our linked list structure. */ 2229130561Sobrien 2230218822Sdimstatic bfd_boolean 2231218822Sdimppc_elf_write_section (bfd *abfd ATTRIBUTE_UNUSED, 2232218822Sdim struct bfd_link_info *link_info ATTRIBUTE_UNUSED, 2233218822Sdim asection *asec, 2234218822Sdim bfd_byte *contents ATTRIBUTE_UNUSED) 2235130561Sobrien{ 2236218822Sdim return (apuinfo_list_length () 2237218822Sdim && strcmp (asec->name, APUINFO_SECTION_NAME) == 0); 2238218822Sdim} 2239130561Sobrien 2240218822Sdim/* Finally we can generate the output section. */ 2241130561Sobrien 2242218822Sdimstatic void 2243218822Sdimppc_elf_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED) 2244218822Sdim{ 2245218822Sdim bfd_byte *buffer; 2246218822Sdim asection *asec; 2247218822Sdim unsigned i; 2248218822Sdim unsigned num_entries; 2249218822Sdim bfd_size_type length; 2250130561Sobrien 2251218822Sdim asec = bfd_get_section_by_name (abfd, APUINFO_SECTION_NAME); 2252218822Sdim if (asec == NULL) 2253218822Sdim return; 2254130561Sobrien 2255218822Sdim if (apuinfo_list_length () == 0) 2256218822Sdim return; 2257130561Sobrien 2258218822Sdim length = asec->size; 2259218822Sdim if (length < 20) 2260218822Sdim return; 2261130561Sobrien 2262218822Sdim buffer = bfd_malloc (length); 2263218822Sdim if (buffer == NULL) 2264218822Sdim { 2265218822Sdim (*_bfd_error_handler) 2266218822Sdim (_("failed to allocate space for new APUinfo section.")); 2267218822Sdim return; 2268130561Sobrien } 2269218822Sdim 2270218822Sdim /* Create the apuinfo header. */ 2271218822Sdim num_entries = apuinfo_list_length (); 2272218822Sdim bfd_put_32 (abfd, sizeof APUINFO_LABEL, buffer); 2273218822Sdim bfd_put_32 (abfd, num_entries * 4, buffer + 4); 2274218822Sdim bfd_put_32 (abfd, 0x2, buffer + 8); 2275218822Sdim strcpy ((char *) buffer + 12, APUINFO_LABEL); 2276218822Sdim 2277218822Sdim length = 20; 2278218822Sdim for (i = 0; i < num_entries; i++) 2279130561Sobrien { 2280218822Sdim bfd_put_32 (abfd, apuinfo_list_element (i), buffer + length); 2281218822Sdim length += 4; 2282218822Sdim } 2283130561Sobrien 2284218822Sdim if (length != asec->size) 2285218822Sdim (*_bfd_error_handler) (_("failed to compute new APUinfo section.")); 2286130561Sobrien 2287218822Sdim if (! bfd_set_section_contents (abfd, asec, buffer, (file_ptr) 0, length)) 2288218822Sdim (*_bfd_error_handler) (_("failed to install new APUinfo section.")); 2289130561Sobrien 2290218822Sdim free (buffer); 2291130561Sobrien 2292218822Sdim apuinfo_list_finish (); 2293218822Sdim} 2294218822Sdim 2295218822Sdim/* The following functions are specific to the ELF linker, while 2296218822Sdim functions above are used generally. They appear in this file more 2297218822Sdim or less in the order in which they are called. eg. 2298218822Sdim ppc_elf_check_relocs is called early in the link process, 2299218822Sdim ppc_elf_finish_dynamic_sections is one of the last functions 2300218822Sdim called. */ 2301130561Sobrien 2302218822Sdim/* The PPC linker needs to keep track of the number of relocs that it 2303218822Sdim decides to copy as dynamic relocs in check_relocs for each symbol. 2304218822Sdim This is so that it can later discard them if they are found to be 2305218822Sdim unnecessary. We store the information in a field extending the 2306218822Sdim regular ELF linker hash table. */ 2307130561Sobrien 2308218822Sdimstruct ppc_elf_dyn_relocs 2309218822Sdim{ 2310218822Sdim struct ppc_elf_dyn_relocs *next; 2311130561Sobrien 2312218822Sdim /* The input section of the reloc. */ 2313218822Sdim asection *sec; 2314130561Sobrien 2315218822Sdim /* Total number of relocs copied for the input section. */ 2316218822Sdim bfd_size_type count; 2317130561Sobrien 2318218822Sdim /* Number of pc-relative relocs copied for the input section. */ 2319218822Sdim bfd_size_type pc_count; 2320218822Sdim}; 2321218822Sdim 2322218822Sdim/* Track PLT entries needed for a given symbol. We might need more 2323218822Sdim than one glink entry per symbol. */ 2324218822Sdimstruct plt_entry 232560484Sobrien{ 2326218822Sdim struct plt_entry *next; 232760484Sobrien 2328218822Sdim /* -fPIC uses multiple GOT sections, one per file, called ".got2". 2329218822Sdim This field stores the offset into .got2 used to initialise the 2330218822Sdim GOT pointer reg. It will always be at least 32768 (and for 2331218822Sdim current gcc this is the only offset used). */ 2332218822Sdim bfd_vma addend; 233360484Sobrien 2334218822Sdim /* The .got2 section. */ 2335218822Sdim asection *sec; 2336130561Sobrien 2337218822Sdim /* PLT refcount or offset. */ 2338218822Sdim union 233960484Sobrien { 2340218822Sdim bfd_signed_vma refcount; 2341218822Sdim bfd_vma offset; 2342218822Sdim } plt; 234360484Sobrien 2344218822Sdim /* .glink stub offset. */ 2345218822Sdim bfd_vma glink_offset; 2346218822Sdim}; 234760484Sobrien 2348218822Sdim/* Of those relocs that might be copied as dynamic relocs, this macro 2349218822Sdim selects those that must be copied when linking a shared library, 2350218822Sdim even when the symbol is local. */ 235160484Sobrien 2352218822Sdim#define MUST_BE_DYN_RELOC(RTYPE) \ 2353218822Sdim ((RTYPE) != R_PPC_REL24 \ 2354218822Sdim && (RTYPE) != R_PPC_REL14 \ 2355218822Sdim && (RTYPE) != R_PPC_REL14_BRTAKEN \ 2356218822Sdim && (RTYPE) != R_PPC_REL14_BRNTAKEN \ 2357218822Sdim && (RTYPE) != R_PPC_REL32) 235860484Sobrien 2359218822Sdim/* If ELIMINATE_COPY_RELOCS is non-zero, the linker will try to avoid 2360218822Sdim copying dynamic variables from a shared lib into an app's dynbss 2361218822Sdim section, and instead use a dynamic relocation to point into the 2362218822Sdim shared lib. */ 2363218822Sdim#define ELIMINATE_COPY_RELOCS 1 236460484Sobrien 2365218822Sdim/* PPC ELF linker hash entry. */ 236660484Sobrien 2367218822Sdimstruct ppc_elf_link_hash_entry 2368218822Sdim{ 2369218822Sdim struct elf_link_hash_entry elf; 237060484Sobrien 2371218822Sdim /* If this symbol is used in the linker created sections, the processor 2372218822Sdim specific backend uses this field to map the field into the offset 2373218822Sdim from the beginning of the section. */ 2374218822Sdim elf_linker_section_pointers_t *linker_section_pointer; 237560484Sobrien 2376218822Sdim /* Track dynamic relocs copied for this symbol. */ 2377218822Sdim struct ppc_elf_dyn_relocs *dyn_relocs; 2378130561Sobrien 2379218822Sdim /* Contexts in which symbol is used in the GOT (or TOC). 2380218822Sdim TLS_GD .. TLS_TLS bits are or'd into the mask as the 2381218822Sdim corresponding relocs are encountered during check_relocs. 2382218822Sdim tls_optimize clears TLS_GD .. TLS_TPREL when optimizing to 2383218822Sdim indicate the corresponding GOT entry type is not needed. */ 2384218822Sdim#define TLS_GD 1 /* GD reloc. */ 2385218822Sdim#define TLS_LD 2 /* LD reloc. */ 2386218822Sdim#define TLS_TPREL 4 /* TPREL reloc, => IE. */ 2387218822Sdim#define TLS_DTPREL 8 /* DTPREL reloc, => LD. */ 2388218822Sdim#define TLS_TLS 16 /* Any TLS reloc. */ 2389218822Sdim#define TLS_TPRELGD 32 /* TPREL reloc resulting from GD->IE. */ 2390218822Sdim char tls_mask; 2391130561Sobrien 2392218822Sdim /* Nonzero if we have seen a small data relocation referring to this 2393218822Sdim symbol. */ 2394218822Sdim unsigned char has_sda_refs; 2395218822Sdim}; 2396130561Sobrien 2397218822Sdim#define ppc_elf_hash_entry(ent) ((struct ppc_elf_link_hash_entry *) (ent)) 2398130561Sobrien 2399218822Sdim/* PPC ELF linker hash table. */ 2400130561Sobrien 2401218822Sdimstruct ppc_elf_link_hash_table 2402218822Sdim{ 2403218822Sdim struct elf_link_hash_table elf; 2404130561Sobrien 2405218822Sdim /* Short-cuts to get to dynamic linker sections. */ 2406218822Sdim asection *got; 2407218822Sdim asection *relgot; 2408218822Sdim asection *glink; 2409218822Sdim asection *plt; 2410218822Sdim asection *relplt; 2411218822Sdim asection *dynbss; 2412218822Sdim asection *relbss; 2413218822Sdim asection *dynsbss; 2414218822Sdim asection *relsbss; 2415218822Sdim elf_linker_section_t sdata[2]; 2416218822Sdim asection *sbss; 2417218822Sdim 2418218822Sdim /* The (unloaded but important) .rela.plt.unloaded on VxWorks. */ 2419218822Sdim asection *srelplt2; 2420218822Sdim 2421218822Sdim /* The .got.plt section (VxWorks only)*/ 2422218822Sdim asection *sgotplt; 2423218822Sdim 2424218822Sdim /* Shortcut to .__tls_get_addr. */ 2425218822Sdim struct elf_link_hash_entry *tls_get_addr; 2426218822Sdim 2427218822Sdim /* The bfd that forced an old-style PLT. */ 2428218822Sdim bfd *old_bfd; 2429218822Sdim 2430218822Sdim /* TLS local dynamic got entry handling. */ 2431218822Sdim union { 2432218822Sdim bfd_signed_vma refcount; 2433218822Sdim bfd_vma offset; 2434218822Sdim } tlsld_got; 2435218822Sdim 2436218822Sdim /* Offset of PltResolve function in glink. */ 2437218822Sdim bfd_vma glink_pltresolve; 2438218822Sdim 2439218822Sdim /* Size of reserved GOT entries. */ 2440218822Sdim unsigned int got_header_size; 2441218822Sdim /* Non-zero if allocating the header left a gap. */ 2442218822Sdim unsigned int got_gap; 2443218822Sdim 2444218822Sdim /* The type of PLT we have chosen to use. */ 2445218822Sdim enum ppc_elf_plt_type plt_type; 2446218822Sdim 2447218822Sdim /* Set if we should emit symbols for stubs. */ 2448218822Sdim unsigned int emit_stub_syms:1; 2449218822Sdim 2450218822Sdim /* True if the target system is VxWorks. */ 2451218822Sdim unsigned int is_vxworks:1; 2452218822Sdim 2453218822Sdim /* The size of PLT entries. */ 2454218822Sdim int plt_entry_size; 2455218822Sdim /* The distance between adjacent PLT slots. */ 2456218822Sdim int plt_slot_size; 2457218822Sdim /* The size of the first PLT entry. */ 2458218822Sdim int plt_initial_entry_size; 2459218822Sdim 2460218822Sdim /* Small local sym to section mapping cache. */ 2461218822Sdim struct sym_sec_cache sym_sec; 2462218822Sdim}; 2463218822Sdim 2464218822Sdim/* Get the PPC ELF linker hash table from a link_info structure. */ 2465218822Sdim 2466218822Sdim#define ppc_elf_hash_table(p) \ 2467218822Sdim ((struct ppc_elf_link_hash_table *) (p)->hash) 2468218822Sdim 2469218822Sdim/* Create an entry in a PPC ELF linker hash table. */ 2470218822Sdim 2471218822Sdimstatic struct bfd_hash_entry * 2472218822Sdimppc_elf_link_hash_newfunc (struct bfd_hash_entry *entry, 2473218822Sdim struct bfd_hash_table *table, 2474218822Sdim const char *string) 2475218822Sdim{ 2476218822Sdim /* Allocate the structure if it has not already been allocated by a 2477218822Sdim subclass. */ 2478218822Sdim if (entry == NULL) 2479218822Sdim { 2480218822Sdim entry = bfd_hash_allocate (table, 2481218822Sdim sizeof (struct ppc_elf_link_hash_entry)); 2482218822Sdim if (entry == NULL) 2483218822Sdim return entry; 248460484Sobrien } 248560484Sobrien 2486218822Sdim /* Call the allocation method of the superclass. */ 2487218822Sdim entry = _bfd_elf_link_hash_newfunc (entry, table, string); 2488218822Sdim if (entry != NULL) 2489130561Sobrien { 2490218822Sdim ppc_elf_hash_entry (entry)->linker_section_pointer = NULL; 2491218822Sdim ppc_elf_hash_entry (entry)->dyn_relocs = NULL; 2492218822Sdim ppc_elf_hash_entry (entry)->tls_mask = 0; 2493130561Sobrien } 2494130561Sobrien 2495218822Sdim return entry; 249660484Sobrien} 249760484Sobrien 2498218822Sdim/* Create a PPC ELF linker hash table. */ 2499218822Sdim 2500218822Sdimstatic struct bfd_link_hash_table * 2501218822Sdimppc_elf_link_hash_table_create (bfd *abfd) 250260484Sobrien{ 2503218822Sdim struct ppc_elf_link_hash_table *ret; 250460484Sobrien 2505218822Sdim ret = bfd_zmalloc (sizeof (struct ppc_elf_link_hash_table)); 2506218822Sdim if (ret == NULL) 2507218822Sdim return NULL; 250860484Sobrien 2509218822Sdim if (!_bfd_elf_link_hash_table_init (&ret->elf, abfd, 2510218822Sdim ppc_elf_link_hash_newfunc, 2511218822Sdim sizeof (struct ppc_elf_link_hash_entry))) 2512218822Sdim { 2513218822Sdim free (ret); 2514218822Sdim return NULL; 2515218822Sdim } 251660484Sobrien 2517218822Sdim ret->elf.init_plt_refcount.refcount = 0; 2518218822Sdim ret->elf.init_plt_refcount.glist = NULL; 2519218822Sdim ret->elf.init_plt_offset.offset = 0; 2520218822Sdim ret->elf.init_plt_offset.glist = NULL; 252160484Sobrien 2522218822Sdim ret->sdata[0].name = ".sdata"; 2523218822Sdim ret->sdata[0].sym_name = "_SDA_BASE_"; 2524218822Sdim ret->sdata[0].bss_name = ".sbss"; 252560484Sobrien 2526218822Sdim ret->sdata[1].name = ".sdata2"; 2527218822Sdim ret->sdata[1].sym_name = "_SDA2_BASE_"; 2528218822Sdim ret->sdata[1].bss_name = ".sbss2"; 252960484Sobrien 2530218822Sdim ret->plt_entry_size = 12; 2531218822Sdim ret->plt_slot_size = 8; 2532218822Sdim ret->plt_initial_entry_size = 72; 253360484Sobrien 2534218822Sdim return &ret->elf.root; 253560484Sobrien} 253699461Sobrien 2537218822Sdim/* Create .got and the related sections. */ 2538218822Sdim 2539130561Sobrienstatic bfd_boolean 2540130561Sobrienppc_elf_create_got (bfd *abfd, struct bfd_link_info *info) 254199461Sobrien{ 2542130561Sobrien struct ppc_elf_link_hash_table *htab; 2543130561Sobrien asection *s; 254499461Sobrien flagword flags; 254599461Sobrien 254699461Sobrien if (!_bfd_elf_create_got_section (abfd, info)) 2547130561Sobrien return FALSE; 254899461Sobrien 2549130561Sobrien htab = ppc_elf_hash_table (info); 2550130561Sobrien htab->got = s = bfd_get_section_by_name (abfd, ".got"); 255199461Sobrien if (s == NULL) 255299461Sobrien abort (); 255399461Sobrien 2554218822Sdim if (htab->is_vxworks) 2555218822Sdim { 2556218822Sdim htab->sgotplt = bfd_get_section_by_name (abfd, ".got.plt"); 2557218822Sdim if (!htab->sgotplt) 2558218822Sdim abort (); 2559218822Sdim } 2560218822Sdim else 2561218822Sdim { 2562218822Sdim /* The powerpc .got has a blrl instruction in it. Mark it 2563218822Sdim executable. */ 2564218822Sdim flags = (SEC_ALLOC | SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS 2565218822Sdim | SEC_IN_MEMORY | SEC_LINKER_CREATED); 2566218822Sdim if (!bfd_set_section_flags (abfd, s, flags)) 2567218822Sdim return FALSE; 2568218822Sdim } 2569130561Sobrien 2570218822Sdim flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY 2571218822Sdim | SEC_LINKER_CREATED | SEC_READONLY); 2572218822Sdim htab->relgot = bfd_make_section_with_flags (abfd, ".rela.got", flags); 2573130561Sobrien if (!htab->relgot 2574130561Sobrien || ! bfd_set_section_alignment (abfd, htab->relgot, 2)) 2575130561Sobrien return FALSE; 2576130561Sobrien 2577130561Sobrien return TRUE; 257899461Sobrien} 257999461Sobrien 258060484Sobrien/* We have to create .dynsbss and .rela.sbss here so that they get mapped 258160484Sobrien to output sections (just like _bfd_elf_create_dynamic_sections has 258260484Sobrien to create .dynbss and .rela.bss). */ 258360484Sobrien 2584130561Sobrienstatic bfd_boolean 2585130561Sobrienppc_elf_create_dynamic_sections (bfd *abfd, struct bfd_link_info *info) 258660484Sobrien{ 2587130561Sobrien struct ppc_elf_link_hash_table *htab; 2588130561Sobrien asection *s; 258960484Sobrien flagword flags; 259060484Sobrien 2591130561Sobrien htab = ppc_elf_hash_table (info); 259299461Sobrien 2593130561Sobrien if (htab->got == NULL 2594130561Sobrien && !ppc_elf_create_got (abfd, info)) 2595130561Sobrien return FALSE; 2596130561Sobrien 259777298Sobrien if (!_bfd_elf_create_dynamic_sections (abfd, info)) 2598130561Sobrien return FALSE; 259960484Sobrien 2600218822Sdim flags = (SEC_ALLOC | SEC_LOAD | SEC_READONLY | SEC_HAS_CONTENTS 2601218822Sdim | SEC_IN_MEMORY | SEC_LINKER_CREATED); 260260484Sobrien 2603218822Sdim s = bfd_make_section_anyway_with_flags (abfd, ".glink", flags | SEC_CODE); 2604218822Sdim htab->glink = s; 260560484Sobrien if (s == NULL 2606218822Sdim || !bfd_set_section_alignment (abfd, s, 4)) 2607130561Sobrien return FALSE; 260860484Sobrien 2609218822Sdim htab->dynbss = bfd_get_section_by_name (abfd, ".dynbss"); 2610218822Sdim s = bfd_make_section_with_flags (abfd, ".dynsbss", 2611218822Sdim SEC_ALLOC | SEC_LINKER_CREATED); 2612218822Sdim htab->dynsbss = s; 2613218822Sdim if (s == NULL) 2614218822Sdim return FALSE; 2615218822Sdim 261660484Sobrien if (! info->shared) 261760484Sobrien { 2618130561Sobrien htab->relbss = bfd_get_section_by_name (abfd, ".rela.bss"); 2619218822Sdim s = bfd_make_section_with_flags (abfd, ".rela.sbss", flags); 2620218822Sdim htab->relsbss = s; 262160484Sobrien if (s == NULL 262260484Sobrien || ! bfd_set_section_alignment (abfd, s, 2)) 2623130561Sobrien return FALSE; 262460484Sobrien } 262599461Sobrien 2626218822Sdim if (htab->is_vxworks 2627218822Sdim && !elf_vxworks_create_dynamic_sections (abfd, info, &htab->srelplt2)) 2628218822Sdim return FALSE; 2629218822Sdim 2630130561Sobrien htab->relplt = bfd_get_section_by_name (abfd, ".rela.plt"); 2631130561Sobrien htab->plt = s = bfd_get_section_by_name (abfd, ".plt"); 263299461Sobrien if (s == NULL) 263399461Sobrien abort (); 263499461Sobrien 2635218822Sdim flags = SEC_ALLOC | SEC_CODE | SEC_LINKER_CREATED; 2636218822Sdim if (htab->plt_type == PLT_VXWORKS) 2637218822Sdim /* The VxWorks PLT is a loaded section with contents. */ 2638218822Sdim flags |= SEC_HAS_CONTENTS | SEC_LOAD | SEC_READONLY; 263999461Sobrien return bfd_set_section_flags (abfd, s, flags); 264060484Sobrien} 264160484Sobrien 2642218822Sdim/* Copy the extra info we tack onto an elf_link_hash_entry. */ 264360484Sobrien 2644218822Sdimstatic void 2645218822Sdimppc_elf_copy_indirect_symbol (struct bfd_link_info *info, 2646218822Sdim struct elf_link_hash_entry *dir, 2647218822Sdim struct elf_link_hash_entry *ind) 264860484Sobrien{ 2649218822Sdim struct ppc_elf_link_hash_entry *edir, *eind; 265060484Sobrien 2651218822Sdim edir = (struct ppc_elf_link_hash_entry *) dir; 2652218822Sdim eind = (struct ppc_elf_link_hash_entry *) ind; 265360484Sobrien 2654218822Sdim if (eind->dyn_relocs != NULL) 265560484Sobrien { 2656218822Sdim if (edir->dyn_relocs != NULL) 265760484Sobrien { 2658218822Sdim struct ppc_elf_dyn_relocs **pp; 2659218822Sdim struct ppc_elf_dyn_relocs *p; 266060484Sobrien 2661218822Sdim /* Add reloc counts against the indirect sym to the direct sym 2662218822Sdim list. Merge any entries against the same section. */ 2663218822Sdim for (pp = &eind->dyn_relocs; (p = *pp) != NULL; ) 2664218822Sdim { 2665218822Sdim struct ppc_elf_dyn_relocs *q; 266660484Sobrien 2667218822Sdim for (q = edir->dyn_relocs; q != NULL; q = q->next) 2668218822Sdim if (q->sec == p->sec) 2669218822Sdim { 2670218822Sdim q->pc_count += p->pc_count; 2671218822Sdim q->count += p->count; 2672218822Sdim *pp = p->next; 2673218822Sdim break; 2674218822Sdim } 2675218822Sdim if (q == NULL) 2676218822Sdim pp = &p->next; 2677218822Sdim } 2678218822Sdim *pp = edir->dyn_relocs; 267960484Sobrien } 268060484Sobrien 2681218822Sdim edir->dyn_relocs = eind->dyn_relocs; 2682218822Sdim eind->dyn_relocs = NULL; 268360484Sobrien } 268460484Sobrien 2685218822Sdim edir->tls_mask |= eind->tls_mask; 2686218822Sdim edir->has_sda_refs |= eind->has_sda_refs; 268760484Sobrien 2688218822Sdim /* If called to transfer flags for a weakdef during processing 2689218822Sdim of elf_adjust_dynamic_symbol, don't copy non_got_ref. 2690218822Sdim We clear it ourselves for ELIMINATE_COPY_RELOCS. */ 2691218822Sdim if (!(ELIMINATE_COPY_RELOCS 2692218822Sdim && eind->elf.root.type != bfd_link_hash_indirect 2693218822Sdim && edir->elf.dynamic_adjusted)) 2694218822Sdim edir->elf.non_got_ref |= eind->elf.non_got_ref; 269560484Sobrien 2696218822Sdim edir->elf.ref_dynamic |= eind->elf.ref_dynamic; 2697218822Sdim edir->elf.ref_regular |= eind->elf.ref_regular; 2698218822Sdim edir->elf.ref_regular_nonweak |= eind->elf.ref_regular_nonweak; 2699218822Sdim edir->elf.needs_plt |= eind->elf.needs_plt; 2700130561Sobrien 2701218822Sdim /* If we were called to copy over info for a weak sym, that's all. */ 2702218822Sdim if (eind->elf.root.type != bfd_link_hash_indirect) 2703218822Sdim return; 2704218822Sdim 2705218822Sdim /* Copy over the GOT refcount entries that we may have already seen to 2706218822Sdim the symbol which just became indirect. */ 2707218822Sdim edir->elf.got.refcount += eind->elf.got.refcount; 2708218822Sdim eind->elf.got.refcount = 0; 2709218822Sdim 2710218822Sdim /* And plt entries. */ 2711218822Sdim if (eind->elf.plt.plist != NULL) 2712130561Sobrien { 2713218822Sdim if (edir->elf.plt.plist != NULL) 2714130561Sobrien { 2715218822Sdim struct plt_entry **entp; 2716218822Sdim struct plt_entry *ent; 2717130561Sobrien 2718218822Sdim for (entp = &eind->elf.plt.plist; (ent = *entp) != NULL; ) 2719218822Sdim { 2720218822Sdim struct plt_entry *dent; 2721218822Sdim 2722218822Sdim for (dent = edir->elf.plt.plist; dent != NULL; dent = dent->next) 2723218822Sdim if (dent->sec == ent->sec && dent->addend == ent->addend) 2724218822Sdim { 2725218822Sdim dent->plt.refcount += ent->plt.refcount; 2726218822Sdim *entp = ent->next; 2727218822Sdim break; 2728218822Sdim } 2729218822Sdim if (dent == NULL) 2730218822Sdim entp = &ent->next; 2731218822Sdim } 2732218822Sdim *entp = edir->elf.plt.plist; 2733130561Sobrien } 2734130561Sobrien 2735218822Sdim edir->elf.plt.plist = eind->elf.plt.plist; 2736218822Sdim eind->elf.plt.plist = NULL; 273760484Sobrien } 273860484Sobrien 2739218822Sdim if (eind->elf.dynindx != -1) 274060484Sobrien { 2741218822Sdim if (edir->elf.dynindx != -1) 2742218822Sdim _bfd_elf_strtab_delref (elf_hash_table (info)->dynstr, 2743218822Sdim edir->elf.dynstr_index); 2744218822Sdim edir->elf.dynindx = eind->elf.dynindx; 2745218822Sdim edir->elf.dynstr_index = eind->elf.dynstr_index; 2746218822Sdim eind->elf.dynindx = -1; 2747218822Sdim eind->elf.dynstr_index = 0; 274860484Sobrien } 2749218822Sdim} 275060484Sobrien 2751218822Sdim/* Return 1 if target is one of ours. */ 275260484Sobrien 2753218822Sdimstatic bfd_boolean 2754218822Sdimis_ppc_elf_target (const struct bfd_target *targ) 2755218822Sdim{ 2756218822Sdim extern const bfd_target bfd_elf32_powerpc_vec; 2757218822Sdim extern const bfd_target bfd_elf32_powerpc_vxworks_vec; 2758218822Sdim extern const bfd_target bfd_elf32_powerpcle_vec; 275960484Sobrien 2760218822Sdim return (targ == &bfd_elf32_powerpc_vec 2761218822Sdim || targ == &bfd_elf32_powerpc_vxworks_vec 2762218822Sdim || targ == &bfd_elf32_powerpcle_vec); 276360484Sobrien} 2764130561Sobrien 2765218822Sdim/* Hook called by the linker routine which adds symbols from an object 2766218822Sdim file. We use it to put .comm items in .sbss, and not .bss. */ 2767130561Sobrien 2768130561Sobrienstatic bfd_boolean 2769218822Sdimppc_elf_add_symbol_hook (bfd *abfd, 2770218822Sdim struct bfd_link_info *info, 2771218822Sdim Elf_Internal_Sym *sym, 2772218822Sdim const char **namep ATTRIBUTE_UNUSED, 2773218822Sdim flagword *flagsp ATTRIBUTE_UNUSED, 2774218822Sdim asection **secp, 2775218822Sdim bfd_vma *valp) 2776130561Sobrien{ 2777218822Sdim if (sym->st_shndx == SHN_COMMON 2778218822Sdim && !info->relocatable 2779218822Sdim && sym->st_size <= elf_gp_size (abfd) 2780218822Sdim && is_ppc_elf_target (info->hash->creator)) 2781130561Sobrien { 2782218822Sdim /* Common symbols less than or equal to -G nn bytes are automatically 2783218822Sdim put into .sbss. */ 2784218822Sdim struct ppc_elf_link_hash_table *htab; 2785130561Sobrien 2786218822Sdim htab = ppc_elf_hash_table (info); 2787218822Sdim if (htab->sbss == NULL) 2788130561Sobrien { 2789218822Sdim flagword flags = SEC_IS_COMMON | SEC_LINKER_CREATED; 2790130561Sobrien 2791218822Sdim if (!htab->elf.dynobj) 2792218822Sdim htab->elf.dynobj = abfd; 2793130561Sobrien 2794218822Sdim htab->sbss = bfd_make_section_anyway_with_flags (htab->elf.dynobj, 2795218822Sdim ".sbss", 2796218822Sdim flags); 2797218822Sdim if (htab->sbss == NULL) 2798130561Sobrien return FALSE; 2799130561Sobrien } 2800130561Sobrien 2801218822Sdim *secp = htab->sbss; 2802218822Sdim *valp = sym->st_size; 2803130561Sobrien } 2804130561Sobrien 2805218822Sdim return TRUE; 2806218822Sdim} 2807218822Sdim 2808218822Sdimstatic bfd_boolean 2809218822Sdimcreate_sdata_sym (struct ppc_elf_link_hash_table *htab, 2810218822Sdim elf_linker_section_t *lsect) 2811218822Sdim{ 2812218822Sdim lsect->sym = elf_link_hash_lookup (&htab->elf, lsect->sym_name, 2813218822Sdim TRUE, FALSE, TRUE); 2814218822Sdim if (lsect->sym == NULL) 2815218822Sdim return FALSE; 2816218822Sdim if (lsect->sym->root.type == bfd_link_hash_new) 2817218822Sdim lsect->sym->non_elf = 0; 2818218822Sdim lsect->sym->ref_regular = 1; 2819218822Sdim return TRUE; 2820218822Sdim} 2821130561Sobrien 2822218822Sdim/* Create a special linker section. */ 2823130561Sobrien 2824218822Sdimstatic bfd_boolean 2825218822Sdimppc_elf_create_linker_section (bfd *abfd, 2826218822Sdim struct bfd_link_info *info, 2827218822Sdim flagword flags, 2828218822Sdim elf_linker_section_t *lsect) 2829218822Sdim{ 2830218822Sdim struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); 2831218822Sdim asection *s; 2832130561Sobrien 2833218822Sdim flags |= (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY 2834218822Sdim | SEC_LINKER_CREATED); 2835130561Sobrien 2836218822Sdim /* Record the first bfd that needs the special sections. */ 2837218822Sdim if (!htab->elf.dynobj) 2838218822Sdim htab->elf.dynobj = abfd; 2839130561Sobrien 2840218822Sdim s = bfd_make_section_anyway_with_flags (htab->elf.dynobj, 2841218822Sdim lsect->name, 2842218822Sdim flags); 2843218822Sdim if (s == NULL 2844218822Sdim || !bfd_set_section_alignment (htab->elf.dynobj, s, 2)) 2845218822Sdim return FALSE; 2846218822Sdim lsect->section = s; 2847130561Sobrien 2848218822Sdim return create_sdata_sym (htab, lsect); 2849130561Sobrien} 2850130561Sobrien 2851218822Sdim/* Find a linker generated pointer with a given addend and type. */ 2852130561Sobrien 2853218822Sdimstatic elf_linker_section_pointers_t * 2854218822Sdimelf_find_pointer_linker_section 2855218822Sdim (elf_linker_section_pointers_t *linker_pointers, 2856218822Sdim bfd_vma addend, 2857218822Sdim elf_linker_section_t *lsect) 2858130561Sobrien{ 2859218822Sdim for ( ; linker_pointers != NULL; linker_pointers = linker_pointers->next) 2860218822Sdim if (lsect == linker_pointers->lsect && addend == linker_pointers->addend) 2861218822Sdim return linker_pointers; 2862130561Sobrien 2863218822Sdim return NULL; 2864130561Sobrien} 2865130561Sobrien 2866218822Sdim/* Allocate a pointer to live in a linker created section. */ 286760484Sobrien 2868130561Sobrienstatic bfd_boolean 2869218822Sdimelf_create_pointer_linker_section (bfd *abfd, 2870218822Sdim elf_linker_section_t *lsect, 2871218822Sdim struct elf_link_hash_entry *h, 2872218822Sdim const Elf_Internal_Rela *rel) 287360484Sobrien{ 2874218822Sdim elf_linker_section_pointers_t **ptr_linker_section_ptr = NULL; 2875218822Sdim elf_linker_section_pointers_t *linker_section_ptr; 2876218822Sdim unsigned long r_symndx = ELF32_R_SYM (rel->r_info); 2877218822Sdim bfd_size_type amt; 287860484Sobrien 2879218822Sdim BFD_ASSERT (lsect != NULL); 288060484Sobrien 2881218822Sdim /* Is this a global symbol? */ 2882218822Sdim if (h != NULL) 288360484Sobrien { 2884218822Sdim struct ppc_elf_link_hash_entry *eh; 2885130561Sobrien 2886218822Sdim /* Has this symbol already been allocated? If so, our work is done. */ 2887218822Sdim eh = (struct ppc_elf_link_hash_entry *) h; 2888218822Sdim if (elf_find_pointer_linker_section (eh->linker_section_pointer, 2889218822Sdim rel->r_addend, 2890218822Sdim lsect)) 2891218822Sdim return TRUE; 2892218822Sdim 2893218822Sdim ptr_linker_section_ptr = &eh->linker_section_pointer; 2894130561Sobrien } 289560484Sobrien else 289660484Sobrien { 2897218822Sdim /* Allocation of a pointer to a local symbol. */ 2898218822Sdim elf_linker_section_pointers_t **ptr = elf_local_ptr_offsets (abfd); 289960484Sobrien 2900218822Sdim /* Allocate a table to hold the local symbols if first time. */ 2901218822Sdim if (!ptr) 290260484Sobrien { 2903218822Sdim unsigned int num_symbols = elf_tdata (abfd)->symtab_hdr.sh_info; 2904130561Sobrien 2905218822Sdim amt = num_symbols; 2906218822Sdim amt *= sizeof (elf_linker_section_pointers_t *); 2907218822Sdim ptr = bfd_zalloc (abfd, amt); 2908130561Sobrien 2909218822Sdim if (!ptr) 2910218822Sdim return FALSE; 2911130561Sobrien 2912218822Sdim elf_local_ptr_offsets (abfd) = ptr; 291360484Sobrien } 291460484Sobrien 2915218822Sdim /* Has this symbol already been allocated? If so, our work is done. */ 2916218822Sdim if (elf_find_pointer_linker_section (ptr[r_symndx], 2917218822Sdim rel->r_addend, 2918218822Sdim lsect)) 2919218822Sdim return TRUE; 292060484Sobrien 2921218822Sdim ptr_linker_section_ptr = &ptr[r_symndx]; 292260484Sobrien } 292360484Sobrien 2924218822Sdim /* Allocate space for a pointer in the linker section, and allocate 2925218822Sdim a new pointer record from internal memory. */ 2926218822Sdim BFD_ASSERT (ptr_linker_section_ptr != NULL); 2927218822Sdim amt = sizeof (elf_linker_section_pointers_t); 2928218822Sdim linker_section_ptr = bfd_alloc (abfd, amt); 292989857Sobrien 2930218822Sdim if (!linker_section_ptr) 2931218822Sdim return FALSE; 293260484Sobrien 2933218822Sdim linker_section_ptr->next = *ptr_linker_section_ptr; 2934218822Sdim linker_section_ptr->addend = rel->r_addend; 2935218822Sdim linker_section_ptr->lsect = lsect; 2936218822Sdim *ptr_linker_section_ptr = linker_section_ptr; 293760484Sobrien 2938218822Sdim linker_section_ptr->offset = lsect->section->size; 2939218822Sdim lsect->section->size += 4; 294060484Sobrien 2941218822Sdim#ifdef DEBUG 2942218822Sdim fprintf (stderr, 2943218822Sdim "Create pointer in linker section %s, offset = %ld, section size = %ld\n", 2944218822Sdim lsect->name, (long) linker_section_ptr->offset, 2945218822Sdim (long) lsect->section->size); 2946218822Sdim#endif 2947130561Sobrien 2948130561Sobrien return TRUE; 294960484Sobrien} 2950218822Sdim 2951130561Sobrienstatic bfd_boolean 2952130561Sobrienupdate_local_sym_info (bfd *abfd, 2953130561Sobrien Elf_Internal_Shdr *symtab_hdr, 2954130561Sobrien unsigned long r_symndx, 2955130561Sobrien int tls_type) 2956130561Sobrien{ 2957130561Sobrien bfd_signed_vma *local_got_refcounts = elf_local_got_refcounts (abfd); 2958130561Sobrien char *local_got_tls_masks; 2959130561Sobrien 2960130561Sobrien if (local_got_refcounts == NULL) 2961130561Sobrien { 2962130561Sobrien bfd_size_type size = symtab_hdr->sh_info; 2963130561Sobrien 2964130561Sobrien size *= sizeof (*local_got_refcounts) + sizeof (*local_got_tls_masks); 2965130561Sobrien local_got_refcounts = bfd_zalloc (abfd, size); 2966130561Sobrien if (local_got_refcounts == NULL) 2967130561Sobrien return FALSE; 2968130561Sobrien elf_local_got_refcounts (abfd) = local_got_refcounts; 2969130561Sobrien } 2970130561Sobrien 2971130561Sobrien local_got_refcounts[r_symndx] += 1; 2972130561Sobrien local_got_tls_masks = (char *) (local_got_refcounts + symtab_hdr->sh_info); 2973130561Sobrien local_got_tls_masks[r_symndx] |= tls_type; 2974130561Sobrien return TRUE; 2975130561Sobrien} 2976130561Sobrien 2977218822Sdimstatic bfd_boolean 2978218822Sdimupdate_plt_info (bfd *abfd, struct elf_link_hash_entry *h, 2979218822Sdim asection *sec, bfd_vma addend) 2980218822Sdim{ 2981218822Sdim struct plt_entry *ent; 2982218822Sdim 2983218822Sdim if (addend < 32768) 2984218822Sdim sec = NULL; 2985218822Sdim for (ent = h->plt.plist; ent != NULL; ent = ent->next) 2986218822Sdim if (ent->sec == sec && ent->addend == addend) 2987218822Sdim break; 2988218822Sdim if (ent == NULL) 2989218822Sdim { 2990218822Sdim bfd_size_type amt = sizeof (*ent); 2991218822Sdim ent = bfd_alloc (abfd, amt); 2992218822Sdim if (ent == NULL) 2993218822Sdim return FALSE; 2994218822Sdim ent->next = h->plt.plist; 2995218822Sdim ent->sec = sec; 2996218822Sdim ent->addend = addend; 2997218822Sdim ent->plt.refcount = 0; 2998218822Sdim h->plt.plist = ent; 2999218822Sdim } 3000218822Sdim ent->plt.refcount += 1; 3001218822Sdim return TRUE; 3002218822Sdim} 3003218822Sdim 3004218822Sdimstatic struct plt_entry * 3005218822Sdimfind_plt_ent (struct elf_link_hash_entry *h, asection *sec, bfd_vma addend) 3006218822Sdim{ 3007218822Sdim struct plt_entry *ent; 3008218822Sdim 3009218822Sdim if (addend < 32768) 3010218822Sdim sec = NULL; 3011218822Sdim for (ent = h->plt.plist; ent != NULL; ent = ent->next) 3012218822Sdim if (ent->sec == sec && ent->addend == addend) 3013218822Sdim break; 3014218822Sdim return ent; 3015218822Sdim} 3016218822Sdim 3017130561Sobrienstatic void 3018130561Sobrienbad_shared_reloc (bfd *abfd, enum elf_ppc_reloc_type r_type) 3019130561Sobrien{ 3020130561Sobrien (*_bfd_error_handler) 3021218822Sdim (_("%B: relocation %s cannot be used when making a shared object"), 3022218822Sdim abfd, 3023130561Sobrien ppc_elf_howto_table[r_type]->name); 3024130561Sobrien bfd_set_error (bfd_error_bad_value); 3025130561Sobrien} 3026130561Sobrien 302760484Sobrien/* Look through the relocs for a section during the first phase, and 302860484Sobrien allocate space in the global offset table or procedure linkage 302960484Sobrien table. */ 303060484Sobrien 3031130561Sobrienstatic bfd_boolean 3032130561Sobrienppc_elf_check_relocs (bfd *abfd, 3033130561Sobrien struct bfd_link_info *info, 3034130561Sobrien asection *sec, 3035130561Sobrien const Elf_Internal_Rela *relocs) 303660484Sobrien{ 3037130561Sobrien struct ppc_elf_link_hash_table *htab; 303860484Sobrien Elf_Internal_Shdr *symtab_hdr; 3039130561Sobrien struct elf_link_hash_entry **sym_hashes; 304060484Sobrien const Elf_Internal_Rela *rel; 304160484Sobrien const Elf_Internal_Rela *rel_end; 3042218822Sdim asection *got2, *sreloc; 304360484Sobrien 3044130561Sobrien if (info->relocatable) 3045130561Sobrien return TRUE; 304660484Sobrien 3047218822Sdim /* Don't do anything special with non-loaded, non-alloced sections. 3048218822Sdim In particular, any relocs in such sections should not affect GOT 3049218822Sdim and PLT reference counting (ie. we don't allow them to create GOT 3050218822Sdim or PLT entries), there's no possibility or desire to optimize TLS 3051218822Sdim relocs, and there's not much point in propagating relocs to shared 3052218822Sdim libs that the dynamic linker won't relocate. */ 3053218822Sdim if ((sec->flags & SEC_ALLOC) == 0) 3054218822Sdim return TRUE; 3055218822Sdim 305660484Sobrien#ifdef DEBUG 3057218822Sdim _bfd_error_handler ("ppc_elf_check_relocs called for section %A in %B", 3058218822Sdim sec, abfd); 305960484Sobrien#endif 306060484Sobrien 3061130561Sobrien /* Initialize howto table if not already done. */ 3062130561Sobrien if (!ppc_elf_howto_table[R_PPC_ADDR32]) 3063130561Sobrien ppc_elf_howto_init (); 3064130561Sobrien 3065130561Sobrien htab = ppc_elf_hash_table (info); 306660484Sobrien symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 306760484Sobrien sym_hashes = elf_sym_hashes (abfd); 3068218822Sdim got2 = bfd_get_section_by_name (abfd, ".got2"); 306960484Sobrien sreloc = NULL; 307060484Sobrien 307160484Sobrien rel_end = relocs + sec->reloc_count; 307260484Sobrien for (rel = relocs; rel < rel_end; rel++) 307360484Sobrien { 307460484Sobrien unsigned long r_symndx; 3075130561Sobrien enum elf_ppc_reloc_type r_type; 307660484Sobrien struct elf_link_hash_entry *h; 3077130561Sobrien int tls_type = 0; 307860484Sobrien 307960484Sobrien r_symndx = ELF32_R_SYM (rel->r_info); 308060484Sobrien if (r_symndx < symtab_hdr->sh_info) 308160484Sobrien h = NULL; 308260484Sobrien else 3083218822Sdim { 3084218822Sdim h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 3085218822Sdim while (h->root.type == bfd_link_hash_indirect 3086218822Sdim || h->root.type == bfd_link_hash_warning) 3087218822Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 3088218822Sdim } 308960484Sobrien 309060484Sobrien /* If a relocation refers to _GLOBAL_OFFSET_TABLE_, create the .got. 309160484Sobrien This shows up in particular in an R_PPC_ADDR32 in the eabi 309260484Sobrien startup code. */ 3093218822Sdim if (h != NULL 3094218822Sdim && htab->got == NULL 3095218822Sdim && strcmp (h->root.root.string, "_GLOBAL_OFFSET_TABLE_") == 0) 309660484Sobrien { 3097218822Sdim if (htab->elf.dynobj == NULL) 3098218822Sdim htab->elf.dynobj = abfd; 3099218822Sdim if (!ppc_elf_create_got (htab->elf.dynobj, info)) 3100218822Sdim return FALSE; 3101218822Sdim BFD_ASSERT (h == htab->elf.hgot); 310260484Sobrien } 310360484Sobrien 3104130561Sobrien r_type = ELF32_R_TYPE (rel->r_info); 3105130561Sobrien switch (r_type) 310660484Sobrien { 3107130561Sobrien case R_PPC_GOT_TLSLD16: 3108130561Sobrien case R_PPC_GOT_TLSLD16_LO: 3109130561Sobrien case R_PPC_GOT_TLSLD16_HI: 3110130561Sobrien case R_PPC_GOT_TLSLD16_HA: 3111130561Sobrien htab->tlsld_got.refcount += 1; 3112130561Sobrien tls_type = TLS_TLS | TLS_LD; 3113130561Sobrien goto dogottls; 3114130561Sobrien 3115130561Sobrien case R_PPC_GOT_TLSGD16: 3116130561Sobrien case R_PPC_GOT_TLSGD16_LO: 3117130561Sobrien case R_PPC_GOT_TLSGD16_HI: 3118130561Sobrien case R_PPC_GOT_TLSGD16_HA: 3119130561Sobrien tls_type = TLS_TLS | TLS_GD; 3120130561Sobrien goto dogottls; 3121130561Sobrien 3122130561Sobrien case R_PPC_GOT_TPREL16: 3123130561Sobrien case R_PPC_GOT_TPREL16_LO: 3124130561Sobrien case R_PPC_GOT_TPREL16_HI: 3125130561Sobrien case R_PPC_GOT_TPREL16_HA: 3126130561Sobrien if (info->shared) 3127130561Sobrien info->flags |= DF_STATIC_TLS; 3128130561Sobrien tls_type = TLS_TLS | TLS_TPREL; 3129130561Sobrien goto dogottls; 3130130561Sobrien 3131130561Sobrien case R_PPC_GOT_DTPREL16: 3132130561Sobrien case R_PPC_GOT_DTPREL16_LO: 3133130561Sobrien case R_PPC_GOT_DTPREL16_HI: 3134130561Sobrien case R_PPC_GOT_DTPREL16_HA: 3135130561Sobrien tls_type = TLS_TLS | TLS_DTPREL; 3136130561Sobrien dogottls: 3137130561Sobrien sec->has_tls_reloc = 1; 3138130561Sobrien /* Fall thru */ 3139130561Sobrien 3140130561Sobrien /* GOT16 relocations */ 314160484Sobrien case R_PPC_GOT16: 314260484Sobrien case R_PPC_GOT16_LO: 314360484Sobrien case R_PPC_GOT16_HI: 314460484Sobrien case R_PPC_GOT16_HA: 314560484Sobrien /* This symbol requires a global offset table entry. */ 3146130561Sobrien if (htab->got == NULL) 314760484Sobrien { 3148130561Sobrien if (htab->elf.dynobj == NULL) 3149130561Sobrien htab->elf.dynobj = abfd; 3150130561Sobrien if (!ppc_elf_create_got (htab->elf.dynobj, info)) 3151130561Sobrien return FALSE; 315260484Sobrien } 315360484Sobrien if (h != NULL) 315460484Sobrien { 3155130561Sobrien h->got.refcount += 1; 3156130561Sobrien ppc_elf_hash_entry (h)->tls_mask |= tls_type; 315760484Sobrien } 315860484Sobrien else 3159130561Sobrien /* This is a global offset table entry for a local symbol. */ 3160130561Sobrien if (!update_local_sym_info (abfd, symtab_hdr, r_symndx, tls_type)) 3161130561Sobrien return FALSE; 316260484Sobrien break; 316360484Sobrien 3164130561Sobrien /* Indirect .sdata relocation. */ 316560484Sobrien case R_PPC_EMB_SDAI16: 316660484Sobrien if (info->shared) 316760484Sobrien { 3168130561Sobrien bad_shared_reloc (abfd, r_type); 3169130561Sobrien return FALSE; 317060484Sobrien } 3171218822Sdim if (htab->sdata[0].section == NULL 3172218822Sdim && !ppc_elf_create_linker_section (abfd, info, 0, 3173218822Sdim &htab->sdata[0])) 3174130561Sobrien return FALSE; 3175218822Sdim if (!elf_create_pointer_linker_section (abfd, &htab->sdata[0], 3176218822Sdim h, rel)) 3177218822Sdim return FALSE; 3178218822Sdim if (h != NULL) 3179218822Sdim { 3180218822Sdim ppc_elf_hash_entry (h)->has_sda_refs = TRUE; 3181218822Sdim h->non_got_ref = TRUE; 3182218822Sdim } 318360484Sobrien break; 318460484Sobrien 3185130561Sobrien /* Indirect .sdata2 relocation. */ 318660484Sobrien case R_PPC_EMB_SDA2I16: 318760484Sobrien if (info->shared) 318860484Sobrien { 3189130561Sobrien bad_shared_reloc (abfd, r_type); 3190130561Sobrien return FALSE; 319160484Sobrien } 3192218822Sdim if (htab->sdata[1].section == NULL 3193218822Sdim && !ppc_elf_create_linker_section (abfd, info, SEC_READONLY, 3194218822Sdim &htab->sdata[1])) 3195130561Sobrien return FALSE; 3196218822Sdim if (!elf_create_pointer_linker_section (abfd, &htab->sdata[1], 3197218822Sdim h, rel)) 3198218822Sdim return FALSE; 3199218822Sdim if (h != NULL) 3200218822Sdim { 3201218822Sdim ppc_elf_hash_entry (h)->has_sda_refs = TRUE; 3202218822Sdim h->non_got_ref = TRUE; 3203218822Sdim } 320460484Sobrien break; 320560484Sobrien 320660484Sobrien case R_PPC_SDAREL16: 3207218822Sdim if (info->shared) 3208218822Sdim { 3209218822Sdim bad_shared_reloc (abfd, r_type); 3210218822Sdim return FALSE; 3211218822Sdim } 3212218822Sdim if (htab->sdata[0].sym == NULL 3213218822Sdim && !create_sdata_sym (htab, &htab->sdata[0])) 3214218822Sdim return FALSE; 3215218822Sdim if (h != NULL) 3216218822Sdim { 3217218822Sdim ppc_elf_hash_entry (h)->has_sda_refs = TRUE; 3218218822Sdim h->non_got_ref = TRUE; 3219218822Sdim } 3220218822Sdim break; 3221218822Sdim 322260484Sobrien case R_PPC_EMB_SDA2REL: 3223218822Sdim if (info->shared) 3224218822Sdim { 3225218822Sdim bad_shared_reloc (abfd, r_type); 3226218822Sdim return FALSE; 3227218822Sdim } 3228218822Sdim if (htab->sdata[1].sym == NULL 3229218822Sdim && !create_sdata_sym (htab, &htab->sdata[1])) 3230218822Sdim return FALSE; 3231218822Sdim if (h != NULL) 3232218822Sdim { 3233218822Sdim ppc_elf_hash_entry (h)->has_sda_refs = TRUE; 3234218822Sdim h->non_got_ref = TRUE; 3235218822Sdim } 3236218822Sdim break; 3237218822Sdim 323860484Sobrien case R_PPC_EMB_SDA21: 3239130561Sobrien case R_PPC_EMB_RELSDA: 3240218822Sdim if (info->shared) 3241218822Sdim { 3242218822Sdim bad_shared_reloc (abfd, r_type); 3243218822Sdim return FALSE; 3244218822Sdim } 3245218822Sdim if (htab->sdata[0].sym == NULL 3246218822Sdim && !create_sdata_sym (htab, &htab->sdata[0])) 3247218822Sdim return FALSE; 3248218822Sdim if (htab->sdata[1].sym == NULL 3249218822Sdim && !create_sdata_sym (htab, &htab->sdata[1])) 3250218822Sdim return FALSE; 3251218822Sdim if (h != NULL) 3252218822Sdim { 3253218822Sdim ppc_elf_hash_entry (h)->has_sda_refs = TRUE; 3254218822Sdim h->non_got_ref = TRUE; 3255218822Sdim } 3256218822Sdim break; 3257218822Sdim 3258130561Sobrien case R_PPC_EMB_NADDR32: 3259130561Sobrien case R_PPC_EMB_NADDR16: 3260130561Sobrien case R_PPC_EMB_NADDR16_LO: 3261130561Sobrien case R_PPC_EMB_NADDR16_HI: 3262130561Sobrien case R_PPC_EMB_NADDR16_HA: 326360484Sobrien if (info->shared) 326460484Sobrien { 3265130561Sobrien bad_shared_reloc (abfd, r_type); 3266130561Sobrien return FALSE; 326760484Sobrien } 3268218822Sdim if (h != NULL) 3269218822Sdim h->non_got_ref = TRUE; 327060484Sobrien break; 327160484Sobrien 327260484Sobrien case R_PPC_PLT32: 327360484Sobrien case R_PPC_PLTREL24: 3274130561Sobrien case R_PPC_PLTREL32: 327560484Sobrien case R_PPC_PLT16_LO: 327660484Sobrien case R_PPC_PLT16_HI: 327760484Sobrien case R_PPC_PLT16_HA: 327860484Sobrien#ifdef DEBUG 327960484Sobrien fprintf (stderr, "Reloc requires a PLT entry\n"); 328060484Sobrien#endif 328160484Sobrien /* This symbol requires a procedure linkage table entry. We 3282130561Sobrien actually build the entry in finish_dynamic_symbol, 3283130561Sobrien because this might be a case of linking PIC code without 3284130561Sobrien linking in any dynamic objects, in which case we don't 3285130561Sobrien need to generate a procedure linkage table after all. */ 328660484Sobrien 328760484Sobrien if (h == NULL) 328860484Sobrien { 328960484Sobrien /* It does not make sense to have a procedure linkage 3290130561Sobrien table entry for a local symbol. */ 3291218822Sdim (*_bfd_error_handler) (_("%B(%A+0x%lx): %s reloc against " 3292130561Sobrien "local symbol"), 3293218822Sdim abfd, 3294218822Sdim sec, 3295130561Sobrien (long) rel->r_offset, 3296130561Sobrien ppc_elf_howto_table[r_type]->name); 329760484Sobrien bfd_set_error (bfd_error_bad_value); 3298130561Sobrien return FALSE; 329960484Sobrien } 3300218822Sdim else 3301218822Sdim { 3302218822Sdim bfd_vma addend = 0; 330360484Sobrien 3304218822Sdim if (r_type == R_PPC_PLTREL24) 3305218822Sdim { 3306218822Sdim ppc_elf_tdata (abfd)->makes_plt_call = 1; 3307218822Sdim addend = rel->r_addend; 3308218822Sdim } 3309218822Sdim h->needs_plt = 1; 3310218822Sdim if (!update_plt_info (abfd, h, got2, addend)) 3311218822Sdim return FALSE; 3312218822Sdim } 331360484Sobrien break; 331460484Sobrien 331560484Sobrien /* The following relocations don't need to propagate the 331660484Sobrien relocation if linking a shared object since they are 331760484Sobrien section relative. */ 331860484Sobrien case R_PPC_SECTOFF: 331960484Sobrien case R_PPC_SECTOFF_LO: 332060484Sobrien case R_PPC_SECTOFF_HI: 332160484Sobrien case R_PPC_SECTOFF_HA: 3322130561Sobrien case R_PPC_DTPREL16: 3323130561Sobrien case R_PPC_DTPREL16_LO: 3324130561Sobrien case R_PPC_DTPREL16_HI: 3325130561Sobrien case R_PPC_DTPREL16_HA: 3326130561Sobrien case R_PPC_TOC16: 332760484Sobrien break; 332860484Sobrien 3329218822Sdim case R_PPC_REL16: 3330218822Sdim case R_PPC_REL16_LO: 3331218822Sdim case R_PPC_REL16_HI: 3332218822Sdim case R_PPC_REL16_HA: 3333218822Sdim ppc_elf_tdata (abfd)->has_rel16 = 1; 3334218822Sdim break; 3335218822Sdim 3336218822Sdim /* These are just markers. */ 3337130561Sobrien case R_PPC_TLS: 3338130561Sobrien case R_PPC_EMB_MRKREF: 3339130561Sobrien case R_PPC_NONE: 3340130561Sobrien case R_PPC_max: 3341130561Sobrien break; 3342130561Sobrien 3343130561Sobrien /* These should only appear in dynamic objects. */ 3344130561Sobrien case R_PPC_COPY: 3345130561Sobrien case R_PPC_GLOB_DAT: 3346130561Sobrien case R_PPC_JMP_SLOT: 3347130561Sobrien case R_PPC_RELATIVE: 3348130561Sobrien break; 3349130561Sobrien 3350130561Sobrien /* These aren't handled yet. We'll report an error later. */ 3351130561Sobrien case R_PPC_ADDR30: 3352130561Sobrien case R_PPC_EMB_RELSEC16: 3353130561Sobrien case R_PPC_EMB_RELST_LO: 3354130561Sobrien case R_PPC_EMB_RELST_HI: 3355130561Sobrien case R_PPC_EMB_RELST_HA: 3356130561Sobrien case R_PPC_EMB_BIT_FLD: 3357130561Sobrien break; 3358130561Sobrien 3359130561Sobrien /* This refers only to functions defined in the shared library. */ 336060484Sobrien case R_PPC_LOCAL24PC: 3361218822Sdim if (h && h == htab->elf.hgot && htab->plt_type == PLT_UNSET) 3362218822Sdim { 3363218822Sdim htab->plt_type = PLT_OLD; 3364218822Sdim htab->old_bfd = abfd; 3365218822Sdim } 336660484Sobrien break; 336760484Sobrien 336860484Sobrien /* This relocation describes the C++ object vtable hierarchy. 336960484Sobrien Reconstruct it for later use during GC. */ 337060484Sobrien case R_PPC_GNU_VTINHERIT: 3371130561Sobrien if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset)) 3372130561Sobrien return FALSE; 337360484Sobrien break; 337460484Sobrien 337560484Sobrien /* This relocation describes which C++ vtable entries are actually 337660484Sobrien used. Record for later use during GC. */ 337760484Sobrien case R_PPC_GNU_VTENTRY: 3378130561Sobrien if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_addend)) 3379130561Sobrien return FALSE; 338060484Sobrien break; 338160484Sobrien 3382130561Sobrien /* We shouldn't really be seeing these. */ 3383130561Sobrien case R_PPC_TPREL32: 3384130561Sobrien if (info->shared) 3385130561Sobrien info->flags |= DF_STATIC_TLS; 3386130561Sobrien goto dodyn; 3387130561Sobrien 3388130561Sobrien /* Nor these. */ 3389130561Sobrien case R_PPC_DTPMOD32: 3390130561Sobrien case R_PPC_DTPREL32: 3391130561Sobrien goto dodyn; 3392130561Sobrien 3393130561Sobrien case R_PPC_TPREL16: 3394130561Sobrien case R_PPC_TPREL16_LO: 3395130561Sobrien case R_PPC_TPREL16_HI: 3396130561Sobrien case R_PPC_TPREL16_HA: 3397130561Sobrien if (info->shared) 3398130561Sobrien info->flags |= DF_STATIC_TLS; 3399130561Sobrien goto dodyn; 3400130561Sobrien 3401218822Sdim case R_PPC_REL32: 3402218822Sdim if (h == NULL 3403218822Sdim && got2 != NULL 3404218822Sdim && (sec->flags & SEC_CODE) != 0 3405218822Sdim && (info->shared || info->pie) 3406218822Sdim && htab->plt_type == PLT_UNSET) 3407218822Sdim { 3408218822Sdim /* Old -fPIC gcc code has .long LCTOC1-LCFx just before 3409218822Sdim the start of a function, which assembles to a REL32 3410218822Sdim reference to .got2. If we detect one of these, then 3411218822Sdim force the old PLT layout because the linker cannot 3412218822Sdim reliably deduce the GOT pointer value needed for 3413218822Sdim PLT call stubs. */ 3414218822Sdim asection *s; 3415218822Sdim 3416218822Sdim s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, sec, 3417218822Sdim r_symndx); 3418218822Sdim if (s == got2) 3419218822Sdim { 3420218822Sdim htab->plt_type = PLT_OLD; 3421218822Sdim htab->old_bfd = abfd; 3422218822Sdim } 3423218822Sdim } 3424218822Sdim if (h == NULL || h == htab->elf.hgot) 3425218822Sdim break; 3426218822Sdim goto dodyn1; 3427218822Sdim 342860484Sobrien case R_PPC_REL24: 342960484Sobrien case R_PPC_REL14: 343060484Sobrien case R_PPC_REL14_BRTAKEN: 343160484Sobrien case R_PPC_REL14_BRNTAKEN: 3432218822Sdim if (h == NULL) 343360484Sobrien break; 3434218822Sdim if (h == htab->elf.hgot) 3435218822Sdim { 3436218822Sdim if (htab->plt_type == PLT_UNSET) 3437218822Sdim { 3438218822Sdim htab->plt_type = PLT_OLD; 3439218822Sdim htab->old_bfd = abfd; 3440218822Sdim } 3441218822Sdim break; 3442218822Sdim } 344360484Sobrien /* fall through */ 344460484Sobrien 3445130561Sobrien case R_PPC_ADDR32: 3446130561Sobrien case R_PPC_ADDR24: 3447130561Sobrien case R_PPC_ADDR16: 3448130561Sobrien case R_PPC_ADDR16_LO: 3449130561Sobrien case R_PPC_ADDR16_HI: 3450130561Sobrien case R_PPC_ADDR16_HA: 3451130561Sobrien case R_PPC_ADDR14: 3452130561Sobrien case R_PPC_ADDR14_BRTAKEN: 3453130561Sobrien case R_PPC_ADDR14_BRNTAKEN: 3454130561Sobrien case R_PPC_UADDR32: 3455130561Sobrien case R_PPC_UADDR16: 3456218822Sdim dodyn1: 3457130561Sobrien if (h != NULL && !info->shared) 345860484Sobrien { 3459130561Sobrien /* We may need a plt entry if the symbol turns out to be 3460130561Sobrien a function defined in a dynamic object. */ 3461218822Sdim if (!update_plt_info (abfd, h, NULL, 0)) 3462218822Sdim return FALSE; 3463130561Sobrien 3464130561Sobrien /* We may need a copy reloc too. */ 3465218822Sdim h->non_got_ref = 1; 3466130561Sobrien } 3467130561Sobrien 3468130561Sobrien dodyn: 3469130561Sobrien /* If we are creating a shared library, and this is a reloc 3470130561Sobrien against a global symbol, or a non PC relative reloc 3471130561Sobrien against a local symbol, then we need to copy the reloc 3472130561Sobrien into the shared library. However, if we are linking with 3473130561Sobrien -Bsymbolic, we do not need to copy a reloc against a 3474130561Sobrien global symbol which is defined in an object we are 3475130561Sobrien including in the link (i.e., DEF_REGULAR is set). At 3476130561Sobrien this point we have not seen all the input files, so it is 3477130561Sobrien possible that DEF_REGULAR is not set now but will be set 3478130561Sobrien later (it is never cleared). In case of a weak definition, 3479130561Sobrien DEF_REGULAR may be cleared later by a strong definition in 3480130561Sobrien a shared library. We account for that possibility below by 3481130561Sobrien storing information in the dyn_relocs field of the hash 3482130561Sobrien table entry. A similar situation occurs when creating 3483130561Sobrien shared libraries and symbol visibility changes render the 3484130561Sobrien symbol local. 3485130561Sobrien 3486130561Sobrien If on the other hand, we are creating an executable, we 3487130561Sobrien may need to keep relocations for symbols satisfied by a 3488130561Sobrien dynamic library if we manage to avoid copy relocs for the 3489130561Sobrien symbol. */ 3490130561Sobrien if ((info->shared 3491130561Sobrien && (MUST_BE_DYN_RELOC (r_type) 3492130561Sobrien || (h != NULL 3493130561Sobrien && (! info->symbolic 3494130561Sobrien || h->root.type == bfd_link_hash_defweak 3495218822Sdim || !h->def_regular)))) 3496130561Sobrien || (ELIMINATE_COPY_RELOCS 3497130561Sobrien && !info->shared 3498130561Sobrien && h != NULL 3499130561Sobrien && (h->root.type == bfd_link_hash_defweak 3500218822Sdim || !h->def_regular))) 3501130561Sobrien { 3502130561Sobrien struct ppc_elf_dyn_relocs *p; 3503130561Sobrien struct ppc_elf_dyn_relocs **head; 3504130561Sobrien 350560484Sobrien#ifdef DEBUG 3506130561Sobrien fprintf (stderr, 3507130561Sobrien "ppc_elf_check_relocs needs to " 3508130561Sobrien "create relocation for %s\n", 3509130561Sobrien (h && h->root.root.string 3510130561Sobrien ? h->root.root.string : "<unknown>")); 351160484Sobrien#endif 351260484Sobrien if (sreloc == NULL) 351360484Sobrien { 351460484Sobrien const char *name; 351560484Sobrien 351660484Sobrien name = (bfd_elf_string_from_elf_section 351760484Sobrien (abfd, 351860484Sobrien elf_elfheader (abfd)->e_shstrndx, 351960484Sobrien elf_section_data (sec)->rel_hdr.sh_name)); 352060484Sobrien if (name == NULL) 3521130561Sobrien return FALSE; 352260484Sobrien 3523218822Sdim BFD_ASSERT (CONST_STRNEQ (name, ".rela") 352460484Sobrien && strcmp (bfd_get_section_name (abfd, sec), 352560484Sobrien name + 5) == 0); 352660484Sobrien 3527218822Sdim if (htab->elf.dynobj == NULL) 3528218822Sdim htab->elf.dynobj = abfd; 3529130561Sobrien sreloc = bfd_get_section_by_name (htab->elf.dynobj, name); 353060484Sobrien if (sreloc == NULL) 353160484Sobrien { 353260484Sobrien flagword flags; 353360484Sobrien 353460484Sobrien flags = (SEC_HAS_CONTENTS | SEC_READONLY 3535218822Sdim | SEC_IN_MEMORY | SEC_LINKER_CREATED 3536218822Sdim | SEC_ALLOC | SEC_LOAD); 3537218822Sdim sreloc = bfd_make_section_with_flags (htab->elf.dynobj, 3538218822Sdim name, 3539218822Sdim flags); 354060484Sobrien if (sreloc == NULL 3541130561Sobrien || ! bfd_set_section_alignment (htab->elf.dynobj, 3542130561Sobrien sreloc, 2)) 3543130561Sobrien return FALSE; 354460484Sobrien } 3545130561Sobrien elf_section_data (sec)->sreloc = sreloc; 354660484Sobrien } 354760484Sobrien 3548130561Sobrien /* If this is a global symbol, we count the number of 3549130561Sobrien relocations we need for this symbol. */ 3550130561Sobrien if (h != NULL) 3551130561Sobrien { 3552130561Sobrien head = &ppc_elf_hash_entry (h)->dyn_relocs; 3553130561Sobrien } 3554130561Sobrien else 3555130561Sobrien { 3556130561Sobrien /* Track dynamic relocs needed for local syms too. 3557130561Sobrien We really need local syms available to do this 3558130561Sobrien easily. Oh well. */ 355960484Sobrien 3560130561Sobrien asection *s; 3561218822Sdim void *vpp; 3562218822Sdim 3563130561Sobrien s = bfd_section_from_r_symndx (abfd, &htab->sym_sec, 3564130561Sobrien sec, r_symndx); 3565130561Sobrien if (s == NULL) 3566130561Sobrien return FALSE; 3567130561Sobrien 3568218822Sdim vpp = &elf_section_data (s)->local_dynrel; 3569218822Sdim head = (struct ppc_elf_dyn_relocs **) vpp; 3570130561Sobrien } 3571130561Sobrien 3572130561Sobrien p = *head; 3573130561Sobrien if (p == NULL || p->sec != sec) 3574130561Sobrien { 3575130561Sobrien p = bfd_alloc (htab->elf.dynobj, sizeof *p); 3576130561Sobrien if (p == NULL) 3577130561Sobrien return FALSE; 3578130561Sobrien p->next = *head; 3579130561Sobrien *head = p; 3580130561Sobrien p->sec = sec; 3581130561Sobrien p->count = 0; 3582130561Sobrien p->pc_count = 0; 3583130561Sobrien } 3584130561Sobrien 3585130561Sobrien p->count += 1; 3586130561Sobrien if (!MUST_BE_DYN_RELOC (r_type)) 3587130561Sobrien p->pc_count += 1; 358860484Sobrien } 358960484Sobrien 359060484Sobrien break; 359160484Sobrien } 359260484Sobrien } 359360484Sobrien 3594130561Sobrien return TRUE; 359560484Sobrien} 3596218822Sdim 359760484Sobrien 3598218822Sdim/* Merge object attributes from IBFD into OBFD. Raise an error if 3599218822Sdim there are conflicting attributes. */ 3600218822Sdimstatic bfd_boolean 3601218822Sdimppc_elf_merge_obj_attributes (bfd *ibfd, bfd *obfd) 3602218822Sdim{ 3603218822Sdim obj_attribute *in_attr; 3604218822Sdim obj_attribute *out_attr; 3605218822Sdim 3606218822Sdim if (!elf_known_obj_attributes_proc (obfd)[0].i) 3607218822Sdim { 3608218822Sdim /* This is the first object. Copy the attributes. */ 3609218822Sdim _bfd_elf_copy_obj_attributes (ibfd, obfd); 3610218822Sdim 3611218822Sdim /* Use the Tag_null value to indicate the attributes have been 3612218822Sdim initialized. */ 3613218822Sdim elf_known_obj_attributes_proc (obfd)[0].i = 1; 3614218822Sdim 3615218822Sdim return TRUE; 3616218822Sdim } 3617218822Sdim 3618218822Sdim /* Check for conflicting Tag_GNU_Power_ABI_FP attributes and merge 3619218822Sdim non-conflicting ones. */ 3620218822Sdim in_attr = elf_known_obj_attributes (ibfd)[OBJ_ATTR_GNU]; 3621218822Sdim out_attr = elf_known_obj_attributes (obfd)[OBJ_ATTR_GNU]; 3622218822Sdim if (in_attr[Tag_GNU_Power_ABI_FP].i != out_attr[Tag_GNU_Power_ABI_FP].i) 3623218822Sdim { 3624218822Sdim out_attr[Tag_GNU_Power_ABI_FP].type = 1; 3625218822Sdim if (out_attr[Tag_GNU_Power_ABI_FP].i == 0) 3626218822Sdim out_attr[Tag_GNU_Power_ABI_FP].i = in_attr[Tag_GNU_Power_ABI_FP].i; 3627218822Sdim else if (in_attr[Tag_GNU_Power_ABI_FP].i == 0) 3628218822Sdim ; 3629218822Sdim else if (out_attr[Tag_GNU_Power_ABI_FP].i == 1 3630218822Sdim && in_attr[Tag_GNU_Power_ABI_FP].i == 2) 3631218822Sdim _bfd_error_handler 3632218822Sdim (_("Warning: %B uses hard float, %B uses soft float"), obfd, ibfd); 3633218822Sdim else if (out_attr[Tag_GNU_Power_ABI_FP].i == 2 3634218822Sdim && in_attr[Tag_GNU_Power_ABI_FP].i == 1) 3635218822Sdim _bfd_error_handler 3636218822Sdim (_("Warning: %B uses hard float, %B uses soft float"), ibfd, obfd); 3637218822Sdim else if (in_attr[Tag_GNU_Power_ABI_FP].i > 2) 3638218822Sdim _bfd_error_handler 3639218822Sdim (_("Warning: %B uses unknown floating point ABI %d"), ibfd, 3640218822Sdim in_attr[Tag_GNU_Power_ABI_FP].i); 3641218822Sdim else 3642218822Sdim _bfd_error_handler 3643218822Sdim (_("Warning: %B uses unknown floating point ABI %d"), obfd, 3644218822Sdim out_attr[Tag_GNU_Power_ABI_FP].i); 3645218822Sdim } 3646218822Sdim 3647218822Sdim /* Merge Tag_compatibility attributes and any common GNU ones. */ 3648218822Sdim _bfd_elf_merge_object_attributes (ibfd, obfd); 3649218822Sdim 3650218822Sdim return TRUE; 3651218822Sdim} 3652218822Sdim 3653218822Sdim/* Merge backend specific data from an object file to the output 3654218822Sdim object file when linking. */ 3655218822Sdim 3656218822Sdimstatic bfd_boolean 3657218822Sdimppc_elf_merge_private_bfd_data (bfd *ibfd, bfd *obfd) 3658218822Sdim{ 3659218822Sdim flagword old_flags; 3660218822Sdim flagword new_flags; 3661218822Sdim bfd_boolean error; 3662218822Sdim 3663218822Sdim if (!is_ppc_elf_target (ibfd->xvec) 3664218822Sdim || !is_ppc_elf_target (obfd->xvec)) 3665218822Sdim return TRUE; 3666218822Sdim 3667218822Sdim /* Check if we have the same endianess. */ 3668218822Sdim if (! _bfd_generic_verify_endian_match (ibfd, obfd)) 3669218822Sdim return FALSE; 3670218822Sdim 3671218822Sdim if (!ppc_elf_merge_obj_attributes (ibfd, obfd)) 3672218822Sdim return FALSE; 3673218822Sdim 3674218822Sdim new_flags = elf_elfheader (ibfd)->e_flags; 3675218822Sdim old_flags = elf_elfheader (obfd)->e_flags; 3676218822Sdim if (!elf_flags_init (obfd)) 3677218822Sdim { 3678218822Sdim /* First call, no flags set. */ 3679218822Sdim elf_flags_init (obfd) = TRUE; 3680218822Sdim elf_elfheader (obfd)->e_flags = new_flags; 3681218822Sdim } 3682218822Sdim 3683218822Sdim /* Compatible flags are ok. */ 3684218822Sdim else if (new_flags == old_flags) 3685218822Sdim ; 3686218822Sdim 3687218822Sdim /* Incompatible flags. */ 3688218822Sdim else 3689218822Sdim { 3690218822Sdim /* Warn about -mrelocatable mismatch. Allow -mrelocatable-lib 3691218822Sdim to be linked with either. */ 3692218822Sdim error = FALSE; 3693218822Sdim if ((new_flags & EF_PPC_RELOCATABLE) != 0 3694218822Sdim && (old_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0) 3695218822Sdim { 3696218822Sdim error = TRUE; 3697218822Sdim (*_bfd_error_handler) 3698218822Sdim (_("%B: compiled with -mrelocatable and linked with " 3699218822Sdim "modules compiled normally"), ibfd); 3700218822Sdim } 3701218822Sdim else if ((new_flags & (EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB)) == 0 3702218822Sdim && (old_flags & EF_PPC_RELOCATABLE) != 0) 3703218822Sdim { 3704218822Sdim error = TRUE; 3705218822Sdim (*_bfd_error_handler) 3706218822Sdim (_("%B: compiled normally and linked with " 3707218822Sdim "modules compiled with -mrelocatable"), ibfd); 3708218822Sdim } 3709218822Sdim 3710218822Sdim /* The output is -mrelocatable-lib iff both the input files are. */ 3711218822Sdim if (! (new_flags & EF_PPC_RELOCATABLE_LIB)) 3712218822Sdim elf_elfheader (obfd)->e_flags &= ~EF_PPC_RELOCATABLE_LIB; 3713218822Sdim 3714218822Sdim /* The output is -mrelocatable iff it can't be -mrelocatable-lib, 3715218822Sdim but each input file is either -mrelocatable or -mrelocatable-lib. */ 3716218822Sdim if (! (elf_elfheader (obfd)->e_flags & EF_PPC_RELOCATABLE_LIB) 3717218822Sdim && (new_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE)) 3718218822Sdim && (old_flags & (EF_PPC_RELOCATABLE_LIB | EF_PPC_RELOCATABLE))) 3719218822Sdim elf_elfheader (obfd)->e_flags |= EF_PPC_RELOCATABLE; 3720218822Sdim 3721218822Sdim /* Do not warn about eabi vs. V.4 mismatch, just or in the bit if 3722218822Sdim any module uses it. */ 3723218822Sdim elf_elfheader (obfd)->e_flags |= (new_flags & EF_PPC_EMB); 3724218822Sdim 3725218822Sdim new_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); 3726218822Sdim old_flags &= ~(EF_PPC_RELOCATABLE | EF_PPC_RELOCATABLE_LIB | EF_PPC_EMB); 3727218822Sdim 3728218822Sdim /* Warn about any other mismatches. */ 3729218822Sdim if (new_flags != old_flags) 3730218822Sdim { 3731218822Sdim error = TRUE; 3732218822Sdim (*_bfd_error_handler) 3733218822Sdim (_("%B: uses different e_flags (0x%lx) fields " 3734218822Sdim "than previous modules (0x%lx)"), 3735218822Sdim ibfd, (long) new_flags, (long) old_flags); 3736218822Sdim } 3737218822Sdim 3738218822Sdim if (error) 3739218822Sdim { 3740218822Sdim bfd_set_error (bfd_error_bad_value); 3741218822Sdim return FALSE; 3742218822Sdim } 3743218822Sdim } 3744218822Sdim 3745218822Sdim return TRUE; 3746218822Sdim} 3747218822Sdim 3748218822Sdim/* Choose which PLT scheme to use, and set .plt flags appropriately. 3749218822Sdim Returns -1 on error, 0 for old PLT, 1 for new PLT. */ 3750218822Sdimint 3751218822Sdimppc_elf_select_plt_layout (bfd *output_bfd ATTRIBUTE_UNUSED, 3752218822Sdim struct bfd_link_info *info, 3753218822Sdim enum ppc_elf_plt_type plt_style, 3754218822Sdim int emit_stub_syms) 3755218822Sdim{ 3756218822Sdim struct ppc_elf_link_hash_table *htab; 3757218822Sdim flagword flags; 3758218822Sdim 3759218822Sdim htab = ppc_elf_hash_table (info); 3760218822Sdim 3761218822Sdim if (htab->plt_type == PLT_UNSET) 3762218822Sdim { 3763218822Sdim if (plt_style == PLT_OLD) 3764218822Sdim htab->plt_type = PLT_OLD; 3765218822Sdim else 3766218822Sdim { 3767218822Sdim bfd *ibfd; 3768218822Sdim enum ppc_elf_plt_type plt_type = plt_style; 3769218822Sdim 3770218822Sdim /* Look through the reloc flags left by ppc_elf_check_relocs. 3771218822Sdim Use the old style bss plt if a file makes plt calls 3772218822Sdim without using the new relocs, and if ld isn't given 3773218822Sdim --secure-plt and we never see REL16 relocs. */ 3774218822Sdim if (plt_type == PLT_UNSET) 3775218822Sdim plt_type = PLT_OLD; 3776218822Sdim for (ibfd = info->input_bfds; ibfd; ibfd = ibfd->link_next) 3777218822Sdim if (is_ppc_elf_target (ibfd->xvec)) 3778218822Sdim { 3779218822Sdim if (ppc_elf_tdata (ibfd)->has_rel16) 3780218822Sdim plt_type = PLT_NEW; 3781218822Sdim else if (ppc_elf_tdata (ibfd)->makes_plt_call) 3782218822Sdim { 3783218822Sdim plt_type = PLT_OLD; 3784218822Sdim htab->old_bfd = ibfd; 3785218822Sdim break; 3786218822Sdim } 3787218822Sdim } 3788218822Sdim htab->plt_type = plt_type; 3789218822Sdim } 3790218822Sdim } 3791218822Sdim if (htab->plt_type == PLT_OLD && plt_style == PLT_NEW) 3792218822Sdim info->callbacks->info (_("Using bss-plt due to %B"), htab->old_bfd); 3793218822Sdim 3794218822Sdim htab->emit_stub_syms = emit_stub_syms; 3795218822Sdim 3796218822Sdim BFD_ASSERT (htab->plt_type != PLT_VXWORKS); 3797218822Sdim 3798218822Sdim if (htab->plt_type == PLT_NEW) 3799218822Sdim { 3800218822Sdim flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS 3801218822Sdim | SEC_IN_MEMORY | SEC_LINKER_CREATED); 3802218822Sdim 3803218822Sdim /* The new PLT is a loaded section. */ 3804218822Sdim if (htab->plt != NULL 3805218822Sdim && !bfd_set_section_flags (htab->elf.dynobj, htab->plt, flags)) 3806218822Sdim return -1; 3807218822Sdim 3808218822Sdim /* The new GOT is not executable. */ 3809218822Sdim if (htab->got != NULL 3810218822Sdim && !bfd_set_section_flags (htab->elf.dynobj, htab->got, flags)) 3811218822Sdim return -1; 3812218822Sdim } 3813218822Sdim else 3814218822Sdim { 3815218822Sdim /* Stop an unused .glink section from affecting .text alignment. */ 3816218822Sdim if (htab->glink != NULL 3817218822Sdim && !bfd_set_section_alignment (htab->elf.dynobj, htab->glink, 0)) 3818218822Sdim return -1; 3819218822Sdim } 3820218822Sdim return htab->plt_type == PLT_NEW; 3821218822Sdim} 3822218822Sdim 382360484Sobrien/* Return the section that should be marked against GC for a given 382460484Sobrien relocation. */ 382560484Sobrien 382660484Sobrienstatic asection * 3827130561Sobrienppc_elf_gc_mark_hook (asection *sec, 3828218822Sdim struct bfd_link_info *info, 3829130561Sobrien Elf_Internal_Rela *rel, 3830130561Sobrien struct elf_link_hash_entry *h, 3831130561Sobrien Elf_Internal_Sym *sym) 383260484Sobrien{ 383360484Sobrien if (h != NULL) 3834218822Sdim switch (ELF32_R_TYPE (rel->r_info)) 3835218822Sdim { 3836218822Sdim case R_PPC_GNU_VTINHERIT: 3837218822Sdim case R_PPC_GNU_VTENTRY: 3838218822Sdim return NULL; 3839218822Sdim } 384060484Sobrien 3841218822Sdim return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym); 384260484Sobrien} 384360484Sobrien 3844130561Sobrien/* Update the got, plt and dynamic reloc reference counts for the 3845130561Sobrien section being removed. */ 384660484Sobrien 3847130561Sobrienstatic bfd_boolean 3848130561Sobrienppc_elf_gc_sweep_hook (bfd *abfd, 3849130561Sobrien struct bfd_link_info *info, 3850130561Sobrien asection *sec, 3851130561Sobrien const Elf_Internal_Rela *relocs) 385260484Sobrien{ 3853130561Sobrien struct ppc_elf_link_hash_table *htab; 385460484Sobrien Elf_Internal_Shdr *symtab_hdr; 385560484Sobrien struct elf_link_hash_entry **sym_hashes; 385660484Sobrien bfd_signed_vma *local_got_refcounts; 385760484Sobrien const Elf_Internal_Rela *rel, *relend; 3858218822Sdim asection *got2; 385960484Sobrien 3860218822Sdim if ((sec->flags & SEC_ALLOC) == 0) 3861218822Sdim return TRUE; 3862218822Sdim 3863130561Sobrien elf_section_data (sec)->local_dynrel = NULL; 3864130561Sobrien 3865130561Sobrien htab = ppc_elf_hash_table (info); 386660484Sobrien symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 386760484Sobrien sym_hashes = elf_sym_hashes (abfd); 386860484Sobrien local_got_refcounts = elf_local_got_refcounts (abfd); 3869218822Sdim got2 = bfd_get_section_by_name (abfd, ".got2"); 387060484Sobrien 387160484Sobrien relend = relocs + sec->reloc_count; 387260484Sobrien for (rel = relocs; rel < relend; rel++) 3873130561Sobrien { 3874130561Sobrien unsigned long r_symndx; 3875130561Sobrien enum elf_ppc_reloc_type r_type; 3876130561Sobrien struct elf_link_hash_entry *h = NULL; 3877130561Sobrien 3878130561Sobrien r_symndx = ELF32_R_SYM (rel->r_info); 3879130561Sobrien if (r_symndx >= symtab_hdr->sh_info) 3880130561Sobrien { 3881130561Sobrien struct ppc_elf_dyn_relocs **pp, *p; 3882130561Sobrien struct ppc_elf_link_hash_entry *eh; 3883130561Sobrien 3884130561Sobrien h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 3885218822Sdim while (h->root.type == bfd_link_hash_indirect 3886218822Sdim || h->root.type == bfd_link_hash_warning) 3887218822Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 3888130561Sobrien eh = (struct ppc_elf_link_hash_entry *) h; 3889130561Sobrien 3890130561Sobrien for (pp = &eh->dyn_relocs; (p = *pp) != NULL; pp = &p->next) 3891130561Sobrien if (p->sec == sec) 3892130561Sobrien { 3893130561Sobrien /* Everything must go for SEC. */ 3894130561Sobrien *pp = p->next; 3895130561Sobrien break; 3896130561Sobrien } 3897130561Sobrien } 3898130561Sobrien 3899130561Sobrien r_type = ELF32_R_TYPE (rel->r_info); 3900130561Sobrien switch (r_type) 3901130561Sobrien { 3902130561Sobrien case R_PPC_GOT_TLSLD16: 3903130561Sobrien case R_PPC_GOT_TLSLD16_LO: 3904130561Sobrien case R_PPC_GOT_TLSLD16_HI: 3905130561Sobrien case R_PPC_GOT_TLSLD16_HA: 3906130561Sobrien htab->tlsld_got.refcount -= 1; 3907130561Sobrien /* Fall thru */ 3908130561Sobrien 3909130561Sobrien case R_PPC_GOT_TLSGD16: 3910130561Sobrien case R_PPC_GOT_TLSGD16_LO: 3911130561Sobrien case R_PPC_GOT_TLSGD16_HI: 3912130561Sobrien case R_PPC_GOT_TLSGD16_HA: 3913130561Sobrien case R_PPC_GOT_TPREL16: 3914130561Sobrien case R_PPC_GOT_TPREL16_LO: 3915130561Sobrien case R_PPC_GOT_TPREL16_HI: 3916130561Sobrien case R_PPC_GOT_TPREL16_HA: 3917130561Sobrien case R_PPC_GOT_DTPREL16: 3918130561Sobrien case R_PPC_GOT_DTPREL16_LO: 3919130561Sobrien case R_PPC_GOT_DTPREL16_HI: 3920130561Sobrien case R_PPC_GOT_DTPREL16_HA: 3921130561Sobrien case R_PPC_GOT16: 3922130561Sobrien case R_PPC_GOT16_LO: 3923130561Sobrien case R_PPC_GOT16_HI: 3924130561Sobrien case R_PPC_GOT16_HA: 3925130561Sobrien if (h != NULL) 3926130561Sobrien { 3927130561Sobrien if (h->got.refcount > 0) 3928130561Sobrien h->got.refcount--; 3929130561Sobrien } 3930130561Sobrien else if (local_got_refcounts != NULL) 3931130561Sobrien { 3932130561Sobrien if (local_got_refcounts[r_symndx] > 0) 3933130561Sobrien local_got_refcounts[r_symndx]--; 3934130561Sobrien } 3935130561Sobrien break; 3936130561Sobrien 3937130561Sobrien case R_PPC_REL24: 3938130561Sobrien case R_PPC_REL14: 3939130561Sobrien case R_PPC_REL14_BRTAKEN: 3940130561Sobrien case R_PPC_REL14_BRNTAKEN: 3941130561Sobrien case R_PPC_REL32: 3942218822Sdim if (h == NULL || h == htab->elf.hgot) 3943130561Sobrien break; 3944130561Sobrien /* Fall thru */ 3945130561Sobrien 3946130561Sobrien case R_PPC_ADDR32: 3947130561Sobrien case R_PPC_ADDR24: 3948130561Sobrien case R_PPC_ADDR16: 3949130561Sobrien case R_PPC_ADDR16_LO: 3950130561Sobrien case R_PPC_ADDR16_HI: 3951130561Sobrien case R_PPC_ADDR16_HA: 3952130561Sobrien case R_PPC_ADDR14: 3953130561Sobrien case R_PPC_ADDR14_BRTAKEN: 3954130561Sobrien case R_PPC_ADDR14_BRNTAKEN: 3955130561Sobrien case R_PPC_UADDR32: 3956130561Sobrien case R_PPC_UADDR16: 3957218822Sdim if (info->shared) 3958218822Sdim break; 3959218822Sdim 3960130561Sobrien case R_PPC_PLT32: 3961130561Sobrien case R_PPC_PLTREL24: 3962218822Sdim case R_PPC_PLTREL32: 3963130561Sobrien case R_PPC_PLT16_LO: 3964130561Sobrien case R_PPC_PLT16_HI: 3965130561Sobrien case R_PPC_PLT16_HA: 3966130561Sobrien if (h != NULL) 3967130561Sobrien { 3968218822Sdim bfd_vma addend = r_type == R_PPC_PLTREL24 ? rel->r_addend : 0; 3969218822Sdim struct plt_entry *ent = find_plt_ent (h, got2, addend); 3970218822Sdim if (ent->plt.refcount > 0) 3971218822Sdim ent->plt.refcount -= 1; 3972130561Sobrien } 3973130561Sobrien break; 3974130561Sobrien 3975130561Sobrien default: 3976130561Sobrien break; 3977130561Sobrien } 3978130561Sobrien } 3979130561Sobrien return TRUE; 3980130561Sobrien} 3981218822Sdim 3982130561Sobrien/* Set htab->tls_get_addr and call the generic ELF tls_setup function. */ 3983130561Sobrien 3984130561Sobrienasection * 3985130561Sobrienppc_elf_tls_setup (bfd *obfd, struct bfd_link_info *info) 3986130561Sobrien{ 3987130561Sobrien struct ppc_elf_link_hash_table *htab; 3988130561Sobrien 3989130561Sobrien htab = ppc_elf_hash_table (info); 3990218822Sdim if (htab->plt_type == PLT_NEW 3991218822Sdim && htab->plt != NULL 3992218822Sdim && htab->plt->output_section != NULL) 3993218822Sdim { 3994218822Sdim elf_section_type (htab->plt->output_section) = SHT_PROGBITS; 3995218822Sdim elf_section_flags (htab->plt->output_section) = SHF_ALLOC + SHF_WRITE; 3996218822Sdim } 3997218822Sdim 3998130561Sobrien htab->tls_get_addr = elf_link_hash_lookup (&htab->elf, "__tls_get_addr", 3999130561Sobrien FALSE, FALSE, TRUE); 4000130561Sobrien return _bfd_elf_tls_setup (obfd, info); 4001130561Sobrien} 4002130561Sobrien 4003130561Sobrien/* Run through all the TLS relocs looking for optimization 4004130561Sobrien opportunities. */ 4005130561Sobrien 4006130561Sobrienbfd_boolean 4007130561Sobrienppc_elf_tls_optimize (bfd *obfd ATTRIBUTE_UNUSED, 4008130561Sobrien struct bfd_link_info *info) 4009130561Sobrien{ 4010130561Sobrien bfd *ibfd; 4011130561Sobrien asection *sec; 4012130561Sobrien struct ppc_elf_link_hash_table *htab; 4013130561Sobrien 4014130561Sobrien if (info->relocatable || info->shared) 4015130561Sobrien return TRUE; 4016130561Sobrien 4017130561Sobrien htab = ppc_elf_hash_table (info); 4018130561Sobrien for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 4019130561Sobrien { 4020130561Sobrien Elf_Internal_Sym *locsyms = NULL; 4021130561Sobrien Elf_Internal_Shdr *symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; 4022130561Sobrien 4023130561Sobrien for (sec = ibfd->sections; sec != NULL; sec = sec->next) 4024130561Sobrien if (sec->has_tls_reloc && !bfd_is_abs_section (sec->output_section)) 402560484Sobrien { 4026130561Sobrien Elf_Internal_Rela *relstart, *rel, *relend; 4027130561Sobrien int expecting_tls_get_addr; 402860484Sobrien 4029130561Sobrien /* Read the relocations. */ 4030130561Sobrien relstart = _bfd_elf_link_read_relocs (ibfd, sec, NULL, NULL, 4031130561Sobrien info->keep_memory); 4032130561Sobrien if (relstart == NULL) 4033130561Sobrien return FALSE; 4034130561Sobrien 4035130561Sobrien expecting_tls_get_addr = 0; 4036130561Sobrien relend = relstart + sec->reloc_count; 4037130561Sobrien for (rel = relstart; rel < relend; rel++) 4038130561Sobrien { 4039130561Sobrien enum elf_ppc_reloc_type r_type; 4040130561Sobrien unsigned long r_symndx; 4041130561Sobrien struct elf_link_hash_entry *h = NULL; 4042130561Sobrien char *tls_mask; 4043130561Sobrien char tls_set, tls_clear; 4044130561Sobrien bfd_boolean is_local; 4045130561Sobrien 4046130561Sobrien r_symndx = ELF32_R_SYM (rel->r_info); 4047130561Sobrien if (r_symndx >= symtab_hdr->sh_info) 4048130561Sobrien { 4049130561Sobrien struct elf_link_hash_entry **sym_hashes; 4050130561Sobrien 4051130561Sobrien sym_hashes = elf_sym_hashes (ibfd); 4052130561Sobrien h = sym_hashes[r_symndx - symtab_hdr->sh_info]; 4053130561Sobrien while (h->root.type == bfd_link_hash_indirect 4054130561Sobrien || h->root.type == bfd_link_hash_warning) 4055130561Sobrien h = (struct elf_link_hash_entry *) h->root.u.i.link; 4056130561Sobrien } 4057130561Sobrien 4058130561Sobrien is_local = FALSE; 4059130561Sobrien if (h == NULL 4060218822Sdim || !h->def_dynamic) 4061130561Sobrien is_local = TRUE; 4062130561Sobrien 4063130561Sobrien r_type = ELF32_R_TYPE (rel->r_info); 4064130561Sobrien switch (r_type) 4065130561Sobrien { 4066130561Sobrien case R_PPC_GOT_TLSLD16: 4067130561Sobrien case R_PPC_GOT_TLSLD16_LO: 4068130561Sobrien case R_PPC_GOT_TLSLD16_HI: 4069130561Sobrien case R_PPC_GOT_TLSLD16_HA: 4070130561Sobrien /* These relocs should never be against a symbol 4071130561Sobrien defined in a shared lib. Leave them alone if 4072130561Sobrien that turns out to be the case. */ 4073130561Sobrien expecting_tls_get_addr = 0; 4074130561Sobrien htab->tlsld_got.refcount -= 1; 4075130561Sobrien if (!is_local) 4076130561Sobrien continue; 4077130561Sobrien 4078130561Sobrien /* LD -> LE */ 4079130561Sobrien tls_set = 0; 4080130561Sobrien tls_clear = TLS_LD; 4081130561Sobrien expecting_tls_get_addr = 1; 4082130561Sobrien break; 4083130561Sobrien 4084130561Sobrien case R_PPC_GOT_TLSGD16: 4085130561Sobrien case R_PPC_GOT_TLSGD16_LO: 4086130561Sobrien case R_PPC_GOT_TLSGD16_HI: 4087130561Sobrien case R_PPC_GOT_TLSGD16_HA: 4088130561Sobrien if (is_local) 4089130561Sobrien /* GD -> LE */ 4090130561Sobrien tls_set = 0; 4091130561Sobrien else 4092130561Sobrien /* GD -> IE */ 4093130561Sobrien tls_set = TLS_TLS | TLS_TPRELGD; 4094130561Sobrien tls_clear = TLS_GD; 4095130561Sobrien expecting_tls_get_addr = 1; 4096130561Sobrien break; 4097130561Sobrien 4098130561Sobrien case R_PPC_GOT_TPREL16: 4099130561Sobrien case R_PPC_GOT_TPREL16_LO: 4100130561Sobrien case R_PPC_GOT_TPREL16_HI: 4101130561Sobrien case R_PPC_GOT_TPREL16_HA: 4102130561Sobrien expecting_tls_get_addr = 0; 4103130561Sobrien if (is_local) 4104130561Sobrien { 4105130561Sobrien /* IE -> LE */ 4106130561Sobrien tls_set = 0; 4107130561Sobrien tls_clear = TLS_TPREL; 4108130561Sobrien break; 4109130561Sobrien } 4110130561Sobrien else 4111130561Sobrien continue; 4112130561Sobrien 4113130561Sobrien case R_PPC_REL14: 4114130561Sobrien case R_PPC_REL14_BRTAKEN: 4115130561Sobrien case R_PPC_REL14_BRNTAKEN: 4116130561Sobrien case R_PPC_REL24: 4117130561Sobrien if (expecting_tls_get_addr 4118130561Sobrien && h != NULL 4119130561Sobrien && h == htab->tls_get_addr) 4120130561Sobrien { 4121218822Sdim struct plt_entry *ent = find_plt_ent (h, NULL, 0); 4122218822Sdim if (ent != NULL && ent->plt.refcount > 0) 4123218822Sdim ent->plt.refcount -= 1; 4124130561Sobrien } 4125130561Sobrien expecting_tls_get_addr = 0; 4126130561Sobrien continue; 4127130561Sobrien 4128130561Sobrien default: 4129130561Sobrien expecting_tls_get_addr = 0; 4130130561Sobrien continue; 4131130561Sobrien } 4132130561Sobrien 4133130561Sobrien if (h != NULL) 4134130561Sobrien { 4135130561Sobrien if (tls_set == 0) 4136130561Sobrien { 4137130561Sobrien /* We managed to get rid of a got entry. */ 4138130561Sobrien if (h->got.refcount > 0) 4139130561Sobrien h->got.refcount -= 1; 4140130561Sobrien } 4141130561Sobrien tls_mask = &ppc_elf_hash_entry (h)->tls_mask; 4142130561Sobrien } 4143130561Sobrien else 4144130561Sobrien { 4145130561Sobrien Elf_Internal_Sym *sym; 4146130561Sobrien bfd_signed_vma *lgot_refs; 4147130561Sobrien char *lgot_masks; 4148130561Sobrien 4149130561Sobrien if (locsyms == NULL) 4150130561Sobrien { 4151130561Sobrien locsyms = (Elf_Internal_Sym *) symtab_hdr->contents; 4152130561Sobrien if (locsyms == NULL) 4153130561Sobrien locsyms = bfd_elf_get_elf_syms (ibfd, symtab_hdr, 4154130561Sobrien symtab_hdr->sh_info, 4155130561Sobrien 0, NULL, NULL, NULL); 4156130561Sobrien if (locsyms == NULL) 4157130561Sobrien { 4158130561Sobrien if (elf_section_data (sec)->relocs != relstart) 4159130561Sobrien free (relstart); 4160130561Sobrien return FALSE; 4161130561Sobrien } 4162130561Sobrien } 4163130561Sobrien sym = locsyms + r_symndx; 4164130561Sobrien lgot_refs = elf_local_got_refcounts (ibfd); 4165130561Sobrien if (lgot_refs == NULL) 4166130561Sobrien abort (); 4167130561Sobrien if (tls_set == 0) 4168130561Sobrien { 4169130561Sobrien /* We managed to get rid of a got entry. */ 4170130561Sobrien if (lgot_refs[r_symndx] > 0) 4171130561Sobrien lgot_refs[r_symndx] -= 1; 4172130561Sobrien } 4173130561Sobrien lgot_masks = (char *) (lgot_refs + symtab_hdr->sh_info); 4174130561Sobrien tls_mask = &lgot_masks[r_symndx]; 4175130561Sobrien } 4176130561Sobrien 4177130561Sobrien *tls_mask |= tls_set; 4178130561Sobrien *tls_mask &= ~tls_clear; 4179130561Sobrien } 4180130561Sobrien 4181130561Sobrien if (elf_section_data (sec)->relocs != relstart) 4182130561Sobrien free (relstart); 418360484Sobrien } 418460484Sobrien 4185130561Sobrien if (locsyms != NULL 4186130561Sobrien && (symtab_hdr->contents != (unsigned char *) locsyms)) 4187130561Sobrien { 4188130561Sobrien if (!info->keep_memory) 4189130561Sobrien free (locsyms); 4190130561Sobrien else 4191130561Sobrien symtab_hdr->contents = (unsigned char *) locsyms; 4192130561Sobrien } 4193130561Sobrien } 4194130561Sobrien return TRUE; 419560484Sobrien} 419660484Sobrien 4197218822Sdim/* Adjust a symbol defined by a dynamic object and referenced by a 4198218822Sdim regular object. The current definition is in some section of the 4199218822Sdim dynamic object, but we're not including those sections. We have to 4200218822Sdim change the definition to something the rest of the link can 4201218822Sdim understand. */ 420260484Sobrien 4203130561Sobrienstatic bfd_boolean 4204218822Sdimppc_elf_adjust_dynamic_symbol (struct bfd_link_info *info, 4205218822Sdim struct elf_link_hash_entry *h) 420660484Sobrien{ 4207218822Sdim struct ppc_elf_link_hash_table *htab; 4208218822Sdim asection *s; 4209218822Sdim 4210218822Sdim#ifdef DEBUG 4211218822Sdim fprintf (stderr, "ppc_elf_adjust_dynamic_symbol called for %s\n", 4212218822Sdim h->root.root.string); 4213218822Sdim#endif 4214218822Sdim 4215218822Sdim /* Make sure we know what is going on here. */ 4216218822Sdim htab = ppc_elf_hash_table (info); 4217218822Sdim BFD_ASSERT (htab->elf.dynobj != NULL 4218218822Sdim && (h->needs_plt 4219218822Sdim || h->u.weakdef != NULL 4220218822Sdim || (h->def_dynamic 4221218822Sdim && h->ref_regular 4222218822Sdim && !h->def_regular))); 4223218822Sdim 4224218822Sdim /* Deal with function syms. */ 4225218822Sdim if (h->type == STT_FUNC 4226218822Sdim || h->needs_plt) 422760484Sobrien { 4228218822Sdim /* Clear procedure linkage table information for any symbol that 4229218822Sdim won't need a .plt entry. */ 4230218822Sdim struct plt_entry *ent; 4231218822Sdim for (ent = h->plt.plist; ent != NULL; ent = ent->next) 4232218822Sdim if (ent->plt.refcount > 0) 4233218822Sdim break; 4234218822Sdim if (ent == NULL 4235218822Sdim || SYMBOL_CALLS_LOCAL (info, h) 4236218822Sdim || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT 4237218822Sdim && h->root.type == bfd_link_hash_undefweak)) 4238218822Sdim { 4239218822Sdim /* A PLT entry is not required/allowed when: 424060484Sobrien 4241218822Sdim 1. We are not using ld.so; because then the PLT entry 4242218822Sdim can't be set up, so we can't use one. In this case, 4243218822Sdim ppc_elf_adjust_dynamic_symbol won't even be called. 4244218822Sdim 4245218822Sdim 2. GC has rendered the entry unused. 4246218822Sdim 4247218822Sdim 3. We know for certain that a call to this symbol 4248218822Sdim will go to this object, or will remain undefined. */ 4249218822Sdim h->plt.plist = NULL; 4250218822Sdim h->needs_plt = 0; 4251218822Sdim } 4252218822Sdim return TRUE; 4253218822Sdim } 4254218822Sdim else 4255218822Sdim h->plt.plist = NULL; 4256218822Sdim 4257218822Sdim /* If this is a weak symbol, and there is a real definition, the 4258218822Sdim processor independent code will have arranged for us to see the 4259218822Sdim real definition first, and we can just use the same value. */ 4260218822Sdim if (h->u.weakdef != NULL) 4261218822Sdim { 4262218822Sdim BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined 4263218822Sdim || h->u.weakdef->root.type == bfd_link_hash_defweak); 4264218822Sdim h->root.u.def.section = h->u.weakdef->root.u.def.section; 4265218822Sdim h->root.u.def.value = h->u.weakdef->root.u.def.value; 4266218822Sdim if (ELIMINATE_COPY_RELOCS) 4267218822Sdim h->non_got_ref = h->u.weakdef->non_got_ref; 4268218822Sdim return TRUE; 4269218822Sdim } 4270218822Sdim 4271218822Sdim /* This is a reference to a symbol defined by a dynamic object which 4272218822Sdim is not a function. */ 4273218822Sdim 4274218822Sdim /* If we are creating a shared library, we must presume that the 4275218822Sdim only references to the symbol are via the global offset table. 4276218822Sdim For such cases we need not do anything here; the relocations will 4277218822Sdim be handled correctly by relocate_section. */ 4278218822Sdim if (info->shared) 4279218822Sdim return TRUE; 4280218822Sdim 4281218822Sdim /* If there are no references to this symbol that do not use the 4282218822Sdim GOT, we don't need to generate a copy reloc. */ 4283218822Sdim if (!h->non_got_ref) 4284218822Sdim return TRUE; 4285218822Sdim 4286218822Sdim /* If we didn't find any dynamic relocs in read-only sections, then we'll 4287218822Sdim be keeping the dynamic relocs and avoiding the copy reloc. We can't 4288218822Sdim do this if there are any small data relocations. */ 4289218822Sdim if (ELIMINATE_COPY_RELOCS 4290218822Sdim && !ppc_elf_hash_entry (h)->has_sda_refs) 4291218822Sdim { 4292218822Sdim struct ppc_elf_dyn_relocs *p; 4293218822Sdim for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) 429460484Sobrien { 4295218822Sdim s = p->sec->output_section; 4296218822Sdim if (s != NULL && (s->flags & SEC_READONLY) != 0) 4297218822Sdim break; 4298218822Sdim } 429989857Sobrien 4300218822Sdim if (p == NULL) 4301218822Sdim { 4302218822Sdim h->non_got_ref = 0; 4303218822Sdim return TRUE; 4304218822Sdim } 4305218822Sdim } 4306218822Sdim 4307218822Sdim if (h->size == 0) 4308218822Sdim { 4309218822Sdim (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"), 4310218822Sdim h->root.root.string); 4311218822Sdim return TRUE; 4312218822Sdim } 4313218822Sdim 4314218822Sdim /* We must allocate the symbol in our .dynbss section, which will 4315218822Sdim become part of the .bss section of the executable. There will be 4316218822Sdim an entry for this symbol in the .dynsym section. The dynamic 4317218822Sdim object will contain position independent code, so all references 4318218822Sdim from the dynamic object to this symbol will go through the global 4319218822Sdim offset table. The dynamic linker will use the .dynsym entry to 4320218822Sdim determine the address it must put in the global offset table, so 4321218822Sdim both the dynamic object and the regular object will refer to the 4322218822Sdim same memory location for the variable. 4323218822Sdim 4324218822Sdim Of course, if the symbol is referenced using SDAREL relocs, we 4325218822Sdim must instead allocate it in .sbss. */ 4326218822Sdim 4327218822Sdim if (ppc_elf_hash_entry (h)->has_sda_refs) 4328218822Sdim s = htab->dynsbss; 4329218822Sdim else 4330218822Sdim s = htab->dynbss; 4331218822Sdim BFD_ASSERT (s != NULL); 4332218822Sdim 4333218822Sdim /* We must generate a R_PPC_COPY reloc to tell the dynamic linker to 4334218822Sdim copy the initial value out of the dynamic object and into the 4335218822Sdim runtime process image. We need to remember the offset into the 4336218822Sdim .rela.bss section we are going to use. */ 4337218822Sdim if ((h->root.u.def.section->flags & SEC_ALLOC) != 0) 4338218822Sdim { 4339218822Sdim asection *srel; 4340218822Sdim 4341218822Sdim if (ppc_elf_hash_entry (h)->has_sda_refs) 4342218822Sdim srel = htab->relsbss; 4343218822Sdim else 4344218822Sdim srel = htab->relbss; 4345218822Sdim BFD_ASSERT (srel != NULL); 4346218822Sdim srel->size += sizeof (Elf32_External_Rela); 4347218822Sdim h->needs_copy = 1; 4348218822Sdim } 4349218822Sdim 4350218822Sdim return _bfd_elf_adjust_dynamic_copy (h, s); 4351218822Sdim} 4352218822Sdim 4353218822Sdim/* Generate a symbol to mark plt call stubs. For non-PIC code the sym is 4354218822Sdim xxxxxxxx.plt_call32.<callee> where xxxxxxxx is a hex number, usually 0, 4355218822Sdim specifying the addend on the plt relocation. For -fpic code, the sym 4356218822Sdim is xxxxxxxx.plt_pic32.<callee>, and for -fPIC 4357218822Sdim xxxxxxxx.got2.plt_pic32.<callee>. */ 4358218822Sdim 4359218822Sdimstatic bfd_boolean 4360218822Sdimadd_stub_sym (struct plt_entry *ent, 4361218822Sdim struct elf_link_hash_entry *h, 4362218822Sdim struct bfd_link_info *info) 4363218822Sdim{ 4364218822Sdim struct elf_link_hash_entry *sh; 4365218822Sdim size_t len1, len2, len3; 4366218822Sdim char *name; 4367218822Sdim const char *stub; 4368218822Sdim struct ppc_elf_link_hash_table *htab = ppc_elf_hash_table (info); 4369218822Sdim 4370218822Sdim if (info->shared || info->pie) 4371218822Sdim stub = ".plt_pic32."; 4372218822Sdim else 4373218822Sdim stub = ".plt_call32."; 4374218822Sdim 4375218822Sdim len1 = strlen (h->root.root.string); 4376218822Sdim len2 = strlen (stub); 4377218822Sdim len3 = 0; 4378218822Sdim if (ent->sec) 4379218822Sdim len3 = strlen (ent->sec->name); 4380218822Sdim name = bfd_malloc (len1 + len2 + len3 + 9); 4381218822Sdim if (name == NULL) 4382218822Sdim return FALSE; 4383218822Sdim sprintf (name, "%08x", (unsigned) ent->addend & 0xffffffff); 4384218822Sdim if (ent->sec) 4385218822Sdim memcpy (name + 8, ent->sec->name, len3); 4386218822Sdim memcpy (name + 8 + len3, stub, len2); 4387218822Sdim memcpy (name + 8 + len3 + len2, h->root.root.string, len1 + 1); 4388218822Sdim sh = elf_link_hash_lookup (&htab->elf, name, TRUE, FALSE, FALSE); 4389218822Sdim if (sh == NULL) 4390218822Sdim return FALSE; 4391218822Sdim if (sh->root.type == bfd_link_hash_new) 4392218822Sdim { 4393218822Sdim sh->root.type = bfd_link_hash_defined; 4394218822Sdim sh->root.u.def.section = htab->glink; 4395218822Sdim sh->root.u.def.value = ent->glink_offset; 4396218822Sdim sh->ref_regular = 1; 4397218822Sdim sh->def_regular = 1; 4398218822Sdim sh->ref_regular_nonweak = 1; 4399218822Sdim sh->forced_local = 1; 4400218822Sdim sh->non_elf = 0; 4401218822Sdim } 4402218822Sdim return TRUE; 4403218822Sdim} 4404218822Sdim 4405218822Sdim/* Allocate NEED contiguous space in .got, and return the offset. 4406218822Sdim Handles allocation of the got header when crossing 32k. */ 4407218822Sdim 4408218822Sdimstatic bfd_vma 4409218822Sdimallocate_got (struct ppc_elf_link_hash_table *htab, unsigned int need) 4410218822Sdim{ 4411218822Sdim bfd_vma where; 4412218822Sdim unsigned int max_before_header; 4413218822Sdim 4414218822Sdim if (htab->plt_type == PLT_VXWORKS) 4415218822Sdim { 4416218822Sdim where = htab->got->size; 4417218822Sdim htab->got->size += need; 4418218822Sdim } 4419218822Sdim else 4420218822Sdim { 4421218822Sdim max_before_header = htab->plt_type == PLT_NEW ? 32768 : 32764; 4422218822Sdim if (need <= htab->got_gap) 4423218822Sdim { 4424218822Sdim where = max_before_header - htab->got_gap; 4425218822Sdim htab->got_gap -= need; 4426218822Sdim } 4427218822Sdim else 4428218822Sdim { 4429218822Sdim if (htab->got->size + need > max_before_header 4430218822Sdim && htab->got->size <= max_before_header) 4431218822Sdim { 4432218822Sdim htab->got_gap = max_before_header - htab->got->size; 4433218822Sdim htab->got->size = max_before_header + htab->got_header_size; 4434218822Sdim } 4435218822Sdim where = htab->got->size; 4436218822Sdim htab->got->size += need; 4437218822Sdim } 4438218822Sdim } 4439218822Sdim return where; 4440218822Sdim} 4441218822Sdim 4442218822Sdim/* Allocate space in associated reloc sections for dynamic relocs. */ 4443218822Sdim 4444218822Sdimstatic bfd_boolean 4445218822Sdimallocate_dynrelocs (struct elf_link_hash_entry *h, void *inf) 4446218822Sdim{ 4447218822Sdim struct bfd_link_info *info = inf; 4448218822Sdim struct ppc_elf_link_hash_entry *eh; 4449218822Sdim struct ppc_elf_link_hash_table *htab; 4450218822Sdim struct ppc_elf_dyn_relocs *p; 4451218822Sdim 4452218822Sdim if (h->root.type == bfd_link_hash_indirect) 4453218822Sdim return TRUE; 4454218822Sdim 4455218822Sdim if (h->root.type == bfd_link_hash_warning) 4456218822Sdim /* When warning symbols are created, they **replace** the "real" 4457218822Sdim entry in the hash table, thus we never get to see the real 4458218822Sdim symbol in a hash traversal. So look at it now. */ 4459218822Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 4460218822Sdim 4461218822Sdim htab = ppc_elf_hash_table (info); 4462218822Sdim if (htab->elf.dynamic_sections_created) 4463218822Sdim { 4464218822Sdim struct plt_entry *ent; 4465218822Sdim bfd_boolean doneone = FALSE; 4466218822Sdim bfd_vma plt_offset = 0, glink_offset = 0; 4467218822Sdim 4468218822Sdim for (ent = h->plt.plist; ent != NULL; ent = ent->next) 4469218822Sdim if (ent->plt.refcount > 0) 4470218822Sdim { 4471218822Sdim /* Make sure this symbol is output as a dynamic symbol. */ 4472218822Sdim if (h->dynindx == -1 4473218822Sdim && !h->forced_local) 4474218822Sdim { 4475218822Sdim if (! bfd_elf_link_record_dynamic_symbol (info, h)) 4476218822Sdim return FALSE; 4477218822Sdim } 4478218822Sdim 4479218822Sdim if (info->shared 4480218822Sdim || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h)) 4481218822Sdim { 4482218822Sdim asection *s = htab->plt; 4483218822Sdim 4484218822Sdim if (htab->plt_type == PLT_NEW) 4485218822Sdim { 4486218822Sdim if (!doneone) 4487218822Sdim { 4488218822Sdim plt_offset = s->size; 4489218822Sdim s->size += 4; 4490218822Sdim } 4491218822Sdim ent->plt.offset = plt_offset; 4492218822Sdim 4493218822Sdim s = htab->glink; 4494218822Sdim if (!doneone || info->shared || info->pie) 4495218822Sdim { 4496218822Sdim glink_offset = s->size; 4497218822Sdim s->size += GLINK_ENTRY_SIZE; 4498218822Sdim } 4499218822Sdim if (!doneone 4500218822Sdim && !info->shared 4501218822Sdim && !h->def_regular) 4502218822Sdim { 4503218822Sdim h->root.u.def.section = s; 4504218822Sdim h->root.u.def.value = glink_offset; 4505218822Sdim } 4506218822Sdim ent->glink_offset = glink_offset; 4507218822Sdim 4508218822Sdim if (htab->emit_stub_syms 4509218822Sdim && !add_stub_sym (ent, h, info)) 4510218822Sdim return FALSE; 4511218822Sdim } 4512218822Sdim else 4513218822Sdim { 4514218822Sdim if (!doneone) 4515218822Sdim { 4516218822Sdim /* If this is the first .plt entry, make room 4517218822Sdim for the special first entry. */ 4518218822Sdim if (s->size == 0) 4519218822Sdim s->size += htab->plt_initial_entry_size; 4520218822Sdim 4521218822Sdim /* The PowerPC PLT is actually composed of two 4522218822Sdim parts, the first part is 2 words (for a load 4523218822Sdim and a jump), and then there is a remaining 4524218822Sdim word available at the end. */ 4525218822Sdim plt_offset = (htab->plt_initial_entry_size 4526218822Sdim + (htab->plt_slot_size 4527218822Sdim * ((s->size 4528218822Sdim - htab->plt_initial_entry_size) 4529218822Sdim / htab->plt_entry_size))); 4530218822Sdim 4531218822Sdim /* If this symbol is not defined in a regular 4532218822Sdim file, and we are not generating a shared 4533218822Sdim library, then set the symbol to this location 4534218822Sdim in the .plt. This is required to make 4535218822Sdim function pointers compare as equal between 4536218822Sdim the normal executable and the shared library. */ 4537218822Sdim if (! info->shared 4538218822Sdim && !h->def_regular) 4539218822Sdim { 4540218822Sdim h->root.u.def.section = s; 4541218822Sdim h->root.u.def.value = plt_offset; 4542218822Sdim } 4543218822Sdim 4544218822Sdim /* Make room for this entry. */ 4545218822Sdim s->size += htab->plt_entry_size; 4546218822Sdim /* After the 8192nd entry, room for two entries 4547218822Sdim is allocated. */ 4548218822Sdim if (htab->plt_type == PLT_OLD 4549218822Sdim && (s->size - htab->plt_initial_entry_size) 4550218822Sdim / htab->plt_entry_size 4551218822Sdim > PLT_NUM_SINGLE_ENTRIES) 4552218822Sdim s->size += htab->plt_entry_size; 4553218822Sdim } 4554218822Sdim ent->plt.offset = plt_offset; 4555218822Sdim } 4556218822Sdim 4557218822Sdim /* We also need to make an entry in the .rela.plt section. */ 4558218822Sdim if (!doneone) 4559218822Sdim { 4560218822Sdim htab->relplt->size += sizeof (Elf32_External_Rela); 4561218822Sdim 4562218822Sdim if (htab->plt_type == PLT_VXWORKS) 4563218822Sdim { 4564218822Sdim /* Allocate space for the unloaded relocations. */ 4565218822Sdim if (!info->shared) 4566218822Sdim { 4567218822Sdim if (ent->plt.offset 4568218822Sdim == (bfd_vma) htab->plt_initial_entry_size) 4569218822Sdim { 4570218822Sdim htab->srelplt2->size 4571218822Sdim += sizeof (Elf32_External_Rela) 4572218822Sdim * VXWORKS_PLTRESOLVE_RELOCS; 4573218822Sdim } 4574218822Sdim 4575218822Sdim htab->srelplt2->size 4576218822Sdim += sizeof (Elf32_External_Rela) 4577218822Sdim * VXWORKS_PLT_NON_JMP_SLOT_RELOCS; 4578218822Sdim } 4579218822Sdim 4580218822Sdim /* Every PLT entry has an associated GOT entry in 4581218822Sdim .got.plt. */ 4582218822Sdim htab->sgotplt->size += 4; 4583218822Sdim } 4584218822Sdim doneone = TRUE; 4585218822Sdim } 4586218822Sdim } 4587218822Sdim else 4588218822Sdim ent->plt.offset = (bfd_vma) -1; 4589218822Sdim } 4590218822Sdim else 4591218822Sdim ent->plt.offset = (bfd_vma) -1; 4592218822Sdim 4593218822Sdim if (!doneone) 4594218822Sdim { 4595218822Sdim h->plt.plist = NULL; 4596218822Sdim h->needs_plt = 0; 4597218822Sdim } 4598218822Sdim } 4599218822Sdim else 4600218822Sdim { 4601218822Sdim h->plt.plist = NULL; 4602218822Sdim h->needs_plt = 0; 4603218822Sdim } 4604218822Sdim 4605218822Sdim eh = (struct ppc_elf_link_hash_entry *) h; 4606218822Sdim if (eh->elf.got.refcount > 0) 4607218822Sdim { 4608218822Sdim /* Make sure this symbol is output as a dynamic symbol. */ 4609218822Sdim if (eh->elf.dynindx == -1 4610218822Sdim && !eh->elf.forced_local) 4611218822Sdim { 4612218822Sdim if (!bfd_elf_link_record_dynamic_symbol (info, &eh->elf)) 4613130561Sobrien return FALSE; 461460484Sobrien } 461560484Sobrien 4616218822Sdim if (eh->tls_mask == (TLS_TLS | TLS_LD) 4617218822Sdim && !eh->elf.def_dynamic) 4618218822Sdim /* If just an LD reloc, we'll just use htab->tlsld_got.offset. */ 4619218822Sdim eh->elf.got.offset = (bfd_vma) -1; 4620218822Sdim else 4621218822Sdim { 4622218822Sdim bfd_boolean dyn; 4623218822Sdim unsigned int need = 0; 4624218822Sdim if ((eh->tls_mask & TLS_TLS) != 0) 4625218822Sdim { 4626218822Sdim if ((eh->tls_mask & TLS_LD) != 0) 4627218822Sdim need += 8; 4628218822Sdim if ((eh->tls_mask & TLS_GD) != 0) 4629218822Sdim need += 8; 4630218822Sdim if ((eh->tls_mask & (TLS_TPREL | TLS_TPRELGD)) != 0) 4631218822Sdim need += 4; 4632218822Sdim if ((eh->tls_mask & TLS_DTPREL) != 0) 4633218822Sdim need += 4; 4634218822Sdim } 4635218822Sdim else 4636218822Sdim need += 4; 4637218822Sdim eh->elf.got.offset = allocate_got (htab, need); 4638218822Sdim dyn = htab->elf.dynamic_sections_created; 4639218822Sdim if ((info->shared 4640218822Sdim || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, &eh->elf)) 4641218822Sdim && (ELF_ST_VISIBILITY (eh->elf.other) == STV_DEFAULT 4642218822Sdim || eh->elf.root.type != bfd_link_hash_undefweak)) 4643218822Sdim { 4644218822Sdim /* All the entries we allocated need relocs. 4645218822Sdim Except LD only needs one. */ 4646218822Sdim if ((eh->tls_mask & TLS_LD) != 0) 4647218822Sdim need -= 4; 4648218822Sdim htab->relgot->size += need * (sizeof (Elf32_External_Rela) / 4); 4649218822Sdim } 4650218822Sdim } 465160484Sobrien } 4652218822Sdim else 4653218822Sdim eh->elf.got.offset = (bfd_vma) -1; 465460484Sobrien 4655218822Sdim if (eh->dyn_relocs == NULL) 4656218822Sdim return TRUE; 4657218822Sdim 4658218822Sdim /* In the shared -Bsymbolic case, discard space allocated for 4659218822Sdim dynamic pc-relative relocs against symbols which turn out to be 4660218822Sdim defined in regular objects. For the normal shared case, discard 4661218822Sdim space for relocs that have become local due to symbol visibility 4662218822Sdim changes. */ 4663218822Sdim 4664218822Sdim if (info->shared) 4665218822Sdim { 4666218822Sdim /* Relocs that use pc_count are those that appear on a call insn, 4667218822Sdim or certain REL relocs (see MUST_BE_DYN_RELOC) that can be 4668218822Sdim generated via assembly. We want calls to protected symbols to 4669218822Sdim resolve directly to the function rather than going via the plt. 4670218822Sdim If people want function pointer comparisons to work as expected 4671218822Sdim then they should avoid writing weird assembly. */ 4672218822Sdim if (SYMBOL_CALLS_LOCAL (info, h)) 4673218822Sdim { 4674218822Sdim struct ppc_elf_dyn_relocs **pp; 4675218822Sdim 4676218822Sdim for (pp = &eh->dyn_relocs; (p = *pp) != NULL; ) 4677218822Sdim { 4678218822Sdim p->count -= p->pc_count; 4679218822Sdim p->pc_count = 0; 4680218822Sdim if (p->count == 0) 4681218822Sdim *pp = p->next; 4682218822Sdim else 4683218822Sdim pp = &p->next; 4684218822Sdim } 4685218822Sdim } 4686218822Sdim 4687218822Sdim /* Also discard relocs on undefined weak syms with non-default 4688218822Sdim visibility. */ 4689218822Sdim if (eh->dyn_relocs != NULL 4690218822Sdim && h->root.type == bfd_link_hash_undefweak) 4691218822Sdim { 4692218822Sdim if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT) 4693218822Sdim eh->dyn_relocs = NULL; 4694218822Sdim 4695218822Sdim /* Make sure undefined weak symbols are output as a dynamic 4696218822Sdim symbol in PIEs. */ 4697218822Sdim else if (h->dynindx == -1 4698218822Sdim && !h->forced_local) 4699218822Sdim { 4700218822Sdim if (! bfd_elf_link_record_dynamic_symbol (info, h)) 4701218822Sdim return FALSE; 4702218822Sdim } 4703218822Sdim } 4704218822Sdim } 4705218822Sdim else if (ELIMINATE_COPY_RELOCS) 4706218822Sdim { 4707218822Sdim /* For the non-shared case, discard space for relocs against 4708218822Sdim symbols which turn out to need copy relocs or are not 4709218822Sdim dynamic. */ 4710218822Sdim 4711218822Sdim if (!h->non_got_ref 4712218822Sdim && h->def_dynamic 4713218822Sdim && !h->def_regular) 4714218822Sdim { 4715218822Sdim /* Make sure this symbol is output as a dynamic symbol. 4716218822Sdim Undefined weak syms won't yet be marked as dynamic. */ 4717218822Sdim if (h->dynindx == -1 4718218822Sdim && !h->forced_local) 4719218822Sdim { 4720218822Sdim if (! bfd_elf_link_record_dynamic_symbol (info, h)) 4721218822Sdim return FALSE; 4722218822Sdim } 4723218822Sdim 4724218822Sdim /* If that succeeded, we know we'll be keeping all the 4725218822Sdim relocs. */ 4726218822Sdim if (h->dynindx != -1) 4727218822Sdim goto keep; 4728218822Sdim } 4729218822Sdim 4730218822Sdim eh->dyn_relocs = NULL; 4731218822Sdim 4732218822Sdim keep: ; 4733218822Sdim } 4734218822Sdim 4735218822Sdim /* Finally, allocate space. */ 4736218822Sdim for (p = eh->dyn_relocs; p != NULL; p = p->next) 4737218822Sdim { 4738218822Sdim asection *sreloc = elf_section_data (p->sec)->sreloc; 4739218822Sdim sreloc->size += p->count * sizeof (Elf32_External_Rela); 4740218822Sdim } 4741218822Sdim 4742130561Sobrien return TRUE; 474360484Sobrien} 474460484Sobrien 4745218822Sdim/* Find any dynamic relocs that apply to read-only sections. */ 4746218822Sdim 4747130561Sobrienstatic bfd_boolean 4748218822Sdimreadonly_dynrelocs (struct elf_link_hash_entry *h, void *info) 474960484Sobrien{ 4750218822Sdim struct ppc_elf_dyn_relocs *p; 4751218822Sdim 4752218822Sdim if (h->root.type == bfd_link_hash_indirect) 4753218822Sdim return TRUE; 4754218822Sdim 4755218822Sdim if (h->root.type == bfd_link_hash_warning) 4756218822Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 4757218822Sdim 4758218822Sdim for (p = ppc_elf_hash_entry (h)->dyn_relocs; p != NULL; p = p->next) 4759218822Sdim { 4760218822Sdim asection *s = p->sec->output_section; 4761218822Sdim 4762218822Sdim if (s != NULL 4763218822Sdim && ((s->flags & (SEC_READONLY | SEC_ALLOC)) 4764218822Sdim == (SEC_READONLY | SEC_ALLOC))) 4765218822Sdim { 4766218822Sdim ((struct bfd_link_info *) info)->flags |= DF_TEXTREL; 4767218822Sdim 4768218822Sdim /* Not an error, just cut short the traversal. */ 4769218822Sdim return FALSE; 4770218822Sdim } 4771218822Sdim } 4772218822Sdim return TRUE; 4773218822Sdim} 4774218822Sdim 4775218822Sdim/* Set the sizes of the dynamic sections. */ 4776218822Sdim 4777218822Sdimstatic bfd_boolean 4778218822Sdimppc_elf_size_dynamic_sections (bfd *output_bfd ATTRIBUTE_UNUSED, 4779218822Sdim struct bfd_link_info *info) 4780218822Sdim{ 4781130561Sobrien struct ppc_elf_link_hash_table *htab; 4782218822Sdim asection *s; 4783218822Sdim bfd_boolean relocs; 4784218822Sdim bfd *ibfd; 478560484Sobrien 478660484Sobrien#ifdef DEBUG 4787218822Sdim fprintf (stderr, "ppc_elf_size_dynamic_sections called\n"); 478860484Sobrien#endif 478960484Sobrien 4790130561Sobrien htab = ppc_elf_hash_table (info); 4791130561Sobrien BFD_ASSERT (htab->elf.dynobj != NULL); 479260484Sobrien 4793218822Sdim if (elf_hash_table (info)->dynamic_sections_created) 479460484Sobrien { 4795218822Sdim /* Set the contents of the .interp section to the interpreter. */ 4796218822Sdim if (info->executable) 4797218822Sdim { 4798218822Sdim s = bfd_get_section_by_name (htab->elf.dynobj, ".interp"); 4799218822Sdim BFD_ASSERT (s != NULL); 4800218822Sdim s->size = sizeof ELF_DYNAMIC_INTERPRETER; 4801218822Sdim s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER; 4802218822Sdim } 4803218822Sdim } 480460484Sobrien 4805218822Sdim if (htab->plt_type == PLT_OLD) 4806218822Sdim htab->got_header_size = 16; 4807218822Sdim else if (htab->plt_type == PLT_NEW) 4808218822Sdim htab->got_header_size = 12; 480960484Sobrien 4810218822Sdim /* Set up .got offsets for local syms, and space for local dynamic 4811218822Sdim relocs. */ 4812218822Sdim for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next) 4813218822Sdim { 4814218822Sdim bfd_signed_vma *local_got; 4815218822Sdim bfd_signed_vma *end_local_got; 4816218822Sdim char *lgot_masks; 4817218822Sdim bfd_size_type locsymcount; 4818218822Sdim Elf_Internal_Shdr *symtab_hdr; 481960484Sobrien 4820218822Sdim if (!is_ppc_elf_target (ibfd->xvec)) 4821218822Sdim continue; 482260484Sobrien 4823218822Sdim for (s = ibfd->sections; s != NULL; s = s->next) 4824218822Sdim { 4825218822Sdim struct ppc_elf_dyn_relocs *p; 482660484Sobrien 4827218822Sdim for (p = ((struct ppc_elf_dyn_relocs *) 4828218822Sdim elf_section_data (s)->local_dynrel); 4829218822Sdim p != NULL; 4830218822Sdim p = p->next) 4831218822Sdim { 4832218822Sdim if (!bfd_is_abs_section (p->sec) 4833218822Sdim && bfd_is_abs_section (p->sec->output_section)) 4834218822Sdim { 4835218822Sdim /* Input section has been discarded, either because 4836218822Sdim it is a copy of a linkonce section or due to 4837218822Sdim linker script /DISCARD/, so we'll be discarding 4838218822Sdim the relocs too. */ 4839218822Sdim } 4840218822Sdim else if (p->count != 0) 4841218822Sdim { 4842218822Sdim elf_section_data (p->sec)->sreloc->size 4843218822Sdim += p->count * sizeof (Elf32_External_Rela); 4844218822Sdim if ((p->sec->output_section->flags 4845218822Sdim & (SEC_READONLY | SEC_ALLOC)) 4846218822Sdim == (SEC_READONLY | SEC_ALLOC)) 4847218822Sdim info->flags |= DF_TEXTREL; 4848218822Sdim } 4849218822Sdim } 4850218822Sdim } 485160484Sobrien 4852218822Sdim local_got = elf_local_got_refcounts (ibfd); 4853218822Sdim if (!local_got) 4854218822Sdim continue; 485560484Sobrien 4856218822Sdim symtab_hdr = &elf_tdata (ibfd)->symtab_hdr; 4857218822Sdim locsymcount = symtab_hdr->sh_info; 4858218822Sdim end_local_got = local_got + locsymcount; 4859218822Sdim lgot_masks = (char *) end_local_got; 4860218822Sdim for (; local_got < end_local_got; ++local_got, ++lgot_masks) 4861218822Sdim if (*local_got > 0) 4862218822Sdim { 4863218822Sdim if (*lgot_masks == (TLS_TLS | TLS_LD)) 4864218822Sdim { 4865218822Sdim /* If just an LD reloc, we'll just use 4866218822Sdim htab->tlsld_got.offset. */ 4867218822Sdim htab->tlsld_got.refcount += 1; 4868218822Sdim *local_got = (bfd_vma) -1; 4869218822Sdim } 4870218822Sdim else 4871218822Sdim { 4872218822Sdim unsigned int need = 0; 4873218822Sdim if ((*lgot_masks & TLS_TLS) != 0) 4874218822Sdim { 4875218822Sdim if ((*lgot_masks & TLS_GD) != 0) 4876218822Sdim need += 8; 4877218822Sdim if ((*lgot_masks & (TLS_TPREL | TLS_TPRELGD)) != 0) 4878218822Sdim need += 4; 4879218822Sdim if ((*lgot_masks & TLS_DTPREL) != 0) 4880218822Sdim need += 4; 4881218822Sdim } 4882218822Sdim else 4883218822Sdim need += 4; 4884218822Sdim *local_got = allocate_got (htab, need); 4885218822Sdim if (info->shared) 4886218822Sdim htab->relgot->size += (need 4887218822Sdim * (sizeof (Elf32_External_Rela) / 4)); 4888218822Sdim } 4889218822Sdim } 4890218822Sdim else 4891218822Sdim *local_got = (bfd_vma) -1; 4892218822Sdim } 4893218822Sdim 4894218822Sdim if (htab->tlsld_got.refcount > 0) 4895218822Sdim { 4896218822Sdim htab->tlsld_got.offset = allocate_got (htab, 8); 4897218822Sdim if (info->shared) 4898218822Sdim htab->relgot->size += sizeof (Elf32_External_Rela); 4899218822Sdim } 4900218822Sdim else 4901218822Sdim htab->tlsld_got.offset = (bfd_vma) -1; 4902218822Sdim 4903218822Sdim /* Allocate space for global sym dynamic relocs. */ 4904218822Sdim elf_link_hash_traverse (elf_hash_table (info), allocate_dynrelocs, info); 4905218822Sdim 4906218822Sdim if (htab->got != NULL && htab->plt_type != PLT_VXWORKS) 4907218822Sdim { 4908218822Sdim unsigned int g_o_t = 32768; 4909218822Sdim 4910218822Sdim /* If we haven't allocated the header, do so now. When we get here, 4911218822Sdim for old plt/got the got size will be 0 to 32764 (not allocated), 4912218822Sdim or 32780 to 65536 (header allocated). For new plt/got, the 4913218822Sdim corresponding ranges are 0 to 32768 and 32780 to 65536. */ 4914218822Sdim if (htab->got->size <= 32768) 491560484Sobrien { 4916218822Sdim g_o_t = htab->got->size; 4917218822Sdim if (htab->plt_type == PLT_OLD) 4918218822Sdim g_o_t += 4; 4919218822Sdim htab->got->size += htab->got_header_size; 492060484Sobrien } 4921218822Sdim 4922218822Sdim htab->elf.hgot->root.u.def.value = g_o_t; 492360484Sobrien } 492460484Sobrien 4925218822Sdim if (htab->glink != NULL && htab->glink->size != 0) 492660484Sobrien { 4927218822Sdim htab->glink_pltresolve = htab->glink->size; 4928218822Sdim /* Space for the branch table. */ 4929218822Sdim htab->glink->size += htab->glink->size / (GLINK_ENTRY_SIZE / 4) - 4; 4930218822Sdim /* Pad out to align the start of PLTresolve. */ 4931218822Sdim htab->glink->size += -htab->glink->size & 15; 4932218822Sdim htab->glink->size += GLINK_PLTRESOLVE; 493360484Sobrien 4934218822Sdim if (htab->emit_stub_syms) 4935218822Sdim { 4936218822Sdim struct elf_link_hash_entry *sh; 4937218822Sdim sh = elf_link_hash_lookup (&htab->elf, "__glink", 4938218822Sdim TRUE, FALSE, FALSE); 4939218822Sdim if (sh == NULL) 4940218822Sdim return FALSE; 4941218822Sdim if (sh->root.type == bfd_link_hash_new) 4942218822Sdim { 4943218822Sdim sh->root.type = bfd_link_hash_defined; 4944218822Sdim sh->root.u.def.section = htab->glink; 4945218822Sdim sh->root.u.def.value = htab->glink_pltresolve; 4946218822Sdim sh->ref_regular = 1; 4947218822Sdim sh->def_regular = 1; 4948218822Sdim sh->ref_regular_nonweak = 1; 4949218822Sdim sh->forced_local = 1; 4950218822Sdim sh->non_elf = 0; 4951218822Sdim } 4952218822Sdim sh = elf_link_hash_lookup (&htab->elf, "__glink_PLTresolve", 4953218822Sdim TRUE, FALSE, FALSE); 4954218822Sdim if (sh == NULL) 4955218822Sdim return FALSE; 4956218822Sdim if (sh->root.type == bfd_link_hash_new) 4957218822Sdim { 4958218822Sdim sh->root.type = bfd_link_hash_defined; 4959218822Sdim sh->root.u.def.section = htab->glink; 4960218822Sdim sh->root.u.def.value = htab->glink->size - GLINK_PLTRESOLVE; 4961218822Sdim sh->ref_regular = 1; 4962218822Sdim sh->def_regular = 1; 4963218822Sdim sh->ref_regular_nonweak = 1; 4964218822Sdim sh->forced_local = 1; 4965218822Sdim sh->non_elf = 0; 4966218822Sdim } 4967218822Sdim } 4968218822Sdim } 496960484Sobrien 4970218822Sdim /* We've now determined the sizes of the various dynamic sections. 4971218822Sdim Allocate memory for them. */ 4972218822Sdim relocs = FALSE; 4973218822Sdim for (s = htab->elf.dynobj->sections; s != NULL; s = s->next) 4974218822Sdim { 4975218822Sdim bfd_boolean strip_section = TRUE; 497660484Sobrien 4977218822Sdim if ((s->flags & SEC_LINKER_CREATED) == 0) 4978218822Sdim continue; 497960484Sobrien 4980218822Sdim if (s == htab->plt 4981218822Sdim || s == htab->glink 4982218822Sdim || s == htab->got 4983218822Sdim || s == htab->sgotplt 4984218822Sdim || s == htab->sbss 4985218822Sdim || s == htab->dynbss 4986218822Sdim || s == htab->dynsbss) 4987218822Sdim { 4988218822Sdim /* We'd like to strip these sections if they aren't needed, but if 4989218822Sdim we've exported dynamic symbols from them we must leave them. 4990218822Sdim It's too late to tell BFD to get rid of the symbols. */ 4991218822Sdim if ((s == htab->plt || s == htab->got) && htab->elf.hplt != NULL) 4992218822Sdim strip_section = FALSE; 4993218822Sdim /* Strip this section if we don't need it; see the 4994218822Sdim comment below. */ 4995218822Sdim } 4996218822Sdim else if (s == htab->sdata[0].section 4997218822Sdim || s == htab->sdata[1].section) 4998218822Sdim { 4999218822Sdim /* Strip these too. */ 5000218822Sdim } 5001218822Sdim else if (CONST_STRNEQ (bfd_get_section_name (dynobj, s), ".rela")) 5002218822Sdim { 5003218822Sdim if (s->size != 0) 5004218822Sdim { 5005218822Sdim /* Remember whether there are any relocation sections. */ 5006218822Sdim relocs = TRUE; 5007218822Sdim 5008218822Sdim /* We use the reloc_count field as a counter if we need 5009218822Sdim to copy relocs into the output file. */ 5010218822Sdim s->reloc_count = 0; 5011218822Sdim } 5012218822Sdim } 501360484Sobrien else 5014218822Sdim { 5015218822Sdim /* It's not one of our sections, so don't allocate space. */ 5016218822Sdim continue; 5017218822Sdim } 501860484Sobrien 5019218822Sdim if (s->size == 0 && strip_section) 5020218822Sdim { 5021218822Sdim /* If we don't need this section, strip it from the 5022218822Sdim output file. This is mostly to handle .rela.bss and 5023218822Sdim .rela.plt. We must create both sections in 5024218822Sdim create_dynamic_sections, because they must be created 5025218822Sdim before the linker maps input sections to output 5026218822Sdim sections. The linker does that before 5027218822Sdim adjust_dynamic_symbol is called, and it is that 5028218822Sdim function which decides whether anything needs to go 5029218822Sdim into these sections. */ 5030218822Sdim s->flags |= SEC_EXCLUDE; 5031218822Sdim continue; 5032218822Sdim } 5033218822Sdim 5034218822Sdim if ((s->flags & SEC_HAS_CONTENTS) == 0) 5035218822Sdim continue; 5036218822Sdim 5037218822Sdim /* Allocate memory for the section contents. */ 5038218822Sdim s->contents = bfd_zalloc (htab->elf.dynobj, s->size); 5039218822Sdim if (s->contents == NULL) 5040218822Sdim return FALSE; 504160484Sobrien } 504260484Sobrien 5043218822Sdim if (htab->elf.dynamic_sections_created) 5044218822Sdim { 5045218822Sdim /* Add some entries to the .dynamic section. We fill in the 5046218822Sdim values later, in ppc_elf_finish_dynamic_sections, but we 5047218822Sdim must add the entries now so that we get the correct size for 5048218822Sdim the .dynamic section. The DT_DEBUG entry is filled in by the 5049218822Sdim dynamic linker and used by the debugger. */ 5050218822Sdim#define add_dynamic_entry(TAG, VAL) \ 5051218822Sdim _bfd_elf_add_dynamic_entry (info, TAG, VAL) 505260484Sobrien 5053218822Sdim if (info->executable) 5054218822Sdim { 5055218822Sdim if (!add_dynamic_entry (DT_DEBUG, 0)) 5056218822Sdim return FALSE; 5057218822Sdim } 505860484Sobrien 5059218822Sdim if (htab->plt != NULL && htab->plt->size != 0) 5060218822Sdim { 5061218822Sdim if (!add_dynamic_entry (DT_PLTGOT, 0) 5062218822Sdim || !add_dynamic_entry (DT_PLTRELSZ, 0) 5063218822Sdim || !add_dynamic_entry (DT_PLTREL, DT_RELA) 5064218822Sdim || !add_dynamic_entry (DT_JMPREL, 0)) 5065218822Sdim return FALSE; 5066218822Sdim } 5067218822Sdim 5068218822Sdim if (htab->glink != NULL && htab->glink->size != 0) 5069218822Sdim { 5070218822Sdim if (!add_dynamic_entry (DT_PPC_GOT, 0)) 5071218822Sdim return FALSE; 5072218822Sdim } 5073218822Sdim 5074218822Sdim if (relocs) 5075218822Sdim { 5076218822Sdim if (!add_dynamic_entry (DT_RELA, 0) 5077218822Sdim || !add_dynamic_entry (DT_RELASZ, 0) 5078218822Sdim || !add_dynamic_entry (DT_RELAENT, sizeof (Elf32_External_Rela))) 5079218822Sdim return FALSE; 5080218822Sdim } 5081218822Sdim 5082218822Sdim /* If any dynamic relocs apply to a read-only section, then we 5083218822Sdim need a DT_TEXTREL entry. */ 5084218822Sdim if ((info->flags & DF_TEXTREL) == 0) 5085218822Sdim elf_link_hash_traverse (elf_hash_table (info), readonly_dynrelocs, 5086218822Sdim info); 5087218822Sdim 5088218822Sdim if ((info->flags & DF_TEXTREL) != 0) 5089218822Sdim { 5090218822Sdim if (!add_dynamic_entry (DT_TEXTREL, 0)) 5091218822Sdim return FALSE; 5092218822Sdim } 5093218822Sdim } 5094218822Sdim#undef add_dynamic_entry 5095218822Sdim 5096130561Sobrien return TRUE; 509760484Sobrien} 509860484Sobrien 5099218822Sdim#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) 510060484Sobrien 5101218822Sdimstatic const int shared_stub_entry[] = 5102218822Sdim { 5103218822Sdim 0x7c0802a6, /* mflr 0 */ 5104218822Sdim 0x429f0005, /* bcl 20, 31, .Lxxx */ 5105218822Sdim 0x7d6802a6, /* mflr 11 */ 5106218822Sdim 0x3d6b0000, /* addis 11, 11, (xxx-.Lxxx)@ha */ 5107218822Sdim 0x396b0018, /* addi 11, 11, (xxx-.Lxxx)@l */ 5108218822Sdim 0x7c0803a6, /* mtlr 0 */ 5109218822Sdim 0x7d6903a6, /* mtctr 11 */ 5110218822Sdim 0x4e800420, /* bctr */ 5111218822Sdim }; 5112218822Sdim 5113218822Sdimstatic const int stub_entry[] = 5114218822Sdim { 5115218822Sdim 0x3d600000, /* lis 11,xxx@ha */ 5116218822Sdim 0x396b0000, /* addi 11,11,xxx@l */ 5117218822Sdim 0x7d6903a6, /* mtctr 11 */ 5118218822Sdim 0x4e800420, /* bctr */ 5119218822Sdim }; 5120218822Sdim 5121130561Sobrienstatic bfd_boolean 5122218822Sdimppc_elf_relax_section (bfd *abfd, 5123218822Sdim asection *isec, 5124218822Sdim struct bfd_link_info *link_info, 5125218822Sdim bfd_boolean *again) 512660484Sobrien{ 5127218822Sdim struct one_fixup 5128218822Sdim { 5129218822Sdim struct one_fixup *next; 5130218822Sdim asection *tsec; 5131218822Sdim bfd_vma toff; 5132218822Sdim bfd_vma trampoff; 5133218822Sdim }; 5134218822Sdim 5135218822Sdim Elf_Internal_Shdr *symtab_hdr; 5136218822Sdim bfd_byte *contents = NULL; 5137218822Sdim Elf_Internal_Sym *isymbuf = NULL; 5138218822Sdim Elf_Internal_Rela *internal_relocs = NULL; 5139218822Sdim Elf_Internal_Rela *irel, *irelend; 5140218822Sdim struct one_fixup *fixups = NULL; 5141218822Sdim bfd_boolean changed; 5142130561Sobrien struct ppc_elf_link_hash_table *htab; 5143218822Sdim bfd_size_type trampoff; 5144218822Sdim asection *got2; 514560484Sobrien 5146218822Sdim *again = FALSE; 514760484Sobrien 5148218822Sdim /* Nothing to do if there are no relocations, and no need to do 5149218822Sdim anything with non-alloc sections. */ 5150218822Sdim if ((isec->flags & SEC_ALLOC) == 0 5151218822Sdim || (isec->flags & SEC_RELOC) == 0 5152218822Sdim || isec->reloc_count == 0) 5153218822Sdim return TRUE; 515460484Sobrien 5155218822Sdim trampoff = (isec->size + 3) & (bfd_vma) -4; 5156218822Sdim /* Space for a branch around any trampolines. */ 5157218822Sdim trampoff += 4; 5158218822Sdim 5159218822Sdim symtab_hdr = &elf_tdata (abfd)->symtab_hdr; 5160218822Sdim 5161218822Sdim /* Get a copy of the native relocations. */ 5162218822Sdim internal_relocs = _bfd_elf_link_read_relocs (abfd, isec, NULL, NULL, 5163218822Sdim link_info->keep_memory); 5164218822Sdim if (internal_relocs == NULL) 5165218822Sdim goto error_return; 5166218822Sdim 5167218822Sdim htab = ppc_elf_hash_table (link_info); 5168218822Sdim got2 = bfd_get_section_by_name (abfd, ".got2"); 5169218822Sdim 5170218822Sdim irelend = internal_relocs + isec->reloc_count; 5171218822Sdim for (irel = internal_relocs; irel < irelend; irel++) 517260484Sobrien { 5173218822Sdim unsigned long r_type = ELF32_R_TYPE (irel->r_info); 5174218822Sdim bfd_vma symaddr, reladdr, toff, roff; 5175218822Sdim asection *tsec; 5176218822Sdim struct one_fixup *f; 5177218822Sdim size_t insn_offset = 0; 5178218822Sdim bfd_vma max_branch_offset, val; 5179218822Sdim bfd_byte *hit_addr; 5180218822Sdim unsigned long t0; 5181218822Sdim unsigned char sym_type; 518260484Sobrien 5183218822Sdim switch (r_type) 5184218822Sdim { 5185218822Sdim case R_PPC_REL24: 5186218822Sdim case R_PPC_LOCAL24PC: 5187218822Sdim case R_PPC_PLTREL24: 5188218822Sdim max_branch_offset = 1 << 25; 5189218822Sdim break; 519060484Sobrien 5191218822Sdim case R_PPC_REL14: 5192218822Sdim case R_PPC_REL14_BRTAKEN: 5193218822Sdim case R_PPC_REL14_BRNTAKEN: 5194218822Sdim max_branch_offset = 1 << 15; 5195218822Sdim break; 5196218822Sdim 5197218822Sdim default: 5198218822Sdim continue; 5199218822Sdim } 5200218822Sdim 5201218822Sdim /* Get the value of the symbol referred to by the reloc. */ 5202218822Sdim if (ELF32_R_SYM (irel->r_info) < symtab_hdr->sh_info) 520360484Sobrien { 5204218822Sdim /* A local symbol. */ 5205218822Sdim Elf_Internal_Sym *isym; 520660484Sobrien 5207218822Sdim /* Read this BFD's local symbols. */ 5208218822Sdim if (isymbuf == NULL) 5209218822Sdim { 5210218822Sdim isymbuf = (Elf_Internal_Sym *) symtab_hdr->contents; 5211218822Sdim if (isymbuf == NULL) 5212218822Sdim isymbuf = bfd_elf_get_elf_syms (abfd, symtab_hdr, 5213218822Sdim symtab_hdr->sh_info, 0, 5214218822Sdim NULL, NULL, NULL); 5215218822Sdim if (isymbuf == 0) 5216218822Sdim goto error_return; 5217218822Sdim } 5218218822Sdim isym = isymbuf + ELF32_R_SYM (irel->r_info); 5219218822Sdim if (isym->st_shndx == SHN_UNDEF) 5220218822Sdim continue; /* We can't do anything with undefined symbols. */ 5221218822Sdim else if (isym->st_shndx == SHN_ABS) 5222218822Sdim tsec = bfd_abs_section_ptr; 5223218822Sdim else if (isym->st_shndx == SHN_COMMON) 5224218822Sdim tsec = bfd_com_section_ptr; 5225218822Sdim else 5226218822Sdim tsec = bfd_section_from_elf_index (abfd, isym->st_shndx); 522760484Sobrien 5228218822Sdim toff = isym->st_value; 5229218822Sdim sym_type = ELF_ST_TYPE (isym->st_info); 5230218822Sdim } 5231218822Sdim else 5232218822Sdim { 5233218822Sdim /* Global symbol handling. */ 5234218822Sdim unsigned long indx; 5235218822Sdim struct elf_link_hash_entry *h; 5236218822Sdim 5237218822Sdim indx = ELF32_R_SYM (irel->r_info) - symtab_hdr->sh_info; 5238218822Sdim h = elf_sym_hashes (abfd)[indx]; 5239218822Sdim 5240218822Sdim while (h->root.type == bfd_link_hash_indirect 5241218822Sdim || h->root.type == bfd_link_hash_warning) 5242218822Sdim h = (struct elf_link_hash_entry *) h->root.u.i.link; 5243218822Sdim 5244218822Sdim tsec = NULL; 5245218822Sdim toff = 0; 5246218822Sdim if (r_type == R_PPC_PLTREL24 5247218822Sdim && htab->plt != NULL) 524860484Sobrien { 5249218822Sdim struct plt_entry *ent = find_plt_ent (h, got2, irel->r_addend); 525060484Sobrien 5251218822Sdim if (ent != NULL) 5252218822Sdim { 5253218822Sdim if (htab->plt_type == PLT_NEW) 5254218822Sdim { 5255218822Sdim tsec = htab->glink; 5256218822Sdim toff = ent->glink_offset; 5257218822Sdim } 5258218822Sdim else 5259218822Sdim { 5260218822Sdim tsec = htab->plt; 5261218822Sdim toff = ent->plt.offset; 5262218822Sdim } 5263218822Sdim } 5264218822Sdim } 5265218822Sdim if (tsec != NULL) 5266218822Sdim ; 5267218822Sdim else if (h->root.type == bfd_link_hash_defined 5268218822Sdim || h->root.type == bfd_link_hash_defweak) 5269218822Sdim { 5270218822Sdim tsec = h->root.u.def.section; 5271218822Sdim toff = h->root.u.def.value; 5272218822Sdim } 5273218822Sdim else 5274218822Sdim continue; 527560484Sobrien 5276218822Sdim sym_type = h->type; 5277218822Sdim } 5278130561Sobrien 5279218822Sdim /* If the branch and target are in the same section, you have 5280218822Sdim no hope of adding stubs. We'll error out later should the 5281218822Sdim branch overflow. */ 5282218822Sdim if (tsec == isec) 5283218822Sdim continue; 5284218822Sdim 5285218822Sdim /* There probably isn't any reason to handle symbols in 5286218822Sdim SEC_MERGE sections; SEC_MERGE doesn't seem a likely 5287218822Sdim attribute for a code section, and we are only looking at 5288218822Sdim branches. However, implement it correctly here as a 5289218822Sdim reference for other target relax_section functions. */ 5290218822Sdim if (0 && tsec->sec_info_type == ELF_INFO_TYPE_MERGE) 5291218822Sdim { 5292218822Sdim /* At this stage in linking, no SEC_MERGE symbol has been 5293218822Sdim adjusted, so all references to such symbols need to be 5294218822Sdim passed through _bfd_merged_section_offset. (Later, in 5295218822Sdim relocate_section, all SEC_MERGE symbols *except* for 5296218822Sdim section symbols have been adjusted.) 5297218822Sdim 5298218822Sdim gas may reduce relocations against symbols in SEC_MERGE 5299218822Sdim sections to a relocation against the section symbol when 5300218822Sdim the original addend was zero. When the reloc is against 5301218822Sdim a section symbol we should include the addend in the 5302218822Sdim offset passed to _bfd_merged_section_offset, since the 5303218822Sdim location of interest is the original symbol. On the 5304218822Sdim other hand, an access to "sym+addend" where "sym" is not 5305218822Sdim a section symbol should not include the addend; Such an 5306218822Sdim access is presumed to be an offset from "sym"; The 5307218822Sdim location of interest is just "sym". */ 5308218822Sdim if (sym_type == STT_SECTION) 5309218822Sdim toff += irel->r_addend; 5310218822Sdim 5311218822Sdim toff = _bfd_merged_section_offset (abfd, &tsec, 5312218822Sdim elf_section_data (tsec)->sec_info, 5313218822Sdim toff); 5314218822Sdim 5315218822Sdim if (sym_type != STT_SECTION) 5316218822Sdim toff += irel->r_addend; 5317218822Sdim } 5318218822Sdim /* PLTREL24 addends are special. */ 5319218822Sdim else if (r_type != R_PPC_PLTREL24) 5320218822Sdim toff += irel->r_addend; 5321218822Sdim 5322218822Sdim /* Attempted -shared link of non-pic code loses. */ 5323218822Sdim if (tsec->output_section == NULL) 5324218822Sdim continue; 5325218822Sdim 5326218822Sdim symaddr = tsec->output_section->vma + tsec->output_offset + toff; 5327218822Sdim 5328218822Sdim roff = irel->r_offset; 5329218822Sdim reladdr = isec->output_section->vma + isec->output_offset + roff; 5330218822Sdim 5331218822Sdim /* If the branch is in range, no need to do anything. */ 5332218822Sdim if (symaddr - reladdr + max_branch_offset < 2 * max_branch_offset) 5333218822Sdim continue; 5334218822Sdim 5335218822Sdim /* Look for an existing fixup to this address. */ 5336218822Sdim for (f = fixups; f ; f = f->next) 5337218822Sdim if (f->tsec == tsec && f->toff == toff) 5338218822Sdim break; 5339218822Sdim 5340218822Sdim if (f == NULL) 5341218822Sdim { 5342218822Sdim size_t size; 5343218822Sdim unsigned long stub_rtype; 5344218822Sdim 5345218822Sdim val = trampoff - roff; 5346218822Sdim if (val >= max_branch_offset) 5347218822Sdim /* Oh dear, we can't reach a trampoline. Don't try to add 5348218822Sdim one. We'll report an error later. */ 5349218822Sdim continue; 5350218822Sdim 5351218822Sdim if (link_info->shared) 5352218822Sdim { 5353218822Sdim size = 4 * ARRAY_SIZE (shared_stub_entry); 5354218822Sdim insn_offset = 12; 5355218822Sdim stub_rtype = R_PPC_RELAX32PC; 535660484Sobrien } 5357218822Sdim else 5358218822Sdim { 5359218822Sdim size = 4 * ARRAY_SIZE (stub_entry); 5360218822Sdim insn_offset = 0; 5361218822Sdim stub_rtype = R_PPC_RELAX32; 5362218822Sdim } 5363130561Sobrien 5364218822Sdim if (R_PPC_RELAX32_PLT - R_PPC_RELAX32 5365218822Sdim != R_PPC_RELAX32PC_PLT - R_PPC_RELAX32PC) 5366218822Sdim abort (); 5367218822Sdim if (tsec == htab->plt 5368218822Sdim || tsec == htab->glink) 5369218822Sdim stub_rtype += R_PPC_RELAX32_PLT - R_PPC_RELAX32; 5370218822Sdim 5371218822Sdim /* Hijack the old relocation. Since we need two 5372218822Sdim relocations for this use a "composite" reloc. */ 5373218822Sdim irel->r_info = ELF32_R_INFO (ELF32_R_SYM (irel->r_info), 5374218822Sdim stub_rtype); 5375218822Sdim irel->r_offset = trampoff + insn_offset; 5376218822Sdim 5377218822Sdim /* Record the fixup so we don't do it again this section. */ 5378218822Sdim f = bfd_malloc (sizeof (*f)); 5379218822Sdim f->next = fixups; 5380218822Sdim f->tsec = tsec; 5381218822Sdim f->toff = toff; 5382218822Sdim f->trampoff = trampoff; 5383218822Sdim fixups = f; 5384218822Sdim 5385218822Sdim trampoff += size; 538660484Sobrien } 5387218822Sdim else 5388218822Sdim { 5389218822Sdim val = f->trampoff - roff; 5390218822Sdim if (val >= max_branch_offset) 5391218822Sdim continue; 5392218822Sdim 5393218822Sdim /* Nop out the reloc, since we're finalizing things here. */ 5394218822Sdim irel->r_info = ELF32_R_INFO (0, R_PPC_NONE); 5395218822Sdim } 5396218822Sdim 5397218822Sdim /* Get the section contents. */ 5398218822Sdim if (contents == NULL) 5399218822Sdim { 5400218822Sdim /* Get cached copy if it exists. */ 5401218822Sdim if (elf_section_data (isec)->this_hdr.contents != NULL) 5402218822Sdim contents = elf_section_data (isec)->this_hdr.contents; 5403218822Sdim else 5404218822Sdim { 5405218822Sdim /* Go get them off disk. */ 5406218822Sdim if (!bfd_malloc_and_get_section (abfd, isec, &contents)) 5407218822Sdim goto error_return; 5408218822Sdim } 5409218822Sdim } 5410218822Sdim 5411218822Sdim /* Fix up the existing branch to hit the trampoline. */ 5412218822Sdim hit_addr = contents + roff; 5413218822Sdim switch (r_type) 5414218822Sdim { 5415218822Sdim case R_PPC_REL24: 5416218822Sdim case R_PPC_LOCAL24PC: 5417218822Sdim case R_PPC_PLTREL24: 5418218822Sdim t0 = bfd_get_32 (abfd, hit_addr); 5419218822Sdim t0 &= ~0x3fffffc; 5420218822Sdim t0 |= val & 0x3fffffc; 5421218822Sdim bfd_put_32 (abfd, t0, hit_addr); 5422218822Sdim break; 5423218822Sdim 5424218822Sdim case R_PPC_REL14: 5425218822Sdim case R_PPC_REL14_BRTAKEN: 5426218822Sdim case R_PPC_REL14_BRNTAKEN: 5427218822Sdim t0 = bfd_get_32 (abfd, hit_addr); 5428218822Sdim t0 &= ~0xfffc; 5429218822Sdim t0 |= val & 0xfffc; 5430218822Sdim bfd_put_32 (abfd, t0, hit_addr); 5431218822Sdim break; 5432218822Sdim } 543360484Sobrien } 543460484Sobrien 5435218822Sdim /* Write out the trampolines. */ 5436218822Sdim changed = fixups != NULL; 5437218822Sdim if (fixups != NULL) 543860484Sobrien { 5439218822Sdim const int *stub; 5440218822Sdim bfd_byte *dest; 5441218822Sdim bfd_vma val; 5442218822Sdim int i, size; 544360484Sobrien 5444218822Sdim do 5445218822Sdim { 5446218822Sdim struct one_fixup *f = fixups; 5447218822Sdim fixups = fixups->next; 5448218822Sdim free (f); 5449218822Sdim } 5450218822Sdim while (fixups); 5451218822Sdim 5452218822Sdim contents = bfd_realloc (contents, trampoff); 5453218822Sdim if (contents == NULL) 5454218822Sdim goto error_return; 5455218822Sdim 5456218822Sdim isec->size = (isec->size + 3) & (bfd_vma) -4; 5457218822Sdim /* Branch around the trampolines. */ 5458218822Sdim val = trampoff - isec->size + 0x48000000; 5459218822Sdim dest = contents + isec->size; 5460218822Sdim isec->size = trampoff; 5461218822Sdim bfd_put_32 (abfd, val, dest); 5462218822Sdim dest += 4; 5463218822Sdim 5464218822Sdim if (link_info->shared) 5465218822Sdim { 5466218822Sdim stub = shared_stub_entry; 5467218822Sdim size = ARRAY_SIZE (shared_stub_entry); 5468218822Sdim } 546960484Sobrien else 5470218822Sdim { 5471218822Sdim stub = stub_entry; 5472218822Sdim size = ARRAY_SIZE (stub_entry); 5473218822Sdim } 547460484Sobrien 5475218822Sdim i = 0; 5476218822Sdim while (dest < contents + trampoff) 5477218822Sdim { 5478218822Sdim bfd_put_32 (abfd, stub[i], dest); 5479218822Sdim i++; 5480218822Sdim if (i == size) 5481218822Sdim i = 0; 5482218822Sdim dest += 4; 5483218822Sdim } 5484218822Sdim BFD_ASSERT (i == 0); 548560484Sobrien } 548660484Sobrien 5487218822Sdim if (isymbuf != NULL 5488218822Sdim && symtab_hdr->contents != (unsigned char *) isymbuf) 5489218822Sdim { 5490218822Sdim if (! link_info->keep_memory) 5491218822Sdim free (isymbuf); 5492218822Sdim else 5493218822Sdim { 5494218822Sdim /* Cache the symbols for elf_link_input_bfd. */ 5495218822Sdim symtab_hdr->contents = (unsigned char *) isymbuf; 5496218822Sdim } 5497218822Sdim } 5498218822Sdim 5499218822Sdim if (contents != NULL 5500218822Sdim && elf_section_data (isec)->this_hdr.contents != contents) 5501218822Sdim { 5502218822Sdim if (!changed && !link_info->keep_memory) 5503218822Sdim free (contents); 5504218822Sdim else 5505218822Sdim { 5506218822Sdim /* Cache the section contents for elf_link_input_bfd. */ 5507218822Sdim elf_section_data (isec)->this_hdr.contents = contents; 5508218822Sdim } 5509218822Sdim } 5510218822Sdim 5511218822Sdim if (elf_section_data (isec)->relocs != internal_relocs) 5512218822Sdim { 5513218822Sdim if (!changed) 5514218822Sdim free (internal_relocs); 5515218822Sdim else 5516218822Sdim elf_section_data (isec)->relocs = internal_relocs; 5517218822Sdim } 5518218822Sdim 5519218822Sdim *again = changed; 5520130561Sobrien return TRUE; 5521218822Sdim 5522218822Sdim error_return: 5523218822Sdim if (isymbuf != NULL && (unsigned char *) isymbuf != symtab_hdr->contents) 5524218822Sdim free (isymbuf); 5525218822Sdim if (contents != NULL 5526218822Sdim && elf_section_data (isec)->this_hdr.contents != contents) 5527218822Sdim free (contents); 5528218822Sdim if (internal_relocs != NULL 5529218822Sdim && elf_section_data (isec)->relocs != internal_relocs) 5530218822Sdim free (internal_relocs); 5531218822Sdim return FALSE; 553260484Sobrien} 553360484Sobrien 5534218822Sdim/* What to do when ld finds relocations against symbols defined in 5535218822Sdim discarded sections. */ 5536218822Sdim 5537218822Sdimstatic unsigned int 5538218822Sdimppc_elf_action_discarded (asection *sec) 5539218822Sdim{ 5540218822Sdim if (strcmp (".fixup", sec->name) == 0) 5541218822Sdim return 0; 5542218822Sdim 5543218822Sdim if (strcmp (".got2", sec->name) == 0) 5544218822Sdim return 0; 5545218822Sdim 5546218822Sdim return _bfd_elf_default_action_discarded (sec); 5547218822Sdim} 5548218822Sdim 5549218822Sdim/* Fill in the address for a pointer generated in a linker section. */ 5550218822Sdim 5551218822Sdimstatic bfd_vma 5552218822Sdimelf_finish_pointer_linker_section (bfd *input_bfd, 5553218822Sdim elf_linker_section_t *lsect, 5554218822Sdim struct elf_link_hash_entry *h, 5555218822Sdim bfd_vma relocation, 5556218822Sdim const Elf_Internal_Rela *rel) 5557218822Sdim{ 5558218822Sdim elf_linker_section_pointers_t *linker_section_ptr; 5559218822Sdim 5560218822Sdim BFD_ASSERT (lsect != NULL); 5561218822Sdim 5562218822Sdim if (h != NULL) 5563218822Sdim { 5564218822Sdim /* Handle global symbol. */ 5565218822Sdim struct ppc_elf_link_hash_entry *eh; 5566218822Sdim 5567218822Sdim eh = (struct ppc_elf_link_hash_entry *) h; 5568218822Sdim BFD_ASSERT (eh->elf.def_regular); 5569218822Sdim linker_section_ptr = eh->linker_section_pointer; 5570218822Sdim } 5571218822Sdim else 5572218822Sdim { 5573218822Sdim /* Handle local symbol. */ 5574218822Sdim unsigned long r_symndx = ELF32_R_SYM (rel->r_info); 5575218822Sdim 5576218822Sdim BFD_ASSERT (elf_local_ptr_offsets (input_bfd) != NULL); 5577218822Sdim linker_section_ptr = elf_local_ptr_offsets (input_bfd)[r_symndx]; 5578218822Sdim } 5579218822Sdim 5580218822Sdim linker_section_ptr = elf_find_pointer_linker_section (linker_section_ptr, 5581218822Sdim rel->r_addend, 5582218822Sdim lsect); 5583218822Sdim BFD_ASSERT (linker_section_ptr != NULL); 5584218822Sdim 5585218822Sdim /* Offset will always be a multiple of four, so use the bottom bit 5586218822Sdim as a "written" flag. */ 5587218822Sdim if ((linker_section_ptr->offset & 1) == 0) 5588218822Sdim { 5589218822Sdim bfd_put_32 (lsect->section->owner, 5590218822Sdim relocation + linker_section_ptr->addend, 5591218822Sdim lsect->section->contents + linker_section_ptr->offset); 5592218822Sdim linker_section_ptr->offset += 1; 5593218822Sdim } 5594218822Sdim 5595218822Sdim relocation = (lsect->section->output_offset 5596218822Sdim + linker_section_ptr->offset - 1 5597218822Sdim - 0x8000); 5598218822Sdim 5599218822Sdim#ifdef DEBUG 5600218822Sdim fprintf (stderr, 5601218822Sdim "Finish pointer in linker section %s, offset = %ld (0x%lx)\n", 5602218822Sdim lsect->name, (long) relocation, (long) relocation); 5603218822Sdim#endif 5604218822Sdim 5605218822Sdim /* Subtract out the addend, because it will get added back in by the normal 5606218822Sdim processing. */ 5607218822Sdim return relocation - linker_section_ptr->addend; 5608218822Sdim} 5609218822Sdim 561060484Sobrien/* The RELOCATE_SECTION function is called by the ELF backend linker 561160484Sobrien to handle the relocations for a section. 561260484Sobrien 561360484Sobrien The relocs are always passed as Rela structures; if the section 561460484Sobrien actually uses Rel structures, the r_addend field will always be 561560484Sobrien zero. 561660484Sobrien 561760484Sobrien This function is responsible for adjust the section contents as 561860484Sobrien necessary, and (if using Rela relocs and generating a 5619130561Sobrien relocatable output file) adjusting the reloc addend as 562060484Sobrien necessary. 562160484Sobrien 562260484Sobrien This function does not have to worry about setting the reloc 562360484Sobrien address or the reloc symbol index. 562460484Sobrien 562560484Sobrien LOCAL_SYMS is a pointer to the swapped in local symbols. 562660484Sobrien 562760484Sobrien LOCAL_SECTIONS is an array giving the section in the input file 562860484Sobrien corresponding to the st_shndx field of each local symbol. 562960484Sobrien 563060484Sobrien The global hash table entry for the global symbols can be found 563160484Sobrien via elf_sym_hashes (input_bfd). 563260484Sobrien 5633130561Sobrien When generating relocatable output, this function must handle 563460484Sobrien STB_LOCAL/STT_SECTION symbols specially. The output symbol is 563560484Sobrien going to be the section symbol corresponding to the output 563660484Sobrien section, which means that the addend must be adjusted 563760484Sobrien accordingly. */ 563860484Sobrien 5639130561Sobrienstatic bfd_boolean 5640130561Sobrienppc_elf_relocate_section (bfd *output_bfd, 5641130561Sobrien struct bfd_link_info *info, 5642130561Sobrien bfd *input_bfd, 5643130561Sobrien asection *input_section, 5644130561Sobrien bfd_byte *contents, 5645130561Sobrien Elf_Internal_Rela *relocs, 5646130561Sobrien Elf_Internal_Sym *local_syms, 5647130561Sobrien asection **local_sections) 564860484Sobrien{ 5649130561Sobrien Elf_Internal_Shdr *symtab_hdr; 5650130561Sobrien struct elf_link_hash_entry **sym_hashes; 5651130561Sobrien struct ppc_elf_link_hash_table *htab; 5652130561Sobrien Elf_Internal_Rela *rel; 5653130561Sobrien Elf_Internal_Rela *relend; 5654130561Sobrien Elf_Internal_Rela outrel; 5655130561Sobrien bfd_byte *loc; 5656218822Sdim asection *got2, *sreloc = NULL; 565760484Sobrien bfd_vma *local_got_offsets; 5658130561Sobrien bfd_boolean ret = TRUE; 5659218822Sdim bfd_vma d_offset = (bfd_big_endian (output_bfd) ? 2 : 0); 566060484Sobrien 566160484Sobrien#ifdef DEBUG 5662218822Sdim _bfd_error_handler ("ppc_elf_relocate_section called for %B section %A, " 5663218822Sdim "%ld relocations%s", 5664218822Sdim input_bfd, input_section, 5665218822Sdim (long) input_section->reloc_count, 5666218822Sdim (info->relocatable) ? " (relocatable)" : ""); 566760484Sobrien#endif 566860484Sobrien 5669218822Sdim got2 = bfd_get_section_by_name (input_bfd, ".got2"); 567099461Sobrien 5671130561Sobrien /* Initialize howto table if not already done. */ 567277298Sobrien if (!ppc_elf_howto_table[R_PPC_ADDR32]) 567360484Sobrien ppc_elf_howto_init (); 567460484Sobrien 5675130561Sobrien htab = ppc_elf_hash_table (info); 567660484Sobrien local_got_offsets = elf_local_got_offsets (input_bfd); 5677130561Sobrien symtab_hdr = &elf_tdata (input_bfd)->symtab_hdr; 5678130561Sobrien sym_hashes = elf_sym_hashes (input_bfd); 5679130561Sobrien rel = relocs; 5680130561Sobrien relend = relocs + input_section->reloc_count; 568160484Sobrien for (; rel < relend; rel++) 568260484Sobrien { 5683130561Sobrien enum elf_ppc_reloc_type r_type; 5684130561Sobrien bfd_vma addend; 5685130561Sobrien bfd_reloc_status_type r; 5686130561Sobrien Elf_Internal_Sym *sym; 5687130561Sobrien asection *sec; 5688130561Sobrien struct elf_link_hash_entry *h; 5689130561Sobrien const char *sym_name; 569060484Sobrien reloc_howto_type *howto; 569160484Sobrien unsigned long r_symndx; 569260484Sobrien bfd_vma relocation; 5693130561Sobrien bfd_vma branch_bit, insn, from; 5694130561Sobrien bfd_boolean unresolved_reloc; 5695130561Sobrien bfd_boolean warned; 5696130561Sobrien unsigned int tls_type, tls_mask, tls_gd; 569760484Sobrien 5698130561Sobrien r_type = ELF32_R_TYPE (rel->r_info); 5699130561Sobrien sym = NULL; 5700130561Sobrien sec = NULL; 5701130561Sobrien h = NULL; 5702130561Sobrien unresolved_reloc = FALSE; 5703130561Sobrien warned = FALSE; 570460484Sobrien r_symndx = ELF32_R_SYM (rel->r_info); 570560484Sobrien 570660484Sobrien if (r_symndx < symtab_hdr->sh_info) 570760484Sobrien { 570860484Sobrien sym = local_syms + r_symndx; 570960484Sobrien sec = local_sections[r_symndx]; 5710218822Sdim sym_name = bfd_elf_sym_name (input_bfd, symtab_hdr, sym, sec); 571160484Sobrien 5712130561Sobrien relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel); 571360484Sobrien } 571460484Sobrien else 571560484Sobrien { 5716130561Sobrien RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel, 5717130561Sobrien r_symndx, symtab_hdr, sym_hashes, 5718130561Sobrien h, sec, relocation, 5719130561Sobrien unresolved_reloc, warned); 5720130561Sobrien 572160484Sobrien sym_name = h->root.root.string; 5722130561Sobrien } 572377298Sobrien 5724218822Sdim if (sec != NULL && elf_discarded_section (sec)) 5725218822Sdim { 5726218822Sdim /* For relocs against symbols from removed linkonce sections, 5727218822Sdim or sections discarded by a linker script, we just want the 5728218822Sdim section contents zeroed. Avoid any special processing. */ 5729218822Sdim howto = NULL; 5730218822Sdim if (r_type < R_PPC_max) 5731218822Sdim howto = ppc_elf_howto_table[r_type]; 5732218822Sdim _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset); 5733218822Sdim rel->r_info = 0; 5734218822Sdim rel->r_addend = 0; 5735218822Sdim continue; 5736218822Sdim } 5737218822Sdim 5738218822Sdim if (info->relocatable) 5739218822Sdim { 5740218822Sdim if (got2 != NULL 5741218822Sdim && r_type == R_PPC_PLTREL24 5742218822Sdim && rel->r_addend >= 32768) 5743218822Sdim { 5744218822Sdim /* R_PPC_PLTREL24 is rather special. If non-zero, the 5745218822Sdim addend specifies the GOT pointer offset within .got2. */ 5746218822Sdim rel->r_addend += got2->output_offset; 5747218822Sdim } 5748218822Sdim continue; 5749218822Sdim } 5750218822Sdim 5751130561Sobrien /* TLS optimizations. Replace instruction sequences and relocs 5752130561Sobrien based on information we collected in tls_optimize. We edit 5753130561Sobrien RELOCS so that --emit-relocs will output something sensible 5754130561Sobrien for the final instruction stream. */ 5755130561Sobrien tls_mask = 0; 5756130561Sobrien tls_gd = 0; 5757130561Sobrien if (IS_PPC_TLS_RELOC (r_type)) 5758130561Sobrien { 5759130561Sobrien if (h != NULL) 5760130561Sobrien tls_mask = ((struct ppc_elf_link_hash_entry *) h)->tls_mask; 5761130561Sobrien else if (local_got_offsets != NULL) 5762130561Sobrien { 5763130561Sobrien char *lgot_masks; 5764130561Sobrien lgot_masks = (char *) (local_got_offsets + symtab_hdr->sh_info); 5765130561Sobrien tls_mask = lgot_masks[r_symndx]; 5766130561Sobrien } 5767130561Sobrien } 576877298Sobrien 5769130561Sobrien /* Ensure reloc mapping code below stays sane. */ 5770130561Sobrien if ((R_PPC_GOT_TLSLD16 & 3) != (R_PPC_GOT_TLSGD16 & 3) 5771130561Sobrien || (R_PPC_GOT_TLSLD16_LO & 3) != (R_PPC_GOT_TLSGD16_LO & 3) 5772130561Sobrien || (R_PPC_GOT_TLSLD16_HI & 3) != (R_PPC_GOT_TLSGD16_HI & 3) 5773130561Sobrien || (R_PPC_GOT_TLSLD16_HA & 3) != (R_PPC_GOT_TLSGD16_HA & 3) 5774130561Sobrien || (R_PPC_GOT_TLSLD16 & 3) != (R_PPC_GOT_TPREL16 & 3) 5775130561Sobrien || (R_PPC_GOT_TLSLD16_LO & 3) != (R_PPC_GOT_TPREL16_LO & 3) 5776130561Sobrien || (R_PPC_GOT_TLSLD16_HI & 3) != (R_PPC_GOT_TPREL16_HI & 3) 5777130561Sobrien || (R_PPC_GOT_TLSLD16_HA & 3) != (R_PPC_GOT_TPREL16_HA & 3)) 5778130561Sobrien abort (); 5779130561Sobrien switch (r_type) 5780130561Sobrien { 5781130561Sobrien default: 5782130561Sobrien break; 5783130561Sobrien 5784130561Sobrien case R_PPC_GOT_TPREL16: 5785130561Sobrien case R_PPC_GOT_TPREL16_LO: 5786130561Sobrien if (tls_mask != 0 5787130561Sobrien && (tls_mask & TLS_TPREL) == 0) 578860484Sobrien { 5789130561Sobrien bfd_vma insn; 5790218822Sdim insn = bfd_get_32 (output_bfd, contents + rel->r_offset - d_offset); 5791130561Sobrien insn &= 31 << 21; 5792130561Sobrien insn |= 0x3c020000; /* addis 0,2,0 */ 5793218822Sdim bfd_put_32 (output_bfd, insn, contents + rel->r_offset - d_offset); 5794130561Sobrien r_type = R_PPC_TPREL16_HA; 5795130561Sobrien rel->r_info = ELF32_R_INFO (r_symndx, r_type); 5796130561Sobrien } 5797130561Sobrien break; 5798130561Sobrien 5799130561Sobrien case R_PPC_TLS: 5800130561Sobrien if (tls_mask != 0 5801130561Sobrien && (tls_mask & TLS_TPREL) == 0) 5802130561Sobrien { 5803130561Sobrien bfd_vma insn, rtra; 5804130561Sobrien insn = bfd_get_32 (output_bfd, contents + rel->r_offset); 5805130561Sobrien if ((insn & ((31 << 26) | (31 << 11))) 5806130561Sobrien == ((31 << 26) | (2 << 11))) 5807130561Sobrien rtra = insn & ((1 << 26) - (1 << 16)); 5808130561Sobrien else if ((insn & ((31 << 26) | (31 << 16))) 5809130561Sobrien == ((31 << 26) | (2 << 16))) 5810130561Sobrien rtra = (insn & (31 << 21)) | ((insn & (31 << 11)) << 5); 5811130561Sobrien else 5812130561Sobrien abort (); 5813130561Sobrien if ((insn & ((1 << 11) - (1 << 1))) == 266 << 1) 5814130561Sobrien /* add -> addi. */ 5815130561Sobrien insn = 14 << 26; 5816130561Sobrien else if ((insn & (31 << 1)) == 23 << 1 5817130561Sobrien && ((insn & (31 << 6)) < 14 << 6 5818130561Sobrien || ((insn & (31 << 6)) >= 16 << 6 5819130561Sobrien && (insn & (31 << 6)) < 24 << 6))) 5820130561Sobrien /* load and store indexed -> dform. */ 5821130561Sobrien insn = (32 | ((insn >> 6) & 31)) << 26; 5822130561Sobrien else if ((insn & (31 << 1)) == 21 << 1 5823130561Sobrien && (insn & (0x1a << 6)) == 0) 5824130561Sobrien /* ldx, ldux, stdx, stdux -> ld, ldu, std, stdu. */ 5825130561Sobrien insn = (((58 | ((insn >> 6) & 4)) << 26) 5826130561Sobrien | ((insn >> 6) & 1)); 5827130561Sobrien else if ((insn & (31 << 1)) == 21 << 1 5828130561Sobrien && (insn & ((1 << 11) - (1 << 1))) == 341 << 1) 5829130561Sobrien /* lwax -> lwa. */ 5830130561Sobrien insn = (58 << 26) | 2; 5831130561Sobrien else 5832130561Sobrien abort (); 5833130561Sobrien insn |= rtra; 5834130561Sobrien bfd_put_32 (output_bfd, insn, contents + rel->r_offset); 5835130561Sobrien r_type = R_PPC_TPREL16_LO; 5836130561Sobrien rel->r_info = ELF32_R_INFO (r_symndx, r_type); 5837218822Sdim 5838130561Sobrien /* Was PPC_TLS which sits on insn boundary, now 5839218822Sdim PPC_TPREL16_LO which is at low-order half-word. */ 5840218822Sdim rel->r_offset += d_offset; 5841130561Sobrien } 5842130561Sobrien break; 5843130561Sobrien 5844130561Sobrien case R_PPC_GOT_TLSGD16_HI: 5845130561Sobrien case R_PPC_GOT_TLSGD16_HA: 5846130561Sobrien tls_gd = TLS_TPRELGD; 5847130561Sobrien if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) 5848130561Sobrien goto tls_gdld_hi; 5849130561Sobrien break; 5850130561Sobrien 5851130561Sobrien case R_PPC_GOT_TLSLD16_HI: 5852130561Sobrien case R_PPC_GOT_TLSLD16_HA: 5853130561Sobrien if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) 5854130561Sobrien { 5855130561Sobrien tls_gdld_hi: 5856130561Sobrien if ((tls_mask & tls_gd) != 0) 5857130561Sobrien r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3) 5858130561Sobrien + R_PPC_GOT_TPREL16); 5859130561Sobrien else 586060484Sobrien { 5861130561Sobrien bfd_put_32 (output_bfd, NOP, contents + rel->r_offset); 5862218822Sdim rel->r_offset -= d_offset; 5863130561Sobrien r_type = R_PPC_NONE; 586460484Sobrien } 5865130561Sobrien rel->r_info = ELF32_R_INFO (r_symndx, r_type); 5866130561Sobrien } 5867130561Sobrien break; 5868130561Sobrien 5869130561Sobrien case R_PPC_GOT_TLSGD16: 5870130561Sobrien case R_PPC_GOT_TLSGD16_LO: 5871130561Sobrien tls_gd = TLS_TPRELGD; 5872130561Sobrien if (tls_mask != 0 && (tls_mask & TLS_GD) == 0) 5873130561Sobrien goto tls_get_addr_check; 5874130561Sobrien break; 5875130561Sobrien 5876130561Sobrien case R_PPC_GOT_TLSLD16: 5877130561Sobrien case R_PPC_GOT_TLSLD16_LO: 5878130561Sobrien if (tls_mask != 0 && (tls_mask & TLS_LD) == 0) 5879130561Sobrien { 5880130561Sobrien tls_get_addr_check: 5881130561Sobrien if (rel + 1 < relend) 588277298Sobrien { 5883130561Sobrien enum elf_ppc_reloc_type r_type2; 5884130561Sobrien unsigned long r_symndx2; 5885130561Sobrien struct elf_link_hash_entry *h2; 5886130561Sobrien bfd_vma insn1, insn2; 5887130561Sobrien bfd_vma offset; 5888130561Sobrien 5889130561Sobrien /* The next instruction should be a call to 5890130561Sobrien __tls_get_addr. Peek at the reloc to be sure. */ 5891130561Sobrien r_type2 = ELF32_R_TYPE (rel[1].r_info); 5892130561Sobrien r_symndx2 = ELF32_R_SYM (rel[1].r_info); 5893130561Sobrien if (r_symndx2 < symtab_hdr->sh_info 5894130561Sobrien || (r_type2 != R_PPC_REL14 5895130561Sobrien && r_type2 != R_PPC_REL14_BRTAKEN 5896130561Sobrien && r_type2 != R_PPC_REL14_BRNTAKEN 5897130561Sobrien && r_type2 != R_PPC_REL24 5898130561Sobrien && r_type2 != R_PPC_PLTREL24)) 5899130561Sobrien break; 5900130561Sobrien 5901130561Sobrien h2 = sym_hashes[r_symndx2 - symtab_hdr->sh_info]; 5902130561Sobrien while (h2->root.type == bfd_link_hash_indirect 5903130561Sobrien || h2->root.type == bfd_link_hash_warning) 5904130561Sobrien h2 = (struct elf_link_hash_entry *) h2->root.u.i.link; 5905130561Sobrien if (h2 == NULL || h2 != htab->tls_get_addr) 5906130561Sobrien break; 5907130561Sobrien 5908130561Sobrien /* OK, it checks out. Replace the call. */ 5909130561Sobrien offset = rel[1].r_offset; 5910130561Sobrien insn1 = bfd_get_32 (output_bfd, 5911218822Sdim contents + rel->r_offset - d_offset); 5912130561Sobrien if ((tls_mask & tls_gd) != 0) 5913130561Sobrien { 5914130561Sobrien /* IE */ 5915130561Sobrien insn1 &= (1 << 26) - 1; 5916130561Sobrien insn1 |= 32 << 26; /* lwz */ 5917130561Sobrien insn2 = 0x7c631214; /* add 3,3,2 */ 5918130561Sobrien rel[1].r_info = ELF32_R_INFO (r_symndx2, R_PPC_NONE); 5919218822Sdim rel[1].r_addend = 0; 5920130561Sobrien r_type = (((r_type - (R_PPC_GOT_TLSGD16 & 3)) & 3) 5921130561Sobrien + R_PPC_GOT_TPREL16); 5922130561Sobrien rel->r_info = ELF32_R_INFO (r_symndx, r_type); 5923130561Sobrien } 5924130561Sobrien else 5925130561Sobrien { 5926130561Sobrien /* LE */ 5927130561Sobrien insn1 = 0x3c620000; /* addis 3,2,0 */ 5928130561Sobrien insn2 = 0x38630000; /* addi 3,3,0 */ 5929130561Sobrien if (tls_gd == 0) 5930130561Sobrien { 5931130561Sobrien /* Was an LD reloc. */ 5932130561Sobrien r_symndx = 0; 5933130561Sobrien rel->r_addend = htab->elf.tls_sec->vma + DTP_OFFSET; 5934130561Sobrien } 5935130561Sobrien r_type = R_PPC_TPREL16_HA; 5936130561Sobrien rel->r_info = ELF32_R_INFO (r_symndx, r_type); 5937130561Sobrien rel[1].r_info = ELF32_R_INFO (r_symndx, 5938130561Sobrien R_PPC_TPREL16_LO); 5939218822Sdim rel[1].r_offset += d_offset; 5940218822Sdim rel[1].r_addend = rel->r_addend; 5941130561Sobrien } 5942218822Sdim bfd_put_32 (output_bfd, insn1, contents + rel->r_offset - d_offset); 5943130561Sobrien bfd_put_32 (output_bfd, insn2, contents + offset); 5944130561Sobrien if (tls_gd == 0) 5945130561Sobrien { 5946130561Sobrien /* We changed the symbol on an LD reloc. Start over 5947130561Sobrien in order to get h, sym, sec etc. right. */ 5948130561Sobrien rel--; 5949130561Sobrien continue; 5950130561Sobrien } 595177298Sobrien } 595260484Sobrien } 5953130561Sobrien break; 595460484Sobrien } 595560484Sobrien 5956130561Sobrien /* Handle other relocations that tweak non-addend part of insn. */ 5957130561Sobrien branch_bit = 0; 5958130561Sobrien switch (r_type) 595960484Sobrien { 596060484Sobrien default: 5961130561Sobrien break; 596260484Sobrien 5963130561Sobrien /* Branch taken prediction relocations. */ 5964130561Sobrien case R_PPC_ADDR14_BRTAKEN: 5965130561Sobrien case R_PPC_REL14_BRTAKEN: 5966130561Sobrien branch_bit = BRANCH_PREDICT_BIT; 5967130561Sobrien /* Fall thru */ 5968130561Sobrien 5969130561Sobrien /* Branch not taken prediction relocations. */ 5970130561Sobrien case R_PPC_ADDR14_BRNTAKEN: 5971130561Sobrien case R_PPC_REL14_BRNTAKEN: 5972130561Sobrien insn = bfd_get_32 (output_bfd, contents + rel->r_offset); 5973130561Sobrien insn &= ~BRANCH_PREDICT_BIT; 5974130561Sobrien insn |= branch_bit; 5975130561Sobrien 5976130561Sobrien from = (rel->r_offset 5977130561Sobrien + input_section->output_offset 5978130561Sobrien + input_section->output_section->vma); 5979130561Sobrien 5980130561Sobrien /* Invert 'y' bit if not the default. */ 5981130561Sobrien if ((bfd_signed_vma) (relocation + rel->r_addend - from) < 0) 5982130561Sobrien insn ^= BRANCH_PREDICT_BIT; 5983130561Sobrien 5984130561Sobrien bfd_put_32 (output_bfd, insn, contents + rel->r_offset); 5985130561Sobrien break; 5986130561Sobrien } 5987130561Sobrien 5988130561Sobrien addend = rel->r_addend; 5989130561Sobrien tls_type = 0; 5990130561Sobrien howto = NULL; 5991130561Sobrien if (r_type < R_PPC_max) 5992130561Sobrien howto = ppc_elf_howto_table[r_type]; 5993130561Sobrien switch (r_type) 5994130561Sobrien { 5995130561Sobrien default: 5996130561Sobrien (*_bfd_error_handler) 5997218822Sdim (_("%B: unknown relocation type %d for symbol %s"), 5998218822Sdim input_bfd, (int) r_type, sym_name); 5999130561Sobrien 600060484Sobrien bfd_set_error (bfd_error_bad_value); 6001130561Sobrien ret = FALSE; 600260484Sobrien continue; 600360484Sobrien 6004130561Sobrien case R_PPC_NONE: 6005130561Sobrien case R_PPC_TLS: 6006130561Sobrien case R_PPC_EMB_MRKREF: 6007130561Sobrien case R_PPC_GNU_VTINHERIT: 6008130561Sobrien case R_PPC_GNU_VTENTRY: 600989857Sobrien continue; 601089857Sobrien 6011130561Sobrien /* GOT16 relocations. Like an ADDR16 using the symbol's 6012130561Sobrien address in the GOT as relocation value instead of the 6013130561Sobrien symbol's value itself. Also, create a GOT entry for the 6014130561Sobrien symbol and put the symbol value there. */ 6015130561Sobrien case R_PPC_GOT_TLSGD16: 6016130561Sobrien case R_PPC_GOT_TLSGD16_LO: 6017130561Sobrien case R_PPC_GOT_TLSGD16_HI: 6018130561Sobrien case R_PPC_GOT_TLSGD16_HA: 6019130561Sobrien tls_type = TLS_TLS | TLS_GD; 6020130561Sobrien goto dogot; 6021130561Sobrien 6022130561Sobrien case R_PPC_GOT_TLSLD16: 6023130561Sobrien case R_PPC_GOT_TLSLD16_LO: 6024130561Sobrien case R_PPC_GOT_TLSLD16_HI: 6025130561Sobrien case R_PPC_GOT_TLSLD16_HA: 6026130561Sobrien tls_type = TLS_TLS | TLS_LD; 6027130561Sobrien goto dogot; 6028130561Sobrien 6029130561Sobrien case R_PPC_GOT_TPREL16: 6030130561Sobrien case R_PPC_GOT_TPREL16_LO: 6031130561Sobrien case R_PPC_GOT_TPREL16_HI: 6032130561Sobrien case R_PPC_GOT_TPREL16_HA: 6033130561Sobrien tls_type = TLS_TLS | TLS_TPREL; 6034130561Sobrien goto dogot; 6035130561Sobrien 6036130561Sobrien case R_PPC_GOT_DTPREL16: 6037130561Sobrien case R_PPC_GOT_DTPREL16_LO: 6038130561Sobrien case R_PPC_GOT_DTPREL16_HI: 6039130561Sobrien case R_PPC_GOT_DTPREL16_HA: 6040130561Sobrien tls_type = TLS_TLS | TLS_DTPREL; 6041130561Sobrien goto dogot; 6042130561Sobrien 6043130561Sobrien case R_PPC_GOT16: 6044130561Sobrien case R_PPC_GOT16_LO: 6045130561Sobrien case R_PPC_GOT16_HI: 6046130561Sobrien case R_PPC_GOT16_HA: 6047130561Sobrien dogot: 6048130561Sobrien { 6049130561Sobrien /* Relocation is to the entry for this symbol in the global 6050130561Sobrien offset table. */ 6051130561Sobrien bfd_vma off; 6052130561Sobrien bfd_vma *offp; 6053130561Sobrien unsigned long indx; 6054130561Sobrien 6055130561Sobrien if (htab->got == NULL) 6056130561Sobrien abort (); 6057130561Sobrien 6058130561Sobrien indx = 0; 6059130561Sobrien if (tls_type == (TLS_TLS | TLS_LD) 6060130561Sobrien && (h == NULL 6061218822Sdim || !h->def_dynamic)) 6062130561Sobrien offp = &htab->tlsld_got.offset; 6063130561Sobrien else if (h != NULL) 6064130561Sobrien { 6065130561Sobrien bfd_boolean dyn; 6066130561Sobrien dyn = htab->elf.dynamic_sections_created; 6067130561Sobrien if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h) 6068130561Sobrien || (info->shared 6069130561Sobrien && SYMBOL_REFERENCES_LOCAL (info, h))) 6070130561Sobrien /* This is actually a static link, or it is a 6071130561Sobrien -Bsymbolic link and the symbol is defined 6072130561Sobrien locally, or the symbol was forced to be local 6073130561Sobrien because of a version file. */ 6074130561Sobrien ; 6075130561Sobrien else 6076130561Sobrien { 6077130561Sobrien indx = h->dynindx; 6078130561Sobrien unresolved_reloc = FALSE; 6079130561Sobrien } 6080130561Sobrien offp = &h->got.offset; 6081130561Sobrien } 6082130561Sobrien else 6083130561Sobrien { 6084130561Sobrien if (local_got_offsets == NULL) 6085130561Sobrien abort (); 6086130561Sobrien offp = &local_got_offsets[r_symndx]; 6087130561Sobrien } 6088130561Sobrien 6089130561Sobrien /* The offset must always be a multiple of 4. We use the 6090130561Sobrien least significant bit to record whether we have already 6091130561Sobrien processed this entry. */ 6092130561Sobrien off = *offp; 6093130561Sobrien if ((off & 1) != 0) 6094130561Sobrien off &= ~1; 6095130561Sobrien else 6096130561Sobrien { 6097130561Sobrien unsigned int tls_m = (tls_mask 6098130561Sobrien & (TLS_LD | TLS_GD | TLS_DTPREL 6099130561Sobrien | TLS_TPREL | TLS_TPRELGD)); 6100130561Sobrien 6101130561Sobrien if (offp == &htab->tlsld_got.offset) 6102130561Sobrien tls_m = TLS_LD; 6103130561Sobrien else if (h == NULL 6104218822Sdim || !h->def_dynamic) 6105130561Sobrien tls_m &= ~TLS_LD; 6106130561Sobrien 6107130561Sobrien /* We might have multiple got entries for this sym. 6108130561Sobrien Initialize them all. */ 6109130561Sobrien do 6110130561Sobrien { 6111130561Sobrien int tls_ty = 0; 6112130561Sobrien 6113130561Sobrien if ((tls_m & TLS_LD) != 0) 6114130561Sobrien { 6115130561Sobrien tls_ty = TLS_TLS | TLS_LD; 6116130561Sobrien tls_m &= ~TLS_LD; 6117130561Sobrien } 6118130561Sobrien else if ((tls_m & TLS_GD) != 0) 6119130561Sobrien { 6120130561Sobrien tls_ty = TLS_TLS | TLS_GD; 6121130561Sobrien tls_m &= ~TLS_GD; 6122130561Sobrien } 6123130561Sobrien else if ((tls_m & TLS_DTPREL) != 0) 6124130561Sobrien { 6125130561Sobrien tls_ty = TLS_TLS | TLS_DTPREL; 6126130561Sobrien tls_m &= ~TLS_DTPREL; 6127130561Sobrien } 6128130561Sobrien else if ((tls_m & (TLS_TPREL | TLS_TPRELGD)) != 0) 6129130561Sobrien { 6130130561Sobrien tls_ty = TLS_TLS | TLS_TPREL; 6131130561Sobrien tls_m = 0; 6132130561Sobrien } 6133130561Sobrien 6134130561Sobrien /* Generate relocs for the dynamic linker. */ 6135130561Sobrien if ((info->shared || indx != 0) 6136130561Sobrien && (h == NULL 6137130561Sobrien || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT 6138130561Sobrien || h->root.type != bfd_link_hash_undefweak)) 6139130561Sobrien { 6140130561Sobrien outrel.r_offset = (htab->got->output_section->vma 6141130561Sobrien + htab->got->output_offset 6142130561Sobrien + off); 6143130561Sobrien outrel.r_addend = 0; 6144130561Sobrien if (tls_ty & (TLS_LD | TLS_GD)) 6145130561Sobrien { 6146130561Sobrien outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPMOD32); 6147130561Sobrien if (tls_ty == (TLS_TLS | TLS_GD)) 6148130561Sobrien { 6149130561Sobrien loc = htab->relgot->contents; 6150130561Sobrien loc += (htab->relgot->reloc_count++ 6151130561Sobrien * sizeof (Elf32_External_Rela)); 6152130561Sobrien bfd_elf32_swap_reloca_out (output_bfd, 6153130561Sobrien &outrel, loc); 6154130561Sobrien outrel.r_offset += 4; 6155130561Sobrien outrel.r_info 6156130561Sobrien = ELF32_R_INFO (indx, R_PPC_DTPREL32); 6157130561Sobrien } 6158130561Sobrien } 6159130561Sobrien else if (tls_ty == (TLS_TLS | TLS_DTPREL)) 6160130561Sobrien outrel.r_info = ELF32_R_INFO (indx, R_PPC_DTPREL32); 6161130561Sobrien else if (tls_ty == (TLS_TLS | TLS_TPREL)) 6162130561Sobrien outrel.r_info = ELF32_R_INFO (indx, R_PPC_TPREL32); 6163130561Sobrien else if (indx == 0) 6164130561Sobrien outrel.r_info = ELF32_R_INFO (indx, R_PPC_RELATIVE); 6165130561Sobrien else 6166130561Sobrien outrel.r_info = ELF32_R_INFO (indx, R_PPC_GLOB_DAT); 6167130561Sobrien if (indx == 0) 6168130561Sobrien { 6169130561Sobrien outrel.r_addend += relocation; 6170130561Sobrien if (tls_ty & (TLS_GD | TLS_DTPREL | TLS_TPREL)) 6171130561Sobrien outrel.r_addend -= htab->elf.tls_sec->vma; 6172130561Sobrien } 6173130561Sobrien loc = htab->relgot->contents; 6174130561Sobrien loc += (htab->relgot->reloc_count++ 6175130561Sobrien * sizeof (Elf32_External_Rela)); 6176130561Sobrien bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); 6177130561Sobrien } 6178130561Sobrien 6179130561Sobrien /* Init the .got section contents if we're not 6180130561Sobrien emitting a reloc. */ 6181130561Sobrien else 6182130561Sobrien { 6183130561Sobrien bfd_vma value = relocation; 6184130561Sobrien 6185130561Sobrien if (tls_ty == (TLS_TLS | TLS_LD)) 6186130561Sobrien value = 1; 6187130561Sobrien else if (tls_ty != 0) 6188130561Sobrien { 6189130561Sobrien value -= htab->elf.tls_sec->vma + DTP_OFFSET; 6190130561Sobrien if (tls_ty == (TLS_TLS | TLS_TPREL)) 6191130561Sobrien value += DTP_OFFSET - TP_OFFSET; 6192130561Sobrien 6193130561Sobrien if (tls_ty == (TLS_TLS | TLS_GD)) 6194130561Sobrien { 6195130561Sobrien bfd_put_32 (output_bfd, value, 6196130561Sobrien htab->got->contents + off + 4); 6197130561Sobrien value = 1; 6198130561Sobrien } 6199130561Sobrien } 6200130561Sobrien bfd_put_32 (output_bfd, value, 6201130561Sobrien htab->got->contents + off); 6202130561Sobrien } 6203130561Sobrien 6204130561Sobrien off += 4; 6205130561Sobrien if (tls_ty & (TLS_LD | TLS_GD)) 6206130561Sobrien off += 4; 6207130561Sobrien } 6208130561Sobrien while (tls_m != 0); 6209130561Sobrien 6210130561Sobrien off = *offp; 6211130561Sobrien *offp = off | 1; 6212130561Sobrien } 6213130561Sobrien 6214130561Sobrien if (off >= (bfd_vma) -2) 6215130561Sobrien abort (); 6216130561Sobrien 6217130561Sobrien if ((tls_type & TLS_TLS) != 0) 6218130561Sobrien { 6219130561Sobrien if (tls_type != (TLS_TLS | TLS_LD)) 6220130561Sobrien { 6221130561Sobrien if ((tls_mask & TLS_LD) != 0 6222130561Sobrien && !(h == NULL 6223218822Sdim || !h->def_dynamic)) 6224130561Sobrien off += 8; 6225130561Sobrien if (tls_type != (TLS_TLS | TLS_GD)) 6226130561Sobrien { 6227130561Sobrien if ((tls_mask & TLS_GD) != 0) 6228130561Sobrien off += 8; 6229130561Sobrien if (tls_type != (TLS_TLS | TLS_DTPREL)) 6230130561Sobrien { 6231130561Sobrien if ((tls_mask & TLS_DTPREL) != 0) 6232130561Sobrien off += 4; 6233130561Sobrien } 6234130561Sobrien } 6235130561Sobrien } 6236130561Sobrien } 6237130561Sobrien 6238218822Sdim relocation = htab->got->output_offset + off; 6239218822Sdim relocation -= htab->elf.hgot->root.u.def.value; 6240130561Sobrien 6241130561Sobrien /* Addends on got relocations don't make much sense. 6242130561Sobrien x+off@got is actually x@got+off, and since the got is 6243130561Sobrien generated by a hash table traversal, the value in the 6244130561Sobrien got at entry m+n bears little relation to the entry m. */ 6245130561Sobrien if (addend != 0) 6246130561Sobrien (*_bfd_error_handler) 6247218822Sdim (_("%B(%A+0x%lx): non-zero addend on %s reloc against `%s'"), 6248218822Sdim input_bfd, 6249218822Sdim input_section, 6250130561Sobrien (long) rel->r_offset, 6251130561Sobrien howto->name, 6252130561Sobrien sym_name); 6253130561Sobrien } 6254130561Sobrien break; 6255130561Sobrien 625660484Sobrien /* Relocations that need no special processing. */ 6257130561Sobrien case R_PPC_LOCAL24PC: 625860484Sobrien /* It makes no sense to point a local relocation 625960484Sobrien at a symbol not in this object. */ 6260130561Sobrien if (unresolved_reloc) 626160484Sobrien { 626260484Sobrien if (! (*info->callbacks->undefined_symbol) (info, 626360484Sobrien h->root.root.string, 626460484Sobrien input_bfd, 626560484Sobrien input_section, 626660484Sobrien rel->r_offset, 6267130561Sobrien TRUE)) 6268130561Sobrien return FALSE; 626960484Sobrien continue; 627060484Sobrien } 627160484Sobrien break; 627260484Sobrien 6273130561Sobrien case R_PPC_DTPREL16: 6274130561Sobrien case R_PPC_DTPREL16_LO: 6275130561Sobrien case R_PPC_DTPREL16_HI: 6276130561Sobrien case R_PPC_DTPREL16_HA: 6277130561Sobrien addend -= htab->elf.tls_sec->vma + DTP_OFFSET; 6278130561Sobrien break; 6279130561Sobrien 6280130561Sobrien /* Relocations that may need to be propagated if this is a shared 6281130561Sobrien object. */ 6282130561Sobrien case R_PPC_TPREL16: 6283130561Sobrien case R_PPC_TPREL16_LO: 6284130561Sobrien case R_PPC_TPREL16_HI: 6285130561Sobrien case R_PPC_TPREL16_HA: 6286130561Sobrien addend -= htab->elf.tls_sec->vma + TP_OFFSET; 6287130561Sobrien /* The TPREL16 relocs shouldn't really be used in shared 6288130561Sobrien libs as they will result in DT_TEXTREL being set, but 6289130561Sobrien support them anyway. */ 6290130561Sobrien goto dodyn; 6291130561Sobrien 6292130561Sobrien case R_PPC_TPREL32: 6293130561Sobrien addend -= htab->elf.tls_sec->vma + TP_OFFSET; 6294130561Sobrien goto dodyn; 6295130561Sobrien 6296130561Sobrien case R_PPC_DTPREL32: 6297130561Sobrien addend -= htab->elf.tls_sec->vma + DTP_OFFSET; 6298130561Sobrien goto dodyn; 6299130561Sobrien 6300130561Sobrien case R_PPC_DTPMOD32: 6301130561Sobrien relocation = 1; 6302130561Sobrien addend = 0; 6303130561Sobrien goto dodyn; 6304130561Sobrien 6305218822Sdim case R_PPC_REL16: 6306218822Sdim case R_PPC_REL16_LO: 6307218822Sdim case R_PPC_REL16_HI: 6308218822Sdim case R_PPC_REL16_HA: 6309218822Sdim break; 6310218822Sdim 6311130561Sobrien case R_PPC_REL24: 6312130561Sobrien case R_PPC_REL32: 6313130561Sobrien case R_PPC_REL14: 6314130561Sobrien case R_PPC_REL14_BRTAKEN: 6315130561Sobrien case R_PPC_REL14_BRNTAKEN: 631660484Sobrien /* If these relocations are not to a named symbol, they can be 631760484Sobrien handled right here, no need to bother the dynamic linker. */ 6318130561Sobrien if (SYMBOL_REFERENCES_LOCAL (info, h) 6319218822Sdim || h == htab->elf.hgot) 632060484Sobrien break; 6321130561Sobrien /* fall through */ 632260484Sobrien 6323130561Sobrien /* Relocations that always need to be propagated if this is a shared 6324130561Sobrien object. */ 6325130561Sobrien case R_PPC_ADDR32: 6326130561Sobrien case R_PPC_ADDR24: 6327130561Sobrien case R_PPC_ADDR16: 6328130561Sobrien case R_PPC_ADDR16_LO: 6329130561Sobrien case R_PPC_ADDR16_HI: 6330130561Sobrien case R_PPC_ADDR16_HA: 6331130561Sobrien case R_PPC_ADDR14: 6332130561Sobrien case R_PPC_ADDR14_BRTAKEN: 6333130561Sobrien case R_PPC_ADDR14_BRNTAKEN: 6334130561Sobrien case R_PPC_UADDR32: 6335130561Sobrien case R_PPC_UADDR16: 6336130561Sobrien dodyn: 6337218822Sdim if ((input_section->flags & SEC_ALLOC) == 0) 6338130561Sobrien break; 6339130561Sobrien /* Fall thru. */ 6340130561Sobrien 6341130561Sobrien if ((info->shared 6342130561Sobrien && (h == NULL 6343130561Sobrien || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT 6344130561Sobrien || h->root.type != bfd_link_hash_undefweak) 6345130561Sobrien && (MUST_BE_DYN_RELOC (r_type) 6346130561Sobrien || !SYMBOL_CALLS_LOCAL (info, h))) 6347130561Sobrien || (ELIMINATE_COPY_RELOCS 6348130561Sobrien && !info->shared 6349130561Sobrien && h != NULL 6350130561Sobrien && h->dynindx != -1 6351218822Sdim && !h->non_got_ref 6352218822Sdim && h->def_dynamic 6353218822Sdim && !h->def_regular)) 635460484Sobrien { 635591041Sobrien int skip; 635660484Sobrien 635760484Sobrien#ifdef DEBUG 6358130561Sobrien fprintf (stderr, "ppc_elf_relocate_section needs to " 6359130561Sobrien "create relocation for %s\n", 6360130561Sobrien (h && h->root.root.string 6361130561Sobrien ? h->root.root.string : "<unknown>")); 636260484Sobrien#endif 636360484Sobrien 636460484Sobrien /* When generating a shared object, these relocations 6365130561Sobrien are copied into the output file to be resolved at run 6366130561Sobrien time. */ 636760484Sobrien if (sreloc == NULL) 636860484Sobrien { 636960484Sobrien const char *name; 637060484Sobrien 637160484Sobrien name = (bfd_elf_string_from_elf_section 637260484Sobrien (input_bfd, 637360484Sobrien elf_elfheader (input_bfd)->e_shstrndx, 637460484Sobrien elf_section_data (input_section)->rel_hdr.sh_name)); 637560484Sobrien if (name == NULL) 6376130561Sobrien return FALSE; 637760484Sobrien 6378218822Sdim BFD_ASSERT (CONST_STRNEQ (name, ".rela") 637960484Sobrien && strcmp (bfd_get_section_name (input_bfd, 638060484Sobrien input_section), 638160484Sobrien name + 5) == 0); 638260484Sobrien 6383130561Sobrien sreloc = bfd_get_section_by_name (htab->elf.dynobj, name); 638460484Sobrien BFD_ASSERT (sreloc != NULL); 638560484Sobrien } 638660484Sobrien 638791041Sobrien skip = 0; 638860484Sobrien 638989857Sobrien outrel.r_offset = 639089857Sobrien _bfd_elf_section_offset (output_bfd, info, input_section, 639189857Sobrien rel->r_offset); 639291041Sobrien if (outrel.r_offset == (bfd_vma) -1 639391041Sobrien || outrel.r_offset == (bfd_vma) -2) 639491041Sobrien skip = (int) outrel.r_offset; 639560484Sobrien outrel.r_offset += (input_section->output_section->vma 639660484Sobrien + input_section->output_offset); 639760484Sobrien 639860484Sobrien if (skip) 639960484Sobrien memset (&outrel, 0, sizeof outrel); 6400130561Sobrien else if (!SYMBOL_REFERENCES_LOCAL (info, h)) 640160484Sobrien { 6402130561Sobrien unresolved_reloc = FALSE; 640360484Sobrien outrel.r_info = ELF32_R_INFO (h->dynindx, r_type); 640460484Sobrien outrel.r_addend = rel->r_addend; 640560484Sobrien } 640660484Sobrien else 640760484Sobrien { 6408130561Sobrien outrel.r_addend = relocation + rel->r_addend; 6409130561Sobrien 641060484Sobrien if (r_type == R_PPC_ADDR32) 6411130561Sobrien outrel.r_info = ELF32_R_INFO (0, R_PPC_RELATIVE); 641260484Sobrien else 641360484Sobrien { 641460484Sobrien long indx; 641560484Sobrien 6416130561Sobrien if (bfd_is_abs_section (sec)) 641760484Sobrien indx = 0; 641860484Sobrien else if (sec == NULL || sec->owner == NULL) 641960484Sobrien { 642060484Sobrien bfd_set_error (bfd_error_bad_value); 6421130561Sobrien return FALSE; 642260484Sobrien } 642360484Sobrien else 642460484Sobrien { 642560484Sobrien asection *osec; 642660484Sobrien 6427130561Sobrien /* We are turning this relocation into one 6428130561Sobrien against a section symbol. It would be 6429130561Sobrien proper to subtract the symbol's value, 6430130561Sobrien osec->vma, from the emitted reloc addend, 6431130561Sobrien but ld.so expects buggy relocs. */ 643260484Sobrien osec = sec->output_section; 643360484Sobrien indx = elf_section_data (osec)->dynindx; 6434218822Sdim if (indx == 0) 6435218822Sdim { 6436218822Sdim osec = htab->elf.text_index_section; 6437218822Sdim indx = elf_section_data (osec)->dynindx; 6438218822Sdim } 6439218822Sdim BFD_ASSERT (indx != 0); 644060484Sobrien#ifdef DEBUG 6441218822Sdim if (indx == 0) 6442218822Sdim printf ("indx=%ld section=%s flags=%08x name=%s\n", 6443130561Sobrien indx, osec->name, osec->flags, 6444130561Sobrien h->root.root.string); 644560484Sobrien#endif 644660484Sobrien } 644760484Sobrien 644860484Sobrien outrel.r_info = ELF32_R_INFO (indx, r_type); 644960484Sobrien } 645060484Sobrien } 645160484Sobrien 6452130561Sobrien loc = sreloc->contents; 6453130561Sobrien loc += sreloc->reloc_count++ * sizeof (Elf32_External_Rela); 6454130561Sobrien bfd_elf32_swap_reloca_out (output_bfd, &outrel, loc); 645560484Sobrien 6456104834Sobrien if (skip == -1) 645760484Sobrien continue; 6458104834Sobrien 6459104834Sobrien /* This reloc will be computed at runtime. We clear the memory 6460104834Sobrien so that it contains predictable value. */ 6461104834Sobrien if (! skip 6462104834Sobrien && ((input_section->flags & SEC_ALLOC) != 0 6463104834Sobrien || ELF32_R_TYPE (outrel.r_info) != R_PPC_RELATIVE)) 6464104834Sobrien { 6465104834Sobrien relocation = howto->pc_relative ? outrel.r_offset : 0; 6466104834Sobrien addend = 0; 6467104834Sobrien break; 6468104834Sobrien } 646960484Sobrien } 647060484Sobrien break; 647160484Sobrien 6472218822Sdim case R_PPC_RELAX32PC_PLT: 6473218822Sdim case R_PPC_RELAX32_PLT: 6474218822Sdim { 6475218822Sdim struct plt_entry *ent = find_plt_ent (h, got2, addend); 6476218822Sdim 6477218822Sdim if (htab->plt_type == PLT_NEW) 6478218822Sdim relocation = (htab->glink->output_section->vma 6479218822Sdim + htab->glink->output_offset 6480218822Sdim + ent->glink_offset); 6481218822Sdim else 6482218822Sdim relocation = (htab->plt->output_section->vma 6483218822Sdim + htab->plt->output_offset 6484218822Sdim + ent->plt.offset); 6485218822Sdim addend = 0; 6486218822Sdim } 6487218822Sdim if (r_type == R_PPC_RELAX32_PLT) 6488218822Sdim goto relax32; 6489218822Sdim /* Fall thru */ 6490218822Sdim 6491130561Sobrien case R_PPC_RELAX32PC: 6492130561Sobrien relocation -= (input_section->output_section->vma 6493130561Sobrien + input_section->output_offset 6494130561Sobrien + rel->r_offset - 4); 6495130561Sobrien /* Fall thru */ 6496218822Sdim 6497130561Sobrien case R_PPC_RELAX32: 6498218822Sdim relax32: 6499130561Sobrien { 6500130561Sobrien unsigned long t0; 6501130561Sobrien unsigned long t1; 650260484Sobrien 6503130561Sobrien t0 = bfd_get_32 (output_bfd, contents + rel->r_offset); 6504130561Sobrien t1 = bfd_get_32 (output_bfd, contents + rel->r_offset + 4); 650560484Sobrien 6506130561Sobrien /* We're clearing the bits for R_PPC_ADDR16_HA 6507130561Sobrien and R_PPC_ADDR16_LO here. */ 6508130561Sobrien t0 &= ~0xffff; 6509130561Sobrien t1 &= ~0xffff; 651060484Sobrien 6511130561Sobrien /* t0 is HA, t1 is LO */ 6512130561Sobrien relocation += addend; 6513130561Sobrien t0 |= ((relocation + 0x8000) >> 16) & 0xffff; 6514130561Sobrien t1 |= relocation & 0xffff; 651560484Sobrien 6516130561Sobrien bfd_put_32 (output_bfd, t0, contents + rel->r_offset); 6517130561Sobrien bfd_put_32 (output_bfd, t1, contents + rel->r_offset + 4); 6518130561Sobrien } 6519130561Sobrien continue; 652060484Sobrien 6521130561Sobrien /* Indirect .sdata relocation. */ 6522130561Sobrien case R_PPC_EMB_SDAI16: 6523218822Sdim BFD_ASSERT (htab->sdata[0].section != NULL); 6524130561Sobrien relocation 6525218822Sdim = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[0], 6526218822Sdim h, relocation, rel); 652760484Sobrien break; 652860484Sobrien 6529130561Sobrien /* Indirect .sdata2 relocation. */ 6530130561Sobrien case R_PPC_EMB_SDA2I16: 6531218822Sdim BFD_ASSERT (htab->sdata[1].section != NULL); 6532130561Sobrien relocation 6533218822Sdim = elf_finish_pointer_linker_section (input_bfd, &htab->sdata[1], 6534218822Sdim h, relocation, rel); 653560484Sobrien break; 653660484Sobrien 6537130561Sobrien /* Handle the TOC16 reloc. We want to use the offset within the .got 6538130561Sobrien section, not the actual VMA. This is appropriate when generating 6539130561Sobrien an embedded ELF object, for which the .got section acts like the 6540130561Sobrien AIX .toc section. */ 6541130561Sobrien case R_PPC_TOC16: /* phony GOT16 relocations */ 6542130561Sobrien BFD_ASSERT (sec != NULL); 654360484Sobrien BFD_ASSERT (bfd_is_und_section (sec) 654460484Sobrien || strcmp (bfd_get_section_name (abfd, sec), ".got") == 0 6545218822Sdim || strcmp (bfd_get_section_name (abfd, sec), ".cgot") == 0); 654660484Sobrien 6547130561Sobrien addend -= sec->output_section->vma + sec->output_offset + 0x8000; 654860484Sobrien break; 654960484Sobrien 6550130561Sobrien case R_PPC_PLTREL24: 655160484Sobrien /* Relocation is to the entry for this symbol in the 6552130561Sobrien procedure linkage table. */ 6553218822Sdim { 6554218822Sdim struct plt_entry *ent = find_plt_ent (h, got2, addend); 655560484Sobrien 6556218822Sdim addend = 0; 6557218822Sdim if (ent == NULL 6558218822Sdim || htab->plt == NULL) 6559218822Sdim { 6560218822Sdim /* We didn't make a PLT entry for this symbol. This 6561218822Sdim happens when statically linking PIC code, or when 6562218822Sdim using -Bsymbolic. */ 6563218822Sdim break; 6564218822Sdim } 656560484Sobrien 6566218822Sdim unresolved_reloc = FALSE; 6567218822Sdim if (htab->plt_type == PLT_NEW) 6568218822Sdim relocation = (htab->glink->output_section->vma 6569218822Sdim + htab->glink->output_offset 6570218822Sdim + ent->glink_offset); 6571218822Sdim else 6572218822Sdim relocation = (htab->plt->output_section->vma 6573218822Sdim + htab->plt->output_offset 6574218822Sdim + ent->plt.offset); 6575218822Sdim } 657677298Sobrien break; 657760484Sobrien 6578130561Sobrien /* Relocate against _SDA_BASE_. */ 6579130561Sobrien case R_PPC_SDAREL16: 658060484Sobrien { 658160484Sobrien const char *name; 6582218822Sdim struct elf_link_hash_entry *sh; 658360484Sobrien 6584130561Sobrien BFD_ASSERT (sec != NULL); 658560484Sobrien name = bfd_get_section_name (abfd, sec->output_section); 6586218822Sdim if (! ((CONST_STRNEQ (name, ".sdata") 6587130561Sobrien && (name[6] == 0 || name[6] == '.')) 6588218822Sdim || (CONST_STRNEQ (name, ".sbss") 6589130561Sobrien && (name[5] == 0 || name[5] == '.')))) 659060484Sobrien { 6591130561Sobrien (*_bfd_error_handler) 6592218822Sdim (_("%B: the target (%s) of a %s relocation is " 6593130561Sobrien "in the wrong output section (%s)"), 6594218822Sdim input_bfd, 6595130561Sobrien sym_name, 6596130561Sobrien howto->name, 6597130561Sobrien name); 659860484Sobrien } 6599218822Sdim sh = htab->sdata[0].sym; 6600130561Sobrien addend -= (sh->root.u.def.value 6601218822Sdim + sh->root.u.def.section->output_offset 6602218822Sdim + sh->root.u.def.section->output_section->vma); 660360484Sobrien } 660460484Sobrien break; 660560484Sobrien 6606130561Sobrien /* Relocate against _SDA2_BASE_. */ 6607130561Sobrien case R_PPC_EMB_SDA2REL: 660860484Sobrien { 660960484Sobrien const char *name; 6610218822Sdim struct elf_link_hash_entry *sh; 661160484Sobrien 6612130561Sobrien BFD_ASSERT (sec != NULL); 661360484Sobrien name = bfd_get_section_name (abfd, sec->output_section); 6614218822Sdim if (! (CONST_STRNEQ (name, ".sdata2") 6615218822Sdim || CONST_STRNEQ (name, ".sbss2"))) 661660484Sobrien { 6617130561Sobrien (*_bfd_error_handler) 6618218822Sdim (_("%B: the target (%s) of a %s relocation is " 6619130561Sobrien "in the wrong output section (%s)"), 6620218822Sdim input_bfd, 6621130561Sobrien sym_name, 6622130561Sobrien howto->name, 6623130561Sobrien name); 662477298Sobrien 662560484Sobrien bfd_set_error (bfd_error_bad_value); 6626130561Sobrien ret = FALSE; 662760484Sobrien continue; 662860484Sobrien } 6629218822Sdim sh = htab->sdata[1].sym; 6630130561Sobrien addend -= (sh->root.u.def.value 6631218822Sdim + sh->root.u.def.section->output_offset 6632218822Sdim + sh->root.u.def.section->output_section->vma); 663360484Sobrien } 663460484Sobrien break; 663560484Sobrien 6636130561Sobrien /* Relocate against either _SDA_BASE_, _SDA2_BASE_, or 0. */ 6637130561Sobrien case R_PPC_EMB_SDA21: 6638130561Sobrien case R_PPC_EMB_RELSDA: 663960484Sobrien { 664060484Sobrien const char *name; 664160484Sobrien int reg; 6642218822Sdim struct elf_link_hash_entry *sh; 664360484Sobrien 6644130561Sobrien BFD_ASSERT (sec != NULL); 664560484Sobrien name = bfd_get_section_name (abfd, sec->output_section); 6646218822Sdim if (((CONST_STRNEQ (name, ".sdata") 6647130561Sobrien && (name[6] == 0 || name[6] == '.')) 6648218822Sdim || (CONST_STRNEQ (name, ".sbss") 6649130561Sobrien && (name[5] == 0 || name[5] == '.')))) 665060484Sobrien { 665160484Sobrien reg = 13; 6652218822Sdim sh = htab->sdata[0].sym; 6653130561Sobrien addend -= (sh->root.u.def.value 6654218822Sdim + sh->root.u.def.section->output_offset 6655218822Sdim + sh->root.u.def.section->output_section->vma); 665660484Sobrien } 665760484Sobrien 6658218822Sdim else if (CONST_STRNEQ (name, ".sdata2") 6659218822Sdim || CONST_STRNEQ (name, ".sbss2")) 666060484Sobrien { 666160484Sobrien reg = 2; 6662218822Sdim sh = htab->sdata[1].sym; 6663130561Sobrien addend -= (sh->root.u.def.value 6664218822Sdim + sh->root.u.def.section->output_offset 6665218822Sdim + sh->root.u.def.section->output_section->vma); 666660484Sobrien } 666760484Sobrien 666877298Sobrien else if (strcmp (name, ".PPC.EMB.sdata0") == 0 666977298Sobrien || strcmp (name, ".PPC.EMB.sbss0") == 0) 667060484Sobrien { 667160484Sobrien reg = 0; 667260484Sobrien } 667360484Sobrien 667460484Sobrien else 667560484Sobrien { 6676130561Sobrien (*_bfd_error_handler) 6677218822Sdim (_("%B: the target (%s) of a %s relocation is " 6678130561Sobrien "in the wrong output section (%s)"), 6679218822Sdim input_bfd, 6680130561Sobrien sym_name, 6681130561Sobrien howto->name, 6682130561Sobrien name); 668360484Sobrien 668460484Sobrien bfd_set_error (bfd_error_bad_value); 6685130561Sobrien ret = FALSE; 668660484Sobrien continue; 668760484Sobrien } 668860484Sobrien 668960484Sobrien if (r_type == R_PPC_EMB_SDA21) 669060484Sobrien { /* fill in register field */ 6691130561Sobrien insn = bfd_get_32 (output_bfd, contents + rel->r_offset); 669260484Sobrien insn = (insn & ~RA_REGISTER_MASK) | (reg << RA_REGISTER_SHIFT); 6693130561Sobrien bfd_put_32 (output_bfd, insn, contents + rel->r_offset); 669460484Sobrien } 669560484Sobrien } 669660484Sobrien break; 669760484Sobrien 6698130561Sobrien /* Relocate against the beginning of the section. */ 6699130561Sobrien case R_PPC_SECTOFF: 6700130561Sobrien case R_PPC_SECTOFF_LO: 6701130561Sobrien case R_PPC_SECTOFF_HI: 6702130561Sobrien case R_PPC_SECTOFF_HA: 6703130561Sobrien BFD_ASSERT (sec != NULL); 670460484Sobrien addend -= sec->output_section->vma; 670560484Sobrien break; 670660484Sobrien 6707130561Sobrien /* Negative relocations. */ 6708130561Sobrien case R_PPC_EMB_NADDR32: 6709130561Sobrien case R_PPC_EMB_NADDR16: 6710130561Sobrien case R_PPC_EMB_NADDR16_LO: 6711130561Sobrien case R_PPC_EMB_NADDR16_HI: 6712130561Sobrien case R_PPC_EMB_NADDR16_HA: 671377298Sobrien addend -= 2 * relocation; 671460484Sobrien break; 671560484Sobrien 6716130561Sobrien case R_PPC_COPY: 6717130561Sobrien case R_PPC_GLOB_DAT: 6718130561Sobrien case R_PPC_JMP_SLOT: 6719130561Sobrien case R_PPC_RELATIVE: 6720130561Sobrien case R_PPC_PLT32: 6721130561Sobrien case R_PPC_PLTREL32: 6722130561Sobrien case R_PPC_PLT16_LO: 6723130561Sobrien case R_PPC_PLT16_HI: 6724130561Sobrien case R_PPC_PLT16_HA: 6725130561Sobrien case R_PPC_ADDR30: 6726130561Sobrien case R_PPC_EMB_RELSEC16: 6727130561Sobrien case R_PPC_EMB_RELST_LO: 6728130561Sobrien case R_PPC_EMB_RELST_HI: 6729130561Sobrien case R_PPC_EMB_RELST_HA: 6730130561Sobrien case R_PPC_EMB_BIT_FLD: 6731130561Sobrien (*_bfd_error_handler) 6732218822Sdim (_("%B: relocation %s is not yet supported for symbol %s."), 6733218822Sdim input_bfd, 6734130561Sobrien howto->name, 6735130561Sobrien sym_name); 673660484Sobrien 6737130561Sobrien bfd_set_error (bfd_error_invalid_operation); 6738130561Sobrien ret = FALSE; 673960484Sobrien continue; 6740130561Sobrien } 674160484Sobrien 6742130561Sobrien /* Do any further special processing. */ 6743130561Sobrien switch (r_type) 6744130561Sobrien { 6745130561Sobrien default: 6746130561Sobrien break; 674760484Sobrien 6748130561Sobrien case R_PPC_ADDR16_HA: 6749218822Sdim case R_PPC_REL16_HA: 6750130561Sobrien case R_PPC_SECTOFF_HA: 6751130561Sobrien case R_PPC_TPREL16_HA: 6752130561Sobrien case R_PPC_DTPREL16_HA: 6753130561Sobrien case R_PPC_EMB_NADDR16_HA: 6754130561Sobrien case R_PPC_EMB_RELST_HA: 6755130561Sobrien /* It's just possible that this symbol is a weak symbol 6756130561Sobrien that's not actually defined anywhere. In that case, 6757130561Sobrien 'sec' would be NULL, and we should leave the symbol 6758130561Sobrien alone (it will be set to zero elsewhere in the link). */ 6759218822Sdim if (sec == NULL) 6760218822Sdim break; 6761218822Sdim /* Fall thru */ 6762218822Sdim 6763218822Sdim case R_PPC_PLT16_HA: 6764218822Sdim case R_PPC_GOT16_HA: 6765218822Sdim case R_PPC_GOT_TLSGD16_HA: 6766218822Sdim case R_PPC_GOT_TLSLD16_HA: 6767218822Sdim case R_PPC_GOT_TPREL16_HA: 6768218822Sdim case R_PPC_GOT_DTPREL16_HA: 6769218822Sdim /* Add 0x10000 if sign bit in 0:15 is set. 6770218822Sdim Bits 0:15 are not used. */ 6771218822Sdim addend += 0x8000; 6772130561Sobrien break; 677360484Sobrien } 677460484Sobrien 677560484Sobrien#ifdef DEBUG 6776130561Sobrien fprintf (stderr, "\ttype = %s (%d), name = %s, symbol index = %ld, " 6777130561Sobrien "offset = %ld, addend = %ld\n", 677860484Sobrien howto->name, 677977298Sobrien (int) r_type, 678060484Sobrien sym_name, 678160484Sobrien r_symndx, 6782130561Sobrien (long) rel->r_offset, 678377298Sobrien (long) addend); 678460484Sobrien#endif 678560484Sobrien 6786130561Sobrien if (unresolved_reloc 6787130561Sobrien && !((input_section->flags & SEC_DEBUGGING) != 0 6788218822Sdim && h->def_dynamic)) 6789130561Sobrien { 6790130561Sobrien (*_bfd_error_handler) 6791218822Sdim (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"), 6792218822Sdim input_bfd, 6793218822Sdim input_section, 6794130561Sobrien (long) rel->r_offset, 6795130561Sobrien howto->name, 6796130561Sobrien sym_name); 6797130561Sobrien ret = FALSE; 6798130561Sobrien } 6799130561Sobrien 680060484Sobrien r = _bfd_final_link_relocate (howto, 680160484Sobrien input_bfd, 680260484Sobrien input_section, 680360484Sobrien contents, 6804130561Sobrien rel->r_offset, 680560484Sobrien relocation, 680660484Sobrien addend); 680760484Sobrien 6808130561Sobrien if (r != bfd_reloc_ok) 680960484Sobrien { 6810130561Sobrien if (r == bfd_reloc_overflow) 681160484Sobrien { 6812130561Sobrien if (warned) 6813130561Sobrien continue; 6814130561Sobrien if (h != NULL 6815130561Sobrien && h->root.type == bfd_link_hash_undefweak 681660484Sobrien && howto->pc_relative) 681760484Sobrien { 681860484Sobrien /* Assume this is a call protected by other code that 681960484Sobrien detect the symbol is undefined. If this is the case, 682060484Sobrien we can safely ignore the overflow. If not, the 682160484Sobrien program is hosed anyway, and a little warning isn't 682260484Sobrien going to help. */ 682360484Sobrien 682460484Sobrien continue; 682560484Sobrien } 682660484Sobrien 6827130561Sobrien if (! (*info->callbacks->reloc_overflow) (info, 6828218822Sdim (h ? &h->root : NULL), 6829130561Sobrien sym_name, 6830130561Sobrien howto->name, 6831130561Sobrien rel->r_addend, 6832130561Sobrien input_bfd, 6833130561Sobrien input_section, 6834130561Sobrien rel->r_offset)) 6835130561Sobrien return FALSE; 683660484Sobrien } 683760484Sobrien else 683860484Sobrien { 6839130561Sobrien (*_bfd_error_handler) 6840218822Sdim (_("%B(%A+0x%lx): %s reloc against `%s': error %d"), 6841218822Sdim input_bfd, input_section, 6842130561Sobrien (long) rel->r_offset, howto->name, sym_name, (int) r); 6843130561Sobrien ret = FALSE; 684460484Sobrien } 684560484Sobrien } 684660484Sobrien } 684760484Sobrien 684860484Sobrien#ifdef DEBUG 684960484Sobrien fprintf (stderr, "\n"); 685060484Sobrien#endif 685160484Sobrien 685260484Sobrien return ret; 685360484Sobrien} 685460484Sobrien 6855218822Sdim#define PPC_LO(v) ((v) & 0xffff) 6856218822Sdim#define PPC_HI(v) (((v) >> 16) & 0xffff) 6857218822Sdim#define PPC_HA(v) PPC_HI ((v) + 0x8000) 6858130561Sobrien 6859218822Sdim/* Finish up dynamic symbol handling. We set the contents of various 6860218822Sdim dynamic sections here. */ 6861218822Sdim 6862130561Sobrienstatic bfd_boolean 6863218822Sdimppc_elf_finish_dynamic_symbol (bfd *output_bfd, 6864218822Sdim struct bfd_link_info *info, 6865218822Sdim struct elf_link_hash_entry *h, 6866218822Sdim Elf_Internal_Sym *sym) 686789857Sobrien{ 6868218822Sdim struct ppc_elf_link_hash_table *htab; 6869218822Sdim struct plt_entry *ent; 6870218822Sdim bfd_boolean doneone; 687189857Sobrien 6872218822Sdim#ifdef DEBUG 6873218822Sdim fprintf (stderr, "ppc_elf_finish_dynamic_symbol called for %s", 6874218822Sdim h->root.root.string); 6875218822Sdim#endif 687689857Sobrien 6877218822Sdim htab = ppc_elf_hash_table (info); 6878218822Sdim BFD_ASSERT (htab->elf.dynobj != NULL); 687989857Sobrien 6880218822Sdim doneone = FALSE; 6881218822Sdim for (ent = h->plt.plist; ent != NULL; ent = ent->next) 6882218822Sdim if (ent->plt.offset != (bfd_vma) -1) 6883218822Sdim { 6884218822Sdim if (!doneone) 6885218822Sdim { 6886218822Sdim Elf_Internal_Rela rela; 6887218822Sdim bfd_byte *loc; 6888218822Sdim bfd_vma reloc_index; 688989857Sobrien 6890218822Sdim if (htab->plt_type == PLT_NEW) 6891218822Sdim reloc_index = ent->plt.offset / 4; 6892218822Sdim else 6893218822Sdim { 6894218822Sdim reloc_index = ((ent->plt.offset - htab->plt_initial_entry_size) 6895218822Sdim / htab->plt_slot_size); 6896218822Sdim if (reloc_index > PLT_NUM_SINGLE_ENTRIES 6897218822Sdim && htab->plt_type == PLT_OLD) 6898218822Sdim reloc_index -= (reloc_index - PLT_NUM_SINGLE_ENTRIES) / 2; 6899218822Sdim } 690089857Sobrien 6901218822Sdim /* This symbol has an entry in the procedure linkage table. 6902218822Sdim Set it up. */ 6903218822Sdim if (htab->plt_type == PLT_VXWORKS) 6904218822Sdim { 6905218822Sdim bfd_vma got_offset; 6906218822Sdim const bfd_vma *plt_entry; 6907218822Sdim 6908218822Sdim /* The first three entries in .got.plt are reserved. */ 6909218822Sdim got_offset = (reloc_index + 3) * 4; 691089857Sobrien 6911218822Sdim /* Use the right PLT. */ 6912218822Sdim plt_entry = info->shared ? ppc_elf_vxworks_pic_plt_entry 6913218822Sdim : ppc_elf_vxworks_plt_entry; 691489857Sobrien 6915218822Sdim /* Fill in the .plt on VxWorks. */ 6916218822Sdim if (info->shared) 6917218822Sdim { 6918218822Sdim bfd_vma got_offset_hi = (got_offset >> 16) 6919218822Sdim + ((got_offset & 0x8000) >> 15); 692089857Sobrien 6921218822Sdim bfd_put_32 (output_bfd, 6922218822Sdim plt_entry[0] | (got_offset_hi & 0xffff), 6923218822Sdim htab->plt->contents + ent->plt.offset + 0); 6924218822Sdim bfd_put_32 (output_bfd, 6925218822Sdim plt_entry[1] | (got_offset & 0xffff), 6926218822Sdim htab->plt->contents + ent->plt.offset + 4); 6927218822Sdim } 6928218822Sdim else 6929218822Sdim { 6930218822Sdim bfd_vma got_loc 6931218822Sdim = (got_offset 6932218822Sdim + htab->elf.hgot->root.u.def.value 6933218822Sdim + htab->elf.hgot->root.u.def.section->output_offset 6934218822Sdim + htab->elf.hgot->root.u.def.section->output_section->vma); 6935218822Sdim bfd_vma got_loc_hi = (got_loc >> 16) 6936218822Sdim + ((got_loc & 0x8000) >> 15); 693789857Sobrien 6938218822Sdim bfd_put_32 (output_bfd, 6939218822Sdim plt_entry[0] | (got_loc_hi & 0xffff), 6940218822Sdim htab->plt->contents + ent->plt.offset + 0); 6941218822Sdim bfd_put_32 (output_bfd, 6942218822Sdim plt_entry[1] | (got_loc & 0xffff), 6943218822Sdim htab->plt->contents + ent->plt.offset + 4); 6944218822Sdim } 694589857Sobrien 6946218822Sdim bfd_put_32 (output_bfd, plt_entry[2], 6947218822Sdim htab->plt->contents + ent->plt.offset + 8); 6948218822Sdim bfd_put_32 (output_bfd, plt_entry[3], 6949218822Sdim htab->plt->contents + ent->plt.offset + 12); 695089857Sobrien 6951218822Sdim /* This instruction is an immediate load. The value loaded is 6952218822Sdim the byte offset of the R_PPC_JMP_SLOT relocation from the 6953218822Sdim start of the .rela.plt section. The value is stored in the 6954218822Sdim low-order 16 bits of the load instruction. */ 6955218822Sdim /* NOTE: It appears that this is now an index rather than a 6956218822Sdim prescaled offset. */ 6957218822Sdim bfd_put_32 (output_bfd, 6958218822Sdim plt_entry[4] | reloc_index, 6959218822Sdim htab->plt->contents + ent->plt.offset + 16); 6960218822Sdim /* This instruction is a PC-relative branch whose target is 6961218822Sdim the start of the PLT section. The address of this branch 6962218822Sdim instruction is 20 bytes beyond the start of this PLT entry. 6963218822Sdim The address is encoded in bits 6-29, inclusive. The value 6964218822Sdim stored is right-shifted by two bits, permitting a 26-bit 6965218822Sdim offset. */ 6966218822Sdim bfd_put_32 (output_bfd, 6967218822Sdim (plt_entry[5] 6968218822Sdim | (-(ent->plt.offset + 20) & 0x03fffffc)), 6969218822Sdim htab->plt->contents + ent->plt.offset + 20); 6970218822Sdim bfd_put_32 (output_bfd, plt_entry[6], 6971218822Sdim htab->plt->contents + ent->plt.offset + 24); 6972218822Sdim bfd_put_32 (output_bfd, plt_entry[7], 6973218822Sdim htab->plt->contents + ent->plt.offset + 28); 697489857Sobrien 6975218822Sdim /* Fill in the GOT entry corresponding to this PLT slot with 6976218822Sdim the address immediately after the the "bctr" instruction 6977218822Sdim in this PLT entry. */ 6978218822Sdim bfd_put_32 (output_bfd, (htab->plt->output_section->vma 6979218822Sdim + htab->plt->output_offset 6980218822Sdim + ent->plt.offset + 16), 6981218822Sdim htab->sgotplt->contents + got_offset); 6982130561Sobrien 6983218822Sdim if (!info->shared) 6984218822Sdim { 6985218822Sdim /* Fill in a couple of entries in .rela.plt.unloaded. */ 6986218822Sdim loc = htab->srelplt2->contents 6987218822Sdim + ((VXWORKS_PLTRESOLVE_RELOCS + reloc_index 6988218822Sdim * VXWORKS_PLT_NON_JMP_SLOT_RELOCS) 6989218822Sdim * sizeof (Elf32_External_Rela)); 6990130561Sobrien 6991218822Sdim /* Provide the @ha relocation for the first instruction. */ 6992218822Sdim rela.r_offset = (htab->plt->output_section->vma 6993218822Sdim + htab->plt->output_offset 6994218822Sdim + ent->plt.offset + 2); 6995218822Sdim rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, 6996218822Sdim R_PPC_ADDR16_HA); 6997218822Sdim rela.r_addend = got_offset; 6998218822Sdim bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); 6999218822Sdim loc += sizeof (Elf32_External_Rela); 7000130561Sobrien 7001218822Sdim /* Provide the @l relocation for the second instruction. */ 7002218822Sdim rela.r_offset = (htab->plt->output_section->vma 7003218822Sdim + htab->plt->output_offset 7004218822Sdim + ent->plt.offset + 6); 7005218822Sdim rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, 7006218822Sdim R_PPC_ADDR16_LO); 7007218822Sdim rela.r_addend = got_offset; 7008218822Sdim bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); 7009218822Sdim loc += sizeof (Elf32_External_Rela); 7010130561Sobrien 7011218822Sdim /* Provide a relocation for the GOT entry corresponding to this 7012218822Sdim PLT slot. Point it at the middle of the .plt entry. */ 7013218822Sdim rela.r_offset = (htab->sgotplt->output_section->vma 7014218822Sdim + htab->sgotplt->output_offset 7015218822Sdim + got_offset); 7016218822Sdim rela.r_info = ELF32_R_INFO (htab->elf.hplt->indx, 7017218822Sdim R_PPC_ADDR32); 7018218822Sdim rela.r_addend = ent->plt.offset + 16; 7019218822Sdim bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); 7020218822Sdim } 7021130561Sobrien 7022218822Sdim /* VxWorks uses non-standard semantics for R_PPC_JMP_SLOT. 7023218822Sdim In particular, the offset for the relocation is not the 7024218822Sdim address of the PLT entry for this function, as specified 7025218822Sdim by the ABI. Instead, the offset is set to the address of 7026218822Sdim the GOT slot for this function. See EABI 4.4.4.1. */ 7027218822Sdim rela.r_offset = (htab->sgotplt->output_section->vma 7028218822Sdim + htab->sgotplt->output_offset 7029218822Sdim + got_offset); 7030130561Sobrien 7031218822Sdim } 7032218822Sdim else 7033218822Sdim { 7034218822Sdim rela.r_offset = (htab->plt->output_section->vma 7035218822Sdim + htab->plt->output_offset 7036218822Sdim + ent->plt.offset); 7037218822Sdim if (htab->plt_type == PLT_OLD) 7038218822Sdim { 7039218822Sdim /* We don't need to fill in the .plt. The ppc dynamic 7040218822Sdim linker will fill it in. */ 7041218822Sdim } 7042218822Sdim else 7043218822Sdim { 7044218822Sdim bfd_vma val = (htab->glink_pltresolve + ent->plt.offset 7045218822Sdim + htab->glink->output_section->vma 7046218822Sdim + htab->glink->output_offset); 7047218822Sdim bfd_put_32 (output_bfd, val, 7048218822Sdim htab->plt->contents + ent->plt.offset); 7049218822Sdim } 7050218822Sdim } 7051130561Sobrien 7052218822Sdim /* Fill in the entry in the .rela.plt section. */ 7053218822Sdim rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_JMP_SLOT); 7054218822Sdim rela.r_addend = 0; 7055130561Sobrien 7056218822Sdim loc = (htab->relplt->contents 7057218822Sdim + reloc_index * sizeof (Elf32_External_Rela)); 7058218822Sdim bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); 7059130561Sobrien 7060218822Sdim if (!h->def_regular) 7061218822Sdim { 7062218822Sdim /* Mark the symbol as undefined, rather than as defined in 7063218822Sdim the .plt section. Leave the value alone. */ 7064218822Sdim sym->st_shndx = SHN_UNDEF; 7065218822Sdim /* If the symbol is weak, we do need to clear the value. 7066218822Sdim Otherwise, the PLT entry would provide a definition for 7067218822Sdim the symbol even if the symbol wasn't defined anywhere, 7068218822Sdim and so the symbol would never be NULL. */ 7069218822Sdim if (!h->ref_regular_nonweak) 7070218822Sdim sym->st_value = 0; 7071218822Sdim } 7072218822Sdim doneone = TRUE; 7073218822Sdim } 7074130561Sobrien 7075218822Sdim if (htab->plt_type == PLT_NEW) 7076218822Sdim { 7077218822Sdim bfd_vma plt; 7078218822Sdim unsigned char *p; 7079130561Sobrien 7080218822Sdim plt = (ent->plt.offset 7081218822Sdim + htab->plt->output_section->vma 7082218822Sdim + htab->plt->output_offset); 7083218822Sdim p = (unsigned char *) htab->glink->contents + ent->glink_offset; 7084130561Sobrien 7085218822Sdim if (info->shared || info->pie) 7086218822Sdim { 7087218822Sdim bfd_vma got = 0; 7088130561Sobrien 7089218822Sdim if (ent->addend >= 32768) 7090218822Sdim got = (ent->addend 7091218822Sdim + ent->sec->output_section->vma 7092218822Sdim + ent->sec->output_offset); 7093218822Sdim else if (htab->elf.hgot != NULL) 7094218822Sdim got = (htab->elf.hgot->root.u.def.value 7095218822Sdim + htab->elf.hgot->root.u.def.section->output_section->vma 7096218822Sdim + htab->elf.hgot->root.u.def.section->output_offset); 7097130561Sobrien 7098218822Sdim plt -= got; 7099130561Sobrien 7100218822Sdim if (plt + 0x8000 < 0x10000) 7101218822Sdim { 7102218822Sdim bfd_put_32 (output_bfd, LWZ_11_30 + PPC_LO (plt), p); 7103218822Sdim p += 4; 7104218822Sdim bfd_put_32 (output_bfd, MTCTR_11, p); 7105218822Sdim p += 4; 7106218822Sdim bfd_put_32 (output_bfd, BCTR, p); 7107218822Sdim p += 4; 7108218822Sdim bfd_put_32 (output_bfd, NOP, p); 7109218822Sdim p += 4; 7110218822Sdim } 7111218822Sdim else 7112218822Sdim { 7113218822Sdim bfd_put_32 (output_bfd, ADDIS_11_30 + PPC_HA (plt), p); 7114218822Sdim p += 4; 7115218822Sdim bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p); 7116218822Sdim p += 4; 7117218822Sdim bfd_put_32 (output_bfd, MTCTR_11, p); 7118218822Sdim p += 4; 7119218822Sdim bfd_put_32 (output_bfd, BCTR, p); 7120218822Sdim p += 4; 7121218822Sdim } 7122218822Sdim } 7123218822Sdim else 7124218822Sdim { 7125218822Sdim bfd_put_32 (output_bfd, LIS_11 + PPC_HA (plt), p); 7126218822Sdim p += 4; 7127218822Sdim bfd_put_32 (output_bfd, LWZ_11_11 + PPC_LO (plt), p); 7128218822Sdim p += 4; 7129218822Sdim bfd_put_32 (output_bfd, MTCTR_11, p); 7130218822Sdim p += 4; 7131218822Sdim bfd_put_32 (output_bfd, BCTR, p); 7132218822Sdim p += 4; 7133218822Sdim 7134218822Sdim /* We only need one non-PIC glink stub. */ 7135218822Sdim break; 7136218822Sdim } 7137218822Sdim } 7138218822Sdim else 7139218822Sdim break; 7140218822Sdim } 7141218822Sdim 7142218822Sdim if (h->needs_copy) 7143130561Sobrien { 7144218822Sdim asection *s; 7145218822Sdim Elf_Internal_Rela rela; 7146218822Sdim bfd_byte *loc; 7147130561Sobrien 7148218822Sdim /* This symbols needs a copy reloc. Set it up. */ 7149130561Sobrien 7150218822Sdim#ifdef DEBUG 7151218822Sdim fprintf (stderr, ", copy"); 7152218822Sdim#endif 7153130561Sobrien 7154218822Sdim BFD_ASSERT (h->dynindx != -1); 7155130561Sobrien 7156218822Sdim if (ppc_elf_hash_entry (h)->has_sda_refs) 7157218822Sdim s = htab->relsbss; 7158218822Sdim else 7159218822Sdim s = htab->relbss; 7160218822Sdim BFD_ASSERT (s != NULL); 7161130561Sobrien 7162218822Sdim rela.r_offset = (h->root.u.def.value 7163218822Sdim + h->root.u.def.section->output_section->vma 7164218822Sdim + h->root.u.def.section->output_offset); 7165218822Sdim rela.r_info = ELF32_R_INFO (h->dynindx, R_PPC_COPY); 7166218822Sdim rela.r_addend = 0; 7167218822Sdim loc = s->contents + s->reloc_count++ * sizeof (Elf32_External_Rela); 7168218822Sdim bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); 7169218822Sdim } 7170130561Sobrien 7171218822Sdim#ifdef DEBUG 7172218822Sdim fprintf (stderr, "\n"); 7173218822Sdim#endif 7174130561Sobrien 7175218822Sdim /* Mark some specially defined symbols as absolute. */ 7176218822Sdim if (strcmp (h->root.root.string, "_DYNAMIC") == 0 7177218822Sdim || (!htab->is_vxworks 7178218822Sdim && (h == htab->elf.hgot 7179218822Sdim || strcmp (h->root.root.string, 7180218822Sdim "_PROCEDURE_LINKAGE_TABLE_") == 0))) 7181218822Sdim sym->st_shndx = SHN_ABS; 7182218822Sdim 7183218822Sdim return TRUE; 7184218822Sdim} 7185218822Sdim 7186218822Sdimstatic enum elf_reloc_type_class 7187218822Sdimppc_elf_reloc_type_class (const Elf_Internal_Rela *rela) 7188218822Sdim{ 7189218822Sdim switch (ELF32_R_TYPE (rela->r_info)) 7190130561Sobrien { 7191218822Sdim case R_PPC_RELATIVE: 7192218822Sdim return reloc_class_relative; 7193218822Sdim case R_PPC_REL24: 7194218822Sdim case R_PPC_ADDR24: 7195218822Sdim case R_PPC_JMP_SLOT: 7196218822Sdim return reloc_class_plt; 7197218822Sdim case R_PPC_COPY: 7198218822Sdim return reloc_class_copy; 7199218822Sdim default: 7200218822Sdim return reloc_class_normal; 7201130561Sobrien } 7202218822Sdim} 7203218822Sdim 7204218822Sdim/* Finish up the dynamic sections. */ 7205130561Sobrien 7206218822Sdimstatic bfd_boolean 7207218822Sdimppc_elf_finish_dynamic_sections (bfd *output_bfd, 7208218822Sdim struct bfd_link_info *info) 7209218822Sdim{ 7210218822Sdim asection *sdyn; 7211218822Sdim asection *splt; 7212218822Sdim struct ppc_elf_link_hash_table *htab; 7213218822Sdim bfd_vma got; 7214218822Sdim bfd * dynobj; 7215130561Sobrien 7216218822Sdim#ifdef DEBUG 7217218822Sdim fprintf (stderr, "ppc_elf_finish_dynamic_sections called\n"); 7218218822Sdim#endif 7219130561Sobrien 7220218822Sdim htab = ppc_elf_hash_table (info); 7221218822Sdim dynobj = elf_hash_table (info)->dynobj; 7222218822Sdim sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); 7223218822Sdim if (htab->is_vxworks) 7224218822Sdim splt = bfd_get_section_by_name (dynobj, ".plt"); 7225218822Sdim else 7226218822Sdim splt = NULL; 7227130561Sobrien 7228218822Sdim got = 0; 7229218822Sdim if (htab->elf.hgot != NULL) 7230218822Sdim got = (htab->elf.hgot->root.u.def.value 7231218822Sdim + htab->elf.hgot->root.u.def.section->output_section->vma 7232218822Sdim + htab->elf.hgot->root.u.def.section->output_offset); 7233130561Sobrien 7234218822Sdim if (htab->elf.dynamic_sections_created) 7235130561Sobrien { 7236218822Sdim Elf32_External_Dyn *dyncon, *dynconend; 7237130561Sobrien 7238218822Sdim BFD_ASSERT (htab->plt != NULL && sdyn != NULL); 7239130561Sobrien 7240218822Sdim dyncon = (Elf32_External_Dyn *) sdyn->contents; 7241218822Sdim dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size); 7242218822Sdim for (; dyncon < dynconend; dyncon++) 7243130561Sobrien { 7244218822Sdim Elf_Internal_Dyn dyn; 7245218822Sdim asection *s; 7246130561Sobrien 7247218822Sdim bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn); 7248130561Sobrien 7249218822Sdim switch (dyn.d_tag) 7250218822Sdim { 7251218822Sdim case DT_PLTGOT: 7252218822Sdim if (htab->is_vxworks) 7253218822Sdim s = htab->sgotplt; 7254218822Sdim else 7255218822Sdim s = htab->plt; 7256218822Sdim dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; 7257218822Sdim break; 7258130561Sobrien 7259218822Sdim case DT_PLTRELSZ: 7260218822Sdim dyn.d_un.d_val = htab->relplt->size; 7261218822Sdim break; 7262130561Sobrien 7263218822Sdim case DT_JMPREL: 7264218822Sdim s = htab->relplt; 7265218822Sdim dyn.d_un.d_ptr = s->output_section->vma + s->output_offset; 7266218822Sdim break; 7267130561Sobrien 7268218822Sdim case DT_PPC_GOT: 7269218822Sdim dyn.d_un.d_ptr = got; 7270218822Sdim break; 7271130561Sobrien 7272218822Sdim case DT_RELASZ: 7273218822Sdim if (htab->is_vxworks) 7274218822Sdim { 7275218822Sdim if (htab->relplt) 7276218822Sdim dyn.d_un.d_ptr -= htab->relplt->size; 7277218822Sdim break; 7278218822Sdim } 7279218822Sdim continue; 7280130561Sobrien 7281218822Sdim default: 7282218822Sdim continue; 7283218822Sdim } 7284130561Sobrien 7285218822Sdim bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon); 7286218822Sdim } 7287218822Sdim } 7288130561Sobrien 7289218822Sdim /* Add a blrl instruction at _GLOBAL_OFFSET_TABLE_-4 so that a function can 7290218822Sdim easily find the address of the _GLOBAL_OFFSET_TABLE_. */ 7291218822Sdim if (htab->got != NULL) 7292218822Sdim { 7293218822Sdim unsigned char *p = htab->got->contents; 7294218822Sdim bfd_vma val; 7295218822Sdim 7296218822Sdim p += htab->elf.hgot->root.u.def.value; 7297218822Sdim if (htab->plt_type == PLT_OLD) 7298218822Sdim bfd_put_32 (output_bfd, 0x4e800021 /* blrl */, p - 4); 7299218822Sdim 7300218822Sdim val = 0; 7301218822Sdim if (sdyn != NULL) 7302218822Sdim val = sdyn->output_section->vma + sdyn->output_offset; 7303218822Sdim bfd_put_32 (output_bfd, val, p); 7304218822Sdim 7305218822Sdim elf_section_data (htab->got->output_section)->this_hdr.sh_entsize = 4; 7306130561Sobrien } 7307130561Sobrien 7308218822Sdim /* Fill in the first entry in the VxWorks procedure linkage table. */ 7309218822Sdim if (splt && splt->size > 0) 7310218822Sdim { 7311218822Sdim /* Use the right PLT. */ 7312218822Sdim static const bfd_vma *plt_entry = NULL; 7313218822Sdim plt_entry = info->shared ? 7314218822Sdim ppc_elf_vxworks_pic_plt0_entry : ppc_elf_vxworks_plt0_entry; 7315130561Sobrien 7316218822Sdim if (!info->shared) 7317218822Sdim { 7318218822Sdim bfd_vma got_value = 7319218822Sdim (htab->elf.hgot->root.u.def.section->output_section->vma 7320218822Sdim + htab->elf.hgot->root.u.def.section->output_offset 7321218822Sdim + htab->elf.hgot->root.u.def.value); 7322218822Sdim bfd_vma got_hi = (got_value >> 16) + ((got_value & 0x8000) >> 15); 7323130561Sobrien 7324218822Sdim bfd_put_32 (output_bfd, plt_entry[0] | (got_hi & 0xffff), 7325218822Sdim splt->contents + 0); 7326218822Sdim bfd_put_32 (output_bfd, plt_entry[1] | (got_value & 0xffff), 7327218822Sdim splt->contents + 4); 7328218822Sdim } 7329218822Sdim else 7330218822Sdim { 7331218822Sdim bfd_put_32 (output_bfd, plt_entry[0], splt->contents + 0); 7332218822Sdim bfd_put_32 (output_bfd, plt_entry[1], splt->contents + 4); 7333218822Sdim } 7334218822Sdim bfd_put_32 (output_bfd, plt_entry[2], splt->contents + 8); 7335218822Sdim bfd_put_32 (output_bfd, plt_entry[3], splt->contents + 12); 7336218822Sdim bfd_put_32 (output_bfd, plt_entry[4], splt->contents + 16); 7337218822Sdim bfd_put_32 (output_bfd, plt_entry[5], splt->contents + 20); 7338218822Sdim bfd_put_32 (output_bfd, plt_entry[6], splt->contents + 24); 7339218822Sdim bfd_put_32 (output_bfd, plt_entry[7], splt->contents + 28); 7340130561Sobrien 7341218822Sdim if (! info->shared) 7342218822Sdim { 7343218822Sdim Elf_Internal_Rela rela; 7344218822Sdim bfd_byte *loc; 7345130561Sobrien 7346218822Sdim loc = htab->srelplt2->contents; 7347130561Sobrien 7348218822Sdim /* Output the @ha relocation for the first instruction. */ 7349218822Sdim rela.r_offset = (htab->plt->output_section->vma 7350218822Sdim + htab->plt->output_offset 7351218822Sdim + 2); 7352218822Sdim rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA); 7353218822Sdim rela.r_addend = 0; 7354218822Sdim bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); 7355218822Sdim loc += sizeof (Elf32_External_Rela); 7356218822Sdim 7357218822Sdim /* Output the @l relocation for the second instruction. */ 7358218822Sdim rela.r_offset = (htab->plt->output_section->vma 7359218822Sdim + htab->plt->output_offset 7360218822Sdim + 6); 7361218822Sdim rela.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO); 7362218822Sdim rela.r_addend = 0; 7363218822Sdim bfd_elf32_swap_reloca_out (output_bfd, &rela, loc); 7364218822Sdim loc += sizeof (Elf32_External_Rela); 7365130561Sobrien 7366218822Sdim /* Fix up the remaining relocations. They may have the wrong 7367218822Sdim symbol index for _G_O_T_ or _P_L_T_ depending on the order 7368218822Sdim in which symbols were output. */ 7369218822Sdim while (loc < htab->srelplt2->contents + htab->srelplt2->size) 7370218822Sdim { 7371218822Sdim Elf_Internal_Rela rel; 7372130561Sobrien 7373218822Sdim bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); 7374218822Sdim rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_HA); 7375218822Sdim bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); 7376218822Sdim loc += sizeof (Elf32_External_Rela); 7377130561Sobrien 7378218822Sdim bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); 7379218822Sdim rel.r_info = ELF32_R_INFO (htab->elf.hgot->indx, R_PPC_ADDR16_LO); 7380218822Sdim bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); 7381218822Sdim loc += sizeof (Elf32_External_Rela); 7382130561Sobrien 7383218822Sdim bfd_elf32_swap_reloc_in (output_bfd, loc, &rel); 7384218822Sdim rel.r_info = ELF32_R_INFO (htab->elf.hplt->indx, R_PPC_ADDR32); 7385218822Sdim bfd_elf32_swap_reloc_out (output_bfd, &rel, loc); 7386218822Sdim loc += sizeof (Elf32_External_Rela); 7387218822Sdim } 7388218822Sdim } 7389218822Sdim } 7390130561Sobrien 7391218822Sdim if (htab->glink != NULL && htab->glink->contents != NULL) 7392218822Sdim { 7393218822Sdim unsigned char *p; 7394218822Sdim unsigned char *endp; 7395218822Sdim bfd_vma res0; 7396218822Sdim unsigned int i; 7397130561Sobrien 7398218822Sdim /* 7399218822Sdim * PIC glink code is the following: 7400218822Sdim * 7401218822Sdim * # ith PLT code stub. 7402218822Sdim * addis 11,30,(plt+(i-1)*4-got)@ha 7403218822Sdim * lwz 11,(plt+(i-1)*4-got)@l(11) 7404218822Sdim * mtctr 11 7405218822Sdim * bctr 7406218822Sdim * 7407218822Sdim * # A table of branches, one for each plt entry. 7408218822Sdim * # The idea is that the plt call stub loads ctr (and r11) with these 7409218822Sdim * # addresses, so (r11 - res_0) gives the plt index * 4. 7410218822Sdim * res_0: b PLTresolve 7411218822Sdim * res_1: b PLTresolve 7412218822Sdim * . 7413218822Sdim * # Some number of entries towards the end can be nops 7414218822Sdim * res_n_m3: nop 7415218822Sdim * res_n_m2: nop 7416218822Sdim * res_n_m1: 7417218822Sdim * 7418218822Sdim * PLTresolve: 7419218822Sdim * addis 11,11,(1f-res_0)@ha 7420218822Sdim * mflr 0 7421218822Sdim * bcl 20,31,1f 7422218822Sdim * 1: addi 11,11,(1b-res_0)@l 7423218822Sdim * mflr 12 7424218822Sdim * mtlr 0 7425218822Sdim * sub 11,11,12 # r11 = index * 4 7426218822Sdim * addis 12,12,(got+4-1b)@ha 7427218822Sdim * lwz 0,(got+4-1b)@l(12) # got[1] address of dl_runtime_resolve 7428218822Sdim * lwz 12,(got+8-1b)@l(12) # got[2] contains the map address 7429218822Sdim * mtctr 0 7430218822Sdim * add 0,11,11 7431218822Sdim * add 11,0,11 # r11 = index * 12 = reloc offset. 7432218822Sdim * bctr 7433218822Sdim */ 7434218822Sdim static const unsigned int pic_plt_resolve[] = 7435218822Sdim { 7436218822Sdim ADDIS_11_11, 7437218822Sdim MFLR_0, 7438218822Sdim BCL_20_31, 7439218822Sdim ADDI_11_11, 7440218822Sdim MFLR_12, 7441218822Sdim MTLR_0, 7442218822Sdim SUB_11_11_12, 7443218822Sdim ADDIS_12_12, 7444218822Sdim LWZ_0_12, 7445218822Sdim LWZ_12_12, 7446218822Sdim MTCTR_0, 7447218822Sdim ADD_0_11_11, 7448218822Sdim ADD_11_0_11, 7449218822Sdim BCTR, 7450218822Sdim NOP, 7451218822Sdim NOP 7452218822Sdim }; 7453130561Sobrien 7454218822Sdim static const unsigned int plt_resolve[] = 7455218822Sdim { 7456218822Sdim LIS_12, 7457218822Sdim ADDIS_11_11, 7458218822Sdim LWZ_0_12, 7459218822Sdim ADDI_11_11, 7460218822Sdim MTCTR_0, 7461218822Sdim ADD_0_11_11, 7462218822Sdim LWZ_12_12, 7463218822Sdim ADD_11_0_11, 7464218822Sdim BCTR, 7465218822Sdim NOP, 7466218822Sdim NOP, 7467218822Sdim NOP, 7468218822Sdim NOP, 7469218822Sdim NOP, 7470218822Sdim NOP, 7471218822Sdim NOP 7472218822Sdim }; 7473130561Sobrien 7474218822Sdim if (ARRAY_SIZE (pic_plt_resolve) != GLINK_PLTRESOLVE / 4) 7475218822Sdim abort (); 7476218822Sdim if (ARRAY_SIZE (plt_resolve) != GLINK_PLTRESOLVE / 4) 7477218822Sdim abort (); 7478130561Sobrien 7479218822Sdim /* Build the branch table, one for each plt entry (less one), 7480218822Sdim and perhaps some padding. */ 7481218822Sdim p = htab->glink->contents; 7482218822Sdim p += htab->glink_pltresolve; 7483218822Sdim endp = htab->glink->contents; 7484218822Sdim endp += htab->glink->size - GLINK_PLTRESOLVE; 7485218822Sdim while (p < endp - 8 * 4) 7486218822Sdim { 7487218822Sdim bfd_put_32 (output_bfd, B + endp - p, p); 7488218822Sdim p += 4; 7489218822Sdim } 7490218822Sdim while (p < endp) 7491218822Sdim { 7492218822Sdim bfd_put_32 (output_bfd, NOP, p); 7493218822Sdim p += 4; 7494218822Sdim } 7495130561Sobrien 7496218822Sdim res0 = (htab->glink_pltresolve 7497218822Sdim + htab->glink->output_section->vma 7498218822Sdim + htab->glink->output_offset); 7499130561Sobrien 7500218822Sdim /* Last comes the PLTresolve stub. */ 7501218822Sdim if (info->shared || info->pie) 7502218822Sdim { 7503218822Sdim bfd_vma bcl; 7504130561Sobrien 7505218822Sdim for (i = 0; i < ARRAY_SIZE (pic_plt_resolve); i++) 7506218822Sdim { 7507218822Sdim bfd_put_32 (output_bfd, pic_plt_resolve[i], p); 7508218822Sdim p += 4; 7509218822Sdim } 7510218822Sdim p -= 4 * ARRAY_SIZE (pic_plt_resolve); 7511130561Sobrien 7512218822Sdim bcl = (htab->glink->size - GLINK_PLTRESOLVE + 3*4 7513218822Sdim + htab->glink->output_section->vma 7514218822Sdim + htab->glink->output_offset); 7515130561Sobrien 7516218822Sdim bfd_put_32 (output_bfd, 7517218822Sdim ADDIS_11_11 + PPC_HA (bcl - res0), p + 0*4); 7518218822Sdim bfd_put_32 (output_bfd, 7519218822Sdim ADDI_11_11 + PPC_LO (bcl - res0), p + 3*4); 7520218822Sdim bfd_put_32 (output_bfd, 7521218822Sdim ADDIS_12_12 + PPC_HA (got + 4 - bcl), p + 7*4); 7522218822Sdim if (PPC_HA (got + 4 - bcl) == PPC_HA (got + 8 - bcl)) 7523218822Sdim { 7524218822Sdim bfd_put_32 (output_bfd, 7525218822Sdim LWZ_0_12 + PPC_LO (got + 4 - bcl), p + 8*4); 7526218822Sdim bfd_put_32 (output_bfd, 7527218822Sdim LWZ_12_12 + PPC_LO (got + 8 - bcl), p + 9*4); 7528218822Sdim } 7529218822Sdim else 7530218822Sdim { 7531218822Sdim bfd_put_32 (output_bfd, 7532218822Sdim LWZU_0_12 + PPC_LO (got + 4 - bcl), p + 8*4); 7533218822Sdim bfd_put_32 (output_bfd, 7534218822Sdim LWZ_12_12 + 4, p + 9*4); 7535218822Sdim } 7536218822Sdim } 7537218822Sdim else 7538218822Sdim { 7539218822Sdim for (i = 0; i < ARRAY_SIZE (plt_resolve); i++) 7540218822Sdim { 7541218822Sdim bfd_put_32 (output_bfd, plt_resolve[i], p); 7542218822Sdim p += 4; 7543218822Sdim } 7544218822Sdim p -= 4 * ARRAY_SIZE (plt_resolve); 7545130561Sobrien 7546218822Sdim bfd_put_32 (output_bfd, 7547218822Sdim LIS_12 + PPC_HA (got + 4), p + 0*4); 7548218822Sdim bfd_put_32 (output_bfd, 7549218822Sdim ADDIS_11_11 + PPC_HA (-res0), p + 1*4); 7550218822Sdim bfd_put_32 (output_bfd, 7551218822Sdim ADDI_11_11 + PPC_LO (-res0), p + 3*4); 7552218822Sdim if (PPC_HA (got + 4) == PPC_HA (got + 8)) 7553218822Sdim { 7554218822Sdim bfd_put_32 (output_bfd, 7555218822Sdim LWZ_0_12 + PPC_LO (got + 4), p + 2*4); 7556218822Sdim bfd_put_32 (output_bfd, 7557218822Sdim LWZ_12_12 + PPC_LO (got + 8), p + 6*4); 7558218822Sdim } 7559218822Sdim else 7560218822Sdim { 7561218822Sdim bfd_put_32 (output_bfd, 7562218822Sdim LWZU_0_12 + PPC_LO (got + 4), p + 2*4); 7563218822Sdim bfd_put_32 (output_bfd, 7564218822Sdim LWZ_12_12 + 4, p + 6*4); 7565218822Sdim } 7566218822Sdim } 7567218822Sdim } 7568130561Sobrien 7569218822Sdim return TRUE; 7570130561Sobrien} 7571130561Sobrien 757260484Sobrien#define TARGET_LITTLE_SYM bfd_elf32_powerpcle_vec 757360484Sobrien#define TARGET_LITTLE_NAME "elf32-powerpcle" 757460484Sobrien#define TARGET_BIG_SYM bfd_elf32_powerpc_vec 757560484Sobrien#define TARGET_BIG_NAME "elf32-powerpc" 757660484Sobrien#define ELF_ARCH bfd_arch_powerpc 757760484Sobrien#define ELF_MACHINE_CODE EM_PPC 7578130561Sobrien#ifdef __QNXTARGET__ 7579130561Sobrien#define ELF_MAXPAGESIZE 0x1000 7580130561Sobrien#else 758160484Sobrien#define ELF_MAXPAGESIZE 0x10000 7582130561Sobrien#endif 7583218822Sdim#define ELF_MINPAGESIZE 0x1000 7584218822Sdim#define ELF_COMMONPAGESIZE 0x1000 758560484Sobrien#define elf_info_to_howto ppc_elf_info_to_howto 758660484Sobrien 758760484Sobrien#ifdef EM_CYGNUS_POWERPC 758860484Sobrien#define ELF_MACHINE_ALT1 EM_CYGNUS_POWERPC 758960484Sobrien#endif 759060484Sobrien 759160484Sobrien#ifdef EM_PPC_OLD 759260484Sobrien#define ELF_MACHINE_ALT2 EM_PPC_OLD 759360484Sobrien#endif 759460484Sobrien 759560484Sobrien#define elf_backend_plt_not_loaded 1 759660484Sobrien#define elf_backend_can_gc_sections 1 759789857Sobrien#define elf_backend_can_refcount 1 759899461Sobrien#define elf_backend_rela_normal 1 759960484Sobrien 7600130561Sobrien#define bfd_elf32_mkobject ppc_elf_mkobject 760160484Sobrien#define bfd_elf32_bfd_merge_private_bfd_data ppc_elf_merge_private_bfd_data 7602130561Sobrien#define bfd_elf32_bfd_relax_section ppc_elf_relax_section 760360484Sobrien#define bfd_elf32_bfd_reloc_type_lookup ppc_elf_reloc_type_lookup 7604218822Sdim#define bfd_elf32_bfd_reloc_name_lookup ppc_elf_reloc_name_lookup 760560484Sobrien#define bfd_elf32_bfd_set_private_flags ppc_elf_set_private_flags 7606130561Sobrien#define bfd_elf32_bfd_link_hash_table_create ppc_elf_link_hash_table_create 760760484Sobrien 7608104834Sobrien#define elf_backend_object_p ppc_elf_object_p 760960484Sobrien#define elf_backend_gc_mark_hook ppc_elf_gc_mark_hook 761060484Sobrien#define elf_backend_gc_sweep_hook ppc_elf_gc_sweep_hook 761160484Sobrien#define elf_backend_section_from_shdr ppc_elf_section_from_shdr 761260484Sobrien#define elf_backend_relocate_section ppc_elf_relocate_section 761360484Sobrien#define elf_backend_create_dynamic_sections ppc_elf_create_dynamic_sections 761460484Sobrien#define elf_backend_check_relocs ppc_elf_check_relocs 7615130561Sobrien#define elf_backend_copy_indirect_symbol ppc_elf_copy_indirect_symbol 761660484Sobrien#define elf_backend_adjust_dynamic_symbol ppc_elf_adjust_dynamic_symbol 761760484Sobrien#define elf_backend_add_symbol_hook ppc_elf_add_symbol_hook 761860484Sobrien#define elf_backend_size_dynamic_sections ppc_elf_size_dynamic_sections 761960484Sobrien#define elf_backend_finish_dynamic_symbol ppc_elf_finish_dynamic_symbol 762060484Sobrien#define elf_backend_finish_dynamic_sections ppc_elf_finish_dynamic_sections 762160484Sobrien#define elf_backend_fake_sections ppc_elf_fake_sections 762260484Sobrien#define elf_backend_additional_program_headers ppc_elf_additional_program_headers 762389857Sobrien#define elf_backend_grok_prstatus ppc_elf_grok_prstatus 762489857Sobrien#define elf_backend_grok_psinfo ppc_elf_grok_psinfo 7625218822Sdim#define elf_backend_write_core_note ppc_elf_write_core_note 762689857Sobrien#define elf_backend_reloc_type_class ppc_elf_reloc_type_class 7627130561Sobrien#define elf_backend_begin_write_processing ppc_elf_begin_write_processing 7628130561Sobrien#define elf_backend_final_write_processing ppc_elf_final_write_processing 7629130561Sobrien#define elf_backend_write_section ppc_elf_write_section 7630218822Sdim#define elf_backend_get_sec_type_attr ppc_elf_get_sec_type_attr 7631218822Sdim#define elf_backend_plt_sym_val ppc_elf_plt_sym_val 7632218822Sdim#define elf_backend_action_discarded ppc_elf_action_discarded 7633218822Sdim#define elf_backend_init_index_section _bfd_elf_init_1_index_section 763460484Sobrien 763560484Sobrien#include "elf32-target.h" 7636218822Sdim 7637218822Sdim/* VxWorks Target */ 7638218822Sdim 7639218822Sdim#undef TARGET_LITTLE_SYM 7640218822Sdim#undef TARGET_LITTLE_NAME 7641218822Sdim 7642218822Sdim#undef TARGET_BIG_SYM 7643218822Sdim#define TARGET_BIG_SYM bfd_elf32_powerpc_vxworks_vec 7644218822Sdim#undef TARGET_BIG_NAME 7645218822Sdim#define TARGET_BIG_NAME "elf32-powerpc-vxworks" 7646218822Sdim 7647218822Sdim/* VxWorks uses the elf default section flags for .plt. */ 7648218822Sdimstatic const struct bfd_elf_special_section * 7649218822Sdimppc_elf_vxworks_get_sec_type_attr (bfd *abfd ATTRIBUTE_UNUSED, asection *sec) 7650218822Sdim{ 7651218822Sdim if (sec->name == NULL) 7652218822Sdim return NULL; 7653218822Sdim 7654218822Sdim if (strcmp (sec->name, ".plt") == 0) 7655218822Sdim return _bfd_elf_get_sec_type_attr (abfd, sec); 7656218822Sdim 7657218822Sdim return ppc_elf_get_sec_type_attr (abfd, sec); 7658218822Sdim} 7659218822Sdim 7660218822Sdim/* Like ppc_elf_link_hash_table_create, but overrides 7661218822Sdim appropriately for VxWorks. */ 7662218822Sdimstatic struct bfd_link_hash_table * 7663218822Sdimppc_elf_vxworks_link_hash_table_create (bfd *abfd) 7664218822Sdim{ 7665218822Sdim struct bfd_link_hash_table *ret; 7666218822Sdim 7667218822Sdim ret = ppc_elf_link_hash_table_create (abfd); 7668218822Sdim if (ret) 7669218822Sdim { 7670218822Sdim struct ppc_elf_link_hash_table *htab 7671218822Sdim = (struct ppc_elf_link_hash_table *)ret; 7672218822Sdim htab->is_vxworks = 1; 7673218822Sdim htab->plt_type = PLT_VXWORKS; 7674218822Sdim htab->plt_entry_size = VXWORKS_PLT_ENTRY_SIZE; 7675218822Sdim htab->plt_slot_size = VXWORKS_PLT_ENTRY_SIZE; 7676218822Sdim htab->plt_initial_entry_size = VXWORKS_PLT_INITIAL_ENTRY_SIZE; 7677218822Sdim } 7678218822Sdim return ret; 7679218822Sdim} 7680218822Sdim 7681218822Sdim/* Tweak magic VxWorks symbols as they are loaded. */ 7682218822Sdimstatic bfd_boolean 7683218822Sdimppc_elf_vxworks_add_symbol_hook (bfd *abfd, 7684218822Sdim struct bfd_link_info *info, 7685218822Sdim Elf_Internal_Sym *sym, 7686218822Sdim const char **namep ATTRIBUTE_UNUSED, 7687218822Sdim flagword *flagsp ATTRIBUTE_UNUSED, 7688218822Sdim asection **secp, 7689218822Sdim bfd_vma *valp) 7690218822Sdim{ 7691218822Sdim if (!elf_vxworks_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, 7692218822Sdim valp)) 7693218822Sdim return FALSE; 7694218822Sdim 7695218822Sdim return ppc_elf_add_symbol_hook(abfd, info, sym,namep, flagsp, secp, valp); 7696218822Sdim} 7697218822Sdim 7698218822Sdimstatic void 7699218822Sdimppc_elf_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker) 7700218822Sdim{ 7701218822Sdim ppc_elf_final_write_processing(abfd, linker); 7702218822Sdim elf_vxworks_final_write_processing(abfd, linker); 7703218822Sdim} 7704218822Sdim 7705218822Sdim/* On VxWorks, we emit relocations against _PROCEDURE_LINKAGE_TABLE_, so 7706218822Sdim define it. */ 7707218822Sdim#undef elf_backend_want_plt_sym 7708218822Sdim#define elf_backend_want_plt_sym 1 7709218822Sdim#undef elf_backend_want_got_plt 7710218822Sdim#define elf_backend_want_got_plt 1 7711218822Sdim#undef elf_backend_got_symbol_offset 7712218822Sdim#define elf_backend_got_symbol_offset 0 7713218822Sdim#undef elf_backend_plt_not_loaded 7714218822Sdim#define elf_backend_plt_not_loaded 0 7715218822Sdim#undef elf_backend_plt_readonly 7716218822Sdim#define elf_backend_plt_readonly 1 7717218822Sdim#undef elf_backend_got_header_size 7718218822Sdim#define elf_backend_got_header_size 12 7719218822Sdim 7720218822Sdim#undef bfd_elf32_bfd_link_hash_table_create 7721218822Sdim#define bfd_elf32_bfd_link_hash_table_create \ 7722218822Sdim ppc_elf_vxworks_link_hash_table_create 7723218822Sdim#undef elf_backend_add_symbol_hook 7724218822Sdim#define elf_backend_add_symbol_hook \ 7725218822Sdim ppc_elf_vxworks_add_symbol_hook 7726218822Sdim#undef elf_backend_link_output_symbol_hook 7727218822Sdim#define elf_backend_link_output_symbol_hook \ 7728218822Sdim elf_vxworks_link_output_symbol_hook 7729218822Sdim#undef elf_backend_final_write_processing 7730218822Sdim#define elf_backend_final_write_processing \ 7731218822Sdim ppc_elf_vxworks_final_write_processing 7732218822Sdim#undef elf_backend_get_sec_type_attr 7733218822Sdim#define elf_backend_get_sec_type_attr \ 7734218822Sdim ppc_elf_vxworks_get_sec_type_attr 7735218822Sdim#undef elf_backend_emit_relocs 7736218822Sdim#define elf_backend_emit_relocs \ 7737218822Sdim elf_vxworks_emit_relocs 7738218822Sdim 7739218822Sdim#undef elf32_bed 7740218822Sdim#define elf32_bed ppc_elf_vxworks_bed 7741218822Sdim 7742218822Sdim#include "elf32-target.h" 7743