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