1214082Sdim/* 32-bit ELF support for ARM
2214634Sdim   Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
3214082Sdim   Free Software Foundation, Inc.
4214082Sdim
5214082Sdim   This file is part of BFD, the Binary File Descriptor library.
6214082Sdim
7214082Sdim   This program is free software; you can redistribute it and/or modify
8214082Sdim   it under the terms of the GNU General Public License as published by
9214082Sdim   the Free Software Foundation; either version 2 of the License, or
10214082Sdim   (at your option) any later version.
11214082Sdim
12214082Sdim   This program is distributed in the hope that it will be useful,
13214082Sdim   but WITHOUT ANY WARRANTY; without even the implied warranty of
14214082Sdim   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15214082Sdim   GNU General Public License for more details.
16214082Sdim
17214082Sdim   You should have received a copy of the GNU General Public License
18214082Sdim   along with this program; if not, write to the Free Software
19214082Sdim   Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
20214082Sdim
21214634Sdim#include "sysdep.h"
22214082Sdim#include "bfd.h"
23214082Sdim#include "libiberty.h"
24214082Sdim#include "libbfd.h"
25214082Sdim#include "elf-bfd.h"
26214082Sdim#include "elf-vxworks.h"
27214082Sdim#include "elf/arm.h"
28214082Sdim
29214082Sdim#ifndef NUM_ELEM
30214082Sdim#define NUM_ELEM(a)  (sizeof (a) / (sizeof (a)[0]))
31214082Sdim#endif
32214082Sdim
33214082Sdim/* Return the relocation section associated with NAME.  HTAB is the
34214082Sdim   bfd's elf32_arm_link_hash_entry.  */
35214082Sdim#define RELOC_SECTION(HTAB, NAME) \
36214082Sdim  ((HTAB)->use_rel ? ".rel" NAME : ".rela" NAME)
37214082Sdim
38214082Sdim/* Return size of a relocation entry.  HTAB is the bfd's
39214082Sdim   elf32_arm_link_hash_entry.  */
40214082Sdim#define RELOC_SIZE(HTAB) \
41214082Sdim  ((HTAB)->use_rel \
42214082Sdim   ? sizeof (Elf32_External_Rel) \
43214082Sdim   : sizeof (Elf32_External_Rela))
44214082Sdim
45214082Sdim/* Return function to swap relocations in.  HTAB is the bfd's
46214082Sdim   elf32_arm_link_hash_entry.  */
47214082Sdim#define SWAP_RELOC_IN(HTAB) \
48214082Sdim  ((HTAB)->use_rel \
49214082Sdim   ? bfd_elf32_swap_reloc_in \
50214082Sdim   : bfd_elf32_swap_reloca_in)
51214082Sdim
52214082Sdim/* Return function to swap relocations out.  HTAB is the bfd's
53214082Sdim   elf32_arm_link_hash_entry.  */
54214082Sdim#define SWAP_RELOC_OUT(HTAB) \
55214082Sdim  ((HTAB)->use_rel \
56214082Sdim   ? bfd_elf32_swap_reloc_out \
57214082Sdim   : bfd_elf32_swap_reloca_out)
58214082Sdim
59214082Sdim#define elf_info_to_howto               0
60214082Sdim#define elf_info_to_howto_rel           elf32_arm_info_to_howto
61214082Sdim
62214082Sdim#define ARM_ELF_ABI_VERSION		0
63214157Sdim#ifdef __FreeBSD__
64214157Sdim#define ARM_ELF_OS_ABI_VERSION		ELFOSABI_FREEBSD
65214157Sdim#else
66214082Sdim#define ARM_ELF_OS_ABI_VERSION		ELFOSABI_ARM
67214157Sdim#endif
68214082Sdim
69214634Sdimstatic struct elf_backend_data elf32_arm_vxworks_bed;
70214082Sdim
71214082Sdim/* Note: code such as elf32_arm_reloc_type_lookup expect to use e.g.
72214082Sdim   R_ARM_PC24 as an index into this, and find the R_ARM_PC24 HOWTO
73214082Sdim   in that slot.  */
74214082Sdim
75214082Sdimstatic reloc_howto_type elf32_arm_howto_table_1[] =
76214082Sdim{
77214082Sdim  /* No relocation */
78214082Sdim  HOWTO (R_ARM_NONE,		/* type */
79214082Sdim	 0,			/* rightshift */
80214082Sdim	 0,			/* size (0 = byte, 1 = short, 2 = long) */
81214082Sdim	 0,			/* bitsize */
82214082Sdim	 FALSE,			/* pc_relative */
83214082Sdim	 0,			/* bitpos */
84214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
85214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
86214082Sdim	 "R_ARM_NONE",		/* name */
87214082Sdim	 FALSE,			/* partial_inplace */
88214082Sdim	 0,			/* src_mask */
89214082Sdim	 0,			/* dst_mask */
90214082Sdim	 FALSE),		/* pcrel_offset */
91214082Sdim
92214082Sdim  HOWTO (R_ARM_PC24,		/* type */
93214082Sdim	 2,			/* rightshift */
94214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
95214082Sdim	 24,			/* bitsize */
96214082Sdim	 TRUE,			/* pc_relative */
97214082Sdim	 0,			/* bitpos */
98214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
99214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
100214082Sdim	 "R_ARM_PC24",		/* name */
101214082Sdim	 FALSE,			/* partial_inplace */
102214082Sdim	 0x00ffffff,		/* src_mask */
103214082Sdim	 0x00ffffff,		/* dst_mask */
104214082Sdim	 TRUE),			/* pcrel_offset */
105214082Sdim
106214082Sdim  /* 32 bit absolute */
107214082Sdim  HOWTO (R_ARM_ABS32,		/* type */
108214082Sdim	 0,			/* rightshift */
109214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
110214082Sdim	 32,			/* bitsize */
111214082Sdim	 FALSE,			/* pc_relative */
112214082Sdim	 0,			/* bitpos */
113214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
114214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
115214082Sdim	 "R_ARM_ABS32",		/* name */
116214082Sdim	 FALSE,			/* partial_inplace */
117214082Sdim	 0xffffffff,		/* src_mask */
118214082Sdim	 0xffffffff,		/* dst_mask */
119214082Sdim	 FALSE),		/* pcrel_offset */
120214082Sdim
121214082Sdim  /* standard 32bit pc-relative reloc */
122214082Sdim  HOWTO (R_ARM_REL32,		/* type */
123214082Sdim	 0,			/* rightshift */
124214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
125214082Sdim	 32,			/* bitsize */
126214082Sdim	 TRUE,			/* pc_relative */
127214082Sdim	 0,			/* bitpos */
128214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
129214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
130214082Sdim	 "R_ARM_REL32",		/* name */
131214082Sdim	 FALSE,			/* partial_inplace */
132214082Sdim	 0xffffffff,		/* src_mask */
133214082Sdim	 0xffffffff,		/* dst_mask */
134214082Sdim	 TRUE),			/* pcrel_offset */
135214082Sdim
136214082Sdim  /* 8 bit absolute - R_ARM_LDR_PC_G0 in AAELF */
137214634Sdim  HOWTO (R_ARM_LDR_PC_G0,	/* type */
138214082Sdim	 0,			/* rightshift */
139214082Sdim	 0,			/* size (0 = byte, 1 = short, 2 = long) */
140214634Sdim	 32,			/* bitsize */
141214634Sdim	 TRUE,			/* pc_relative */
142214082Sdim	 0,			/* bitpos */
143214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
144214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
145214634Sdim	 "R_ARM_LDR_PC_G0",     /* name */
146214082Sdim	 FALSE,			/* partial_inplace */
147214634Sdim	 0xffffffff,		/* src_mask */
148214634Sdim	 0xffffffff,		/* dst_mask */
149214634Sdim	 TRUE),			/* pcrel_offset */
150214082Sdim
151214082Sdim   /* 16 bit absolute */
152214082Sdim  HOWTO (R_ARM_ABS16,		/* type */
153214082Sdim	 0,			/* rightshift */
154214082Sdim	 1,			/* size (0 = byte, 1 = short, 2 = long) */
155214082Sdim	 16,			/* bitsize */
156214082Sdim	 FALSE,			/* pc_relative */
157214082Sdim	 0,			/* bitpos */
158214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
159214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
160214082Sdim	 "R_ARM_ABS16",		/* name */
161214082Sdim	 FALSE,			/* partial_inplace */
162214082Sdim	 0x0000ffff,		/* src_mask */
163214082Sdim	 0x0000ffff,		/* dst_mask */
164214082Sdim	 FALSE),		/* pcrel_offset */
165214082Sdim
166214082Sdim  /* 12 bit absolute */
167214082Sdim  HOWTO (R_ARM_ABS12,		/* type */
168214082Sdim	 0,			/* rightshift */
169214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
170214082Sdim	 12,			/* bitsize */
171214082Sdim	 FALSE,			/* pc_relative */
172214082Sdim	 0,			/* bitpos */
173214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
174214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
175214082Sdim	 "R_ARM_ABS12",		/* name */
176214082Sdim	 FALSE,			/* partial_inplace */
177214082Sdim	 0x00000fff,		/* src_mask */
178214082Sdim	 0x00000fff,		/* dst_mask */
179214082Sdim	 FALSE),		/* pcrel_offset */
180214082Sdim
181214082Sdim  HOWTO (R_ARM_THM_ABS5,	/* type */
182214082Sdim	 6,			/* rightshift */
183214082Sdim	 1,			/* size (0 = byte, 1 = short, 2 = long) */
184214082Sdim	 5,			/* bitsize */
185214082Sdim	 FALSE,			/* pc_relative */
186214082Sdim	 0,			/* bitpos */
187214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
188214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
189214082Sdim	 "R_ARM_THM_ABS5",	/* name */
190214082Sdim	 FALSE,			/* partial_inplace */
191214082Sdim	 0x000007e0,		/* src_mask */
192214082Sdim	 0x000007e0,		/* dst_mask */
193214082Sdim	 FALSE),		/* pcrel_offset */
194214082Sdim
195214082Sdim  /* 8 bit absolute */
196214082Sdim  HOWTO (R_ARM_ABS8,		/* type */
197214082Sdim	 0,			/* rightshift */
198214082Sdim	 0,			/* size (0 = byte, 1 = short, 2 = long) */
199214082Sdim	 8,			/* bitsize */
200214082Sdim	 FALSE,			/* pc_relative */
201214082Sdim	 0,			/* bitpos */
202214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
203214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
204214082Sdim	 "R_ARM_ABS8",		/* name */
205214082Sdim	 FALSE,			/* partial_inplace */
206214082Sdim	 0x000000ff,		/* src_mask */
207214082Sdim	 0x000000ff,		/* dst_mask */
208214082Sdim	 FALSE),		/* pcrel_offset */
209214082Sdim
210214082Sdim  HOWTO (R_ARM_SBREL32,		/* type */
211214082Sdim	 0,			/* rightshift */
212214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
213214082Sdim	 32,			/* bitsize */
214214082Sdim	 FALSE,			/* pc_relative */
215214082Sdim	 0,			/* bitpos */
216214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
217214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
218214082Sdim	 "R_ARM_SBREL32",	/* name */
219214082Sdim	 FALSE,			/* partial_inplace */
220214082Sdim	 0xffffffff,		/* src_mask */
221214082Sdim	 0xffffffff,		/* dst_mask */
222214082Sdim	 FALSE),		/* pcrel_offset */
223214082Sdim
224214082Sdim  HOWTO (R_ARM_THM_CALL,	/* type */
225214082Sdim	 1,			/* rightshift */
226214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
227214634Sdim	 25,			/* bitsize */
228214082Sdim	 TRUE,			/* pc_relative */
229214082Sdim	 0,			/* bitpos */
230214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
231214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
232214082Sdim	 "R_ARM_THM_CALL",	/* name */
233214082Sdim	 FALSE,			/* partial_inplace */
234214082Sdim	 0x07ff07ff,		/* src_mask */
235214082Sdim	 0x07ff07ff,		/* dst_mask */
236214082Sdim	 TRUE),			/* pcrel_offset */
237214082Sdim
238214082Sdim  HOWTO (R_ARM_THM_PC8,	        /* type */
239214082Sdim	 1,			/* rightshift */
240214082Sdim	 1,			/* size (0 = byte, 1 = short, 2 = long) */
241214082Sdim	 8,			/* bitsize */
242214082Sdim	 TRUE,			/* pc_relative */
243214082Sdim	 0,			/* bitpos */
244214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
245214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
246214082Sdim	 "R_ARM_THM_PC8",	/* name */
247214082Sdim	 FALSE,			/* partial_inplace */
248214082Sdim	 0x000000ff,		/* src_mask */
249214082Sdim	 0x000000ff,		/* dst_mask */
250214082Sdim	 TRUE),			/* pcrel_offset */
251214082Sdim
252214082Sdim  HOWTO (R_ARM_BREL_ADJ,	/* type */
253214082Sdim	 1,			/* rightshift */
254214082Sdim	 1,			/* size (0 = byte, 1 = short, 2 = long) */
255214082Sdim	 32,			/* bitsize */
256214082Sdim	 FALSE,			/* pc_relative */
257214082Sdim	 0,			/* bitpos */
258214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
259214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
260214082Sdim	 "R_ARM_BREL_ADJ",	/* name */
261214082Sdim	 FALSE,			/* partial_inplace */
262214082Sdim	 0xffffffff,		/* src_mask */
263214082Sdim	 0xffffffff,		/* dst_mask */
264214082Sdim	 FALSE),		/* pcrel_offset */
265214082Sdim
266214082Sdim  HOWTO (R_ARM_SWI24,		/* type */
267214082Sdim	 0,			/* rightshift */
268214082Sdim	 0,			/* size (0 = byte, 1 = short, 2 = long) */
269214082Sdim	 0,			/* bitsize */
270214082Sdim	 FALSE,			/* pc_relative */
271214082Sdim	 0,			/* bitpos */
272214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
273214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
274214082Sdim	 "R_ARM_SWI24",		/* name */
275214082Sdim	 FALSE,			/* partial_inplace */
276214082Sdim	 0x00000000,		/* src_mask */
277214082Sdim	 0x00000000,		/* dst_mask */
278214082Sdim	 FALSE),		/* pcrel_offset */
279214082Sdim
280214082Sdim  HOWTO (R_ARM_THM_SWI8,	/* type */
281214082Sdim	 0,			/* rightshift */
282214082Sdim	 0,			/* size (0 = byte, 1 = short, 2 = long) */
283214082Sdim	 0,			/* bitsize */
284214082Sdim	 FALSE,			/* pc_relative */
285214082Sdim	 0,			/* bitpos */
286214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
287214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
288214082Sdim	 "R_ARM_SWI8",		/* name */
289214082Sdim	 FALSE,			/* partial_inplace */
290214082Sdim	 0x00000000,		/* src_mask */
291214082Sdim	 0x00000000,		/* dst_mask */
292214082Sdim	 FALSE),		/* pcrel_offset */
293214082Sdim
294214082Sdim  /* BLX instruction for the ARM.  */
295214082Sdim  HOWTO (R_ARM_XPC25,		/* type */
296214082Sdim	 2,			/* rightshift */
297214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
298214082Sdim	 25,			/* bitsize */
299214082Sdim	 TRUE,			/* pc_relative */
300214082Sdim	 0,			/* bitpos */
301214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
302214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
303214082Sdim	 "R_ARM_XPC25",		/* name */
304214082Sdim	 FALSE,			/* partial_inplace */
305214082Sdim	 0x00ffffff,		/* src_mask */
306214082Sdim	 0x00ffffff,		/* dst_mask */
307214082Sdim	 TRUE),			/* pcrel_offset */
308214082Sdim
309214082Sdim  /* BLX instruction for the Thumb.  */
310214082Sdim  HOWTO (R_ARM_THM_XPC22,	/* type */
311214082Sdim	 2,			/* rightshift */
312214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
313214082Sdim	 22,			/* bitsize */
314214082Sdim	 TRUE,			/* pc_relative */
315214082Sdim	 0,			/* bitpos */
316214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
317214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
318214082Sdim	 "R_ARM_THM_XPC22",	/* name */
319214082Sdim	 FALSE,			/* partial_inplace */
320214082Sdim	 0x07ff07ff,		/* src_mask */
321214082Sdim	 0x07ff07ff,		/* dst_mask */
322214082Sdim	 TRUE),			/* pcrel_offset */
323214082Sdim
324214082Sdim  /* Dynamic TLS relocations.  */
325214082Sdim
326214082Sdim  HOWTO (R_ARM_TLS_DTPMOD32,	/* type */
327214082Sdim         0,                     /* rightshift */
328214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
329214082Sdim         32,                    /* bitsize */
330214082Sdim         FALSE,                 /* pc_relative */
331214082Sdim         0,                     /* bitpos */
332214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
333214082Sdim         bfd_elf_generic_reloc, /* special_function */
334214082Sdim         "R_ARM_TLS_DTPMOD32",	/* name */
335214082Sdim         TRUE,			/* partial_inplace */
336214082Sdim         0xffffffff,		/* src_mask */
337214082Sdim         0xffffffff,		/* dst_mask */
338214082Sdim         FALSE),                /* pcrel_offset */
339214082Sdim
340214082Sdim  HOWTO (R_ARM_TLS_DTPOFF32,	/* type */
341214082Sdim         0,                     /* rightshift */
342214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
343214082Sdim         32,                    /* bitsize */
344214082Sdim         FALSE,                 /* pc_relative */
345214082Sdim         0,                     /* bitpos */
346214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
347214082Sdim         bfd_elf_generic_reloc, /* special_function */
348214082Sdim         "R_ARM_TLS_DTPOFF32",	/* name */
349214082Sdim         TRUE,			/* partial_inplace */
350214082Sdim         0xffffffff,		/* src_mask */
351214082Sdim         0xffffffff,		/* dst_mask */
352214082Sdim         FALSE),                /* pcrel_offset */
353214082Sdim
354214082Sdim  HOWTO (R_ARM_TLS_TPOFF32,	/* type */
355214082Sdim         0,                     /* rightshift */
356214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
357214082Sdim         32,                    /* bitsize */
358214082Sdim         FALSE,                 /* pc_relative */
359214082Sdim         0,                     /* bitpos */
360214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
361214082Sdim         bfd_elf_generic_reloc, /* special_function */
362214082Sdim         "R_ARM_TLS_TPOFF32",	/* name */
363214082Sdim         TRUE,			/* partial_inplace */
364214082Sdim         0xffffffff,		/* src_mask */
365214082Sdim         0xffffffff,		/* dst_mask */
366214082Sdim         FALSE),                /* pcrel_offset */
367214082Sdim
368214082Sdim  /* Relocs used in ARM Linux */
369214082Sdim
370214082Sdim  HOWTO (R_ARM_COPY,		/* type */
371214082Sdim         0,                     /* rightshift */
372214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
373214082Sdim         32,                    /* bitsize */
374214082Sdim         FALSE,                 /* pc_relative */
375214082Sdim         0,                     /* bitpos */
376214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
377214082Sdim         bfd_elf_generic_reloc, /* special_function */
378214082Sdim         "R_ARM_COPY",		/* name */
379214082Sdim         TRUE,			/* partial_inplace */
380214082Sdim         0xffffffff,		/* src_mask */
381214082Sdim         0xffffffff,		/* dst_mask */
382214082Sdim         FALSE),                /* pcrel_offset */
383214082Sdim
384214082Sdim  HOWTO (R_ARM_GLOB_DAT,	/* type */
385214082Sdim         0,                     /* rightshift */
386214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
387214082Sdim         32,                    /* bitsize */
388214082Sdim         FALSE,                 /* pc_relative */
389214082Sdim         0,                     /* bitpos */
390214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
391214082Sdim         bfd_elf_generic_reloc, /* special_function */
392214082Sdim         "R_ARM_GLOB_DAT",	/* name */
393214082Sdim         TRUE,			/* partial_inplace */
394214082Sdim         0xffffffff,		/* src_mask */
395214082Sdim         0xffffffff,		/* dst_mask */
396214082Sdim         FALSE),                /* pcrel_offset */
397214082Sdim
398214082Sdim  HOWTO (R_ARM_JUMP_SLOT,	/* type */
399214082Sdim         0,                     /* rightshift */
400214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
401214082Sdim         32,                    /* bitsize */
402214082Sdim         FALSE,                 /* pc_relative */
403214082Sdim         0,                     /* bitpos */
404214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
405214082Sdim         bfd_elf_generic_reloc, /* special_function */
406214082Sdim         "R_ARM_JUMP_SLOT",	/* name */
407214082Sdim         TRUE,			/* partial_inplace */
408214082Sdim         0xffffffff,		/* src_mask */
409214082Sdim         0xffffffff,		/* dst_mask */
410214082Sdim         FALSE),                /* pcrel_offset */
411214082Sdim
412214082Sdim  HOWTO (R_ARM_RELATIVE,	/* type */
413214082Sdim         0,                     /* rightshift */
414214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
415214082Sdim         32,                    /* bitsize */
416214082Sdim         FALSE,                 /* pc_relative */
417214082Sdim         0,                     /* bitpos */
418214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
419214082Sdim         bfd_elf_generic_reloc, /* special_function */
420214082Sdim         "R_ARM_RELATIVE",	/* name */
421214082Sdim         TRUE,			/* partial_inplace */
422214082Sdim         0xffffffff,		/* src_mask */
423214082Sdim         0xffffffff,		/* dst_mask */
424214082Sdim         FALSE),                /* pcrel_offset */
425214082Sdim
426214082Sdim  HOWTO (R_ARM_GOTOFF32,	/* type */
427214082Sdim         0,                     /* rightshift */
428214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
429214082Sdim         32,                    /* bitsize */
430214082Sdim         FALSE,                 /* pc_relative */
431214082Sdim         0,                     /* bitpos */
432214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
433214082Sdim         bfd_elf_generic_reloc, /* special_function */
434214082Sdim         "R_ARM_GOTOFF32",	/* name */
435214082Sdim         TRUE,			/* partial_inplace */
436214082Sdim         0xffffffff,		/* src_mask */
437214082Sdim         0xffffffff,		/* dst_mask */
438214082Sdim         FALSE),                /* pcrel_offset */
439214082Sdim
440214082Sdim  HOWTO (R_ARM_GOTPC,		/* type */
441214082Sdim         0,                     /* rightshift */
442214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
443214082Sdim         32,                    /* bitsize */
444214082Sdim         TRUE,			/* pc_relative */
445214082Sdim         0,                     /* bitpos */
446214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
447214082Sdim         bfd_elf_generic_reloc, /* special_function */
448214082Sdim         "R_ARM_GOTPC",		/* name */
449214082Sdim         TRUE,			/* partial_inplace */
450214082Sdim         0xffffffff,		/* src_mask */
451214082Sdim         0xffffffff,		/* dst_mask */
452214082Sdim         TRUE),			/* pcrel_offset */
453214082Sdim
454214082Sdim  HOWTO (R_ARM_GOT32,		/* type */
455214082Sdim         0,                     /* rightshift */
456214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
457214082Sdim         32,                    /* bitsize */
458214082Sdim         FALSE,			/* pc_relative */
459214082Sdim         0,                     /* bitpos */
460214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
461214082Sdim         bfd_elf_generic_reloc, /* special_function */
462214082Sdim         "R_ARM_GOT32",		/* name */
463214082Sdim         TRUE,			/* partial_inplace */
464214082Sdim         0xffffffff,		/* src_mask */
465214082Sdim         0xffffffff,		/* dst_mask */
466214082Sdim         FALSE),		/* pcrel_offset */
467214082Sdim
468214082Sdim  HOWTO (R_ARM_PLT32,		/* type */
469214082Sdim         2,                     /* rightshift */
470214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
471214082Sdim         24,                    /* bitsize */
472214082Sdim         TRUE,			/* pc_relative */
473214082Sdim         0,                     /* bitpos */
474214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
475214082Sdim         bfd_elf_generic_reloc, /* special_function */
476214082Sdim         "R_ARM_PLT32",		/* name */
477214082Sdim         FALSE,			/* partial_inplace */
478214082Sdim         0x00ffffff,		/* src_mask */
479214082Sdim         0x00ffffff,		/* dst_mask */
480214082Sdim         TRUE),			/* pcrel_offset */
481214082Sdim
482214082Sdim  HOWTO (R_ARM_CALL,		/* type */
483214082Sdim	 2,			/* rightshift */
484214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
485214082Sdim	 24,			/* bitsize */
486214082Sdim	 TRUE,			/* pc_relative */
487214082Sdim	 0,			/* bitpos */
488214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
489214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
490214082Sdim	 "R_ARM_CALL",		/* name */
491214082Sdim	 FALSE,			/* partial_inplace */
492214082Sdim	 0x00ffffff,		/* src_mask */
493214082Sdim	 0x00ffffff,		/* dst_mask */
494214082Sdim	 TRUE),			/* pcrel_offset */
495214082Sdim
496214082Sdim  HOWTO (R_ARM_JUMP24,		/* type */
497214082Sdim	 2,			/* rightshift */
498214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
499214082Sdim	 24,			/* bitsize */
500214082Sdim	 TRUE,			/* pc_relative */
501214082Sdim	 0,			/* bitpos */
502214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
503214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
504214082Sdim	 "R_ARM_JUMP24",	/* name */
505214082Sdim	 FALSE,			/* partial_inplace */
506214082Sdim	 0x00ffffff,		/* src_mask */
507214082Sdim	 0x00ffffff,		/* dst_mask */
508214082Sdim	 TRUE),			/* pcrel_offset */
509214082Sdim
510214082Sdim  HOWTO (R_ARM_THM_JUMP24,	/* type */
511214082Sdim	 1,			/* rightshift */
512214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
513214082Sdim	 24,			/* bitsize */
514214082Sdim	 TRUE,			/* pc_relative */
515214082Sdim	 0,			/* bitpos */
516214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
517214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
518214082Sdim	 "R_ARM_THM_JUMP24",	/* name */
519214082Sdim	 FALSE,			/* partial_inplace */
520214082Sdim	 0x07ff2fff,		/* src_mask */
521214082Sdim	 0x07ff2fff,		/* dst_mask */
522214082Sdim	 TRUE),			/* pcrel_offset */
523214082Sdim
524214082Sdim  HOWTO (R_ARM_BASE_ABS,	/* type */
525214082Sdim	 0,			/* rightshift */
526214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
527214082Sdim	 32,			/* bitsize */
528214082Sdim	 FALSE,			/* pc_relative */
529214082Sdim	 0,			/* bitpos */
530214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
531214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
532214082Sdim	 "R_ARM_BASE_ABS",	/* name */
533214082Sdim	 FALSE,			/* partial_inplace */
534214082Sdim	 0xffffffff,		/* src_mask */
535214082Sdim	 0xffffffff,		/* dst_mask */
536214082Sdim	 FALSE),		/* pcrel_offset */
537214082Sdim
538214082Sdim  HOWTO (R_ARM_ALU_PCREL7_0,	/* type */
539214082Sdim	 0,			/* rightshift */
540214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
541214082Sdim	 12,			/* bitsize */
542214082Sdim	 TRUE,			/* pc_relative */
543214082Sdim	 0,			/* bitpos */
544214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
545214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
546214082Sdim	 "R_ARM_ALU_PCREL_7_0",	/* name */
547214082Sdim	 FALSE,			/* partial_inplace */
548214082Sdim	 0x00000fff,		/* src_mask */
549214082Sdim	 0x00000fff,		/* dst_mask */
550214082Sdim	 TRUE),			/* pcrel_offset */
551214082Sdim
552214082Sdim  HOWTO (R_ARM_ALU_PCREL15_8,	/* type */
553214082Sdim	 0,			/* rightshift */
554214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
555214082Sdim	 12,			/* bitsize */
556214082Sdim	 TRUE,			/* pc_relative */
557214082Sdim	 8,			/* bitpos */
558214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
559214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
560214082Sdim	 "R_ARM_ALU_PCREL_15_8",/* name */
561214082Sdim	 FALSE,			/* partial_inplace */
562214082Sdim	 0x00000fff,		/* src_mask */
563214082Sdim	 0x00000fff,		/* dst_mask */
564214082Sdim	 TRUE),			/* pcrel_offset */
565214082Sdim
566214082Sdim  HOWTO (R_ARM_ALU_PCREL23_15,	/* type */
567214082Sdim	 0,			/* rightshift */
568214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
569214082Sdim	 12,			/* bitsize */
570214082Sdim	 TRUE,			/* pc_relative */
571214082Sdim	 16,			/* bitpos */
572214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
573214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
574214082Sdim	 "R_ARM_ALU_PCREL_23_15",/* name */
575214082Sdim	 FALSE,			/* partial_inplace */
576214082Sdim	 0x00000fff,		/* src_mask */
577214082Sdim	 0x00000fff,		/* dst_mask */
578214082Sdim	 TRUE),			/* pcrel_offset */
579214082Sdim
580214082Sdim  HOWTO (R_ARM_LDR_SBREL_11_0,	/* type */
581214082Sdim	 0,			/* rightshift */
582214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
583214082Sdim	 12,			/* bitsize */
584214082Sdim	 FALSE,			/* pc_relative */
585214082Sdim	 0,			/* bitpos */
586214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
587214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
588214082Sdim	 "R_ARM_LDR_SBREL_11_0",/* name */
589214082Sdim	 FALSE,			/* partial_inplace */
590214082Sdim	 0x00000fff,		/* src_mask */
591214082Sdim	 0x00000fff,		/* dst_mask */
592214082Sdim	 FALSE),		/* pcrel_offset */
593214082Sdim
594214082Sdim  HOWTO (R_ARM_ALU_SBREL_19_12,	/* type */
595214082Sdim	 0,			/* rightshift */
596214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
597214082Sdim	 8,			/* bitsize */
598214082Sdim	 FALSE,			/* pc_relative */
599214082Sdim	 12,			/* bitpos */
600214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
601214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
602214082Sdim	 "R_ARM_ALU_SBREL_19_12",/* name */
603214082Sdim	 FALSE,			/* partial_inplace */
604214082Sdim	 0x000ff000,		/* src_mask */
605214082Sdim	 0x000ff000,		/* dst_mask */
606214082Sdim	 FALSE),		/* pcrel_offset */
607214082Sdim
608214082Sdim  HOWTO (R_ARM_ALU_SBREL_27_20,	/* type */
609214082Sdim	 0,			/* rightshift */
610214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
611214082Sdim	 8,			/* bitsize */
612214082Sdim	 FALSE,			/* pc_relative */
613214082Sdim	 20,			/* bitpos */
614214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
615214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
616214082Sdim	 "R_ARM_ALU_SBREL_27_20",/* name */
617214082Sdim	 FALSE,			/* partial_inplace */
618214082Sdim	 0x0ff00000,		/* src_mask */
619214082Sdim	 0x0ff00000,		/* dst_mask */
620214082Sdim	 FALSE),		/* pcrel_offset */
621214082Sdim
622214082Sdim  HOWTO (R_ARM_TARGET1,		/* type */
623214082Sdim	 0,			/* rightshift */
624214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
625214082Sdim	 32,			/* bitsize */
626214082Sdim	 FALSE,			/* pc_relative */
627214082Sdim	 0,			/* bitpos */
628214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
629214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
630214082Sdim	 "R_ARM_TARGET1",	/* name */
631214082Sdim	 FALSE,			/* partial_inplace */
632214082Sdim	 0xffffffff,		/* src_mask */
633214082Sdim	 0xffffffff,		/* dst_mask */
634214082Sdim	 FALSE),		/* pcrel_offset */
635214082Sdim
636214082Sdim  HOWTO (R_ARM_ROSEGREL32,	/* type */
637214082Sdim	 0,			/* rightshift */
638214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
639214082Sdim	 32,			/* bitsize */
640214082Sdim	 FALSE,			/* pc_relative */
641214082Sdim	 0,			/* bitpos */
642214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
643214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
644214082Sdim	 "R_ARM_ROSEGREL32",	/* name */
645214082Sdim	 FALSE,			/* partial_inplace */
646214082Sdim	 0xffffffff,		/* src_mask */
647214082Sdim	 0xffffffff,		/* dst_mask */
648214082Sdim	 FALSE),		/* pcrel_offset */
649214082Sdim
650214082Sdim  HOWTO (R_ARM_V4BX,		/* type */
651214082Sdim	 0,			/* rightshift */
652214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
653214082Sdim	 32,			/* bitsize */
654214082Sdim	 FALSE,			/* pc_relative */
655214082Sdim	 0,			/* bitpos */
656214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
657214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
658214082Sdim	 "R_ARM_V4BX",		/* name */
659214082Sdim	 FALSE,			/* partial_inplace */
660214082Sdim	 0xffffffff,		/* src_mask */
661214082Sdim	 0xffffffff,		/* dst_mask */
662214082Sdim	 FALSE),		/* pcrel_offset */
663214082Sdim
664214082Sdim  HOWTO (R_ARM_TARGET2,		/* type */
665214082Sdim	 0,			/* rightshift */
666214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
667214082Sdim	 32,			/* bitsize */
668214082Sdim	 FALSE,			/* pc_relative */
669214082Sdim	 0,			/* bitpos */
670214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
671214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
672214082Sdim	 "R_ARM_TARGET2",	/* name */
673214082Sdim	 FALSE,			/* partial_inplace */
674214082Sdim	 0xffffffff,		/* src_mask */
675214082Sdim	 0xffffffff,		/* dst_mask */
676214082Sdim	 TRUE),			/* pcrel_offset */
677214082Sdim
678214082Sdim  HOWTO (R_ARM_PREL31,		/* type */
679214082Sdim	 0,			/* rightshift */
680214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
681214082Sdim	 31,			/* bitsize */
682214082Sdim	 TRUE,			/* pc_relative */
683214082Sdim	 0,			/* bitpos */
684214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
685214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
686214082Sdim	 "R_ARM_PREL31",	/* name */
687214082Sdim	 FALSE,			/* partial_inplace */
688214082Sdim	 0x7fffffff,		/* src_mask */
689214082Sdim	 0x7fffffff,		/* dst_mask */
690214082Sdim	 TRUE),			/* pcrel_offset */
691214082Sdim
692214082Sdim  HOWTO (R_ARM_MOVW_ABS_NC,	/* type */
693214082Sdim	 0,			/* rightshift */
694214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
695214082Sdim	 16,			/* bitsize */
696214082Sdim	 FALSE,			/* pc_relative */
697214082Sdim	 0,			/* bitpos */
698214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
699214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
700214082Sdim	 "R_ARM_MOVW_ABS_NC",	/* name */
701214082Sdim	 FALSE,			/* partial_inplace */
702214082Sdim	 0x0000ffff,		/* src_mask */
703214082Sdim	 0x0000ffff,		/* dst_mask */
704214082Sdim	 FALSE),		/* pcrel_offset */
705214082Sdim
706214082Sdim  HOWTO (R_ARM_MOVT_ABS,	/* type */
707214082Sdim	 0,			/* rightshift */
708214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
709214082Sdim	 16,			/* bitsize */
710214082Sdim	 FALSE,			/* pc_relative */
711214082Sdim	 0,			/* bitpos */
712214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
713214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
714214082Sdim	 "R_ARM_MOVT_ABS",	/* name */
715214082Sdim	 FALSE,			/* partial_inplace */
716214082Sdim	 0x0000ffff,		/* src_mask */
717214082Sdim	 0x0000ffff,		/* dst_mask */
718214082Sdim	 FALSE),		/* pcrel_offset */
719214082Sdim
720214082Sdim  HOWTO (R_ARM_MOVW_PREL_NC,	/* type */
721214082Sdim	 0,			/* rightshift */
722214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
723214082Sdim	 16,			/* bitsize */
724214082Sdim	 TRUE,			/* pc_relative */
725214082Sdim	 0,			/* bitpos */
726214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
727214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
728214082Sdim	 "R_ARM_MOVW_PREL_NC",	/* name */
729214082Sdim	 FALSE,			/* partial_inplace */
730214082Sdim	 0x0000ffff,		/* src_mask */
731214082Sdim	 0x0000ffff,		/* dst_mask */
732214082Sdim	 TRUE),			/* pcrel_offset */
733214082Sdim
734214082Sdim  HOWTO (R_ARM_MOVT_PREL,	/* type */
735214082Sdim	 0,			/* rightshift */
736214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
737214082Sdim	 16,			/* bitsize */
738214082Sdim	 TRUE,			/* pc_relative */
739214082Sdim	 0,			/* bitpos */
740214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
741214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
742214082Sdim	 "R_ARM_MOVT_PREL",	/* name */
743214082Sdim	 FALSE,			/* partial_inplace */
744214082Sdim	 0x0000ffff,		/* src_mask */
745214082Sdim	 0x0000ffff,		/* dst_mask */
746214082Sdim	 TRUE),			/* pcrel_offset */
747214082Sdim
748214082Sdim  HOWTO (R_ARM_THM_MOVW_ABS_NC,	/* type */
749214082Sdim	 0,			/* rightshift */
750214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
751214082Sdim	 16,			/* bitsize */
752214082Sdim	 FALSE,			/* pc_relative */
753214082Sdim	 0,			/* bitpos */
754214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
755214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
756214082Sdim	 "R_ARM_THM_MOVW_ABS_NC",/* name */
757214082Sdim	 FALSE,			/* partial_inplace */
758214082Sdim	 0x040f70ff,		/* src_mask */
759214082Sdim	 0x040f70ff,		/* dst_mask */
760214082Sdim	 FALSE),		/* pcrel_offset */
761214082Sdim
762214082Sdim  HOWTO (R_ARM_THM_MOVT_ABS,	/* type */
763214082Sdim	 0,			/* rightshift */
764214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
765214082Sdim	 16,			/* bitsize */
766214082Sdim	 FALSE,			/* pc_relative */
767214082Sdim	 0,			/* bitpos */
768214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
769214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
770214082Sdim	 "R_ARM_THM_MOVT_ABS",	/* name */
771214082Sdim	 FALSE,			/* partial_inplace */
772214082Sdim	 0x040f70ff,		/* src_mask */
773214082Sdim	 0x040f70ff,		/* dst_mask */
774214082Sdim	 FALSE),		/* pcrel_offset */
775214082Sdim
776214082Sdim  HOWTO (R_ARM_THM_MOVW_PREL_NC,/* type */
777214082Sdim	 0,			/* rightshift */
778214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
779214082Sdim	 16,			/* bitsize */
780214082Sdim	 TRUE,			/* pc_relative */
781214082Sdim	 0,			/* bitpos */
782214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
783214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
784214082Sdim	 "R_ARM_THM_MOVW_PREL_NC",/* name */
785214082Sdim	 FALSE,			/* partial_inplace */
786214082Sdim	 0x040f70ff,		/* src_mask */
787214082Sdim	 0x040f70ff,		/* dst_mask */
788214082Sdim	 TRUE),			/* pcrel_offset */
789214082Sdim
790214082Sdim  HOWTO (R_ARM_THM_MOVT_PREL,	/* type */
791214082Sdim	 0,			/* rightshift */
792214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
793214082Sdim	 16,			/* bitsize */
794214082Sdim	 TRUE,			/* pc_relative */
795214082Sdim	 0,			/* bitpos */
796214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
797214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
798214082Sdim	 "R_ARM_THM_MOVT_PREL",	/* name */
799214082Sdim	 FALSE,			/* partial_inplace */
800214082Sdim	 0x040f70ff,		/* src_mask */
801214082Sdim	 0x040f70ff,		/* dst_mask */
802214082Sdim	 TRUE),			/* pcrel_offset */
803214082Sdim
804214082Sdim  HOWTO (R_ARM_THM_JUMP19,	/* type */
805214082Sdim	 1,			/* rightshift */
806214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
807214082Sdim	 19,			/* bitsize */
808214082Sdim	 TRUE,			/* pc_relative */
809214082Sdim	 0,			/* bitpos */
810214082Sdim	 complain_overflow_signed,/* complain_on_overflow */
811214082Sdim	 bfd_elf_generic_reloc, /* special_function */
812214082Sdim	 "R_ARM_THM_JUMP19",	/* name */
813214082Sdim	 FALSE,			/* partial_inplace */
814214082Sdim	 0x043f2fff,		/* src_mask */
815214082Sdim	 0x043f2fff,		/* dst_mask */
816214082Sdim	 TRUE),			/* pcrel_offset */
817214082Sdim
818214082Sdim  HOWTO (R_ARM_THM_JUMP6,	/* type */
819214082Sdim	 1,			/* rightshift */
820214082Sdim	 1,			/* size (0 = byte, 1 = short, 2 = long) */
821214082Sdim	 6,			/* bitsize */
822214082Sdim	 TRUE,			/* pc_relative */
823214082Sdim	 0,			/* bitpos */
824214082Sdim	 complain_overflow_unsigned,/* complain_on_overflow */
825214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
826214082Sdim	 "R_ARM_THM_JUMP6",	/* name */
827214082Sdim	 FALSE,			/* partial_inplace */
828214082Sdim	 0x02f8,		/* src_mask */
829214082Sdim	 0x02f8,		/* dst_mask */
830214082Sdim	 TRUE),			/* pcrel_offset */
831214082Sdim
832214082Sdim  /* These are declared as 13-bit signed relocations because we can
833214082Sdim     address -4095 .. 4095(base) by altering ADDW to SUBW or vice
834214082Sdim     versa.  */
835214082Sdim  HOWTO (R_ARM_THM_ALU_PREL_11_0,/* type */
836214082Sdim	 0,			/* rightshift */
837214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
838214082Sdim	 13,			/* bitsize */
839214082Sdim	 TRUE,			/* pc_relative */
840214082Sdim	 0,			/* bitpos */
841214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
842214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
843214082Sdim	 "R_ARM_THM_ALU_PREL_11_0",/* name */
844214082Sdim	 FALSE,			/* partial_inplace */
845214634Sdim	 0xffffffff,		/* src_mask */
846214634Sdim	 0xffffffff,		/* dst_mask */
847214082Sdim	 TRUE),			/* pcrel_offset */
848214082Sdim
849214082Sdim  HOWTO (R_ARM_THM_PC12,	/* type */
850214082Sdim	 0,			/* rightshift */
851214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
852214082Sdim	 13,			/* bitsize */
853214082Sdim	 TRUE,			/* pc_relative */
854214082Sdim	 0,			/* bitpos */
855214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
856214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
857214082Sdim	 "R_ARM_THM_PC12",	/* name */
858214082Sdim	 FALSE,			/* partial_inplace */
859214634Sdim	 0xffffffff,		/* src_mask */
860214634Sdim	 0xffffffff,		/* dst_mask */
861214082Sdim	 TRUE),			/* pcrel_offset */
862214082Sdim
863214082Sdim  HOWTO (R_ARM_ABS32_NOI,	/* type */
864214082Sdim	 0,			/* rightshift */
865214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
866214082Sdim	 32,			/* bitsize */
867214082Sdim	 FALSE,			/* pc_relative */
868214082Sdim	 0,			/* bitpos */
869214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
870214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
871214082Sdim	 "R_ARM_ABS32_NOI",	/* name */
872214082Sdim	 FALSE,			/* partial_inplace */
873214082Sdim	 0xffffffff,		/* src_mask */
874214082Sdim	 0xffffffff,		/* dst_mask */
875214082Sdim	 FALSE),		/* pcrel_offset */
876214082Sdim
877214082Sdim  HOWTO (R_ARM_REL32_NOI,	/* type */
878214082Sdim	 0,			/* rightshift */
879214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
880214082Sdim	 32,			/* bitsize */
881214082Sdim	 TRUE,			/* pc_relative */
882214082Sdim	 0,			/* bitpos */
883214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
884214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
885214082Sdim	 "R_ARM_REL32_NOI",	/* name */
886214082Sdim	 FALSE,			/* partial_inplace */
887214082Sdim	 0xffffffff,		/* src_mask */
888214082Sdim	 0xffffffff,		/* dst_mask */
889214082Sdim	 FALSE),		/* pcrel_offset */
890214082Sdim
891214634Sdim  /* Group relocations.  */
892214082Sdim
893214634Sdim  HOWTO (R_ARM_ALU_PC_G0_NC,	/* type */
894214634Sdim	 0,			/* rightshift */
895214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
896214634Sdim	 32,			/* bitsize */
897214634Sdim	 TRUE,			/* pc_relative */
898214634Sdim	 0,			/* bitpos */
899214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
900214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
901214634Sdim	 "R_ARM_ALU_PC_G0_NC",	/* name */
902214634Sdim	 FALSE,			/* partial_inplace */
903214634Sdim	 0xffffffff,		/* src_mask */
904214634Sdim	 0xffffffff,		/* dst_mask */
905214634Sdim	 TRUE),			/* pcrel_offset */
906214634Sdim
907214634Sdim  HOWTO (R_ARM_ALU_PC_G0,   	/* type */
908214634Sdim	 0,			/* rightshift */
909214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
910214634Sdim	 32,			/* bitsize */
911214634Sdim	 TRUE,			/* pc_relative */
912214634Sdim	 0,			/* bitpos */
913214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
914214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
915214634Sdim	 "R_ARM_ALU_PC_G0",   	/* name */
916214634Sdim	 FALSE,			/* partial_inplace */
917214634Sdim	 0xffffffff,		/* src_mask */
918214634Sdim	 0xffffffff,		/* dst_mask */
919214634Sdim	 TRUE),			/* pcrel_offset */
920214634Sdim
921214634Sdim  HOWTO (R_ARM_ALU_PC_G1_NC,	/* type */
922214634Sdim	 0,			/* rightshift */
923214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
924214634Sdim	 32,			/* bitsize */
925214634Sdim	 TRUE,			/* pc_relative */
926214634Sdim	 0,			/* bitpos */
927214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
928214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
929214634Sdim	 "R_ARM_ALU_PC_G1_NC",	/* name */
930214634Sdim	 FALSE,			/* partial_inplace */
931214634Sdim	 0xffffffff,		/* src_mask */
932214634Sdim	 0xffffffff,		/* dst_mask */
933214634Sdim	 TRUE),			/* pcrel_offset */
934214634Sdim
935214634Sdim  HOWTO (R_ARM_ALU_PC_G1,   	/* type */
936214634Sdim	 0,			/* rightshift */
937214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
938214634Sdim	 32,			/* bitsize */
939214634Sdim	 TRUE,			/* pc_relative */
940214634Sdim	 0,			/* bitpos */
941214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
942214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
943214634Sdim	 "R_ARM_ALU_PC_G1",   	/* name */
944214634Sdim	 FALSE,			/* partial_inplace */
945214634Sdim	 0xffffffff,		/* src_mask */
946214634Sdim	 0xffffffff,		/* dst_mask */
947214634Sdim	 TRUE),			/* pcrel_offset */
948214634Sdim
949214634Sdim  HOWTO (R_ARM_ALU_PC_G2,   	/* type */
950214634Sdim	 0,			/* rightshift */
951214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
952214634Sdim	 32,			/* bitsize */
953214634Sdim	 TRUE,			/* pc_relative */
954214634Sdim	 0,			/* bitpos */
955214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
956214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
957214634Sdim	 "R_ARM_ALU_PC_G2",   	/* name */
958214634Sdim	 FALSE,			/* partial_inplace */
959214634Sdim	 0xffffffff,		/* src_mask */
960214634Sdim	 0xffffffff,		/* dst_mask */
961214634Sdim	 TRUE),			/* pcrel_offset */
962214634Sdim
963214634Sdim  HOWTO (R_ARM_LDR_PC_G1,   	/* type */
964214634Sdim	 0,			/* rightshift */
965214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
966214634Sdim	 32,			/* bitsize */
967214634Sdim	 TRUE,			/* pc_relative */
968214634Sdim	 0,			/* bitpos */
969214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
970214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
971214634Sdim	 "R_ARM_LDR_PC_G1",   	/* name */
972214634Sdim	 FALSE,			/* partial_inplace */
973214634Sdim	 0xffffffff,		/* src_mask */
974214634Sdim	 0xffffffff,		/* dst_mask */
975214634Sdim	 TRUE),			/* pcrel_offset */
976214634Sdim
977214634Sdim  HOWTO (R_ARM_LDR_PC_G2,   	/* type */
978214634Sdim	 0,			/* rightshift */
979214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
980214634Sdim	 32,			/* bitsize */
981214634Sdim	 TRUE,			/* pc_relative */
982214634Sdim	 0,			/* bitpos */
983214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
984214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
985214634Sdim	 "R_ARM_LDR_PC_G2",   	/* name */
986214634Sdim	 FALSE,			/* partial_inplace */
987214634Sdim	 0xffffffff,		/* src_mask */
988214634Sdim	 0xffffffff,		/* dst_mask */
989214634Sdim	 TRUE),			/* pcrel_offset */
990214634Sdim
991214634Sdim  HOWTO (R_ARM_LDRS_PC_G0,   	/* type */
992214634Sdim	 0,			/* rightshift */
993214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
994214634Sdim	 32,			/* bitsize */
995214634Sdim	 TRUE,			/* pc_relative */
996214634Sdim	 0,			/* bitpos */
997214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
998214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
999214634Sdim	 "R_ARM_LDRS_PC_G0",   	/* name */
1000214634Sdim	 FALSE,			/* partial_inplace */
1001214634Sdim	 0xffffffff,		/* src_mask */
1002214634Sdim	 0xffffffff,		/* dst_mask */
1003214634Sdim	 TRUE),			/* pcrel_offset */
1004214634Sdim
1005214634Sdim  HOWTO (R_ARM_LDRS_PC_G1,   	/* type */
1006214634Sdim	 0,			/* rightshift */
1007214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1008214634Sdim	 32,			/* bitsize */
1009214634Sdim	 TRUE,			/* pc_relative */
1010214634Sdim	 0,			/* bitpos */
1011214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1012214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1013214634Sdim	 "R_ARM_LDRS_PC_G1",   	/* name */
1014214634Sdim	 FALSE,			/* partial_inplace */
1015214634Sdim	 0xffffffff,		/* src_mask */
1016214634Sdim	 0xffffffff,		/* dst_mask */
1017214634Sdim	 TRUE),			/* pcrel_offset */
1018214634Sdim
1019214634Sdim  HOWTO (R_ARM_LDRS_PC_G2,   	/* type */
1020214634Sdim	 0,			/* rightshift */
1021214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1022214634Sdim	 32,			/* bitsize */
1023214634Sdim	 TRUE,			/* pc_relative */
1024214634Sdim	 0,			/* bitpos */
1025214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1026214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1027214634Sdim	 "R_ARM_LDRS_PC_G2",   	/* name */
1028214634Sdim	 FALSE,			/* partial_inplace */
1029214634Sdim	 0xffffffff,		/* src_mask */
1030214634Sdim	 0xffffffff,		/* dst_mask */
1031214634Sdim	 TRUE),			/* pcrel_offset */
1032214634Sdim
1033214634Sdim  HOWTO (R_ARM_LDC_PC_G0,   	/* type */
1034214634Sdim	 0,			/* rightshift */
1035214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1036214634Sdim	 32,			/* bitsize */
1037214634Sdim	 TRUE,			/* pc_relative */
1038214634Sdim	 0,			/* bitpos */
1039214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1040214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1041214634Sdim	 "R_ARM_LDC_PC_G0",   	/* name */
1042214634Sdim	 FALSE,			/* partial_inplace */
1043214634Sdim	 0xffffffff,		/* src_mask */
1044214634Sdim	 0xffffffff,		/* dst_mask */
1045214634Sdim	 TRUE),			/* pcrel_offset */
1046214634Sdim
1047214634Sdim  HOWTO (R_ARM_LDC_PC_G1,   	/* type */
1048214634Sdim	 0,			/* rightshift */
1049214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1050214634Sdim	 32,			/* bitsize */
1051214634Sdim	 TRUE,			/* pc_relative */
1052214634Sdim	 0,			/* bitpos */
1053214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1054214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1055214634Sdim	 "R_ARM_LDC_PC_G1",   	/* name */
1056214634Sdim	 FALSE,			/* partial_inplace */
1057214634Sdim	 0xffffffff,		/* src_mask */
1058214634Sdim	 0xffffffff,		/* dst_mask */
1059214634Sdim	 TRUE),			/* pcrel_offset */
1060214634Sdim
1061214634Sdim  HOWTO (R_ARM_LDC_PC_G2,   	/* type */
1062214634Sdim	 0,			/* rightshift */
1063214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1064214634Sdim	 32,			/* bitsize */
1065214634Sdim	 TRUE,			/* pc_relative */
1066214634Sdim	 0,			/* bitpos */
1067214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1068214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1069214634Sdim	 "R_ARM_LDC_PC_G2",   	/* name */
1070214634Sdim	 FALSE,			/* partial_inplace */
1071214634Sdim	 0xffffffff,		/* src_mask */
1072214634Sdim	 0xffffffff,		/* dst_mask */
1073214634Sdim	 TRUE),			/* pcrel_offset */
1074214634Sdim
1075214634Sdim  HOWTO (R_ARM_ALU_SB_G0_NC,   	/* type */
1076214634Sdim	 0,			/* rightshift */
1077214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1078214634Sdim	 32,			/* bitsize */
1079214634Sdim	 TRUE,			/* pc_relative */
1080214634Sdim	 0,			/* bitpos */
1081214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1082214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1083214634Sdim	 "R_ARM_ALU_SB_G0_NC", 	/* name */
1084214634Sdim	 FALSE,			/* partial_inplace */
1085214634Sdim	 0xffffffff,		/* src_mask */
1086214634Sdim	 0xffffffff,		/* dst_mask */
1087214634Sdim	 TRUE),			/* pcrel_offset */
1088214634Sdim
1089214634Sdim  HOWTO (R_ARM_ALU_SB_G0,   	/* type */
1090214634Sdim	 0,			/* rightshift */
1091214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1092214634Sdim	 32,			/* bitsize */
1093214634Sdim	 TRUE,			/* pc_relative */
1094214634Sdim	 0,			/* bitpos */
1095214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1096214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1097214634Sdim	 "R_ARM_ALU_SB_G0", 	/* name */
1098214634Sdim	 FALSE,			/* partial_inplace */
1099214634Sdim	 0xffffffff,		/* src_mask */
1100214634Sdim	 0xffffffff,		/* dst_mask */
1101214634Sdim	 TRUE),			/* pcrel_offset */
1102214634Sdim
1103214634Sdim  HOWTO (R_ARM_ALU_SB_G1_NC,   	/* type */
1104214634Sdim	 0,			/* rightshift */
1105214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1106214634Sdim	 32,			/* bitsize */
1107214634Sdim	 TRUE,			/* pc_relative */
1108214634Sdim	 0,			/* bitpos */
1109214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1110214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1111214634Sdim	 "R_ARM_ALU_SB_G1_NC", 	/* name */
1112214634Sdim	 FALSE,			/* partial_inplace */
1113214634Sdim	 0xffffffff,		/* src_mask */
1114214634Sdim	 0xffffffff,		/* dst_mask */
1115214634Sdim	 TRUE),			/* pcrel_offset */
1116214634Sdim
1117214634Sdim  HOWTO (R_ARM_ALU_SB_G1,   	/* type */
1118214634Sdim	 0,			/* rightshift */
1119214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1120214634Sdim	 32,			/* bitsize */
1121214634Sdim	 TRUE,			/* pc_relative */
1122214634Sdim	 0,			/* bitpos */
1123214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1124214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1125214634Sdim	 "R_ARM_ALU_SB_G1", 	/* name */
1126214634Sdim	 FALSE,			/* partial_inplace */
1127214634Sdim	 0xffffffff,		/* src_mask */
1128214634Sdim	 0xffffffff,		/* dst_mask */
1129214634Sdim	 TRUE),			/* pcrel_offset */
1130214634Sdim
1131214634Sdim  HOWTO (R_ARM_ALU_SB_G2,   	/* type */
1132214634Sdim	 0,			/* rightshift */
1133214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1134214634Sdim	 32,			/* bitsize */
1135214634Sdim	 TRUE,			/* pc_relative */
1136214634Sdim	 0,			/* bitpos */
1137214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1138214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1139214634Sdim	 "R_ARM_ALU_SB_G2", 	/* name */
1140214634Sdim	 FALSE,			/* partial_inplace */
1141214634Sdim	 0xffffffff,		/* src_mask */
1142214634Sdim	 0xffffffff,		/* dst_mask */
1143214634Sdim	 TRUE),			/* pcrel_offset */
1144214634Sdim
1145214634Sdim  HOWTO (R_ARM_LDR_SB_G0,   	/* type */
1146214634Sdim	 0,			/* rightshift */
1147214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1148214634Sdim	 32,			/* bitsize */
1149214634Sdim	 TRUE,			/* pc_relative */
1150214634Sdim	 0,			/* bitpos */
1151214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1152214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1153214634Sdim	 "R_ARM_LDR_SB_G0", 	/* name */
1154214634Sdim	 FALSE,			/* partial_inplace */
1155214634Sdim	 0xffffffff,		/* src_mask */
1156214634Sdim	 0xffffffff,		/* dst_mask */
1157214634Sdim	 TRUE),			/* pcrel_offset */
1158214634Sdim
1159214634Sdim  HOWTO (R_ARM_LDR_SB_G1,   	/* type */
1160214634Sdim	 0,			/* rightshift */
1161214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1162214634Sdim	 32,			/* bitsize */
1163214634Sdim	 TRUE,			/* pc_relative */
1164214634Sdim	 0,			/* bitpos */
1165214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1166214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1167214634Sdim	 "R_ARM_LDR_SB_G1", 	/* name */
1168214634Sdim	 FALSE,			/* partial_inplace */
1169214634Sdim	 0xffffffff,		/* src_mask */
1170214634Sdim	 0xffffffff,		/* dst_mask */
1171214634Sdim	 TRUE),			/* pcrel_offset */
1172214634Sdim
1173214634Sdim  HOWTO (R_ARM_LDR_SB_G2,   	/* type */
1174214634Sdim	 0,			/* rightshift */
1175214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1176214634Sdim	 32,			/* bitsize */
1177214634Sdim	 TRUE,			/* pc_relative */
1178214634Sdim	 0,			/* bitpos */
1179214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1180214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1181214634Sdim	 "R_ARM_LDR_SB_G2", 	/* name */
1182214634Sdim	 FALSE,			/* partial_inplace */
1183214634Sdim	 0xffffffff,		/* src_mask */
1184214634Sdim	 0xffffffff,		/* dst_mask */
1185214634Sdim	 TRUE),			/* pcrel_offset */
1186214634Sdim
1187214634Sdim  HOWTO (R_ARM_LDRS_SB_G0,   	/* type */
1188214634Sdim	 0,			/* rightshift */
1189214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1190214634Sdim	 32,			/* bitsize */
1191214634Sdim	 TRUE,			/* pc_relative */
1192214634Sdim	 0,			/* bitpos */
1193214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1194214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1195214634Sdim	 "R_ARM_LDRS_SB_G0", 	/* name */
1196214634Sdim	 FALSE,			/* partial_inplace */
1197214634Sdim	 0xffffffff,		/* src_mask */
1198214634Sdim	 0xffffffff,		/* dst_mask */
1199214634Sdim	 TRUE),			/* pcrel_offset */
1200214634Sdim
1201214634Sdim  HOWTO (R_ARM_LDRS_SB_G1,   	/* type */
1202214634Sdim	 0,			/* rightshift */
1203214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1204214634Sdim	 32,			/* bitsize */
1205214634Sdim	 TRUE,			/* pc_relative */
1206214634Sdim	 0,			/* bitpos */
1207214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1208214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1209214634Sdim	 "R_ARM_LDRS_SB_G1", 	/* name */
1210214634Sdim	 FALSE,			/* partial_inplace */
1211214634Sdim	 0xffffffff,		/* src_mask */
1212214634Sdim	 0xffffffff,		/* dst_mask */
1213214634Sdim	 TRUE),			/* pcrel_offset */
1214214634Sdim
1215214634Sdim  HOWTO (R_ARM_LDRS_SB_G2,   	/* type */
1216214634Sdim	 0,			/* rightshift */
1217214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1218214634Sdim	 32,			/* bitsize */
1219214634Sdim	 TRUE,			/* pc_relative */
1220214634Sdim	 0,			/* bitpos */
1221214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1222214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1223214634Sdim	 "R_ARM_LDRS_SB_G2", 	/* name */
1224214634Sdim	 FALSE,			/* partial_inplace */
1225214634Sdim	 0xffffffff,		/* src_mask */
1226214634Sdim	 0xffffffff,		/* dst_mask */
1227214634Sdim	 TRUE),			/* pcrel_offset */
1228214634Sdim
1229214634Sdim  HOWTO (R_ARM_LDC_SB_G0,   	/* type */
1230214634Sdim	 0,			/* rightshift */
1231214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1232214634Sdim	 32,			/* bitsize */
1233214634Sdim	 TRUE,			/* pc_relative */
1234214634Sdim	 0,			/* bitpos */
1235214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1236214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1237214634Sdim	 "R_ARM_LDC_SB_G0", 	/* name */
1238214634Sdim	 FALSE,			/* partial_inplace */
1239214634Sdim	 0xffffffff,		/* src_mask */
1240214634Sdim	 0xffffffff,		/* dst_mask */
1241214634Sdim	 TRUE),			/* pcrel_offset */
1242214634Sdim
1243214634Sdim  HOWTO (R_ARM_LDC_SB_G1,   	/* type */
1244214634Sdim	 0,			/* rightshift */
1245214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1246214634Sdim	 32,			/* bitsize */
1247214634Sdim	 TRUE,			/* pc_relative */
1248214634Sdim	 0,			/* bitpos */
1249214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1250214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1251214634Sdim	 "R_ARM_LDC_SB_G1", 	/* name */
1252214634Sdim	 FALSE,			/* partial_inplace */
1253214634Sdim	 0xffffffff,		/* src_mask */
1254214634Sdim	 0xffffffff,		/* dst_mask */
1255214634Sdim	 TRUE),			/* pcrel_offset */
1256214634Sdim
1257214634Sdim  HOWTO (R_ARM_LDC_SB_G2,   	/* type */
1258214634Sdim	 0,			/* rightshift */
1259214634Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1260214634Sdim	 32,			/* bitsize */
1261214634Sdim	 TRUE,			/* pc_relative */
1262214634Sdim	 0,			/* bitpos */
1263214634Sdim	 complain_overflow_dont,/* complain_on_overflow */
1264214634Sdim	 bfd_elf_generic_reloc,	/* special_function */
1265214634Sdim	 "R_ARM_LDC_SB_G2", 	/* name */
1266214634Sdim	 FALSE,			/* partial_inplace */
1267214634Sdim	 0xffffffff,		/* src_mask */
1268214634Sdim	 0xffffffff,		/* dst_mask */
1269214634Sdim	 TRUE),			/* pcrel_offset */
1270214634Sdim
1271214634Sdim  /* End of group relocations.  */
1272214634Sdim
1273214082Sdim  HOWTO (R_ARM_MOVW_BREL_NC,	/* type */
1274214082Sdim	 0,			/* rightshift */
1275214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1276214082Sdim	 16,			/* bitsize */
1277214082Sdim	 FALSE,			/* pc_relative */
1278214082Sdim	 0,			/* bitpos */
1279214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
1280214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1281214082Sdim	 "R_ARM_MOVW_BREL_NC",	/* name */
1282214082Sdim	 FALSE,			/* partial_inplace */
1283214082Sdim	 0x0000ffff,		/* src_mask */
1284214082Sdim	 0x0000ffff,		/* dst_mask */
1285214082Sdim	 FALSE),		/* pcrel_offset */
1286214082Sdim
1287214082Sdim  HOWTO (R_ARM_MOVT_BREL,	/* type */
1288214082Sdim	 0,			/* rightshift */
1289214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1290214082Sdim	 16,			/* bitsize */
1291214082Sdim	 FALSE,			/* pc_relative */
1292214082Sdim	 0,			/* bitpos */
1293214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
1294214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1295214082Sdim	 "R_ARM_MOVT_BREL",	/* name */
1296214082Sdim	 FALSE,			/* partial_inplace */
1297214082Sdim	 0x0000ffff,		/* src_mask */
1298214082Sdim	 0x0000ffff,		/* dst_mask */
1299214082Sdim	 FALSE),		/* pcrel_offset */
1300214082Sdim
1301214082Sdim  HOWTO (R_ARM_MOVW_BREL,	/* type */
1302214082Sdim	 0,			/* rightshift */
1303214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1304214082Sdim	 16,			/* bitsize */
1305214082Sdim	 FALSE,			/* pc_relative */
1306214082Sdim	 0,			/* bitpos */
1307214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
1308214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1309214082Sdim	 "R_ARM_MOVW_BREL",	/* name */
1310214082Sdim	 FALSE,			/* partial_inplace */
1311214082Sdim	 0x0000ffff,		/* src_mask */
1312214082Sdim	 0x0000ffff,		/* dst_mask */
1313214082Sdim	 FALSE),		/* pcrel_offset */
1314214082Sdim
1315214082Sdim  HOWTO (R_ARM_THM_MOVW_BREL_NC,/* type */
1316214082Sdim	 0,			/* rightshift */
1317214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1318214082Sdim	 16,			/* bitsize */
1319214082Sdim	 FALSE,			/* pc_relative */
1320214082Sdim	 0,			/* bitpos */
1321214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
1322214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1323214082Sdim	 "R_ARM_THM_MOVW_BREL_NC",/* name */
1324214082Sdim	 FALSE,			/* partial_inplace */
1325214082Sdim	 0x040f70ff,		/* src_mask */
1326214082Sdim	 0x040f70ff,		/* dst_mask */
1327214082Sdim	 FALSE),		/* pcrel_offset */
1328214082Sdim
1329214082Sdim  HOWTO (R_ARM_THM_MOVT_BREL,	/* type */
1330214082Sdim	 0,			/* rightshift */
1331214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1332214082Sdim	 16,			/* bitsize */
1333214082Sdim	 FALSE,			/* pc_relative */
1334214082Sdim	 0,			/* bitpos */
1335214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
1336214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1337214082Sdim	 "R_ARM_THM_MOVT_BREL",	/* name */
1338214082Sdim	 FALSE,			/* partial_inplace */
1339214082Sdim	 0x040f70ff,		/* src_mask */
1340214082Sdim	 0x040f70ff,		/* dst_mask */
1341214082Sdim	 FALSE),		/* pcrel_offset */
1342214082Sdim
1343214082Sdim  HOWTO (R_ARM_THM_MOVW_BREL,	/* type */
1344214082Sdim	 0,			/* rightshift */
1345214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1346214082Sdim	 16,			/* bitsize */
1347214082Sdim	 FALSE,			/* pc_relative */
1348214082Sdim	 0,			/* bitpos */
1349214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
1350214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1351214082Sdim	 "R_ARM_THM_MOVW_BREL",	/* name */
1352214082Sdim	 FALSE,			/* partial_inplace */
1353214082Sdim	 0x040f70ff,		/* src_mask */
1354214082Sdim	 0x040f70ff,		/* dst_mask */
1355214082Sdim	 FALSE),		/* pcrel_offset */
1356214082Sdim
1357214082Sdim  EMPTY_HOWTO (90),   /* unallocated */
1358214082Sdim  EMPTY_HOWTO (91),
1359214082Sdim  EMPTY_HOWTO (92),
1360214082Sdim  EMPTY_HOWTO (93),
1361214082Sdim
1362214082Sdim  HOWTO (R_ARM_PLT32_ABS,	/* type */
1363214082Sdim	 0,			/* rightshift */
1364214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1365214082Sdim	 32,			/* bitsize */
1366214082Sdim	 FALSE,			/* pc_relative */
1367214082Sdim	 0,			/* bitpos */
1368214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
1369214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1370214082Sdim	 "R_ARM_PLT32_ABS",	/* name */
1371214082Sdim	 FALSE,			/* partial_inplace */
1372214082Sdim	 0xffffffff,		/* src_mask */
1373214082Sdim	 0xffffffff,		/* dst_mask */
1374214082Sdim	 FALSE),		/* pcrel_offset */
1375214082Sdim
1376214082Sdim  HOWTO (R_ARM_GOT_ABS,		/* type */
1377214082Sdim	 0,			/* rightshift */
1378214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1379214082Sdim	 32,			/* bitsize */
1380214082Sdim	 FALSE,			/* pc_relative */
1381214082Sdim	 0,			/* bitpos */
1382214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
1383214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1384214082Sdim	 "R_ARM_GOT_ABS",	/* name */
1385214082Sdim	 FALSE,			/* partial_inplace */
1386214082Sdim	 0xffffffff,		/* src_mask */
1387214082Sdim	 0xffffffff,		/* dst_mask */
1388214082Sdim	 FALSE),			/* pcrel_offset */
1389214082Sdim
1390214082Sdim  HOWTO (R_ARM_GOT_PREL,	/* type */
1391214082Sdim	 0,			/* rightshift */
1392214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1393214082Sdim	 32,			/* bitsize */
1394214082Sdim	 TRUE,			/* pc_relative */
1395214082Sdim	 0,			/* bitpos */
1396214082Sdim	 complain_overflow_dont,	/* complain_on_overflow */
1397214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1398214082Sdim	 "R_ARM_GOT_PREL",	/* name */
1399214082Sdim	 FALSE,			/* partial_inplace */
1400214082Sdim	 0xffffffff,		/* src_mask */
1401214082Sdim	 0xffffffff,		/* dst_mask */
1402214082Sdim	 TRUE),			/* pcrel_offset */
1403214082Sdim
1404214082Sdim  HOWTO (R_ARM_GOT_BREL12,	/* type */
1405214082Sdim	 0,			/* rightshift */
1406214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1407214082Sdim	 12,			/* bitsize */
1408214082Sdim	 FALSE,			/* pc_relative */
1409214082Sdim	 0,			/* bitpos */
1410214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
1411214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1412214082Sdim	 "R_ARM_GOT_BREL12",	/* name */
1413214082Sdim	 FALSE,			/* partial_inplace */
1414214082Sdim	 0x00000fff,		/* src_mask */
1415214082Sdim	 0x00000fff,		/* dst_mask */
1416214082Sdim	 FALSE),		/* pcrel_offset */
1417214082Sdim
1418214082Sdim  HOWTO (R_ARM_GOTOFF12,	/* type */
1419214082Sdim	 0,			/* rightshift */
1420214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1421214082Sdim	 12,			/* bitsize */
1422214082Sdim	 FALSE,			/* pc_relative */
1423214082Sdim	 0,			/* bitpos */
1424214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
1425214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1426214082Sdim	 "R_ARM_GOTOFF12",	/* name */
1427214082Sdim	 FALSE,			/* partial_inplace */
1428214082Sdim	 0x00000fff,		/* src_mask */
1429214082Sdim	 0x00000fff,		/* dst_mask */
1430214082Sdim	 FALSE),		/* pcrel_offset */
1431214082Sdim
1432214082Sdim  EMPTY_HOWTO (R_ARM_GOTRELAX),  /* reserved for future GOT-load optimizations */
1433214082Sdim
1434214082Sdim  /* GNU extension to record C++ vtable member usage */
1435214082Sdim  HOWTO (R_ARM_GNU_VTENTRY,     /* type */
1436214082Sdim         0,                     /* rightshift */
1437214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
1438214082Sdim         0,                     /* bitsize */
1439214082Sdim         FALSE,                 /* pc_relative */
1440214082Sdim         0,                     /* bitpos */
1441214082Sdim         complain_overflow_dont, /* complain_on_overflow */
1442214082Sdim         _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
1443214082Sdim         "R_ARM_GNU_VTENTRY",   /* name */
1444214082Sdim         FALSE,                 /* partial_inplace */
1445214082Sdim         0,                     /* src_mask */
1446214082Sdim         0,                     /* dst_mask */
1447214082Sdim         FALSE),                /* pcrel_offset */
1448214082Sdim
1449214082Sdim  /* GNU extension to record C++ vtable hierarchy */
1450214082Sdim  HOWTO (R_ARM_GNU_VTINHERIT, /* type */
1451214082Sdim         0,                     /* rightshift */
1452214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
1453214082Sdim         0,                     /* bitsize */
1454214082Sdim         FALSE,                 /* pc_relative */
1455214082Sdim         0,                     /* bitpos */
1456214082Sdim         complain_overflow_dont, /* complain_on_overflow */
1457214082Sdim         NULL,                  /* special_function */
1458214082Sdim         "R_ARM_GNU_VTINHERIT", /* name */
1459214082Sdim         FALSE,                 /* partial_inplace */
1460214082Sdim         0,                     /* src_mask */
1461214082Sdim         0,                     /* dst_mask */
1462214082Sdim         FALSE),                /* pcrel_offset */
1463214082Sdim
1464214082Sdim  HOWTO (R_ARM_THM_JUMP11,	/* type */
1465214082Sdim	 1,			/* rightshift */
1466214082Sdim	 1,			/* size (0 = byte, 1 = short, 2 = long) */
1467214082Sdim	 11,			/* bitsize */
1468214082Sdim	 TRUE,			/* pc_relative */
1469214082Sdim	 0,			/* bitpos */
1470214082Sdim	 complain_overflow_signed,	/* complain_on_overflow */
1471214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1472214082Sdim	 "R_ARM_THM_JUMP11",	/* name */
1473214082Sdim	 FALSE,			/* partial_inplace */
1474214082Sdim	 0x000007ff,		/* src_mask */
1475214082Sdim	 0x000007ff,		/* dst_mask */
1476214082Sdim	 TRUE),			/* pcrel_offset */
1477214082Sdim
1478214082Sdim  HOWTO (R_ARM_THM_JUMP8,	/* type */
1479214082Sdim	 1,			/* rightshift */
1480214082Sdim	 1,			/* size (0 = byte, 1 = short, 2 = long) */
1481214082Sdim	 8,			/* bitsize */
1482214082Sdim	 TRUE,			/* pc_relative */
1483214082Sdim	 0,			/* bitpos */
1484214082Sdim	 complain_overflow_signed,	/* complain_on_overflow */
1485214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1486214082Sdim	 "R_ARM_THM_JUMP8",	/* name */
1487214082Sdim	 FALSE,			/* partial_inplace */
1488214082Sdim	 0x000000ff,		/* src_mask */
1489214082Sdim	 0x000000ff,		/* dst_mask */
1490214082Sdim	 TRUE),			/* pcrel_offset */
1491214082Sdim
1492214082Sdim  /* TLS relocations */
1493214082Sdim  HOWTO (R_ARM_TLS_GD32,	/* type */
1494214082Sdim         0,                     /* rightshift */
1495214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
1496214082Sdim         32,                    /* bitsize */
1497214082Sdim         FALSE,                 /* pc_relative */
1498214082Sdim         0,                     /* bitpos */
1499214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
1500214082Sdim         NULL,			/* special_function */
1501214082Sdim         "R_ARM_TLS_GD32",	/* name */
1502214082Sdim         TRUE,			/* partial_inplace */
1503214082Sdim         0xffffffff,		/* src_mask */
1504214082Sdim         0xffffffff,		/* dst_mask */
1505214082Sdim         FALSE),                /* pcrel_offset */
1506214082Sdim
1507214082Sdim  HOWTO (R_ARM_TLS_LDM32,	/* type */
1508214082Sdim         0,                     /* rightshift */
1509214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
1510214082Sdim         32,                    /* bitsize */
1511214082Sdim         FALSE,                 /* pc_relative */
1512214082Sdim         0,                     /* bitpos */
1513214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
1514214082Sdim         bfd_elf_generic_reloc, /* special_function */
1515214082Sdim         "R_ARM_TLS_LDM32",	/* name */
1516214082Sdim         TRUE,			/* partial_inplace */
1517214082Sdim         0xffffffff,		/* src_mask */
1518214082Sdim         0xffffffff,		/* dst_mask */
1519214082Sdim         FALSE),                /* pcrel_offset */
1520214082Sdim
1521214082Sdim  HOWTO (R_ARM_TLS_LDO32,	/* type */
1522214082Sdim         0,                     /* rightshift */
1523214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
1524214082Sdim         32,                    /* bitsize */
1525214082Sdim         FALSE,                 /* pc_relative */
1526214082Sdim         0,                     /* bitpos */
1527214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
1528214082Sdim         bfd_elf_generic_reloc, /* special_function */
1529214082Sdim         "R_ARM_TLS_LDO32",	/* name */
1530214082Sdim         TRUE,			/* partial_inplace */
1531214082Sdim         0xffffffff,		/* src_mask */
1532214082Sdim         0xffffffff,		/* dst_mask */
1533214082Sdim         FALSE),                /* pcrel_offset */
1534214082Sdim
1535214082Sdim  HOWTO (R_ARM_TLS_IE32,	/* type */
1536214082Sdim         0,                     /* rightshift */
1537214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
1538214082Sdim         32,                    /* bitsize */
1539214082Sdim         FALSE,                  /* pc_relative */
1540214082Sdim         0,                     /* bitpos */
1541214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
1542214082Sdim         NULL,			/* special_function */
1543214082Sdim         "R_ARM_TLS_IE32",	/* name */
1544214082Sdim         TRUE,			/* partial_inplace */
1545214082Sdim         0xffffffff,		/* src_mask */
1546214082Sdim         0xffffffff,		/* dst_mask */
1547214082Sdim         FALSE),                /* pcrel_offset */
1548214082Sdim
1549214082Sdim  HOWTO (R_ARM_TLS_LE32,	/* type */
1550214082Sdim         0,                     /* rightshift */
1551214082Sdim         2,                     /* size (0 = byte, 1 = short, 2 = long) */
1552214082Sdim         32,                    /* bitsize */
1553214082Sdim         FALSE,                 /* pc_relative */
1554214082Sdim         0,                     /* bitpos */
1555214082Sdim         complain_overflow_bitfield,/* complain_on_overflow */
1556214082Sdim         bfd_elf_generic_reloc, /* special_function */
1557214082Sdim         "R_ARM_TLS_LE32",	/* name */
1558214082Sdim         TRUE,			/* partial_inplace */
1559214082Sdim         0xffffffff,		/* src_mask */
1560214082Sdim         0xffffffff,		/* dst_mask */
1561214082Sdim         FALSE),                /* pcrel_offset */
1562214082Sdim
1563214082Sdim  HOWTO (R_ARM_TLS_LDO12,	/* type */
1564214082Sdim	 0,			/* rightshift */
1565214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1566214082Sdim	 12,			/* bitsize */
1567214082Sdim	 FALSE,			/* pc_relative */
1568214082Sdim	 0,			/* bitpos */
1569214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
1570214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1571214082Sdim	 "R_ARM_TLS_LDO12",	/* name */
1572214082Sdim	 FALSE,			/* partial_inplace */
1573214082Sdim	 0x00000fff,		/* src_mask */
1574214082Sdim	 0x00000fff,		/* dst_mask */
1575214082Sdim	 FALSE),		/* pcrel_offset */
1576214082Sdim
1577214082Sdim  HOWTO (R_ARM_TLS_LE12,	/* type */
1578214082Sdim	 0,			/* rightshift */
1579214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1580214082Sdim	 12,			/* bitsize */
1581214082Sdim	 FALSE,			/* pc_relative */
1582214082Sdim	 0,			/* bitpos */
1583214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
1584214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1585214082Sdim	 "R_ARM_TLS_LE12",	/* name */
1586214082Sdim	 FALSE,			/* partial_inplace */
1587214082Sdim	 0x00000fff,		/* src_mask */
1588214082Sdim	 0x00000fff,		/* dst_mask */
1589214082Sdim	 FALSE),		/* pcrel_offset */
1590214082Sdim
1591214082Sdim  HOWTO (R_ARM_TLS_IE12GP,	/* type */
1592214082Sdim	 0,			/* rightshift */
1593214082Sdim	 2,			/* size (0 = byte, 1 = short, 2 = long) */
1594214082Sdim	 12,			/* bitsize */
1595214082Sdim	 FALSE,			/* pc_relative */
1596214082Sdim	 0,			/* bitpos */
1597214082Sdim	 complain_overflow_bitfield,/* complain_on_overflow */
1598214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1599214082Sdim	 "R_ARM_TLS_IE12GP",	/* name */
1600214082Sdim	 FALSE,			/* partial_inplace */
1601214082Sdim	 0x00000fff,		/* src_mask */
1602214082Sdim	 0x00000fff,		/* dst_mask */
1603214082Sdim	 FALSE),		/* pcrel_offset */
1604214082Sdim};
1605214082Sdim
1606214082Sdim/* 112-127 private relocations
1607214082Sdim   128 R_ARM_ME_TOO, obsolete
1608214082Sdim   129-255 unallocated in AAELF.
1609214082Sdim
1610214082Sdim   249-255 extended, currently unused, relocations:  */
1611214082Sdim
1612214634Sdimstatic reloc_howto_type elf32_arm_howto_table_2[4] =
1613214082Sdim{
1614214082Sdim  HOWTO (R_ARM_RREL32,		/* type */
1615214082Sdim	 0,			/* rightshift */
1616214082Sdim	 0,			/* size (0 = byte, 1 = short, 2 = long) */
1617214082Sdim	 0,			/* bitsize */
1618214082Sdim	 FALSE,			/* pc_relative */
1619214082Sdim	 0,			/* bitpos */
1620214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
1621214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1622214082Sdim	 "R_ARM_RREL32",	/* name */
1623214082Sdim	 FALSE,			/* partial_inplace */
1624214082Sdim	 0,			/* src_mask */
1625214082Sdim	 0,			/* dst_mask */
1626214082Sdim	 FALSE),		/* pcrel_offset */
1627214082Sdim
1628214082Sdim  HOWTO (R_ARM_RABS32,		/* type */
1629214082Sdim	 0,			/* rightshift */
1630214082Sdim	 0,			/* size (0 = byte, 1 = short, 2 = long) */
1631214082Sdim	 0,			/* bitsize */
1632214082Sdim	 FALSE,			/* pc_relative */
1633214082Sdim	 0,			/* bitpos */
1634214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
1635214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1636214082Sdim	 "R_ARM_RABS32",	/* name */
1637214082Sdim	 FALSE,			/* partial_inplace */
1638214082Sdim	 0,			/* src_mask */
1639214082Sdim	 0,			/* dst_mask */
1640214082Sdim	 FALSE),		/* pcrel_offset */
1641214082Sdim
1642214082Sdim  HOWTO (R_ARM_RPC24,		/* type */
1643214082Sdim	 0,			/* rightshift */
1644214082Sdim	 0,			/* size (0 = byte, 1 = short, 2 = long) */
1645214082Sdim	 0,			/* bitsize */
1646214082Sdim	 FALSE,			/* pc_relative */
1647214082Sdim	 0,			/* bitpos */
1648214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
1649214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1650214082Sdim	 "R_ARM_RPC24",		/* name */
1651214082Sdim	 FALSE,			/* partial_inplace */
1652214082Sdim	 0,			/* src_mask */
1653214082Sdim	 0,			/* dst_mask */
1654214082Sdim	 FALSE),		/* pcrel_offset */
1655214082Sdim
1656214082Sdim  HOWTO (R_ARM_RBASE,		/* type */
1657214082Sdim	 0,			/* rightshift */
1658214082Sdim	 0,			/* size (0 = byte, 1 = short, 2 = long) */
1659214082Sdim	 0,			/* bitsize */
1660214082Sdim	 FALSE,			/* pc_relative */
1661214082Sdim	 0,			/* bitpos */
1662214082Sdim	 complain_overflow_dont,/* complain_on_overflow */
1663214082Sdim	 bfd_elf_generic_reloc,	/* special_function */
1664214082Sdim	 "R_ARM_RBASE",		/* name */
1665214082Sdim	 FALSE,			/* partial_inplace */
1666214082Sdim	 0,			/* src_mask */
1667214082Sdim	 0,			/* dst_mask */
1668214082Sdim	 FALSE)			/* pcrel_offset */
1669214082Sdim};
1670214082Sdim
1671214082Sdimstatic reloc_howto_type *
1672214082Sdimelf32_arm_howto_from_type (unsigned int r_type)
1673214082Sdim{
1674214082Sdim  if (r_type < NUM_ELEM (elf32_arm_howto_table_1))
1675214082Sdim    return &elf32_arm_howto_table_1[r_type];
1676214082Sdim
1677214082Sdim  if (r_type >= R_ARM_RREL32
1678214082Sdim      && r_type < R_ARM_RREL32 + NUM_ELEM (elf32_arm_howto_table_2))
1679214634Sdim    return &elf32_arm_howto_table_2[r_type - R_ARM_RREL32];
1680214082Sdim
1681214082Sdim  return NULL;
1682214082Sdim}
1683214082Sdim
1684214082Sdimstatic void
1685214082Sdimelf32_arm_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED, arelent * bfd_reloc,
1686214082Sdim			 Elf_Internal_Rela * elf_reloc)
1687214082Sdim{
1688214082Sdim  unsigned int r_type;
1689214082Sdim
1690214082Sdim  r_type = ELF32_R_TYPE (elf_reloc->r_info);
1691214082Sdim  bfd_reloc->howto = elf32_arm_howto_from_type (r_type);
1692214082Sdim}
1693214082Sdim
1694214082Sdimstruct elf32_arm_reloc_map
1695214082Sdim  {
1696214082Sdim    bfd_reloc_code_real_type  bfd_reloc_val;
1697214082Sdim    unsigned char             elf_reloc_val;
1698214082Sdim  };
1699214082Sdim
1700214082Sdim/* All entries in this list must also be present in elf32_arm_howto_table.  */
1701214082Sdimstatic const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
1702214082Sdim  {
1703214082Sdim    {BFD_RELOC_NONE,                 R_ARM_NONE},
1704214082Sdim    {BFD_RELOC_ARM_PCREL_BRANCH,     R_ARM_PC24},
1705214082Sdim    {BFD_RELOC_ARM_PCREL_CALL,	     R_ARM_CALL},
1706214082Sdim    {BFD_RELOC_ARM_PCREL_JUMP,	     R_ARM_JUMP24},
1707214082Sdim    {BFD_RELOC_ARM_PCREL_BLX,        R_ARM_XPC25},
1708214082Sdim    {BFD_RELOC_THUMB_PCREL_BLX,      R_ARM_THM_XPC22},
1709214082Sdim    {BFD_RELOC_32,                   R_ARM_ABS32},
1710214082Sdim    {BFD_RELOC_32_PCREL,             R_ARM_REL32},
1711214082Sdim    {BFD_RELOC_8,                    R_ARM_ABS8},
1712214082Sdim    {BFD_RELOC_16,                   R_ARM_ABS16},
1713214082Sdim    {BFD_RELOC_ARM_OFFSET_IMM,       R_ARM_ABS12},
1714214082Sdim    {BFD_RELOC_ARM_THUMB_OFFSET,     R_ARM_THM_ABS5},
1715214082Sdim    {BFD_RELOC_THUMB_PCREL_BRANCH25, R_ARM_THM_JUMP24},
1716214082Sdim    {BFD_RELOC_THUMB_PCREL_BRANCH23, R_ARM_THM_CALL},
1717214082Sdim    {BFD_RELOC_THUMB_PCREL_BRANCH12, R_ARM_THM_JUMP11},
1718214082Sdim    {BFD_RELOC_THUMB_PCREL_BRANCH20, R_ARM_THM_JUMP19},
1719214082Sdim    {BFD_RELOC_THUMB_PCREL_BRANCH9,  R_ARM_THM_JUMP8},
1720214082Sdim    {BFD_RELOC_THUMB_PCREL_BRANCH7,  R_ARM_THM_JUMP6},
1721214082Sdim    {BFD_RELOC_ARM_GLOB_DAT,         R_ARM_GLOB_DAT},
1722214082Sdim    {BFD_RELOC_ARM_JUMP_SLOT,        R_ARM_JUMP_SLOT},
1723214082Sdim    {BFD_RELOC_ARM_RELATIVE,         R_ARM_RELATIVE},
1724214082Sdim    {BFD_RELOC_ARM_GOTOFF,           R_ARM_GOTOFF32},
1725214082Sdim    {BFD_RELOC_ARM_GOTPC,            R_ARM_GOTPC},
1726214082Sdim    {BFD_RELOC_ARM_GOT32,            R_ARM_GOT32},
1727214082Sdim    {BFD_RELOC_ARM_PLT32,            R_ARM_PLT32},
1728214082Sdim    {BFD_RELOC_ARM_TARGET1,	     R_ARM_TARGET1},
1729214082Sdim    {BFD_RELOC_ARM_ROSEGREL32,	     R_ARM_ROSEGREL32},
1730214082Sdim    {BFD_RELOC_ARM_SBREL32,	     R_ARM_SBREL32},
1731214082Sdim    {BFD_RELOC_ARM_PREL31,	     R_ARM_PREL31},
1732214082Sdim    {BFD_RELOC_ARM_TARGET2,	     R_ARM_TARGET2},
1733214082Sdim    {BFD_RELOC_ARM_PLT32,            R_ARM_PLT32},
1734214082Sdim    {BFD_RELOC_ARM_TLS_GD32,	     R_ARM_TLS_GD32},
1735214082Sdim    {BFD_RELOC_ARM_TLS_LDO32,	     R_ARM_TLS_LDO32},
1736214082Sdim    {BFD_RELOC_ARM_TLS_LDM32,	     R_ARM_TLS_LDM32},
1737214082Sdim    {BFD_RELOC_ARM_TLS_DTPMOD32,     R_ARM_TLS_DTPMOD32},
1738214082Sdim    {BFD_RELOC_ARM_TLS_DTPOFF32,     R_ARM_TLS_DTPOFF32},
1739214082Sdim    {BFD_RELOC_ARM_TLS_TPOFF32,      R_ARM_TLS_TPOFF32},
1740214082Sdim    {BFD_RELOC_ARM_TLS_IE32,         R_ARM_TLS_IE32},
1741214082Sdim    {BFD_RELOC_ARM_TLS_LE32,         R_ARM_TLS_LE32},
1742214082Sdim    {BFD_RELOC_VTABLE_INHERIT,	     R_ARM_GNU_VTINHERIT},
1743214082Sdim    {BFD_RELOC_VTABLE_ENTRY,	     R_ARM_GNU_VTENTRY},
1744214634Sdim    {BFD_RELOC_ARM_MOVW,	     R_ARM_MOVW_ABS_NC},
1745214634Sdim    {BFD_RELOC_ARM_MOVT,	     R_ARM_MOVT_ABS},
1746214634Sdim    {BFD_RELOC_ARM_MOVW_PCREL,	     R_ARM_MOVW_PREL_NC},
1747214634Sdim    {BFD_RELOC_ARM_MOVT_PCREL,	     R_ARM_MOVT_PREL},
1748214634Sdim    {BFD_RELOC_ARM_THUMB_MOVW,	     R_ARM_THM_MOVW_ABS_NC},
1749214634Sdim    {BFD_RELOC_ARM_THUMB_MOVT,	     R_ARM_THM_MOVT_ABS},
1750214634Sdim    {BFD_RELOC_ARM_THUMB_MOVW_PCREL, R_ARM_THM_MOVW_PREL_NC},
1751214634Sdim    {BFD_RELOC_ARM_THUMB_MOVT_PCREL, R_ARM_THM_MOVT_PREL},
1752214634Sdim    {BFD_RELOC_ARM_ALU_PC_G0_NC, R_ARM_ALU_PC_G0_NC},
1753214634Sdim    {BFD_RELOC_ARM_ALU_PC_G0, R_ARM_ALU_PC_G0},
1754214634Sdim    {BFD_RELOC_ARM_ALU_PC_G1_NC, R_ARM_ALU_PC_G1_NC},
1755214634Sdim    {BFD_RELOC_ARM_ALU_PC_G1, R_ARM_ALU_PC_G1},
1756214634Sdim    {BFD_RELOC_ARM_ALU_PC_G2, R_ARM_ALU_PC_G2},
1757214634Sdim    {BFD_RELOC_ARM_LDR_PC_G0, R_ARM_LDR_PC_G0},
1758214634Sdim    {BFD_RELOC_ARM_LDR_PC_G1, R_ARM_LDR_PC_G1},
1759214634Sdim    {BFD_RELOC_ARM_LDR_PC_G2, R_ARM_LDR_PC_G2},
1760214634Sdim    {BFD_RELOC_ARM_LDRS_PC_G0, R_ARM_LDRS_PC_G0},
1761214634Sdim    {BFD_RELOC_ARM_LDRS_PC_G1, R_ARM_LDRS_PC_G1},
1762214634Sdim    {BFD_RELOC_ARM_LDRS_PC_G2, R_ARM_LDRS_PC_G2},
1763214634Sdim    {BFD_RELOC_ARM_LDC_PC_G0, R_ARM_LDC_PC_G0},
1764214634Sdim    {BFD_RELOC_ARM_LDC_PC_G1, R_ARM_LDC_PC_G1},
1765214634Sdim    {BFD_RELOC_ARM_LDC_PC_G2, R_ARM_LDC_PC_G2},
1766214634Sdim    {BFD_RELOC_ARM_ALU_SB_G0_NC, R_ARM_ALU_SB_G0_NC},
1767214634Sdim    {BFD_RELOC_ARM_ALU_SB_G0, R_ARM_ALU_SB_G0},
1768214634Sdim    {BFD_RELOC_ARM_ALU_SB_G1_NC, R_ARM_ALU_SB_G1_NC},
1769214634Sdim    {BFD_RELOC_ARM_ALU_SB_G1, R_ARM_ALU_SB_G1},
1770214634Sdim    {BFD_RELOC_ARM_ALU_SB_G2, R_ARM_ALU_SB_G2},
1771214634Sdim    {BFD_RELOC_ARM_LDR_SB_G0, R_ARM_LDR_SB_G0},
1772214634Sdim    {BFD_RELOC_ARM_LDR_SB_G1, R_ARM_LDR_SB_G1},
1773214634Sdim    {BFD_RELOC_ARM_LDR_SB_G2, R_ARM_LDR_SB_G2},
1774214634Sdim    {BFD_RELOC_ARM_LDRS_SB_G0, R_ARM_LDRS_SB_G0},
1775214634Sdim    {BFD_RELOC_ARM_LDRS_SB_G1, R_ARM_LDRS_SB_G1},
1776214634Sdim    {BFD_RELOC_ARM_LDRS_SB_G2, R_ARM_LDRS_SB_G2},
1777214634Sdim    {BFD_RELOC_ARM_LDC_SB_G0, R_ARM_LDC_SB_G0},
1778214634Sdim    {BFD_RELOC_ARM_LDC_SB_G1, R_ARM_LDC_SB_G1},
1779214634Sdim    {BFD_RELOC_ARM_LDC_SB_G2, R_ARM_LDC_SB_G2}
1780214082Sdim  };
1781214082Sdim
1782214082Sdimstatic reloc_howto_type *
1783214082Sdimelf32_arm_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
1784214082Sdim			     bfd_reloc_code_real_type code)
1785214082Sdim{
1786214082Sdim  unsigned int i;
1787214082Sdim  for (i = 0; i < NUM_ELEM (elf32_arm_reloc_map); i ++)
1788214082Sdim    if (elf32_arm_reloc_map[i].bfd_reloc_val == code)
1789214082Sdim      return elf32_arm_howto_from_type (elf32_arm_reloc_map[i].elf_reloc_val);
1790214082Sdim
1791214082Sdim  return NULL;
1792214082Sdim}
1793214082Sdim
1794214634Sdimstatic reloc_howto_type *
1795214634Sdimelf32_arm_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
1796214634Sdim			     const char *r_name)
1797214634Sdim{
1798214634Sdim  unsigned int i;
1799214634Sdim
1800214634Sdim  for (i = 0;
1801214634Sdim       i < (sizeof (elf32_arm_howto_table_1)
1802214634Sdim	    / sizeof (elf32_arm_howto_table_1[0]));
1803214634Sdim       i++)
1804214634Sdim    if (elf32_arm_howto_table_1[i].name != NULL
1805214634Sdim	&& strcasecmp (elf32_arm_howto_table_1[i].name, r_name) == 0)
1806214634Sdim      return &elf32_arm_howto_table_1[i];
1807214634Sdim
1808214634Sdim  for (i = 0;
1809214634Sdim       i < (sizeof (elf32_arm_howto_table_2)
1810214634Sdim	    / sizeof (elf32_arm_howto_table_2[0]));
1811214634Sdim       i++)
1812214634Sdim    if (elf32_arm_howto_table_2[i].name != NULL
1813214634Sdim	&& strcasecmp (elf32_arm_howto_table_2[i].name, r_name) == 0)
1814214634Sdim      return &elf32_arm_howto_table_2[i];
1815214634Sdim
1816214634Sdim  return NULL;
1817214634Sdim}
1818214634Sdim
1819214082Sdim/* Support for core dump NOTE sections */
1820214082Sdimstatic bfd_boolean
1821214082Sdimelf32_arm_nabi_grok_prstatus (bfd *abfd, Elf_Internal_Note *note)
1822214082Sdim{
1823214082Sdim  int offset;
1824214082Sdim  size_t size;
1825214082Sdim
1826214082Sdim  switch (note->descsz)
1827214082Sdim    {
1828214082Sdim      default:
1829214082Sdim	return FALSE;
1830214082Sdim
1831214082Sdim      case 148:		/* Linux/ARM 32-bit*/
1832214082Sdim	/* pr_cursig */
1833214082Sdim	elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
1834214082Sdim
1835214082Sdim	/* pr_pid */
1836214082Sdim	elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24);
1837214082Sdim
1838214082Sdim	/* pr_reg */
1839214082Sdim	offset = 72;
1840214082Sdim	size = 72;
1841214082Sdim
1842214082Sdim	break;
1843214157Sdim
1844214157Sdim      case 96:		/* FreeBSD/ARM */
1845214157Sdim	/* pr_cursig */
1846214157Sdim	if (elf_tdata(abfd)->core_signal == 0)
1847214157Sdim	  elf_tdata (abfd)->core_signal = ((int *)(note->descdata))[5];
1848214157Sdim
1849214157Sdim	/* pr_pid */
1850214157Sdim	elf_tdata (abfd)->core_pid = ((int *)(note->descdata))[6];
1851214157Sdim
1852214157Sdim	/* pr_reg */
1853214157Sdim	offset = 28;
1854214157Sdim	size = 68;
1855214157Sdim	break;
1856214082Sdim    }
1857214082Sdim
1858214082Sdim  /* Make a ".reg/999" section.  */
1859214082Sdim  return _bfd_elfcore_make_pseudosection (abfd, ".reg",
1860214082Sdim					  size, note->descpos + offset);
1861214082Sdim}
1862214082Sdim
1863214082Sdimstatic bfd_boolean
1864214082Sdimelf32_arm_nabi_grok_psinfo (bfd *abfd, Elf_Internal_Note *note)
1865214082Sdim{
1866214082Sdim  switch (note->descsz)
1867214082Sdim    {
1868214082Sdim      default:
1869214082Sdim	return FALSE;
1870214082Sdim
1871214082Sdim      case 124:		/* Linux/ARM elf_prpsinfo */
1872214082Sdim	elf_tdata (abfd)->core_program
1873214082Sdim	 = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
1874214082Sdim	elf_tdata (abfd)->core_command
1875214082Sdim	 = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
1876214082Sdim    }
1877214082Sdim
1878214082Sdim  /* Note that for some reason, a spurious space is tacked
1879214082Sdim     onto the end of the args in some (at least one anyway)
1880214082Sdim     implementations, so strip it off if it exists.  */
1881214082Sdim
1882214082Sdim  {
1883214082Sdim    char *command = elf_tdata (abfd)->core_command;
1884214082Sdim    int n = strlen (command);
1885214082Sdim
1886214082Sdim    if (0 < n && command[n - 1] == ' ')
1887214082Sdim      command[n - 1] = '\0';
1888214082Sdim  }
1889214082Sdim
1890214082Sdim  return TRUE;
1891214082Sdim}
1892214082Sdim
1893214082Sdim#define TARGET_LITTLE_SYM               bfd_elf32_littlearm_vec
1894214082Sdim#define TARGET_LITTLE_NAME              "elf32-littlearm"
1895214082Sdim#define TARGET_BIG_SYM                  bfd_elf32_bigarm_vec
1896214082Sdim#define TARGET_BIG_NAME                 "elf32-bigarm"
1897214082Sdim
1898214082Sdim#define elf_backend_grok_prstatus	elf32_arm_nabi_grok_prstatus
1899214082Sdim#define elf_backend_grok_psinfo		elf32_arm_nabi_grok_psinfo
1900214082Sdim
1901214082Sdimtypedef unsigned long int insn32;
1902214082Sdimtypedef unsigned short int insn16;
1903214082Sdim
1904214082Sdim/* In lieu of proper flags, assume all EABIv4 or later objects are
1905214082Sdim   interworkable.  */
1906214082Sdim#define INTERWORK_FLAG(abfd)  \
1907214082Sdim  (EF_ARM_EABI_VERSION (elf_elfheader (abfd)->e_flags) >= EF_ARM_EABI_VER4 \
1908214082Sdim  || (elf_elfheader (abfd)->e_flags & EF_ARM_INTERWORK))
1909214082Sdim
1910214082Sdim/* The linker script knows the section names for placement.
1911214082Sdim   The entry_names are used to do simple name mangling on the stubs.
1912214082Sdim   Given a function name, and its type, the stub can be found. The
1913214082Sdim   name can be changed. The only requirement is the %s be present.  */
1914214082Sdim#define THUMB2ARM_GLUE_SECTION_NAME ".glue_7t"
1915214082Sdim#define THUMB2ARM_GLUE_ENTRY_NAME   "__%s_from_thumb"
1916214082Sdim
1917214082Sdim#define ARM2THUMB_GLUE_SECTION_NAME ".glue_7"
1918214082Sdim#define ARM2THUMB_GLUE_ENTRY_NAME   "__%s_from_arm"
1919214082Sdim
1920214634Sdim#define VFP11_ERRATUM_VENEER_SECTION_NAME ".vfp11_veneer"
1921214634Sdim#define VFP11_ERRATUM_VENEER_ENTRY_NAME   "__vfp11_veneer_%x"
1922214634Sdim
1923214082Sdim/* The name of the dynamic interpreter.  This is put in the .interp
1924214082Sdim   section.  */
1925214082Sdim#define ELF_DYNAMIC_INTERPRETER     "/usr/lib/ld.so.1"
1926214082Sdim
1927214082Sdim#ifdef FOUR_WORD_PLT
1928214082Sdim
1929214082Sdim/* The first entry in a procedure linkage table looks like
1930214082Sdim   this.  It is set up so that any shared library function that is
1931214082Sdim   called before the relocation has been set up calls the dynamic
1932214082Sdim   linker first.  */
1933214082Sdimstatic const bfd_vma elf32_arm_plt0_entry [] =
1934214082Sdim  {
1935214082Sdim    0xe52de004,		/* str   lr, [sp, #-4]! */
1936214082Sdim    0xe59fe010,		/* ldr   lr, [pc, #16]  */
1937214082Sdim    0xe08fe00e,		/* add   lr, pc, lr     */
1938214082Sdim    0xe5bef008,		/* ldr   pc, [lr, #8]!  */
1939214082Sdim  };
1940214082Sdim
1941214082Sdim/* Subsequent entries in a procedure linkage table look like
1942214082Sdim   this.  */
1943214082Sdimstatic const bfd_vma elf32_arm_plt_entry [] =
1944214082Sdim  {
1945214082Sdim    0xe28fc600,		/* add   ip, pc, #NN	*/
1946214082Sdim    0xe28cca00,		/* add	 ip, ip, #NN	*/
1947214082Sdim    0xe5bcf000,		/* ldr	 pc, [ip, #NN]! */
1948214082Sdim    0x00000000,		/* unused		*/
1949214082Sdim  };
1950214082Sdim
1951214082Sdim#else
1952214082Sdim
1953214082Sdim/* The first entry in a procedure linkage table looks like
1954214082Sdim   this.  It is set up so that any shared library function that is
1955214082Sdim   called before the relocation has been set up calls the dynamic
1956214082Sdim   linker first.  */
1957214082Sdimstatic const bfd_vma elf32_arm_plt0_entry [] =
1958214082Sdim  {
1959214082Sdim    0xe52de004,		/* str   lr, [sp, #-4]! */
1960214082Sdim    0xe59fe004,		/* ldr   lr, [pc, #4]   */
1961214082Sdim    0xe08fe00e,		/* add   lr, pc, lr     */
1962214082Sdim    0xe5bef008,		/* ldr   pc, [lr, #8]!  */
1963214082Sdim    0x00000000,		/* &GOT[0] - .          */
1964214082Sdim  };
1965214082Sdim
1966214082Sdim/* Subsequent entries in a procedure linkage table look like
1967214082Sdim   this.  */
1968214082Sdimstatic const bfd_vma elf32_arm_plt_entry [] =
1969214082Sdim  {
1970214082Sdim    0xe28fc600,		/* add   ip, pc, #0xNN00000 */
1971214082Sdim    0xe28cca00,		/* add	 ip, ip, #0xNN000   */
1972214082Sdim    0xe5bcf000,		/* ldr	 pc, [ip, #0xNNN]!  */
1973214082Sdim  };
1974214082Sdim
1975214082Sdim#endif
1976214082Sdim
1977214082Sdim/* The format of the first entry in the procedure linkage table
1978214082Sdim   for a VxWorks executable.  */
1979214082Sdimstatic const bfd_vma elf32_arm_vxworks_exec_plt0_entry[] =
1980214082Sdim  {
1981214082Sdim    0xe52dc008,	        /* str    ip,[sp,#-8]!			*/
1982214082Sdim    0xe59fc000,         /* ldr    ip,[pc]			*/
1983214082Sdim    0xe59cf008,         /* ldr    pc,[ip,#8]			*/
1984214082Sdim    0x00000000,         /* .long  _GLOBAL_OFFSET_TABLE_		*/
1985214082Sdim  };
1986214082Sdim
1987214082Sdim/* The format of subsequent entries in a VxWorks executable.  */
1988214082Sdimstatic const bfd_vma elf32_arm_vxworks_exec_plt_entry[] =
1989214082Sdim  {
1990214082Sdim    0xe59fc000,         /* ldr    ip,[pc]			*/
1991214082Sdim    0xe59cf000,         /* ldr    pc,[ip]			*/
1992214082Sdim    0x00000000,         /* .long  @got				*/
1993214082Sdim    0xe59fc000,         /* ldr    ip,[pc]			*/
1994214082Sdim    0xea000000,         /* b      _PLT				*/
1995214082Sdim    0x00000000,         /* .long  @pltindex*sizeof(Elf32_Rela)	*/
1996214082Sdim  };
1997214082Sdim
1998214082Sdim/* The format of entries in a VxWorks shared library.  */
1999214082Sdimstatic const bfd_vma elf32_arm_vxworks_shared_plt_entry[] =
2000214082Sdim  {
2001214082Sdim    0xe59fc000,         /* ldr    ip,[pc]			*/
2002214082Sdim    0xe79cf009,         /* ldr    pc,[ip,r9]			*/
2003214082Sdim    0x00000000,         /* .long  @got				*/
2004214082Sdim    0xe59fc000,         /* ldr    ip,[pc]			*/
2005214082Sdim    0xe599f008,         /* ldr    pc,[r9,#8]			*/
2006214082Sdim    0x00000000,         /* .long  @pltindex*sizeof(Elf32_Rela)	*/
2007214082Sdim  };
2008214082Sdim
2009214082Sdim/* An initial stub used if the PLT entry is referenced from Thumb code.  */
2010214082Sdim#define PLT_THUMB_STUB_SIZE 4
2011214082Sdimstatic const bfd_vma elf32_arm_plt_thumb_stub [] =
2012214082Sdim  {
2013214082Sdim    0x4778,		/* bx pc */
2014214082Sdim    0x46c0		/* nop   */
2015214082Sdim  };
2016214082Sdim
2017214082Sdim/* The entries in a PLT when using a DLL-based target with multiple
2018214082Sdim   address spaces.  */
2019214082Sdimstatic const bfd_vma elf32_arm_symbian_plt_entry [] =
2020214082Sdim  {
2021214082Sdim    0xe51ff004,         /* ldr   pc, [pc, #-4] */
2022214082Sdim    0x00000000,         /* dcd   R_ARM_GLOB_DAT(X) */
2023214082Sdim  };
2024214082Sdim
2025214082Sdim/* Used to build a map of a section.  This is required for mixed-endian
2026214082Sdim   code/data.  */
2027214082Sdim
2028214082Sdimtypedef struct elf32_elf_section_map
2029214082Sdim{
2030214082Sdim  bfd_vma vma;
2031214082Sdim  char type;
2032214082Sdim}
2033214082Sdimelf32_arm_section_map;
2034214082Sdim
2035214634Sdim/* Information about a VFP11 erratum veneer, or a branch to such a veneer.  */
2036214634Sdim
2037214634Sdimtypedef enum
2038214634Sdim{
2039214634Sdim  VFP11_ERRATUM_BRANCH_TO_ARM_VENEER,
2040214634Sdim  VFP11_ERRATUM_BRANCH_TO_THUMB_VENEER,
2041214634Sdim  VFP11_ERRATUM_ARM_VENEER,
2042214634Sdim  VFP11_ERRATUM_THUMB_VENEER
2043214634Sdim}
2044214634Sdimelf32_vfp11_erratum_type;
2045214634Sdim
2046214634Sdimtypedef struct elf32_vfp11_erratum_list
2047214634Sdim{
2048214634Sdim  struct elf32_vfp11_erratum_list *next;
2049214634Sdim  bfd_vma vma;
2050214634Sdim  union
2051214634Sdim  {
2052214634Sdim    struct
2053214634Sdim    {
2054214634Sdim      struct elf32_vfp11_erratum_list *veneer;
2055214634Sdim      unsigned int vfp_insn;
2056214634Sdim    } b;
2057214634Sdim    struct
2058214634Sdim    {
2059214634Sdim      struct elf32_vfp11_erratum_list *branch;
2060214634Sdim      unsigned int id;
2061214634Sdim    } v;
2062214634Sdim  } u;
2063214634Sdim  elf32_vfp11_erratum_type type;
2064214634Sdim}
2065214634Sdimelf32_vfp11_erratum_list;
2066214634Sdim
2067214082Sdimtypedef struct _arm_elf_section_data
2068214082Sdim{
2069214082Sdim  struct bfd_elf_section_data elf;
2070214082Sdim  unsigned int mapcount;
2071214634Sdim  unsigned int mapsize;
2072214082Sdim  elf32_arm_section_map *map;
2073214634Sdim  unsigned int erratumcount;
2074214634Sdim  elf32_vfp11_erratum_list *erratumlist;
2075214082Sdim}
2076214082Sdim_arm_elf_section_data;
2077214082Sdim
2078214082Sdim#define elf32_arm_section_data(sec) \
2079214082Sdim  ((_arm_elf_section_data *) elf_section_data (sec))
2080214082Sdim
2081214082Sdim/* The size of the thread control block.  */
2082214082Sdim#define TCB_SIZE	8
2083214082Sdim
2084214082Sdimstruct elf32_arm_obj_tdata
2085214082Sdim{
2086214082Sdim  struct elf_obj_tdata root;
2087214082Sdim
2088214082Sdim  /* tls_type for each local got entry.  */
2089214082Sdim  char *local_got_tls_type;
2090214082Sdim
2091214634Sdim  /* Zero to warn when linking objects with incompatible enum sizes.  */
2092214634Sdim  int no_enum_size_warning;
2093214082Sdim};
2094214082Sdim
2095214082Sdim#define elf32_arm_tdata(abfd) \
2096214082Sdim  ((struct elf32_arm_obj_tdata *) (abfd)->tdata.any)
2097214082Sdim
2098214082Sdim#define elf32_arm_local_got_tls_type(abfd) \
2099214082Sdim  (elf32_arm_tdata (abfd)->local_got_tls_type)
2100214082Sdim
2101214082Sdimstatic bfd_boolean
2102214082Sdimelf32_arm_mkobject (bfd *abfd)
2103214082Sdim{
2104214082Sdim  if (abfd->tdata.any == NULL)
2105214634Sdim    {
2106214634Sdim      bfd_size_type amt = sizeof (struct elf32_arm_obj_tdata);
2107214634Sdim      abfd->tdata.any = bfd_zalloc (abfd, amt);
2108214634Sdim      if (abfd->tdata.any == NULL)
2109214634Sdim	return FALSE;
2110214634Sdim    }
2111214634Sdim  return bfd_elf_mkobject (abfd);
2112214082Sdim}
2113214082Sdim
2114214082Sdim/* The ARM linker needs to keep track of the number of relocs that it
2115214082Sdim   decides to copy in check_relocs for each symbol.  This is so that
2116214082Sdim   it can discard PC relative relocs if it doesn't need them when
2117214082Sdim   linking with -Bsymbolic.  We store the information in a field
2118214082Sdim   extending the regular ELF linker hash table.  */
2119214082Sdim
2120214082Sdim/* This structure keeps track of the number of relocs we have copied
2121214082Sdim   for a given symbol.  */
2122214082Sdimstruct elf32_arm_relocs_copied
2123214082Sdim  {
2124214082Sdim    /* Next section.  */
2125214082Sdim    struct elf32_arm_relocs_copied * next;
2126214082Sdim    /* A section in dynobj.  */
2127214082Sdim    asection * section;
2128214082Sdim    /* Number of relocs copied in this section.  */
2129214082Sdim    bfd_size_type count;
2130214082Sdim    /* Number of PC-relative relocs copied in this section.  */
2131214082Sdim    bfd_size_type pc_count;
2132214082Sdim  };
2133214082Sdim
2134214082Sdim#define elf32_arm_hash_entry(ent) ((struct elf32_arm_link_hash_entry *)(ent))
2135214082Sdim
2136214082Sdim/* Arm ELF linker hash entry.  */
2137214082Sdimstruct elf32_arm_link_hash_entry
2138214082Sdim  {
2139214082Sdim    struct elf_link_hash_entry root;
2140214082Sdim
2141214082Sdim    /* Number of PC relative relocs copied for this symbol.  */
2142214082Sdim    struct elf32_arm_relocs_copied * relocs_copied;
2143214082Sdim
2144214082Sdim    /* We reference count Thumb references to a PLT entry separately,
2145214082Sdim       so that we can emit the Thumb trampoline only if needed.  */
2146214082Sdim    bfd_signed_vma plt_thumb_refcount;
2147214082Sdim
2148214082Sdim    /* Since PLT entries have variable size if the Thumb prologue is
2149214082Sdim       used, we need to record the index into .got.plt instead of
2150214082Sdim       recomputing it from the PLT offset.  */
2151214082Sdim    bfd_signed_vma plt_got_offset;
2152214082Sdim
2153214082Sdim#define GOT_UNKNOWN	0
2154214082Sdim#define GOT_NORMAL	1
2155214082Sdim#define GOT_TLS_GD	2
2156214082Sdim#define GOT_TLS_IE	4
2157214082Sdim    unsigned char tls_type;
2158214634Sdim
2159214634Sdim    /* The symbol marking the real symbol location for exported thumb
2160214634Sdim       symbols with Arm stubs.  */
2161214634Sdim    struct elf_link_hash_entry *export_glue;
2162214082Sdim  };
2163214082Sdim
2164214082Sdim/* Traverse an arm ELF linker hash table.  */
2165214082Sdim#define elf32_arm_link_hash_traverse(table, func, info)			\
2166214082Sdim  (elf_link_hash_traverse						\
2167214082Sdim   (&(table)->root,							\
2168214082Sdim    (bfd_boolean (*) (struct elf_link_hash_entry *, void *)) (func),	\
2169214082Sdim    (info)))
2170214082Sdim
2171214082Sdim/* Get the ARM elf linker hash table from a link_info structure.  */
2172214082Sdim#define elf32_arm_hash_table(info) \
2173214082Sdim  ((struct elf32_arm_link_hash_table *) ((info)->hash))
2174214082Sdim
2175214082Sdim/* ARM ELF linker hash table.  */
2176214082Sdimstruct elf32_arm_link_hash_table
2177214082Sdim  {
2178214082Sdim    /* The main hash table.  */
2179214082Sdim    struct elf_link_hash_table root;
2180214082Sdim
2181214082Sdim    /* The size in bytes of the section containing the Thumb-to-ARM glue.  */
2182214082Sdim    bfd_size_type thumb_glue_size;
2183214082Sdim
2184214082Sdim    /* The size in bytes of the section containing the ARM-to-Thumb glue.  */
2185214082Sdim    bfd_size_type arm_glue_size;
2186214082Sdim
2187214634Sdim    /* The size in bytes of the section containing glue for VFP11 erratum
2188214634Sdim       veneers.  */
2189214634Sdim    bfd_size_type vfp11_erratum_glue_size;
2190214634Sdim
2191214082Sdim    /* An arbitrary input BFD chosen to hold the glue sections.  */
2192214082Sdim    bfd * bfd_of_glue_owner;
2193214082Sdim
2194214082Sdim    /* Nonzero to output a BE8 image.  */
2195214082Sdim    int byteswap_code;
2196214082Sdim
2197214082Sdim    /* Zero if R_ARM_TARGET1 means R_ARM_ABS32.
2198214634Sdim       Nonzero if R_ARM_TARGET1 means R_ARM_REL32.  */
2199214082Sdim    int target1_is_rel;
2200214082Sdim
2201214082Sdim    /* The relocation to use for R_ARM_TARGET2 relocations.  */
2202214082Sdim    int target2_reloc;
2203214082Sdim
2204214082Sdim    /* Nonzero to fix BX instructions for ARMv4 targets.  */
2205214082Sdim    int fix_v4bx;
2206214082Sdim
2207214082Sdim    /* Nonzero if the ARM/Thumb BLX instructions are available for use.  */
2208214082Sdim    int use_blx;
2209214082Sdim
2210214634Sdim    /* What sort of code sequences we should look for which may trigger the
2211214634Sdim       VFP11 denorm erratum.  */
2212214634Sdim    bfd_arm_vfp11_fix vfp11_fix;
2213214634Sdim
2214214634Sdim    /* Global counter for the number of fixes we have emitted.  */
2215214634Sdim    int num_vfp11_fixes;
2216214634Sdim
2217214634Sdim    /* Nonzero to force PIC branch veneers.  */
2218214634Sdim    int pic_veneer;
2219214634Sdim
2220214082Sdim    /* The number of bytes in the initial entry in the PLT.  */
2221214082Sdim    bfd_size_type plt_header_size;
2222214082Sdim
2223214082Sdim    /* The number of bytes in the subsequent PLT etries.  */
2224214082Sdim    bfd_size_type plt_entry_size;
2225214082Sdim
2226214082Sdim    /* True if the target system is VxWorks.  */
2227214082Sdim    int vxworks_p;
2228214082Sdim
2229214082Sdim    /* True if the target system is Symbian OS.  */
2230214082Sdim    int symbian_p;
2231214082Sdim
2232214082Sdim    /* True if the target uses REL relocations.  */
2233214082Sdim    int use_rel;
2234214082Sdim
2235214082Sdim    /* Short-cuts to get to dynamic linker sections.  */
2236214082Sdim    asection *sgot;
2237214082Sdim    asection *sgotplt;
2238214082Sdim    asection *srelgot;
2239214082Sdim    asection *splt;
2240214082Sdim    asection *srelplt;
2241214082Sdim    asection *sdynbss;
2242214082Sdim    asection *srelbss;
2243214082Sdim
2244214082Sdim    /* The (unloaded but important) VxWorks .rela.plt.unloaded section.  */
2245214082Sdim    asection *srelplt2;
2246214082Sdim
2247214082Sdim    /* Data for R_ARM_TLS_LDM32 relocations.  */
2248214082Sdim    union {
2249214082Sdim      bfd_signed_vma refcount;
2250214082Sdim      bfd_vma offset;
2251214082Sdim    } tls_ldm_got;
2252214082Sdim
2253214082Sdim    /* Small local sym to section mapping cache.  */
2254214082Sdim    struct sym_sec_cache sym_sec;
2255214082Sdim
2256214082Sdim    /* For convenience in allocate_dynrelocs.  */
2257214082Sdim    bfd * obfd;
2258214082Sdim  };
2259214082Sdim
2260214082Sdim/* Create an entry in an ARM ELF linker hash table.  */
2261214082Sdim
2262214082Sdimstatic struct bfd_hash_entry *
2263214082Sdimelf32_arm_link_hash_newfunc (struct bfd_hash_entry * entry,
2264214082Sdim                             struct bfd_hash_table * table,
2265214082Sdim                             const char * string)
2266214082Sdim{
2267214082Sdim  struct elf32_arm_link_hash_entry * ret =
2268214082Sdim    (struct elf32_arm_link_hash_entry *) entry;
2269214082Sdim
2270214082Sdim  /* Allocate the structure if it has not already been allocated by a
2271214082Sdim     subclass.  */
2272214082Sdim  if (ret == (struct elf32_arm_link_hash_entry *) NULL)
2273214082Sdim    ret = bfd_hash_allocate (table, sizeof (struct elf32_arm_link_hash_entry));
2274214082Sdim  if (ret == NULL)
2275214082Sdim    return (struct bfd_hash_entry *) ret;
2276214082Sdim
2277214082Sdim  /* Call the allocation method of the superclass.  */
2278214082Sdim  ret = ((struct elf32_arm_link_hash_entry *)
2279214082Sdim	 _bfd_elf_link_hash_newfunc ((struct bfd_hash_entry *) ret,
2280214082Sdim				     table, string));
2281214082Sdim  if (ret != NULL)
2282214082Sdim    {
2283214082Sdim      ret->relocs_copied = NULL;
2284214082Sdim      ret->tls_type = GOT_UNKNOWN;
2285214082Sdim      ret->plt_thumb_refcount = 0;
2286214082Sdim      ret->plt_got_offset = -1;
2287214634Sdim      ret->export_glue = NULL;
2288214082Sdim    }
2289214082Sdim
2290214082Sdim  return (struct bfd_hash_entry *) ret;
2291214082Sdim}
2292214082Sdim
2293214082Sdim/* Return true if NAME is the name of the relocation section associated
2294214082Sdim   with S.  */
2295214082Sdim
2296214082Sdimstatic bfd_boolean
2297214082Sdimreloc_section_p (struct elf32_arm_link_hash_table *htab,
2298214082Sdim		 const char *name, asection *s)
2299214082Sdim{
2300214082Sdim  if (htab->use_rel)
2301214634Sdim    return CONST_STRNEQ (name, ".rel") && strcmp (s->name, name + 4) == 0;
2302214082Sdim  else
2303214634Sdim    return CONST_STRNEQ (name, ".rela") && strcmp (s->name, name + 5) == 0;
2304214082Sdim}
2305214082Sdim
2306214082Sdim/* Create .got, .gotplt, and .rel(a).got sections in DYNOBJ, and set up
2307214082Sdim   shortcuts to them in our hash table.  */
2308214082Sdim
2309214082Sdimstatic bfd_boolean
2310214082Sdimcreate_got_section (bfd *dynobj, struct bfd_link_info *info)
2311214082Sdim{
2312214082Sdim  struct elf32_arm_link_hash_table *htab;
2313214082Sdim
2314214082Sdim  htab = elf32_arm_hash_table (info);
2315214082Sdim  /* BPABI objects never have a GOT, or associated sections.  */
2316214082Sdim  if (htab->symbian_p)
2317214082Sdim    return TRUE;
2318214082Sdim
2319214082Sdim  if (! _bfd_elf_create_got_section (dynobj, info))
2320214082Sdim    return FALSE;
2321214082Sdim
2322214082Sdim  htab->sgot = bfd_get_section_by_name (dynobj, ".got");
2323214082Sdim  htab->sgotplt = bfd_get_section_by_name (dynobj, ".got.plt");
2324214082Sdim  if (!htab->sgot || !htab->sgotplt)
2325214082Sdim    abort ();
2326214082Sdim
2327214082Sdim  htab->srelgot = bfd_make_section_with_flags (dynobj,
2328214082Sdim					       RELOC_SECTION (htab, ".got"),
2329214082Sdim					       (SEC_ALLOC | SEC_LOAD
2330214082Sdim						| SEC_HAS_CONTENTS
2331214082Sdim						| SEC_IN_MEMORY
2332214082Sdim						| SEC_LINKER_CREATED
2333214082Sdim						| SEC_READONLY));
2334214082Sdim  if (htab->srelgot == NULL
2335214082Sdim      || ! bfd_set_section_alignment (dynobj, htab->srelgot, 2))
2336214082Sdim    return FALSE;
2337214082Sdim  return TRUE;
2338214082Sdim}
2339214082Sdim
2340214082Sdim/* Create .plt, .rel(a).plt, .got, .got.plt, .rel(a).got, .dynbss, and
2341214082Sdim   .rel(a).bss sections in DYNOBJ, and set up shortcuts to them in our
2342214082Sdim   hash table.  */
2343214082Sdim
2344214082Sdimstatic bfd_boolean
2345214082Sdimelf32_arm_create_dynamic_sections (bfd *dynobj, struct bfd_link_info *info)
2346214082Sdim{
2347214082Sdim  struct elf32_arm_link_hash_table *htab;
2348214082Sdim
2349214082Sdim  htab = elf32_arm_hash_table (info);
2350214082Sdim  if (!htab->sgot && !create_got_section (dynobj, info))
2351214082Sdim    return FALSE;
2352214082Sdim
2353214082Sdim  if (!_bfd_elf_create_dynamic_sections (dynobj, info))
2354214082Sdim    return FALSE;
2355214082Sdim
2356214082Sdim  htab->splt = bfd_get_section_by_name (dynobj, ".plt");
2357214082Sdim  htab->srelplt = bfd_get_section_by_name (dynobj,
2358214082Sdim					   RELOC_SECTION (htab, ".plt"));
2359214082Sdim  htab->sdynbss = bfd_get_section_by_name (dynobj, ".dynbss");
2360214082Sdim  if (!info->shared)
2361214082Sdim    htab->srelbss = bfd_get_section_by_name (dynobj,
2362214082Sdim					     RELOC_SECTION (htab, ".bss"));
2363214082Sdim
2364214082Sdim  if (htab->vxworks_p)
2365214082Sdim    {
2366214082Sdim      if (!elf_vxworks_create_dynamic_sections (dynobj, info, &htab->srelplt2))
2367214082Sdim	return FALSE;
2368214082Sdim
2369214082Sdim      if (info->shared)
2370214082Sdim	{
2371214082Sdim	  htab->plt_header_size = 0;
2372214082Sdim	  htab->plt_entry_size
2373214082Sdim	    = 4 * ARRAY_SIZE (elf32_arm_vxworks_shared_plt_entry);
2374214082Sdim	}
2375214082Sdim      else
2376214082Sdim	{
2377214082Sdim	  htab->plt_header_size
2378214082Sdim	    = 4 * ARRAY_SIZE (elf32_arm_vxworks_exec_plt0_entry);
2379214082Sdim	  htab->plt_entry_size
2380214082Sdim	    = 4 * ARRAY_SIZE (elf32_arm_vxworks_exec_plt_entry);
2381214082Sdim	}
2382214082Sdim    }
2383214082Sdim
2384214082Sdim  if (!htab->splt
2385214082Sdim      || !htab->srelplt
2386214082Sdim      || !htab->sdynbss
2387214082Sdim      || (!info->shared && !htab->srelbss))
2388214082Sdim    abort ();
2389214082Sdim
2390214082Sdim  return TRUE;
2391214082Sdim}
2392214082Sdim
2393214082Sdim/* Copy the extra info we tack onto an elf_link_hash_entry.  */
2394214082Sdim
2395214082Sdimstatic void
2396214082Sdimelf32_arm_copy_indirect_symbol (struct bfd_link_info *info,
2397214082Sdim				struct elf_link_hash_entry *dir,
2398214082Sdim				struct elf_link_hash_entry *ind)
2399214082Sdim{
2400214082Sdim  struct elf32_arm_link_hash_entry *edir, *eind;
2401214082Sdim
2402214082Sdim  edir = (struct elf32_arm_link_hash_entry *) dir;
2403214082Sdim  eind = (struct elf32_arm_link_hash_entry *) ind;
2404214082Sdim
2405214082Sdim  if (eind->relocs_copied != NULL)
2406214082Sdim    {
2407214082Sdim      if (edir->relocs_copied != NULL)
2408214082Sdim	{
2409214082Sdim	  struct elf32_arm_relocs_copied **pp;
2410214082Sdim	  struct elf32_arm_relocs_copied *p;
2411214082Sdim
2412214082Sdim	  /* Add reloc counts against the indirect sym to the direct sym
2413214082Sdim	     list.  Merge any entries against the same section.  */
2414214082Sdim	  for (pp = &eind->relocs_copied; (p = *pp) != NULL; )
2415214082Sdim	    {
2416214082Sdim	      struct elf32_arm_relocs_copied *q;
2417214082Sdim
2418214082Sdim	      for (q = edir->relocs_copied; q != NULL; q = q->next)
2419214082Sdim		if (q->section == p->section)
2420214082Sdim		  {
2421214082Sdim		    q->pc_count += p->pc_count;
2422214082Sdim		    q->count += p->count;
2423214082Sdim		    *pp = p->next;
2424214082Sdim		    break;
2425214082Sdim		  }
2426214082Sdim	      if (q == NULL)
2427214082Sdim		pp = &p->next;
2428214082Sdim	    }
2429214082Sdim	  *pp = edir->relocs_copied;
2430214082Sdim	}
2431214082Sdim
2432214082Sdim      edir->relocs_copied = eind->relocs_copied;
2433214082Sdim      eind->relocs_copied = NULL;
2434214082Sdim    }
2435214082Sdim
2436214634Sdim  if (ind->root.type == bfd_link_hash_indirect)
2437214634Sdim    {
2438214634Sdim      /* Copy over PLT info.  */
2439214634Sdim      edir->plt_thumb_refcount += eind->plt_thumb_refcount;
2440214634Sdim      eind->plt_thumb_refcount = 0;
2441214082Sdim
2442214634Sdim      if (dir->got.refcount <= 0)
2443214634Sdim	{
2444214634Sdim	  edir->tls_type = eind->tls_type;
2445214634Sdim	  eind->tls_type = GOT_UNKNOWN;
2446214634Sdim	}
2447214082Sdim    }
2448214082Sdim
2449214082Sdim  _bfd_elf_link_hash_copy_indirect (info, dir, ind);
2450214082Sdim}
2451214082Sdim
2452214082Sdim/* Create an ARM elf linker hash table.  */
2453214082Sdim
2454214082Sdimstatic struct bfd_link_hash_table *
2455214082Sdimelf32_arm_link_hash_table_create (bfd *abfd)
2456214082Sdim{
2457214082Sdim  struct elf32_arm_link_hash_table *ret;
2458214082Sdim  bfd_size_type amt = sizeof (struct elf32_arm_link_hash_table);
2459214082Sdim
2460214082Sdim  ret = bfd_malloc (amt);
2461214082Sdim  if (ret == NULL)
2462214082Sdim    return NULL;
2463214082Sdim
2464214082Sdim  if (!_bfd_elf_link_hash_table_init (& ret->root, abfd,
2465214082Sdim				      elf32_arm_link_hash_newfunc,
2466214082Sdim				      sizeof (struct elf32_arm_link_hash_entry)))
2467214082Sdim    {
2468214082Sdim      free (ret);
2469214082Sdim      return NULL;
2470214082Sdim    }
2471214082Sdim
2472214082Sdim  ret->sgot = NULL;
2473214082Sdim  ret->sgotplt = NULL;
2474214082Sdim  ret->srelgot = NULL;
2475214082Sdim  ret->splt = NULL;
2476214082Sdim  ret->srelplt = NULL;
2477214082Sdim  ret->sdynbss = NULL;
2478214082Sdim  ret->srelbss = NULL;
2479214082Sdim  ret->srelplt2 = NULL;
2480214082Sdim  ret->thumb_glue_size = 0;
2481214082Sdim  ret->arm_glue_size = 0;
2482214634Sdim  ret->vfp11_fix = BFD_ARM_VFP11_FIX_NONE;
2483214634Sdim  ret->vfp11_erratum_glue_size = 0;
2484214634Sdim  ret->num_vfp11_fixes = 0;
2485214082Sdim  ret->bfd_of_glue_owner = NULL;
2486214082Sdim  ret->byteswap_code = 0;
2487214082Sdim  ret->target1_is_rel = 0;
2488214082Sdim  ret->target2_reloc = R_ARM_NONE;
2489214082Sdim#ifdef FOUR_WORD_PLT
2490214082Sdim  ret->plt_header_size = 16;
2491214082Sdim  ret->plt_entry_size = 16;
2492214082Sdim#else
2493214082Sdim  ret->plt_header_size = 20;
2494214082Sdim  ret->plt_entry_size = 12;
2495214082Sdim#endif
2496214082Sdim  ret->fix_v4bx = 0;
2497214082Sdim  ret->use_blx = 0;
2498214082Sdim  ret->vxworks_p = 0;
2499214082Sdim  ret->symbian_p = 0;
2500214082Sdim  ret->use_rel = 1;
2501214082Sdim  ret->sym_sec.abfd = NULL;
2502214082Sdim  ret->obfd = abfd;
2503214082Sdim  ret->tls_ldm_got.refcount = 0;
2504214082Sdim
2505214082Sdim  return &ret->root.root;
2506214082Sdim}
2507214082Sdim
2508214082Sdim/* Locate the Thumb encoded calling stub for NAME.  */
2509214082Sdim
2510214082Sdimstatic struct elf_link_hash_entry *
2511214082Sdimfind_thumb_glue (struct bfd_link_info *link_info,
2512214082Sdim		 const char *name,
2513214634Sdim		 char **error_message)
2514214082Sdim{
2515214082Sdim  char *tmp_name;
2516214082Sdim  struct elf_link_hash_entry *hash;
2517214082Sdim  struct elf32_arm_link_hash_table *hash_table;
2518214082Sdim
2519214082Sdim  /* We need a pointer to the armelf specific hash table.  */
2520214082Sdim  hash_table = elf32_arm_hash_table (link_info);
2521214082Sdim
2522214082Sdim  tmp_name = bfd_malloc ((bfd_size_type) strlen (name)
2523214082Sdim			 + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1);
2524214082Sdim
2525214082Sdim  BFD_ASSERT (tmp_name);
2526214082Sdim
2527214082Sdim  sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name);
2528214082Sdim
2529214082Sdim  hash = elf_link_hash_lookup
2530214082Sdim    (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE);
2531214082Sdim
2532214082Sdim  if (hash == NULL)
2533214634Sdim    asprintf (error_message, _("unable to find THUMB glue '%s' for '%s'"),
2534214634Sdim	      tmp_name, name);
2535214082Sdim
2536214082Sdim  free (tmp_name);
2537214082Sdim
2538214082Sdim  return hash;
2539214082Sdim}
2540214082Sdim
2541214082Sdim/* Locate the ARM encoded calling stub for NAME.  */
2542214082Sdim
2543214082Sdimstatic struct elf_link_hash_entry *
2544214082Sdimfind_arm_glue (struct bfd_link_info *link_info,
2545214082Sdim	       const char *name,
2546214634Sdim	       char **error_message)
2547214082Sdim{
2548214082Sdim  char *tmp_name;
2549214082Sdim  struct elf_link_hash_entry *myh;
2550214082Sdim  struct elf32_arm_link_hash_table *hash_table;
2551214082Sdim
2552214082Sdim  /* We need a pointer to the elfarm specific hash table.  */
2553214082Sdim  hash_table = elf32_arm_hash_table (link_info);
2554214082Sdim
2555214082Sdim  tmp_name = bfd_malloc ((bfd_size_type) strlen (name)
2556214082Sdim			 + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1);
2557214082Sdim
2558214082Sdim  BFD_ASSERT (tmp_name);
2559214082Sdim
2560214082Sdim  sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name);
2561214082Sdim
2562214082Sdim  myh = elf_link_hash_lookup
2563214082Sdim    (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE);
2564214082Sdim
2565214082Sdim  if (myh == NULL)
2566214634Sdim    asprintf (error_message, _("unable to find ARM glue '%s' for '%s'"),
2567214634Sdim	      tmp_name, name);
2568214082Sdim
2569214082Sdim  free (tmp_name);
2570214082Sdim
2571214082Sdim  return myh;
2572214082Sdim}
2573214082Sdim
2574214082Sdim/* ARM->Thumb glue (static images):
2575214082Sdim
2576214082Sdim   .arm
2577214082Sdim   __func_from_arm:
2578214082Sdim   ldr r12, __func_addr
2579214082Sdim   bx  r12
2580214082Sdim   __func_addr:
2581214082Sdim   .word func    @ behave as if you saw a ARM_32 reloc.
2582214082Sdim
2583214634Sdim   (v5t static images)
2584214634Sdim   .arm
2585214634Sdim   __func_from_arm:
2586214634Sdim   ldr pc, __func_addr
2587214634Sdim   __func_addr:
2588214634Sdim   .word func    @ behave as if you saw a ARM_32 reloc.
2589214634Sdim
2590214082Sdim   (relocatable images)
2591214082Sdim   .arm
2592214082Sdim   __func_from_arm:
2593214082Sdim   ldr r12, __func_offset
2594214082Sdim   add r12, r12, pc
2595214082Sdim   bx  r12
2596214082Sdim   __func_offset:
2597214082Sdim   .word func - .
2598214082Sdim   */
2599214082Sdim
2600214082Sdim#define ARM2THUMB_STATIC_GLUE_SIZE 12
2601214082Sdimstatic const insn32 a2t1_ldr_insn = 0xe59fc000;
2602214082Sdimstatic const insn32 a2t2_bx_r12_insn = 0xe12fff1c;
2603214082Sdimstatic const insn32 a2t3_func_addr_insn = 0x00000001;
2604214082Sdim
2605214634Sdim#define ARM2THUMB_V5_STATIC_GLUE_SIZE 8
2606214634Sdimstatic const insn32 a2t1v5_ldr_insn = 0xe51ff004;
2607214634Sdimstatic const insn32 a2t2v5_func_addr_insn = 0x00000001;
2608214634Sdim
2609214082Sdim#define ARM2THUMB_PIC_GLUE_SIZE 16
2610214082Sdimstatic const insn32 a2t1p_ldr_insn = 0xe59fc004;
2611214082Sdimstatic const insn32 a2t2p_add_pc_insn = 0xe08cc00f;
2612214082Sdimstatic const insn32 a2t3p_bx_r12_insn = 0xe12fff1c;
2613214082Sdim
2614214082Sdim/* Thumb->ARM:                          Thumb->(non-interworking aware) ARM
2615214082Sdim
2616214082Sdim   .thumb                               .thumb
2617214082Sdim   .align 2                             .align 2
2618214082Sdim   __func_from_thumb:              __func_from_thumb:
2619214082Sdim   bx pc                                push {r6, lr}
2620214082Sdim   nop                                  ldr  r6, __func_addr
2621214082Sdim   .arm                                         mov  lr, pc
2622214082Sdim   __func_change_to_arm:                        bx   r6
2623214082Sdim   b func                       .arm
2624214082Sdim   __func_back_to_thumb:
2625214082Sdim   ldmia r13! {r6, lr}
2626214082Sdim   bx    lr
2627214082Sdim   __func_addr:
2628214082Sdim   .word        func  */
2629214082Sdim
2630214082Sdim#define THUMB2ARM_GLUE_SIZE 8
2631214082Sdimstatic const insn16 t2a1_bx_pc_insn = 0x4778;
2632214082Sdimstatic const insn16 t2a2_noop_insn = 0x46c0;
2633214082Sdimstatic const insn32 t2a3_b_insn = 0xea000000;
2634214082Sdim
2635214634Sdim#define VFP11_ERRATUM_VENEER_SIZE 8
2636214634Sdim
2637214082Sdim#ifndef ELFARM_NABI_C_INCLUDED
2638214082Sdimbfd_boolean
2639214082Sdimbfd_elf32_arm_allocate_interworking_sections (struct bfd_link_info * info)
2640214082Sdim{
2641214082Sdim  asection * s;
2642214082Sdim  bfd_byte * foo;
2643214082Sdim  struct elf32_arm_link_hash_table * globals;
2644214082Sdim
2645214082Sdim  globals = elf32_arm_hash_table (info);
2646214082Sdim
2647214082Sdim  BFD_ASSERT (globals != NULL);
2648214082Sdim
2649214082Sdim  if (globals->arm_glue_size != 0)
2650214082Sdim    {
2651214082Sdim      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
2652214082Sdim
2653214082Sdim      s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
2654214082Sdim				   ARM2THUMB_GLUE_SECTION_NAME);
2655214082Sdim
2656214082Sdim      BFD_ASSERT (s != NULL);
2657214082Sdim
2658214082Sdim      foo = bfd_alloc (globals->bfd_of_glue_owner, globals->arm_glue_size);
2659214082Sdim
2660214634Sdim      BFD_ASSERT (s->size == globals->arm_glue_size);
2661214082Sdim      s->contents = foo;
2662214082Sdim    }
2663214082Sdim
2664214082Sdim  if (globals->thumb_glue_size != 0)
2665214082Sdim    {
2666214082Sdim      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
2667214082Sdim
2668214082Sdim      s = bfd_get_section_by_name
2669214082Sdim	(globals->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME);
2670214082Sdim
2671214082Sdim      BFD_ASSERT (s != NULL);
2672214082Sdim
2673214082Sdim      foo = bfd_alloc (globals->bfd_of_glue_owner, globals->thumb_glue_size);
2674214082Sdim
2675214634Sdim      BFD_ASSERT (s->size == globals->thumb_glue_size);
2676214082Sdim      s->contents = foo;
2677214082Sdim    }
2678214634Sdim
2679214634Sdim  if (globals->vfp11_erratum_glue_size != 0)
2680214634Sdim    {
2681214634Sdim      BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
2682214634Sdim
2683214634Sdim      s = bfd_get_section_by_name
2684214634Sdim        (globals->bfd_of_glue_owner, VFP11_ERRATUM_VENEER_SECTION_NAME);
2685214634Sdim
2686214634Sdim      BFD_ASSERT (s != NULL);
2687214634Sdim
2688214634Sdim      foo = bfd_alloc (globals->bfd_of_glue_owner,
2689214634Sdim		       globals->vfp11_erratum_glue_size);
2690214634Sdim
2691214634Sdim      BFD_ASSERT (s->size == globals->vfp11_erratum_glue_size);
2692214634Sdim      s->contents = foo;
2693214634Sdim    }
2694214082Sdim
2695214082Sdim  return TRUE;
2696214082Sdim}
2697214082Sdim
2698214634Sdim/* Allocate space and symbols for calling a Thumb function from Arm mode.
2699214634Sdim   returns the symbol identifying teh stub.  */
2700214634Sdimstatic struct elf_link_hash_entry *
2701214082Sdimrecord_arm_to_thumb_glue (struct bfd_link_info * link_info,
2702214082Sdim			  struct elf_link_hash_entry * h)
2703214082Sdim{
2704214082Sdim  const char * name = h->root.root.string;
2705214082Sdim  asection * s;
2706214082Sdim  char * tmp_name;
2707214082Sdim  struct elf_link_hash_entry * myh;
2708214082Sdim  struct bfd_link_hash_entry * bh;
2709214082Sdim  struct elf32_arm_link_hash_table * globals;
2710214082Sdim  bfd_vma val;
2711214634Sdim  bfd_size_type size;
2712214082Sdim
2713214082Sdim  globals = elf32_arm_hash_table (link_info);
2714214082Sdim
2715214082Sdim  BFD_ASSERT (globals != NULL);
2716214082Sdim  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
2717214082Sdim
2718214082Sdim  s = bfd_get_section_by_name
2719214082Sdim    (globals->bfd_of_glue_owner, ARM2THUMB_GLUE_SECTION_NAME);
2720214082Sdim
2721214082Sdim  BFD_ASSERT (s != NULL);
2722214082Sdim
2723214082Sdim  tmp_name = bfd_malloc ((bfd_size_type) strlen (name) + strlen (ARM2THUMB_GLUE_ENTRY_NAME) + 1);
2724214082Sdim
2725214082Sdim  BFD_ASSERT (tmp_name);
2726214082Sdim
2727214082Sdim  sprintf (tmp_name, ARM2THUMB_GLUE_ENTRY_NAME, name);
2728214082Sdim
2729214082Sdim  myh = elf_link_hash_lookup
2730214082Sdim    (&(globals)->root, tmp_name, FALSE, FALSE, TRUE);
2731214082Sdim
2732214082Sdim  if (myh != NULL)
2733214082Sdim    {
2734214082Sdim      /* We've already seen this guy.  */
2735214082Sdim      free (tmp_name);
2736214634Sdim      return myh;
2737214082Sdim    }
2738214082Sdim
2739214082Sdim  /* The only trick here is using hash_table->arm_glue_size as the value.
2740214082Sdim     Even though the section isn't allocated yet, this is where we will be
2741214082Sdim     putting it.  */
2742214082Sdim  bh = NULL;
2743214082Sdim  val = globals->arm_glue_size + 1;
2744214082Sdim  _bfd_generic_link_add_one_symbol (link_info, globals->bfd_of_glue_owner,
2745214082Sdim				    tmp_name, BSF_GLOBAL, s, val,
2746214082Sdim				    NULL, TRUE, FALSE, &bh);
2747214082Sdim
2748214082Sdim  myh = (struct elf_link_hash_entry *) bh;
2749214082Sdim  myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
2750214082Sdim  myh->forced_local = 1;
2751214082Sdim
2752214082Sdim  free (tmp_name);
2753214082Sdim
2754214634Sdim  if (link_info->shared || globals->root.is_relocatable_executable
2755214634Sdim      || globals->pic_veneer)
2756214634Sdim    size = ARM2THUMB_PIC_GLUE_SIZE;
2757214634Sdim  else if (globals->use_blx)
2758214634Sdim    size = ARM2THUMB_V5_STATIC_GLUE_SIZE;
2759214082Sdim  else
2760214634Sdim    size = ARM2THUMB_STATIC_GLUE_SIZE;
2761214082Sdim
2762214634Sdim  s->size += size;
2763214634Sdim  globals->arm_glue_size += size;
2764214634Sdim
2765214634Sdim  return myh;
2766214082Sdim}
2767214082Sdim
2768214082Sdimstatic void
2769214082Sdimrecord_thumb_to_arm_glue (struct bfd_link_info *link_info,
2770214082Sdim			  struct elf_link_hash_entry *h)
2771214082Sdim{
2772214082Sdim  const char *name = h->root.root.string;
2773214082Sdim  asection *s;
2774214082Sdim  char *tmp_name;
2775214082Sdim  struct elf_link_hash_entry *myh;
2776214082Sdim  struct bfd_link_hash_entry *bh;
2777214082Sdim  struct elf32_arm_link_hash_table *hash_table;
2778214082Sdim  bfd_vma val;
2779214082Sdim
2780214082Sdim  hash_table = elf32_arm_hash_table (link_info);
2781214082Sdim
2782214082Sdim  BFD_ASSERT (hash_table != NULL);
2783214082Sdim  BFD_ASSERT (hash_table->bfd_of_glue_owner != NULL);
2784214082Sdim
2785214082Sdim  s = bfd_get_section_by_name
2786214082Sdim    (hash_table->bfd_of_glue_owner, THUMB2ARM_GLUE_SECTION_NAME);
2787214082Sdim
2788214082Sdim  BFD_ASSERT (s != NULL);
2789214082Sdim
2790214082Sdim  tmp_name = bfd_malloc ((bfd_size_type) strlen (name)
2791214082Sdim			 + strlen (THUMB2ARM_GLUE_ENTRY_NAME) + 1);
2792214082Sdim
2793214082Sdim  BFD_ASSERT (tmp_name);
2794214082Sdim
2795214082Sdim  sprintf (tmp_name, THUMB2ARM_GLUE_ENTRY_NAME, name);
2796214082Sdim
2797214082Sdim  myh = elf_link_hash_lookup
2798214082Sdim    (&(hash_table)->root, tmp_name, FALSE, FALSE, TRUE);
2799214082Sdim
2800214082Sdim  if (myh != NULL)
2801214082Sdim    {
2802214082Sdim      /* We've already seen this guy.  */
2803214082Sdim      free (tmp_name);
2804214082Sdim      return;
2805214082Sdim    }
2806214082Sdim
2807214082Sdim  bh = NULL;
2808214082Sdim  val = hash_table->thumb_glue_size + 1;
2809214082Sdim  _bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner,
2810214082Sdim				    tmp_name, BSF_GLOBAL, s, val,
2811214082Sdim				    NULL, TRUE, FALSE, &bh);
2812214082Sdim
2813214082Sdim  /* If we mark it 'Thumb', the disassembler will do a better job.  */
2814214082Sdim  myh = (struct elf_link_hash_entry *) bh;
2815214082Sdim  myh->type = ELF_ST_INFO (STB_LOCAL, STT_ARM_TFUNC);
2816214082Sdim  myh->forced_local = 1;
2817214082Sdim
2818214082Sdim  free (tmp_name);
2819214082Sdim
2820214082Sdim#define CHANGE_TO_ARM "__%s_change_to_arm"
2821214082Sdim#define BACK_FROM_ARM "__%s_back_from_arm"
2822214082Sdim
2823214082Sdim  /* Allocate another symbol to mark where we switch to Arm mode.  */
2824214082Sdim  tmp_name = bfd_malloc ((bfd_size_type) strlen (name)
2825214082Sdim			 + strlen (CHANGE_TO_ARM) + 1);
2826214082Sdim
2827214082Sdim  BFD_ASSERT (tmp_name);
2828214082Sdim
2829214082Sdim  sprintf (tmp_name, CHANGE_TO_ARM, name);
2830214082Sdim
2831214082Sdim  bh = NULL;
2832214082Sdim  val = hash_table->thumb_glue_size + 4,
2833214082Sdim  _bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner,
2834214082Sdim				    tmp_name, BSF_LOCAL, s, val,
2835214082Sdim				    NULL, TRUE, FALSE, &bh);
2836214082Sdim
2837214082Sdim  free (tmp_name);
2838214082Sdim
2839214634Sdim  s->size += THUMB2ARM_GLUE_SIZE;
2840214082Sdim  hash_table->thumb_glue_size += THUMB2ARM_GLUE_SIZE;
2841214082Sdim
2842214082Sdim  return;
2843214082Sdim}
2844214082Sdim
2845214634Sdim
2846214634Sdim/* Add an entry to the code/data map for section SEC.  */
2847214634Sdim
2848214634Sdimstatic void
2849214634Sdimelf32_arm_section_map_add (asection *sec, char type, bfd_vma vma)
2850214634Sdim{
2851214634Sdim  struct _arm_elf_section_data *sec_data = elf32_arm_section_data (sec);
2852214634Sdim  unsigned int newidx;
2853214634Sdim
2854214634Sdim  if (sec_data->map == NULL)
2855214634Sdim    {
2856214634Sdim      sec_data->map = bfd_malloc (sizeof (elf32_arm_section_map));
2857214634Sdim      sec_data->mapcount = 0;
2858214634Sdim      sec_data->mapsize = 1;
2859214634Sdim    }
2860214634Sdim
2861214634Sdim  newidx = sec_data->mapcount++;
2862214634Sdim
2863214634Sdim  if (sec_data->mapcount > sec_data->mapsize)
2864214634Sdim    {
2865214634Sdim      sec_data->mapsize *= 2;
2866214634Sdim      sec_data->map = bfd_realloc (sec_data->map, sec_data->mapsize
2867214634Sdim				     * sizeof (elf32_arm_section_map));
2868214634Sdim    }
2869214634Sdim
2870214634Sdim  sec_data->map[newidx].vma = vma;
2871214634Sdim  sec_data->map[newidx].type = type;
2872214634Sdim}
2873214634Sdim
2874214634Sdim
2875214634Sdim/* Record information about a VFP11 denorm-erratum veneer.  Only ARM-mode
2876214634Sdim   veneers are handled for now.  */
2877214634Sdim
2878214634Sdimstatic bfd_vma
2879214634Sdimrecord_vfp11_erratum_veneer (struct bfd_link_info *link_info,
2880214634Sdim                             elf32_vfp11_erratum_list *branch,
2881214634Sdim                             bfd *branch_bfd,
2882214634Sdim                             asection *branch_sec,
2883214634Sdim                             unsigned int offset)
2884214634Sdim{
2885214634Sdim  asection *s;
2886214634Sdim  struct elf32_arm_link_hash_table *hash_table;
2887214634Sdim  char *tmp_name;
2888214634Sdim  struct elf_link_hash_entry *myh;
2889214634Sdim  struct bfd_link_hash_entry *bh;
2890214634Sdim  bfd_vma val;
2891214634Sdim  struct _arm_elf_section_data *sec_data;
2892214634Sdim  int errcount;
2893214634Sdim  elf32_vfp11_erratum_list *newerr;
2894214634Sdim
2895214634Sdim  hash_table = elf32_arm_hash_table (link_info);
2896214634Sdim
2897214634Sdim  BFD_ASSERT (hash_table != NULL);
2898214634Sdim  BFD_ASSERT (hash_table->bfd_of_glue_owner != NULL);
2899214634Sdim
2900214634Sdim  s = bfd_get_section_by_name
2901214634Sdim    (hash_table->bfd_of_glue_owner, VFP11_ERRATUM_VENEER_SECTION_NAME);
2902214634Sdim
2903214634Sdim  sec_data = elf32_arm_section_data (s);
2904214634Sdim
2905214634Sdim  BFD_ASSERT (s != NULL);
2906214634Sdim
2907214634Sdim  tmp_name = bfd_malloc ((bfd_size_type) strlen
2908214634Sdim			 (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10);
2909214634Sdim
2910214634Sdim  BFD_ASSERT (tmp_name);
2911214634Sdim
2912214634Sdim  sprintf (tmp_name, VFP11_ERRATUM_VENEER_ENTRY_NAME,
2913214634Sdim	   hash_table->num_vfp11_fixes);
2914214634Sdim
2915214634Sdim  myh = elf_link_hash_lookup
2916214634Sdim    (&(hash_table)->root, tmp_name, FALSE, FALSE, FALSE);
2917214634Sdim
2918214634Sdim  BFD_ASSERT (myh == NULL);
2919214634Sdim
2920214634Sdim  bh = NULL;
2921214634Sdim  val = hash_table->vfp11_erratum_glue_size;
2922214634Sdim  _bfd_generic_link_add_one_symbol (link_info, hash_table->bfd_of_glue_owner,
2923214634Sdim                                    tmp_name, BSF_FUNCTION | BSF_LOCAL, s, val,
2924214634Sdim                                    NULL, TRUE, FALSE, &bh);
2925214634Sdim
2926214634Sdim  myh = (struct elf_link_hash_entry *) bh;
2927214634Sdim  myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
2928214634Sdim  myh->forced_local = 1;
2929214634Sdim
2930214634Sdim  /* Link veneer back to calling location.  */
2931214634Sdim  errcount = ++(sec_data->erratumcount);
2932214634Sdim  newerr = bfd_zmalloc (sizeof (elf32_vfp11_erratum_list));
2933214634Sdim
2934214634Sdim  newerr->type = VFP11_ERRATUM_ARM_VENEER;
2935214634Sdim  newerr->vma = -1;
2936214634Sdim  newerr->u.v.branch = branch;
2937214634Sdim  newerr->u.v.id = hash_table->num_vfp11_fixes;
2938214634Sdim  branch->u.b.veneer = newerr;
2939214634Sdim
2940214634Sdim  newerr->next = sec_data->erratumlist;
2941214634Sdim  sec_data->erratumlist = newerr;
2942214634Sdim
2943214634Sdim  /* A symbol for the return from the veneer.  */
2944214634Sdim  sprintf (tmp_name, VFP11_ERRATUM_VENEER_ENTRY_NAME "_r",
2945214634Sdim	   hash_table->num_vfp11_fixes);
2946214634Sdim
2947214634Sdim  myh = elf_link_hash_lookup
2948214634Sdim    (&(hash_table)->root, tmp_name, FALSE, FALSE, FALSE);
2949214634Sdim
2950214634Sdim  if (myh != NULL)
2951214634Sdim    abort ();
2952214634Sdim
2953214634Sdim  bh = NULL;
2954214634Sdim  val = offset + 4;
2955214634Sdim  _bfd_generic_link_add_one_symbol (link_info, branch_bfd, tmp_name, BSF_LOCAL,
2956214634Sdim				    branch_sec, val, NULL, TRUE, FALSE, &bh);
2957214634Sdim
2958214634Sdim  myh = (struct elf_link_hash_entry *) bh;
2959214634Sdim  myh->type = ELF_ST_INFO (STB_LOCAL, STT_FUNC);
2960214634Sdim  myh->forced_local = 1;
2961214634Sdim
2962214634Sdim  free (tmp_name);
2963214634Sdim
2964214634Sdim  /* Generate a mapping symbol for the veneer section, and explicitly add an
2965214634Sdim     entry for that symbol to the code/data map for the section.  */
2966214634Sdim  if (hash_table->vfp11_erratum_glue_size == 0)
2967214634Sdim    {
2968214634Sdim      bh = NULL;
2969214634Sdim      /* FIXME: Creates an ARM symbol.  Thumb mode will need attention if it
2970214634Sdim         ever requires this erratum fix.  */
2971214634Sdim      _bfd_generic_link_add_one_symbol (link_info,
2972214634Sdim					hash_table->bfd_of_glue_owner, "$a",
2973214634Sdim					BSF_LOCAL, s, 0, NULL,
2974214634Sdim                                        TRUE, FALSE, &bh);
2975214634Sdim
2976214634Sdim      myh = (struct elf_link_hash_entry *) bh;
2977214634Sdim      myh->type = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE);
2978214634Sdim      myh->forced_local = 1;
2979214634Sdim
2980214634Sdim      /* The elf32_arm_init_maps function only cares about symbols from input
2981214634Sdim         BFDs.  We must make a note of this generated mapping symbol
2982214634Sdim         ourselves so that code byteswapping works properly in
2983214634Sdim         elf32_arm_write_section.  */
2984214634Sdim      elf32_arm_section_map_add (s, 'a', 0);
2985214634Sdim    }
2986214634Sdim
2987214634Sdim  s->size += VFP11_ERRATUM_VENEER_SIZE;
2988214634Sdim  hash_table->vfp11_erratum_glue_size += VFP11_ERRATUM_VENEER_SIZE;
2989214634Sdim  hash_table->num_vfp11_fixes++;
2990214634Sdim
2991214634Sdim  /* The offset of the veneer.  */
2992214634Sdim  return val;
2993214634Sdim}
2994214634Sdim
2995214082Sdim/* Add the glue sections to ABFD.  This function is called from the
2996214082Sdim   linker scripts in ld/emultempl/{armelf}.em.  */
2997214082Sdim
2998214082Sdimbfd_boolean
2999214082Sdimbfd_elf32_arm_add_glue_sections_to_bfd (bfd *abfd,
3000214082Sdim					struct bfd_link_info *info)
3001214082Sdim{
3002214082Sdim  flagword flags;
3003214082Sdim  asection *sec;
3004214082Sdim
3005214082Sdim  /* If we are only performing a partial
3006214082Sdim     link do not bother adding the glue.  */
3007214082Sdim  if (info->relocatable)
3008214082Sdim    return TRUE;
3009214082Sdim
3010214082Sdim  sec = bfd_get_section_by_name (abfd, ARM2THUMB_GLUE_SECTION_NAME);
3011214082Sdim
3012214082Sdim  if (sec == NULL)
3013214082Sdim    {
3014214082Sdim      /* Note: we do not include the flag SEC_LINKER_CREATED, as this
3015214082Sdim	 will prevent elf_link_input_bfd() from processing the contents
3016214082Sdim	 of this section.  */
3017214634Sdim      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
3018214634Sdim	       | SEC_CODE | SEC_READONLY);
3019214082Sdim
3020214082Sdim      sec = bfd_make_section_with_flags (abfd,
3021214082Sdim					 ARM2THUMB_GLUE_SECTION_NAME,
3022214082Sdim					 flags);
3023214082Sdim
3024214082Sdim      if (sec == NULL
3025214082Sdim	  || !bfd_set_section_alignment (abfd, sec, 2))
3026214082Sdim	return FALSE;
3027214082Sdim
3028214082Sdim      /* Set the gc mark to prevent the section from being removed by garbage
3029214082Sdim	 collection, despite the fact that no relocs refer to this section.  */
3030214082Sdim      sec->gc_mark = 1;
3031214082Sdim    }
3032214082Sdim
3033214082Sdim  sec = bfd_get_section_by_name (abfd, THUMB2ARM_GLUE_SECTION_NAME);
3034214082Sdim
3035214082Sdim  if (sec == NULL)
3036214082Sdim    {
3037214634Sdim      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
3038214634Sdim	       | SEC_CODE | SEC_READONLY);
3039214082Sdim
3040214082Sdim      sec = bfd_make_section_with_flags (abfd,
3041214082Sdim					 THUMB2ARM_GLUE_SECTION_NAME,
3042214082Sdim					 flags);
3043214082Sdim
3044214082Sdim      if (sec == NULL
3045214082Sdim	  || !bfd_set_section_alignment (abfd, sec, 2))
3046214082Sdim	return FALSE;
3047214082Sdim
3048214082Sdim      sec->gc_mark = 1;
3049214082Sdim    }
3050214082Sdim
3051214634Sdim  sec = bfd_get_section_by_name (abfd, VFP11_ERRATUM_VENEER_SECTION_NAME);
3052214634Sdim
3053214634Sdim  if (sec == NULL)
3054214634Sdim    {
3055214634Sdim      flags = (SEC_ALLOC | SEC_LOAD | SEC_HAS_CONTENTS | SEC_IN_MEMORY
3056214634Sdim	       | SEC_CODE | SEC_READONLY);
3057214634Sdim
3058214634Sdim      sec = bfd_make_section_with_flags (abfd,
3059214634Sdim					 VFP11_ERRATUM_VENEER_SECTION_NAME,
3060214634Sdim                                         flags);
3061214634Sdim
3062214634Sdim      if (sec == NULL
3063214634Sdim	  || !bfd_set_section_alignment (abfd, sec, 2))
3064214634Sdim	return FALSE;
3065214634Sdim
3066214634Sdim      sec->gc_mark = 1;
3067214634Sdim    }
3068214634Sdim
3069214082Sdim  return TRUE;
3070214082Sdim}
3071214082Sdim
3072214082Sdim/* Select a BFD to be used to hold the sections used by the glue code.
3073214082Sdim   This function is called from the linker scripts in ld/emultempl/
3074214082Sdim   {armelf/pe}.em  */
3075214082Sdim
3076214082Sdimbfd_boolean
3077214082Sdimbfd_elf32_arm_get_bfd_for_interworking (bfd *abfd, struct bfd_link_info *info)
3078214082Sdim{
3079214082Sdim  struct elf32_arm_link_hash_table *globals;
3080214082Sdim
3081214082Sdim  /* If we are only performing a partial link
3082214082Sdim     do not bother getting a bfd to hold the glue.  */
3083214082Sdim  if (info->relocatable)
3084214082Sdim    return TRUE;
3085214082Sdim
3086214082Sdim  /* Make sure we don't attach the glue sections to a dynamic object.  */
3087214082Sdim  BFD_ASSERT (!(abfd->flags & DYNAMIC));
3088214082Sdim
3089214082Sdim  globals = elf32_arm_hash_table (info);
3090214082Sdim
3091214082Sdim  BFD_ASSERT (globals != NULL);
3092214082Sdim
3093214082Sdim  if (globals->bfd_of_glue_owner != NULL)
3094214082Sdim    return TRUE;
3095214082Sdim
3096214082Sdim  /* Save the bfd for later use.  */
3097214082Sdim  globals->bfd_of_glue_owner = abfd;
3098214082Sdim
3099214082Sdim  return TRUE;
3100214082Sdim}
3101214082Sdim
3102214082Sdimstatic void check_use_blx(struct elf32_arm_link_hash_table *globals)
3103214082Sdim{
3104214634Sdim  if (bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
3105214634Sdim				Tag_CPU_arch) > 2)
3106214082Sdim    globals->use_blx = 1;
3107214082Sdim}
3108214082Sdim
3109214082Sdimbfd_boolean
3110214082Sdimbfd_elf32_arm_process_before_allocation (bfd *abfd,
3111214634Sdim					 struct bfd_link_info *link_info)
3112214082Sdim{
3113214082Sdim  Elf_Internal_Shdr *symtab_hdr;
3114214082Sdim  Elf_Internal_Rela *internal_relocs = NULL;
3115214082Sdim  Elf_Internal_Rela *irel, *irelend;
3116214082Sdim  bfd_byte *contents = NULL;
3117214082Sdim
3118214082Sdim  asection *sec;
3119214082Sdim  struct elf32_arm_link_hash_table *globals;
3120214082Sdim
3121214082Sdim  /* If we are only performing a partial link do not bother
3122214082Sdim     to construct any glue.  */
3123214082Sdim  if (link_info->relocatable)
3124214082Sdim    return TRUE;
3125214082Sdim
3126214082Sdim  /* Here we have a bfd that is to be included on the link.  We have a hook
3127214082Sdim     to do reloc rummaging, before section sizes are nailed down.  */
3128214082Sdim  globals = elf32_arm_hash_table (link_info);
3129214082Sdim  check_use_blx (globals);
3130214082Sdim
3131214082Sdim  BFD_ASSERT (globals != NULL);
3132214082Sdim  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
3133214082Sdim
3134214634Sdim  if (globals->byteswap_code && !bfd_big_endian (abfd))
3135214082Sdim    {
3136214082Sdim      _bfd_error_handler (_("%B: BE8 images only valid in big-endian mode."),
3137214082Sdim			  abfd);
3138214082Sdim      return FALSE;
3139214082Sdim    }
3140214082Sdim
3141214082Sdim  /* Rummage around all the relocs and map the glue vectors.  */
3142214082Sdim  sec = abfd->sections;
3143214082Sdim
3144214082Sdim  if (sec == NULL)
3145214082Sdim    return TRUE;
3146214082Sdim
3147214082Sdim  for (; sec != NULL; sec = sec->next)
3148214082Sdim    {
3149214082Sdim      if (sec->reloc_count == 0)
3150214082Sdim	continue;
3151214082Sdim
3152214634Sdim      if ((sec->flags & SEC_EXCLUDE) != 0)
3153214634Sdim	continue;
3154214634Sdim
3155214082Sdim      symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
3156214082Sdim
3157214082Sdim      /* Load the relocs.  */
3158214082Sdim      internal_relocs
3159214082Sdim	= _bfd_elf_link_read_relocs (abfd, sec, (void *) NULL,
3160214082Sdim				     (Elf_Internal_Rela *) NULL, FALSE);
3161214082Sdim
3162214082Sdim      if (internal_relocs == NULL)
3163214082Sdim	goto error_return;
3164214082Sdim
3165214082Sdim      irelend = internal_relocs + sec->reloc_count;
3166214082Sdim      for (irel = internal_relocs; irel < irelend; irel++)
3167214082Sdim	{
3168214082Sdim	  long r_type;
3169214082Sdim	  unsigned long r_index;
3170214082Sdim
3171214082Sdim	  struct elf_link_hash_entry *h;
3172214082Sdim
3173214082Sdim	  r_type = ELF32_R_TYPE (irel->r_info);
3174214082Sdim	  r_index = ELF32_R_SYM (irel->r_info);
3175214082Sdim
3176214082Sdim	  /* These are the only relocation types we care about.  */
3177214082Sdim	  if (   r_type != R_ARM_PC24
3178214082Sdim	      && r_type != R_ARM_PLT32
3179214082Sdim	      && r_type != R_ARM_CALL
3180214082Sdim	      && r_type != R_ARM_JUMP24
3181214082Sdim	      && r_type != R_ARM_THM_CALL)
3182214082Sdim	    continue;
3183214082Sdim
3184214082Sdim	  /* Get the section contents if we haven't done so already.  */
3185214082Sdim	  if (contents == NULL)
3186214082Sdim	    {
3187214082Sdim	      /* Get cached copy if it exists.  */
3188214082Sdim	      if (elf_section_data (sec)->this_hdr.contents != NULL)
3189214082Sdim		contents = elf_section_data (sec)->this_hdr.contents;
3190214082Sdim	      else
3191214082Sdim		{
3192214082Sdim		  /* Go get them off disk.  */
3193214082Sdim		  if (! bfd_malloc_and_get_section (abfd, sec, &contents))
3194214082Sdim		    goto error_return;
3195214082Sdim		}
3196214082Sdim	    }
3197214082Sdim
3198214082Sdim	  /* If the relocation is not against a symbol it cannot concern us.  */
3199214082Sdim	  h = NULL;
3200214082Sdim
3201214082Sdim	  /* We don't care about local symbols.  */
3202214082Sdim	  if (r_index < symtab_hdr->sh_info)
3203214082Sdim	    continue;
3204214082Sdim
3205214082Sdim	  /* This is an external symbol.  */
3206214082Sdim	  r_index -= symtab_hdr->sh_info;
3207214082Sdim	  h = (struct elf_link_hash_entry *)
3208214082Sdim	    elf_sym_hashes (abfd)[r_index];
3209214082Sdim
3210214082Sdim	  /* If the relocation is against a static symbol it must be within
3211214082Sdim	     the current section and so cannot be a cross ARM/Thumb relocation.  */
3212214082Sdim	  if (h == NULL)
3213214082Sdim	    continue;
3214214082Sdim
3215214082Sdim	  /* If the call will go through a PLT entry then we do not need
3216214082Sdim	     glue.  */
3217214082Sdim	  if (globals->splt != NULL && h->plt.offset != (bfd_vma) -1)
3218214082Sdim	    continue;
3219214082Sdim
3220214082Sdim	  switch (r_type)
3221214082Sdim	    {
3222214082Sdim	    case R_ARM_PC24:
3223214082Sdim	    case R_ARM_PLT32:
3224214082Sdim	    case R_ARM_CALL:
3225214082Sdim	    case R_ARM_JUMP24:
3226214082Sdim	      /* This one is a call from arm code.  We need to look up
3227214082Sdim	         the target of the call.  If it is a thumb target, we
3228214082Sdim	         insert glue.  */
3229214082Sdim	      if (ELF_ST_TYPE(h->type) == STT_ARM_TFUNC
3230214082Sdim		  && !(r_type == R_ARM_CALL && globals->use_blx))
3231214082Sdim		record_arm_to_thumb_glue (link_info, h);
3232214082Sdim	      break;
3233214082Sdim
3234214082Sdim	    case R_ARM_THM_CALL:
3235214082Sdim	      /* This one is a call from thumb code.  We look
3236214082Sdim	         up the target of the call.  If it is not a thumb
3237214082Sdim                 target, we insert glue.  */
3238214634Sdim	      if (ELF_ST_TYPE (h->type) != STT_ARM_TFUNC && !globals->use_blx
3239214634Sdim		  && h->root.type != bfd_link_hash_undefweak)
3240214082Sdim		record_thumb_to_arm_glue (link_info, h);
3241214082Sdim	      break;
3242214082Sdim
3243214082Sdim	    default:
3244214082Sdim	      abort ();
3245214082Sdim	    }
3246214082Sdim	}
3247214082Sdim
3248214082Sdim      if (contents != NULL
3249214082Sdim	  && elf_section_data (sec)->this_hdr.contents != contents)
3250214082Sdim	free (contents);
3251214082Sdim      contents = NULL;
3252214082Sdim
3253214082Sdim      if (internal_relocs != NULL
3254214082Sdim	  && elf_section_data (sec)->relocs != internal_relocs)
3255214082Sdim	free (internal_relocs);
3256214082Sdim      internal_relocs = NULL;
3257214082Sdim    }
3258214082Sdim
3259214082Sdim  return TRUE;
3260214082Sdim
3261214082Sdimerror_return:
3262214082Sdim  if (contents != NULL
3263214082Sdim      && elf_section_data (sec)->this_hdr.contents != contents)
3264214082Sdim    free (contents);
3265214082Sdim  if (internal_relocs != NULL
3266214082Sdim      && elf_section_data (sec)->relocs != internal_relocs)
3267214082Sdim    free (internal_relocs);
3268214082Sdim
3269214082Sdim  return FALSE;
3270214082Sdim}
3271214082Sdim#endif
3272214082Sdim
3273214082Sdim
3274214634Sdim/* Initialise maps of ARM/Thumb/data for input BFDs.  */
3275214634Sdim
3276214634Sdimvoid
3277214634Sdimbfd_elf32_arm_init_maps (bfd *abfd)
3278214634Sdim{
3279214634Sdim  Elf_Internal_Sym *isymbuf;
3280214634Sdim  Elf_Internal_Shdr *hdr;
3281214634Sdim  unsigned int i, localsyms;
3282214634Sdim
3283214751Sdim  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour || elf_tdata (abfd) == NULL)
3284214751Sdim    return;
3285214751Sdim
3286214634Sdim  if ((abfd->flags & DYNAMIC) != 0)
3287214634Sdim    return;
3288214634Sdim
3289214634Sdim  hdr = &elf_tdata (abfd)->symtab_hdr;
3290214634Sdim  localsyms = hdr->sh_info;
3291214634Sdim
3292214634Sdim  /* Obtain a buffer full of symbols for this BFD. The hdr->sh_info field
3293214634Sdim     should contain the number of local symbols, which should come before any
3294214634Sdim     global symbols.  Mapping symbols are always local.  */
3295214634Sdim  isymbuf = bfd_elf_get_elf_syms (abfd, hdr, localsyms, 0, NULL, NULL,
3296214634Sdim				  NULL);
3297214634Sdim
3298214634Sdim  /* No internal symbols read?  Skip this BFD.  */
3299214634Sdim  if (isymbuf == NULL)
3300214634Sdim    return;
3301214634Sdim
3302214634Sdim  for (i = 0; i < localsyms; i++)
3303214634Sdim    {
3304214634Sdim      Elf_Internal_Sym *isym = &isymbuf[i];
3305214634Sdim      asection *sec = bfd_section_from_elf_index (abfd, isym->st_shndx);
3306214634Sdim      const char *name;
3307214634Sdim
3308214634Sdim      if (sec != NULL
3309214634Sdim          && ELF_ST_BIND (isym->st_info) == STB_LOCAL)
3310214634Sdim        {
3311214634Sdim          name = bfd_elf_string_from_elf_section (abfd,
3312214634Sdim            hdr->sh_link, isym->st_name);
3313214634Sdim
3314214634Sdim          if (bfd_is_arm_special_symbol_name (name,
3315214634Sdim					      BFD_ARM_SPECIAL_SYM_TYPE_MAP))
3316214634Sdim            elf32_arm_section_map_add (sec, name[1], isym->st_value);
3317214634Sdim        }
3318214634Sdim    }
3319214634Sdim}
3320214634Sdim
3321214634Sdim
3322214634Sdimvoid
3323214634Sdimbfd_elf32_arm_set_vfp11_fix (bfd *obfd, struct bfd_link_info *link_info)
3324214634Sdim{
3325214634Sdim  struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info);
3326214634Sdim  obj_attribute *out_attr = elf_known_obj_attributes_proc (obfd);
3327214634Sdim
3328214634Sdim  /* We assume that ARMv7+ does not need the VFP11 denorm erratum fix.  */
3329214634Sdim  if (out_attr[Tag_CPU_arch].i >= TAG_CPU_ARCH_V7)
3330214634Sdim    {
3331214634Sdim      switch (globals->vfp11_fix)
3332214634Sdim        {
3333214634Sdim        case BFD_ARM_VFP11_FIX_DEFAULT:
3334214634Sdim        case BFD_ARM_VFP11_FIX_NONE:
3335214634Sdim          globals->vfp11_fix = BFD_ARM_VFP11_FIX_NONE;
3336214634Sdim          break;
3337214634Sdim
3338214634Sdim        default:
3339214634Sdim          /* Give a warning, but do as the user requests anyway.  */
3340214634Sdim          (*_bfd_error_handler) (_("%B: warning: selected VFP11 erratum "
3341214634Sdim            "workaround is not necessary for target architecture"), obfd);
3342214634Sdim        }
3343214634Sdim    }
3344214634Sdim  else if (globals->vfp11_fix == BFD_ARM_VFP11_FIX_DEFAULT)
3345214634Sdim    /* For earlier architectures, we might need the workaround, but do not
3346214634Sdim       enable it by default.  If users is running with broken hardware, they
3347214634Sdim       must enable the erratum fix explicitly.  */
3348214634Sdim    globals->vfp11_fix = BFD_ARM_VFP11_FIX_NONE;
3349214634Sdim}
3350214634Sdim
3351214634Sdim
3352214634Sdimenum bfd_arm_vfp11_pipe {
3353214634Sdim  VFP11_FMAC,
3354214634Sdim  VFP11_LS,
3355214634Sdim  VFP11_DS,
3356214634Sdim  VFP11_BAD
3357214634Sdim};
3358214634Sdim
3359214634Sdim/* Return a VFP register number.  This is encoded as RX:X for single-precision
3360214634Sdim   registers, or X:RX for double-precision registers, where RX is the group of
3361214634Sdim   four bits in the instruction encoding and X is the single extension bit.
3362214634Sdim   RX and X fields are specified using their lowest (starting) bit.  The return
3363214634Sdim   value is:
3364214634Sdim
3365214634Sdim     0...31: single-precision registers s0...s31
3366214634Sdim     32...63: double-precision registers d0...d31.
3367214634Sdim
3368214634Sdim   Although X should be zero for VFP11 (encoding d0...d15 only), we might
3369214634Sdim   encounter VFP3 instructions, so we allow the full range for DP registers.  */
3370214634Sdim
3371214634Sdimstatic unsigned int
3372214634Sdimbfd_arm_vfp11_regno (unsigned int insn, bfd_boolean is_double, unsigned int rx,
3373214634Sdim                     unsigned int x)
3374214634Sdim{
3375214634Sdim  if (is_double)
3376214634Sdim    return (((insn >> rx) & 0xf) | (((insn >> x) & 1) << 4)) + 32;
3377214634Sdim  else
3378214634Sdim    return (((insn >> rx) & 0xf) << 1) | ((insn >> x) & 1);
3379214634Sdim}
3380214634Sdim
3381214634Sdim/* Set bits in *WMASK according to a register number REG as encoded by
3382214634Sdim   bfd_arm_vfp11_regno().  Ignore d16-d31.  */
3383214634Sdim
3384214634Sdimstatic void
3385214634Sdimbfd_arm_vfp11_write_mask (unsigned int *wmask, unsigned int reg)
3386214634Sdim{
3387214634Sdim  if (reg < 32)
3388214634Sdim    *wmask |= 1 << reg;
3389214634Sdim  else if (reg < 48)
3390214634Sdim    *wmask |= 3 << ((reg - 32) * 2);
3391214634Sdim}
3392214634Sdim
3393214634Sdim/* Return TRUE if WMASK overwrites anything in REGS.  */
3394214634Sdim
3395214634Sdimstatic bfd_boolean
3396214634Sdimbfd_arm_vfp11_antidependency (unsigned int wmask, int *regs, int numregs)
3397214634Sdim{
3398214634Sdim  int i;
3399214634Sdim
3400214634Sdim  for (i = 0; i < numregs; i++)
3401214634Sdim    {
3402214634Sdim      unsigned int reg = regs[i];
3403214634Sdim
3404214634Sdim      if (reg < 32 && (wmask & (1 << reg)) != 0)
3405214634Sdim        return TRUE;
3406214634Sdim
3407214634Sdim      reg -= 32;
3408214634Sdim
3409214634Sdim      if (reg >= 16)
3410214634Sdim        continue;
3411214634Sdim
3412214634Sdim      if ((wmask & (3 << (reg * 2))) != 0)
3413214634Sdim        return TRUE;
3414214634Sdim    }
3415214634Sdim
3416214634Sdim  return FALSE;
3417214634Sdim}
3418214634Sdim
3419214634Sdim/* In this function, we're interested in two things: finding input registers
3420214634Sdim   for VFP data-processing instructions, and finding the set of registers which
3421214634Sdim   arbitrary VFP instructions may write to.  We use a 32-bit unsigned int to
3422214634Sdim   hold the written set, so FLDM etc. are easy to deal with (we're only
3423214634Sdim   interested in 32 SP registers or 16 dp registers, due to the VFP version
3424214634Sdim   implemented by the chip in question).  DP registers are marked by setting
3425214634Sdim   both SP registers in the write mask).  */
3426214634Sdim
3427214634Sdimstatic enum bfd_arm_vfp11_pipe
3428214634Sdimbfd_arm_vfp11_insn_decode (unsigned int insn, unsigned int *destmask, int *regs,
3429214634Sdim                           int *numregs)
3430214634Sdim{
3431214634Sdim  enum bfd_arm_vfp11_pipe pipe = VFP11_BAD;
3432214634Sdim  bfd_boolean is_double = ((insn & 0xf00) == 0xb00) ? 1 : 0;
3433214634Sdim
3434214634Sdim  if ((insn & 0x0f000e10) == 0x0e000a00)  /* A data-processing insn.  */
3435214634Sdim    {
3436214634Sdim      unsigned int pqrs;
3437214634Sdim      unsigned int fd = bfd_arm_vfp11_regno (insn, is_double, 12, 22);
3438214634Sdim      unsigned int fm = bfd_arm_vfp11_regno (insn, is_double, 0, 5);
3439214634Sdim
3440214634Sdim      pqrs = ((insn & 0x00800000) >> 20)
3441214634Sdim           | ((insn & 0x00300000) >> 19)
3442214634Sdim           | ((insn & 0x00000040) >> 6);
3443214634Sdim
3444214634Sdim      switch (pqrs)
3445214634Sdim        {
3446214634Sdim        case 0: /* fmac[sd].  */
3447214634Sdim        case 1: /* fnmac[sd].  */
3448214634Sdim        case 2: /* fmsc[sd].  */
3449214634Sdim        case 3: /* fnmsc[sd].  */
3450214634Sdim          pipe = VFP11_FMAC;
3451214634Sdim          bfd_arm_vfp11_write_mask (destmask, fd);
3452214634Sdim          regs[0] = fd;
3453214634Sdim          regs[1] = bfd_arm_vfp11_regno (insn, is_double, 16, 7);  /* Fn.  */
3454214634Sdim          regs[2] = fm;
3455214634Sdim          *numregs = 3;
3456214634Sdim          break;
3457214634Sdim
3458214634Sdim        case 4: /* fmul[sd].  */
3459214634Sdim        case 5: /* fnmul[sd].  */
3460214634Sdim        case 6: /* fadd[sd].  */
3461214634Sdim        case 7: /* fsub[sd].  */
3462214634Sdim          pipe = VFP11_FMAC;
3463214634Sdim          goto vfp_binop;
3464214634Sdim
3465214634Sdim        case 8: /* fdiv[sd].  */
3466214634Sdim          pipe = VFP11_DS;
3467214634Sdim          vfp_binop:
3468214634Sdim          bfd_arm_vfp11_write_mask (destmask, fd);
3469214634Sdim          regs[0] = bfd_arm_vfp11_regno (insn, is_double, 16, 7);   /* Fn.  */
3470214634Sdim          regs[1] = fm;
3471214634Sdim          *numregs = 2;
3472214634Sdim          break;
3473214634Sdim
3474214634Sdim        case 15: /* extended opcode.  */
3475214634Sdim          {
3476214634Sdim            unsigned int extn = ((insn >> 15) & 0x1e)
3477214634Sdim                              | ((insn >> 7) & 1);
3478214634Sdim
3479214634Sdim            switch (extn)
3480214634Sdim              {
3481214634Sdim              case 0: /* fcpy[sd].  */
3482214634Sdim              case 1: /* fabs[sd].  */
3483214634Sdim              case 2: /* fneg[sd].  */
3484214634Sdim              case 8: /* fcmp[sd].  */
3485214634Sdim              case 9: /* fcmpe[sd].  */
3486214634Sdim              case 10: /* fcmpz[sd].  */
3487214634Sdim              case 11: /* fcmpez[sd].  */
3488214634Sdim              case 16: /* fuito[sd].  */
3489214634Sdim              case 17: /* fsito[sd].  */
3490214634Sdim              case 24: /* ftoui[sd].  */
3491214634Sdim              case 25: /* ftouiz[sd].  */
3492214634Sdim              case 26: /* ftosi[sd].  */
3493214634Sdim              case 27: /* ftosiz[sd].  */
3494214634Sdim                /* These instructions will not bounce due to underflow.  */
3495214634Sdim                *numregs = 0;
3496214634Sdim                pipe = VFP11_FMAC;
3497214634Sdim                break;
3498214634Sdim
3499214634Sdim              case 3: /* fsqrt[sd].  */
3500214634Sdim                /* fsqrt cannot underflow, but it can (perhaps) overwrite
3501214634Sdim                   registers to cause the erratum in previous instructions.  */
3502214634Sdim                bfd_arm_vfp11_write_mask (destmask, fd);
3503214634Sdim                pipe = VFP11_DS;
3504214634Sdim                break;
3505214634Sdim
3506214634Sdim              case 15: /* fcvt{ds,sd}.  */
3507214634Sdim                {
3508214634Sdim                  int rnum = 0;
3509214634Sdim
3510214634Sdim                  bfd_arm_vfp11_write_mask (destmask, fd);
3511214634Sdim
3512214634Sdim		  /* Only FCVTSD can underflow.  */
3513214634Sdim                  if ((insn & 0x100) != 0)
3514214634Sdim                    regs[rnum++] = fm;
3515214634Sdim
3516214634Sdim                  *numregs = rnum;
3517214634Sdim
3518214634Sdim                  pipe = VFP11_FMAC;
3519214634Sdim                }
3520214634Sdim                break;
3521214634Sdim
3522214634Sdim              default:
3523214634Sdim                return VFP11_BAD;
3524214634Sdim              }
3525214634Sdim          }
3526214634Sdim          break;
3527214634Sdim
3528214634Sdim        default:
3529214634Sdim          return VFP11_BAD;
3530214634Sdim        }
3531214634Sdim    }
3532214634Sdim  /* Two-register transfer.  */
3533214634Sdim  else if ((insn & 0x0fe00ed0) == 0x0c400a10)
3534214634Sdim    {
3535214634Sdim      unsigned int fm = bfd_arm_vfp11_regno (insn, is_double, 0, 5);
3536214634Sdim
3537214634Sdim      if ((insn & 0x100000) == 0)
3538214634Sdim	{
3539214634Sdim          if (is_double)
3540214634Sdim            bfd_arm_vfp11_write_mask (destmask, fm);
3541214634Sdim          else
3542214634Sdim            {
3543214634Sdim              bfd_arm_vfp11_write_mask (destmask, fm);
3544214634Sdim              bfd_arm_vfp11_write_mask (destmask, fm + 1);
3545214634Sdim            }
3546214634Sdim	}
3547214634Sdim
3548214634Sdim      pipe = VFP11_LS;
3549214634Sdim    }
3550214634Sdim  else if ((insn & 0x0e100e00) == 0x0c100a00)  /* A load insn.  */
3551214634Sdim    {
3552214634Sdim      int fd = bfd_arm_vfp11_regno (insn, is_double, 12, 22);
3553214634Sdim      unsigned int puw = ((insn >> 21) & 0x1) | (((insn >> 23) & 3) << 1);
3554214634Sdim
3555214634Sdim      switch (puw)
3556214634Sdim        {
3557214634Sdim        case 0: /* Two-reg transfer.  We should catch these above.  */
3558214634Sdim          abort ();
3559214634Sdim
3560214634Sdim        case 2: /* fldm[sdx].  */
3561214634Sdim        case 3:
3562214634Sdim        case 5:
3563214634Sdim          {
3564214634Sdim            unsigned int i, offset = insn & 0xff;
3565214634Sdim
3566214634Sdim            if (is_double)
3567214634Sdim              offset >>= 1;
3568214634Sdim
3569214634Sdim            for (i = fd; i < fd + offset; i++)
3570214634Sdim              bfd_arm_vfp11_write_mask (destmask, i);
3571214634Sdim          }
3572214634Sdim          break;
3573214634Sdim
3574214634Sdim        case 4: /* fld[sd].  */
3575214634Sdim        case 6:
3576214634Sdim          bfd_arm_vfp11_write_mask (destmask, fd);
3577214634Sdim          break;
3578214634Sdim
3579214634Sdim        default:
3580214634Sdim          return VFP11_BAD;
3581214634Sdim        }
3582214634Sdim
3583214634Sdim      pipe = VFP11_LS;
3584214634Sdim    }
3585214634Sdim  /* Single-register transfer. Note L==0.  */
3586214634Sdim  else if ((insn & 0x0f100e10) == 0x0e000a10)
3587214634Sdim    {
3588214634Sdim      unsigned int opcode = (insn >> 21) & 7;
3589214634Sdim      unsigned int fn = bfd_arm_vfp11_regno (insn, is_double, 16, 7);
3590214634Sdim
3591214634Sdim      switch (opcode)
3592214634Sdim        {
3593214634Sdim        case 0: /* fmsr/fmdlr.  */
3594214634Sdim        case 1: /* fmdhr.  */
3595214634Sdim          /* Mark fmdhr and fmdlr as writing to the whole of the DP
3596214634Sdim             destination register.  I don't know if this is exactly right,
3597214634Sdim             but it is the conservative choice.  */
3598214634Sdim          bfd_arm_vfp11_write_mask (destmask, fn);
3599214634Sdim          break;
3600214634Sdim
3601214634Sdim        case 7: /* fmxr.  */
3602214634Sdim          break;
3603214634Sdim        }
3604214634Sdim
3605214634Sdim      pipe = VFP11_LS;
3606214634Sdim    }
3607214634Sdim
3608214634Sdim  return pipe;
3609214634Sdim}
3610214634Sdim
3611214634Sdim
3612214634Sdimstatic int elf32_arm_compare_mapping (const void * a, const void * b);
3613214634Sdim
3614214634Sdim
3615214634Sdim/* Look for potentially-troublesome code sequences which might trigger the
3616214634Sdim   VFP11 denormal/antidependency erratum.  See, e.g., the ARM1136 errata sheet
3617214634Sdim   (available from ARM) for details of the erratum.  A short version is
3618214634Sdim   described in ld.texinfo.  */
3619214634Sdim
3620214634Sdimbfd_boolean
3621214634Sdimbfd_elf32_arm_vfp11_erratum_scan (bfd *abfd, struct bfd_link_info *link_info)
3622214634Sdim{
3623214634Sdim  asection *sec;
3624214634Sdim  bfd_byte *contents = NULL;
3625214634Sdim  int state = 0;
3626214634Sdim  int regs[3], numregs = 0;
3627214634Sdim  struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info);
3628214634Sdim  int use_vector = (globals->vfp11_fix == BFD_ARM_VFP11_FIX_VECTOR);
3629214634Sdim
3630214634Sdim  /* We use a simple FSM to match troublesome VFP11 instruction sequences.
3631214634Sdim     The states transition as follows:
3632214634Sdim
3633214634Sdim       0 -> 1 (vector) or 0 -> 2 (scalar)
3634214634Sdim           A VFP FMAC-pipeline instruction has been seen. Fill
3635214634Sdim           regs[0]..regs[numregs-1] with its input operands. Remember this
3636214634Sdim           instruction in 'first_fmac'.
3637214634Sdim
3638214634Sdim       1 -> 2
3639214634Sdim           Any instruction, except for a VFP instruction which overwrites
3640214634Sdim           regs[*].
3641214634Sdim
3642214634Sdim       1 -> 3 [ -> 0 ]  or
3643214634Sdim       2 -> 3 [ -> 0 ]
3644214634Sdim           A VFP instruction has been seen which overwrites any of regs[*].
3645214634Sdim           We must make a veneer!  Reset state to 0 before examining next
3646214634Sdim           instruction.
3647214634Sdim
3648214634Sdim       2 -> 0
3649214634Sdim           If we fail to match anything in state 2, reset to state 0 and reset
3650214634Sdim           the instruction pointer to the instruction after 'first_fmac'.
3651214634Sdim
3652214634Sdim     If the VFP11 vector mode is in use, there must be at least two unrelated
3653214634Sdim     instructions between anti-dependent VFP11 instructions to properly avoid
3654214634Sdim     triggering the erratum, hence the use of the extra state 1.
3655214634Sdim  */
3656214634Sdim
3657214634Sdim  /* If we are only performing a partial link do not bother
3658214634Sdim     to construct any glue.  */
3659214634Sdim  if (link_info->relocatable)
3660214634Sdim    return TRUE;
3661214634Sdim
3662214634Sdim  /* We should have chosen a fix type by the time we get here.  */
3663214634Sdim  BFD_ASSERT (globals->vfp11_fix != BFD_ARM_VFP11_FIX_DEFAULT);
3664214634Sdim
3665214634Sdim  if (globals->vfp11_fix == BFD_ARM_VFP11_FIX_NONE)
3666214634Sdim    return TRUE;
3667214634Sdim
3668214634Sdim  /* Skip if this bfd does not correspond to an ELF image.  */
3669214634Sdim  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
3670214634Sdim    return TRUE;
3671214634Sdim
3672214634Sdim  for (sec = abfd->sections; sec != NULL; sec = sec->next)
3673214634Sdim    {
3674214634Sdim      unsigned int i, span, first_fmac = 0, veneer_of_insn = 0;
3675214634Sdim      struct _arm_elf_section_data *sec_data;
3676214634Sdim
3677214634Sdim      /* If we don't have executable progbits, we're not interested in this
3678214634Sdim         section.  Also skip if section is to be excluded.  */
3679214634Sdim      if (elf_section_type (sec) != SHT_PROGBITS
3680214634Sdim          || (elf_section_flags (sec) & SHF_EXECINSTR) == 0
3681214634Sdim          || (sec->flags & SEC_EXCLUDE) != 0
3682214634Sdim          || strcmp (sec->name, VFP11_ERRATUM_VENEER_SECTION_NAME) == 0)
3683214634Sdim        continue;
3684214634Sdim
3685214634Sdim      sec_data = elf32_arm_section_data (sec);
3686214634Sdim
3687214634Sdim      if (sec_data->mapcount == 0)
3688214634Sdim        continue;
3689214634Sdim
3690214634Sdim      if (elf_section_data (sec)->this_hdr.contents != NULL)
3691214634Sdim	contents = elf_section_data (sec)->this_hdr.contents;
3692214634Sdim      else if (! bfd_malloc_and_get_section (abfd, sec, &contents))
3693214634Sdim	goto error_return;
3694214634Sdim
3695214634Sdim      qsort (sec_data->map, sec_data->mapcount, sizeof (elf32_arm_section_map),
3696214634Sdim	     elf32_arm_compare_mapping);
3697214634Sdim
3698214634Sdim      for (span = 0; span < sec_data->mapcount; span++)
3699214634Sdim        {
3700214634Sdim          unsigned int span_start = sec_data->map[span].vma;
3701214634Sdim          unsigned int span_end = (span == sec_data->mapcount - 1)
3702214634Sdim				  ? sec->size : sec_data->map[span + 1].vma;
3703214634Sdim          char span_type = sec_data->map[span].type;
3704214634Sdim
3705214634Sdim          /* FIXME: Only ARM mode is supported at present.  We may need to
3706214634Sdim             support Thumb-2 mode also at some point.  */
3707214634Sdim          if (span_type != 'a')
3708214634Sdim            continue;
3709214634Sdim
3710214634Sdim          for (i = span_start; i < span_end;)
3711214634Sdim            {
3712214634Sdim              unsigned int next_i = i + 4;
3713214634Sdim              unsigned int insn = bfd_big_endian (abfd)
3714214634Sdim                ? (contents[i] << 24)
3715214634Sdim                  | (contents[i + 1] << 16)
3716214634Sdim                  | (contents[i + 2] << 8)
3717214634Sdim                  | contents[i + 3]
3718214634Sdim                : (contents[i + 3] << 24)
3719214634Sdim                  | (contents[i + 2] << 16)
3720214634Sdim                  | (contents[i + 1] << 8)
3721214634Sdim                  | contents[i];
3722214634Sdim              unsigned int writemask = 0;
3723214634Sdim              enum bfd_arm_vfp11_pipe pipe;
3724214634Sdim
3725214634Sdim              switch (state)
3726214634Sdim                {
3727214634Sdim                case 0:
3728214634Sdim                  pipe = bfd_arm_vfp11_insn_decode (insn, &writemask, regs,
3729214634Sdim                                                    &numregs);
3730214634Sdim                  /* I'm assuming the VFP11 erratum can trigger with denorm
3731214634Sdim                     operands on either the FMAC or the DS pipeline. This might
3732214634Sdim                     lead to slightly overenthusiastic veneer insertion.  */
3733214634Sdim                  if (pipe == VFP11_FMAC || pipe == VFP11_DS)
3734214634Sdim                    {
3735214634Sdim                      state = use_vector ? 1 : 2;
3736214634Sdim                      first_fmac = i;
3737214634Sdim                      veneer_of_insn = insn;
3738214634Sdim                    }
3739214634Sdim                  break;
3740214634Sdim
3741214634Sdim                case 1:
3742214634Sdim                  {
3743214634Sdim                    int other_regs[3], other_numregs;
3744214634Sdim                    pipe = bfd_arm_vfp11_insn_decode (insn, &writemask,
3745214634Sdim						      other_regs,
3746214634Sdim                                                      &other_numregs);
3747214634Sdim                    if (pipe != VFP11_BAD
3748214634Sdim                        && bfd_arm_vfp11_antidependency (writemask, regs,
3749214634Sdim							 numregs))
3750214634Sdim                      state = 3;
3751214634Sdim                    else
3752214634Sdim                      state = 2;
3753214634Sdim                  }
3754214634Sdim                  break;
3755214634Sdim
3756214634Sdim                case 2:
3757214634Sdim                  {
3758214634Sdim                    int other_regs[3], other_numregs;
3759214634Sdim                    pipe = bfd_arm_vfp11_insn_decode (insn, &writemask,
3760214634Sdim						      other_regs,
3761214634Sdim                                                      &other_numregs);
3762214634Sdim                    if (pipe != VFP11_BAD
3763214634Sdim                        && bfd_arm_vfp11_antidependency (writemask, regs,
3764214634Sdim							 numregs))
3765214634Sdim                      state = 3;
3766214634Sdim                    else
3767214634Sdim                      {
3768214634Sdim                        state = 0;
3769214634Sdim                        next_i = first_fmac + 4;
3770214634Sdim                      }
3771214634Sdim                  }
3772214634Sdim                  break;
3773214634Sdim
3774214634Sdim                case 3:
3775214634Sdim                  abort ();  /* Should be unreachable.  */
3776214634Sdim                }
3777214634Sdim
3778214634Sdim              if (state == 3)
3779214634Sdim                {
3780214634Sdim                  elf32_vfp11_erratum_list *newerr
3781214634Sdim                    = bfd_zmalloc (sizeof (elf32_vfp11_erratum_list));
3782214634Sdim                  int errcount;
3783214634Sdim
3784214634Sdim                  errcount = ++(elf32_arm_section_data (sec)->erratumcount);
3785214634Sdim
3786214634Sdim                  newerr->u.b.vfp_insn = veneer_of_insn;
3787214634Sdim
3788214634Sdim                  switch (span_type)
3789214634Sdim                    {
3790214634Sdim                    case 'a':
3791214634Sdim                      newerr->type = VFP11_ERRATUM_BRANCH_TO_ARM_VENEER;
3792214634Sdim                      break;
3793214634Sdim
3794214634Sdim                    default:
3795214634Sdim                      abort ();
3796214634Sdim                    }
3797214634Sdim
3798214634Sdim                  record_vfp11_erratum_veneer (link_info, newerr, abfd, sec,
3799214634Sdim					       first_fmac);
3800214634Sdim
3801214634Sdim                  newerr->vma = -1;
3802214634Sdim
3803214634Sdim                  newerr->next = sec_data->erratumlist;
3804214634Sdim                  sec_data->erratumlist = newerr;
3805214634Sdim
3806214634Sdim                  state = 0;
3807214634Sdim                }
3808214634Sdim
3809214634Sdim              i = next_i;
3810214634Sdim            }
3811214634Sdim        }
3812214634Sdim
3813214634Sdim      if (contents != NULL
3814214634Sdim          && elf_section_data (sec)->this_hdr.contents != contents)
3815214634Sdim        free (contents);
3816214634Sdim      contents = NULL;
3817214634Sdim    }
3818214634Sdim
3819214634Sdim  return TRUE;
3820214634Sdim
3821214634Sdimerror_return:
3822214634Sdim  if (contents != NULL
3823214634Sdim      && elf_section_data (sec)->this_hdr.contents != contents)
3824214634Sdim    free (contents);
3825214634Sdim
3826214634Sdim  return FALSE;
3827214634Sdim}
3828214634Sdim
3829214634Sdim/* Find virtual-memory addresses for VFP11 erratum veneers and return locations
3830214634Sdim   after sections have been laid out, using specially-named symbols.  */
3831214634Sdim
3832214634Sdimvoid
3833214634Sdimbfd_elf32_arm_vfp11_fix_veneer_locations (bfd *abfd,
3834214634Sdim					  struct bfd_link_info *link_info)
3835214634Sdim{
3836214634Sdim  asection *sec;
3837214634Sdim  struct elf32_arm_link_hash_table *globals;
3838214634Sdim  char *tmp_name;
3839214634Sdim
3840214634Sdim  if (link_info->relocatable)
3841214634Sdim    return;
3842214634Sdim
3843214634Sdim  /* Skip if this bfd does not correspond to an ELF image.  */
3844214634Sdim  if (bfd_get_flavour (abfd) != bfd_target_elf_flavour)
3845214634Sdim    return;
3846214634Sdim
3847214634Sdim  globals = elf32_arm_hash_table (link_info);
3848214634Sdim
3849214634Sdim  tmp_name = bfd_malloc ((bfd_size_type) strlen
3850214634Sdim			   (VFP11_ERRATUM_VENEER_ENTRY_NAME) + 10);
3851214634Sdim
3852214634Sdim  for (sec = abfd->sections; sec != NULL; sec = sec->next)
3853214634Sdim    {
3854214634Sdim      struct _arm_elf_section_data *sec_data = elf32_arm_section_data (sec);
3855214634Sdim      elf32_vfp11_erratum_list *errnode = sec_data->erratumlist;
3856214634Sdim
3857214634Sdim      for (; errnode != NULL; errnode = errnode->next)
3858214634Sdim        {
3859214634Sdim          struct elf_link_hash_entry *myh;
3860214634Sdim          bfd_vma vma;
3861214634Sdim
3862214634Sdim          switch (errnode->type)
3863214634Sdim            {
3864214634Sdim            case VFP11_ERRATUM_BRANCH_TO_ARM_VENEER:
3865214634Sdim            case VFP11_ERRATUM_BRANCH_TO_THUMB_VENEER:
3866214634Sdim              /* Find veneer symbol.  */
3867214634Sdim              sprintf (tmp_name, VFP11_ERRATUM_VENEER_ENTRY_NAME,
3868214634Sdim		       errnode->u.b.veneer->u.v.id);
3869214634Sdim
3870214634Sdim              myh = elf_link_hash_lookup
3871214634Sdim                (&(globals)->root, tmp_name, FALSE, FALSE, TRUE);
3872214634Sdim
3873214634Sdim              if (myh == NULL)
3874214634Sdim                (*_bfd_error_handler) (_("%B: unable to find VFP11 veneer "
3875214634Sdim                			 "`%s'"), abfd, tmp_name);
3876214634Sdim
3877214634Sdim              vma = myh->root.u.def.section->output_section->vma
3878214634Sdim                    + myh->root.u.def.section->output_offset
3879214634Sdim                    + myh->root.u.def.value;
3880214634Sdim
3881214634Sdim              errnode->u.b.veneer->vma = vma;
3882214634Sdim              break;
3883214634Sdim
3884214634Sdim	    case VFP11_ERRATUM_ARM_VENEER:
3885214634Sdim            case VFP11_ERRATUM_THUMB_VENEER:
3886214634Sdim              /* Find return location.  */
3887214634Sdim              sprintf (tmp_name, VFP11_ERRATUM_VENEER_ENTRY_NAME "_r",
3888214634Sdim                       errnode->u.v.id);
3889214634Sdim
3890214634Sdim              myh = elf_link_hash_lookup
3891214634Sdim                (&(globals)->root, tmp_name, FALSE, FALSE, TRUE);
3892214634Sdim
3893214634Sdim              if (myh == NULL)
3894214634Sdim                (*_bfd_error_handler) (_("%B: unable to find VFP11 veneer "
3895214634Sdim					 "`%s'"), abfd, tmp_name);
3896214634Sdim
3897214634Sdim              vma = myh->root.u.def.section->output_section->vma
3898214634Sdim                    + myh->root.u.def.section->output_offset
3899214634Sdim                    + myh->root.u.def.value;
3900214634Sdim
3901214634Sdim              errnode->u.v.branch->vma = vma;
3902214634Sdim              break;
3903214634Sdim
3904214634Sdim            default:
3905214634Sdim              abort ();
3906214634Sdim            }
3907214634Sdim        }
3908214634Sdim    }
3909214634Sdim
3910214634Sdim  free (tmp_name);
3911214634Sdim}
3912214634Sdim
3913214634Sdim
3914214082Sdim/* Set target relocation values needed during linking.  */
3915214082Sdim
3916214082Sdimvoid
3917214634Sdimbfd_elf32_arm_set_target_relocs (struct bfd *output_bfd,
3918214634Sdim				 struct bfd_link_info *link_info,
3919214082Sdim				 int target1_is_rel,
3920214082Sdim				 char * target2_type,
3921214082Sdim                                 int fix_v4bx,
3922214634Sdim				 int use_blx,
3923214634Sdim                                 bfd_arm_vfp11_fix vfp11_fix,
3924214634Sdim				 int no_enum_warn, int pic_veneer)
3925214082Sdim{
3926214082Sdim  struct elf32_arm_link_hash_table *globals;
3927214082Sdim
3928214082Sdim  globals = elf32_arm_hash_table (link_info);
3929214082Sdim
3930214082Sdim  globals->target1_is_rel = target1_is_rel;
3931214082Sdim  if (strcmp (target2_type, "rel") == 0)
3932214082Sdim    globals->target2_reloc = R_ARM_REL32;
3933214082Sdim  else if (strcmp (target2_type, "abs") == 0)
3934214082Sdim    globals->target2_reloc = R_ARM_ABS32;
3935214082Sdim  else if (strcmp (target2_type, "got-rel") == 0)
3936214082Sdim    globals->target2_reloc = R_ARM_GOT_PREL;
3937214082Sdim  else
3938214082Sdim    {
3939214082Sdim      _bfd_error_handler (_("Invalid TARGET2 relocation type '%s'."),
3940214082Sdim			  target2_type);
3941214082Sdim    }
3942214082Sdim  globals->fix_v4bx = fix_v4bx;
3943214082Sdim  globals->use_blx |= use_blx;
3944214634Sdim  globals->vfp11_fix = vfp11_fix;
3945214634Sdim  globals->pic_veneer = pic_veneer;
3946214634Sdim
3947214634Sdim  elf32_arm_tdata (output_bfd)->no_enum_size_warning = no_enum_warn;
3948214082Sdim}
3949214082Sdim
3950214082Sdim/* The thumb form of a long branch is a bit finicky, because the offset
3951214082Sdim   encoding is split over two fields, each in it's own instruction. They
3952214082Sdim   can occur in any order. So given a thumb form of long branch, and an
3953214082Sdim   offset, insert the offset into the thumb branch and return finished
3954214082Sdim   instruction.
3955214082Sdim
3956214082Sdim   It takes two thumb instructions to encode the target address. Each has
3957214082Sdim   11 bits to invest. The upper 11 bits are stored in one (identified by
3958214082Sdim   H-0.. see below), the lower 11 bits are stored in the other (identified
3959214082Sdim   by H-1).
3960214082Sdim
3961214082Sdim   Combine together and shifted left by 1 (it's a half word address) and
3962214082Sdim   there you have it.
3963214082Sdim
3964214082Sdim   Op: 1111 = F,
3965214082Sdim   H-0, upper address-0 = 000
3966214082Sdim   Op: 1111 = F,
3967214082Sdim   H-1, lower address-0 = 800
3968214082Sdim
3969214082Sdim   They can be ordered either way, but the arm tools I've seen always put
3970214082Sdim   the lower one first. It probably doesn't matter. krk@cygnus.com
3971214082Sdim
3972214082Sdim   XXX:  Actually the order does matter.  The second instruction (H-1)
3973214082Sdim   moves the computed address into the PC, so it must be the second one
3974214082Sdim   in the sequence.  The problem, however is that whilst little endian code
3975214082Sdim   stores the instructions in HI then LOW order, big endian code does the
3976214082Sdim   reverse.  nickc@cygnus.com.  */
3977214082Sdim
3978214082Sdim#define LOW_HI_ORDER      0xF800F000
3979214082Sdim#define HI_LOW_ORDER      0xF000F800
3980214082Sdim
3981214082Sdimstatic insn32
3982214082Sdiminsert_thumb_branch (insn32 br_insn, int rel_off)
3983214082Sdim{
3984214082Sdim  unsigned int low_bits;
3985214082Sdim  unsigned int high_bits;
3986214082Sdim
3987214082Sdim  BFD_ASSERT ((rel_off & 1) != 1);
3988214082Sdim
3989214082Sdim  rel_off >>= 1;				/* Half word aligned address.  */
3990214082Sdim  low_bits = rel_off & 0x000007FF;		/* The bottom 11 bits.  */
3991214082Sdim  high_bits = (rel_off >> 11) & 0x000007FF;	/* The top 11 bits.  */
3992214082Sdim
3993214082Sdim  if ((br_insn & LOW_HI_ORDER) == LOW_HI_ORDER)
3994214082Sdim    br_insn = LOW_HI_ORDER | (low_bits << 16) | high_bits;
3995214082Sdim  else if ((br_insn & HI_LOW_ORDER) == HI_LOW_ORDER)
3996214082Sdim    br_insn = HI_LOW_ORDER | (high_bits << 16) | low_bits;
3997214082Sdim  else
3998214082Sdim    /* FIXME: abort is probably not the right call. krk@cygnus.com  */
3999214082Sdim    abort ();	/* Error - not a valid branch instruction form.  */
4000214082Sdim
4001214082Sdim  return br_insn;
4002214082Sdim}
4003214082Sdim
4004214634Sdim
4005214634Sdim/* Store an Arm insn into an output section not processed by
4006214634Sdim   elf32_arm_write_section.  */
4007214634Sdim
4008214634Sdimstatic void
4009214634Sdimput_arm_insn (struct elf32_arm_link_hash_table *htab,
4010214634Sdim	     bfd * output_bfd, bfd_vma val, void * ptr)
4011214634Sdim{
4012214634Sdim    if (htab->byteswap_code != bfd_little_endian (output_bfd))
4013214634Sdim      bfd_putl32 (val, ptr);
4014214634Sdim    else
4015214634Sdim      bfd_putb32 (val, ptr);
4016214634Sdim}
4017214634Sdim
4018214634Sdim
4019214634Sdim/* Store a 16-bit Thumb insn into an output section not processed by
4020214634Sdim   elf32_arm_write_section.  */
4021214634Sdim
4022214634Sdimstatic void
4023214634Sdimput_thumb_insn (struct elf32_arm_link_hash_table *htab,
4024214634Sdim	       bfd * output_bfd, bfd_vma val, void * ptr)
4025214634Sdim{
4026214634Sdim    if (htab->byteswap_code != bfd_little_endian (output_bfd))
4027214634Sdim      bfd_putl16 (val, ptr);
4028214634Sdim    else
4029214634Sdim      bfd_putb16 (val, ptr);
4030214634Sdim}
4031214634Sdim
4032214634Sdim
4033214082Sdim/* Thumb code calling an ARM function.  */
4034214082Sdim
4035214082Sdimstatic int
4036214082Sdimelf32_thumb_to_arm_stub (struct bfd_link_info * info,
4037214082Sdim			 const char *           name,
4038214082Sdim			 bfd *                  input_bfd,
4039214082Sdim			 bfd *                  output_bfd,
4040214082Sdim			 asection *             input_section,
4041214082Sdim			 bfd_byte *             hit_data,
4042214082Sdim			 asection *             sym_sec,
4043214082Sdim			 bfd_vma                offset,
4044214082Sdim			 bfd_signed_vma         addend,
4045214634Sdim			 bfd_vma                val,
4046214634Sdim			 char **error_message)
4047214082Sdim{
4048214082Sdim  asection * s = 0;
4049214082Sdim  bfd_vma my_offset;
4050214082Sdim  unsigned long int tmp;
4051214082Sdim  long int ret_offset;
4052214082Sdim  struct elf_link_hash_entry * myh;
4053214082Sdim  struct elf32_arm_link_hash_table * globals;
4054214082Sdim
4055214634Sdim  myh = find_thumb_glue (info, name, error_message);
4056214082Sdim  if (myh == NULL)
4057214082Sdim    return FALSE;
4058214082Sdim
4059214082Sdim  globals = elf32_arm_hash_table (info);
4060214082Sdim
4061214082Sdim  BFD_ASSERT (globals != NULL);
4062214082Sdim  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
4063214082Sdim
4064214082Sdim  my_offset = myh->root.u.def.value;
4065214082Sdim
4066214082Sdim  s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
4067214082Sdim			       THUMB2ARM_GLUE_SECTION_NAME);
4068214082Sdim
4069214082Sdim  BFD_ASSERT (s != NULL);
4070214082Sdim  BFD_ASSERT (s->contents != NULL);
4071214082Sdim  BFD_ASSERT (s->output_section != NULL);
4072214082Sdim
4073214082Sdim  if ((my_offset & 0x01) == 0x01)
4074214082Sdim    {
4075214082Sdim      if (sym_sec != NULL
4076214082Sdim	  && sym_sec->owner != NULL
4077214082Sdim	  && !INTERWORK_FLAG (sym_sec->owner))
4078214082Sdim	{
4079214082Sdim	  (*_bfd_error_handler)
4080214082Sdim	    (_("%B(%s): warning: interworking not enabled.\n"
4081214082Sdim	       "  first occurrence: %B: thumb call to arm"),
4082214082Sdim	     sym_sec->owner, input_bfd, name);
4083214082Sdim
4084214082Sdim	  return FALSE;
4085214082Sdim	}
4086214082Sdim
4087214082Sdim      --my_offset;
4088214082Sdim      myh->root.u.def.value = my_offset;
4089214082Sdim
4090214634Sdim      put_thumb_insn (globals, output_bfd, (bfd_vma) t2a1_bx_pc_insn,
4091214634Sdim		      s->contents + my_offset);
4092214082Sdim
4093214634Sdim      put_thumb_insn (globals, output_bfd, (bfd_vma) t2a2_noop_insn,
4094214634Sdim		      s->contents + my_offset + 2);
4095214082Sdim
4096214082Sdim      ret_offset =
4097214082Sdim	/* Address of destination of the stub.  */
4098214082Sdim	((bfd_signed_vma) val)
4099214082Sdim	- ((bfd_signed_vma)
4100214082Sdim	   /* Offset from the start of the current section
4101214082Sdim	      to the start of the stubs.  */
4102214082Sdim	   (s->output_offset
4103214082Sdim	    /* Offset of the start of this stub from the start of the stubs.  */
4104214082Sdim	    + my_offset
4105214082Sdim	    /* Address of the start of the current section.  */
4106214082Sdim	    + s->output_section->vma)
4107214082Sdim	   /* The branch instruction is 4 bytes into the stub.  */
4108214082Sdim	   + 4
4109214082Sdim	   /* ARM branches work from the pc of the instruction + 8.  */
4110214082Sdim	   + 8);
4111214082Sdim
4112214634Sdim      put_arm_insn (globals, output_bfd,
4113214634Sdim		    (bfd_vma) t2a3_b_insn | ((ret_offset >> 2) & 0x00FFFFFF),
4114214634Sdim		    s->contents + my_offset + 4);
4115214082Sdim    }
4116214082Sdim
4117214082Sdim  BFD_ASSERT (my_offset <= globals->thumb_glue_size);
4118214082Sdim
4119214082Sdim  /* Now go back and fix up the original BL insn to point to here.  */
4120214082Sdim  ret_offset =
4121214082Sdim    /* Address of where the stub is located.  */
4122214082Sdim    (s->output_section->vma + s->output_offset + my_offset)
4123214082Sdim     /* Address of where the BL is located.  */
4124214082Sdim    - (input_section->output_section->vma + input_section->output_offset
4125214082Sdim       + offset)
4126214082Sdim    /* Addend in the relocation.  */
4127214082Sdim    - addend
4128214082Sdim    /* Biassing for PC-relative addressing.  */
4129214082Sdim    - 8;
4130214082Sdim
4131214082Sdim  tmp = bfd_get_32 (input_bfd, hit_data
4132214082Sdim		    - input_section->vma);
4133214082Sdim
4134214082Sdim  bfd_put_32 (output_bfd,
4135214082Sdim	      (bfd_vma) insert_thumb_branch (tmp, ret_offset),
4136214082Sdim	      hit_data - input_section->vma);
4137214082Sdim
4138214082Sdim  return TRUE;
4139214082Sdim}
4140214082Sdim
4141214634Sdim/* Populate an Arm to Thumb stub.  Returns the stub symbol.  */
4142214082Sdim
4143214634Sdimstatic struct elf_link_hash_entry *
4144214634Sdimelf32_arm_create_thumb_stub (struct bfd_link_info * info,
4145214634Sdim			     const char *           name,
4146214634Sdim			     bfd *                  input_bfd,
4147214634Sdim			     bfd *                  output_bfd,
4148214634Sdim			     asection *             sym_sec,
4149214634Sdim			     bfd_vma                val,
4150214634Sdim			     asection		    *s,
4151214634Sdim			     char **error_message)
4152214082Sdim{
4153214082Sdim  bfd_vma my_offset;
4154214082Sdim  long int ret_offset;
4155214082Sdim  struct elf_link_hash_entry * myh;
4156214082Sdim  struct elf32_arm_link_hash_table * globals;
4157214082Sdim
4158214634Sdim  myh = find_arm_glue (info, name, error_message);
4159214082Sdim  if (myh == NULL)
4160214634Sdim    return NULL;
4161214082Sdim
4162214082Sdim  globals = elf32_arm_hash_table (info);
4163214082Sdim
4164214082Sdim  BFD_ASSERT (globals != NULL);
4165214082Sdim  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
4166214082Sdim
4167214082Sdim  my_offset = myh->root.u.def.value;
4168214082Sdim
4169214082Sdim  if ((my_offset & 0x01) == 0x01)
4170214082Sdim    {
4171214082Sdim      if (sym_sec != NULL
4172214082Sdim	  && sym_sec->owner != NULL
4173214082Sdim	  && !INTERWORK_FLAG (sym_sec->owner))
4174214082Sdim	{
4175214082Sdim	  (*_bfd_error_handler)
4176214082Sdim	    (_("%B(%s): warning: interworking not enabled.\n"
4177214082Sdim	       "  first occurrence: %B: arm call to thumb"),
4178214082Sdim	     sym_sec->owner, input_bfd, name);
4179214082Sdim	}
4180214082Sdim
4181214082Sdim      --my_offset;
4182214082Sdim      myh->root.u.def.value = my_offset;
4183214082Sdim
4184214634Sdim      if (info->shared || globals->root.is_relocatable_executable
4185214634Sdim	  || globals->pic_veneer)
4186214082Sdim	{
4187214082Sdim	  /* For relocatable objects we can't use absolute addresses,
4188214082Sdim	     so construct the address from a relative offset.  */
4189214082Sdim	  /* TODO: If the offset is small it's probably worth
4190214082Sdim	     constructing the address with adds.  */
4191214634Sdim	  put_arm_insn (globals, output_bfd, (bfd_vma) a2t1p_ldr_insn,
4192214634Sdim			s->contents + my_offset);
4193214634Sdim	  put_arm_insn (globals, output_bfd, (bfd_vma) a2t2p_add_pc_insn,
4194214634Sdim			s->contents + my_offset + 4);
4195214634Sdim	  put_arm_insn (globals, output_bfd, (bfd_vma) a2t3p_bx_r12_insn,
4196214634Sdim			s->contents + my_offset + 8);
4197214082Sdim	  /* Adjust the offset by 4 for the position of the add,
4198214082Sdim	     and 8 for the pipeline offset.  */
4199214082Sdim	  ret_offset = (val - (s->output_offset
4200214082Sdim			       + s->output_section->vma
4201214082Sdim			       + my_offset + 12))
4202214082Sdim		       | 1;
4203214082Sdim	  bfd_put_32 (output_bfd, ret_offset,
4204214082Sdim		      s->contents + my_offset + 12);
4205214082Sdim	}
4206214634Sdim      else if (globals->use_blx)
4207214082Sdim	{
4208214634Sdim	  put_arm_insn (globals, output_bfd, (bfd_vma) a2t1v5_ldr_insn,
4209214634Sdim			s->contents + my_offset);
4210214082Sdim
4211214634Sdim	  /* It's a thumb address.  Add the low order bit.  */
4212214634Sdim	  bfd_put_32 (output_bfd, val | a2t2v5_func_addr_insn,
4213214082Sdim		      s->contents + my_offset + 4);
4214214634Sdim	}
4215214634Sdim      else
4216214634Sdim	{
4217214634Sdim	  put_arm_insn (globals, output_bfd, (bfd_vma) a2t1_ldr_insn,
4218214634Sdim			s->contents + my_offset);
4219214082Sdim
4220214634Sdim	  put_arm_insn (globals, output_bfd, (bfd_vma) a2t2_bx_r12_insn,
4221214634Sdim			s->contents + my_offset + 4);
4222214634Sdim
4223214082Sdim	  /* It's a thumb address.  Add the low order bit.  */
4224214082Sdim	  bfd_put_32 (output_bfd, val | a2t3_func_addr_insn,
4225214082Sdim		      s->contents + my_offset + 8);
4226214082Sdim	}
4227214082Sdim    }
4228214082Sdim
4229214082Sdim  BFD_ASSERT (my_offset <= globals->arm_glue_size);
4230214082Sdim
4231214634Sdim  return myh;
4232214634Sdim}
4233214634Sdim
4234214634Sdim/* Arm code calling a Thumb function.  */
4235214634Sdim
4236214634Sdimstatic int
4237214634Sdimelf32_arm_to_thumb_stub (struct bfd_link_info * info,
4238214634Sdim			 const char *           name,
4239214634Sdim			 bfd *                  input_bfd,
4240214634Sdim			 bfd *                  output_bfd,
4241214634Sdim			 asection *             input_section,
4242214634Sdim			 bfd_byte *             hit_data,
4243214634Sdim			 asection *             sym_sec,
4244214634Sdim			 bfd_vma                offset,
4245214634Sdim			 bfd_signed_vma         addend,
4246214634Sdim			 bfd_vma                val,
4247214634Sdim			 char **error_message)
4248214634Sdim{
4249214634Sdim  unsigned long int tmp;
4250214634Sdim  bfd_vma my_offset;
4251214634Sdim  asection * s;
4252214634Sdim  long int ret_offset;
4253214634Sdim  struct elf_link_hash_entry * myh;
4254214634Sdim  struct elf32_arm_link_hash_table * globals;
4255214634Sdim
4256214634Sdim  globals = elf32_arm_hash_table (info);
4257214634Sdim
4258214634Sdim  BFD_ASSERT (globals != NULL);
4259214634Sdim  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
4260214634Sdim
4261214634Sdim  s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
4262214634Sdim			       ARM2THUMB_GLUE_SECTION_NAME);
4263214634Sdim  BFD_ASSERT (s != NULL);
4264214634Sdim  BFD_ASSERT (s->contents != NULL);
4265214634Sdim  BFD_ASSERT (s->output_section != NULL);
4266214634Sdim
4267214634Sdim  myh = elf32_arm_create_thumb_stub (info, name, input_bfd, output_bfd,
4268214634Sdim				     sym_sec, val, s, error_message);
4269214634Sdim  if (!myh)
4270214634Sdim    return FALSE;
4271214634Sdim
4272214634Sdim  my_offset = myh->root.u.def.value;
4273214082Sdim  tmp = bfd_get_32 (input_bfd, hit_data);
4274214082Sdim  tmp = tmp & 0xFF000000;
4275214082Sdim
4276214082Sdim  /* Somehow these are both 4 too far, so subtract 8.  */
4277214082Sdim  ret_offset = (s->output_offset
4278214082Sdim		+ my_offset
4279214082Sdim		+ s->output_section->vma
4280214082Sdim		- (input_section->output_offset
4281214082Sdim		   + input_section->output_section->vma
4282214082Sdim		   + offset + addend)
4283214082Sdim		- 8);
4284214082Sdim
4285214082Sdim  tmp = tmp | ((ret_offset >> 2) & 0x00FFFFFF);
4286214082Sdim
4287214082Sdim  bfd_put_32 (output_bfd, (bfd_vma) tmp, hit_data - input_section->vma);
4288214082Sdim
4289214082Sdim  return TRUE;
4290214082Sdim}
4291214082Sdim
4292214634Sdim/* Populate Arm stub for an exported Thumb function.  */
4293214634Sdim
4294214634Sdimstatic bfd_boolean
4295214634Sdimelf32_arm_to_thumb_export_stub (struct elf_link_hash_entry *h, void * inf)
4296214634Sdim{
4297214634Sdim  struct bfd_link_info * info = (struct bfd_link_info *) inf;
4298214634Sdim  asection * s;
4299214634Sdim  struct elf_link_hash_entry * myh;
4300214634Sdim  struct elf32_arm_link_hash_entry *eh;
4301214634Sdim  struct elf32_arm_link_hash_table * globals;
4302214634Sdim  asection *sec;
4303214634Sdim  bfd_vma val;
4304214634Sdim  char *error_message;
4305214634Sdim
4306214634Sdim  eh = elf32_arm_hash_entry(h);
4307214634Sdim  /* Allocate stubs for exported Thumb functions on v4t.  */
4308214634Sdim  if (eh->export_glue == NULL)
4309214634Sdim    return TRUE;
4310214634Sdim
4311214634Sdim  globals = elf32_arm_hash_table (info);
4312214634Sdim
4313214634Sdim  BFD_ASSERT (globals != NULL);
4314214634Sdim  BFD_ASSERT (globals->bfd_of_glue_owner != NULL);
4315214634Sdim
4316214634Sdim  s = bfd_get_section_by_name (globals->bfd_of_glue_owner,
4317214634Sdim			       ARM2THUMB_GLUE_SECTION_NAME);
4318214634Sdim  BFD_ASSERT (s != NULL);
4319214634Sdim  BFD_ASSERT (s->contents != NULL);
4320214634Sdim  BFD_ASSERT (s->output_section != NULL);
4321214634Sdim
4322214634Sdim  sec = eh->export_glue->root.u.def.section;
4323214634Sdim
4324214634Sdim  BFD_ASSERT (sec->output_section != NULL);
4325214634Sdim
4326214634Sdim  val = eh->export_glue->root.u.def.value + sec->output_offset
4327214634Sdim	+ sec->output_section->vma;
4328214634Sdim  myh = elf32_arm_create_thumb_stub (info, h->root.root.string,
4329214634Sdim				     h->root.u.def.section->owner,
4330214634Sdim				     globals->obfd, sec, val, s,
4331214634Sdim				     &error_message);
4332214634Sdim  BFD_ASSERT (myh);
4333214634Sdim  return TRUE;
4334214634Sdim}
4335214634Sdim
4336214634Sdim/* Generate Arm stubs for exported Thumb symbols.  */
4337214634Sdimstatic void
4338214634Sdimelf32_arm_begin_write_processing (bfd *abfd ATTRIBUTE_UNUSED,
4339214634Sdim				  struct bfd_link_info *link_info)
4340214634Sdim{
4341214634Sdim  struct elf32_arm_link_hash_table * globals;
4342214634Sdim
4343214634Sdim  if (!link_info)
4344214634Sdim    return;
4345214634Sdim
4346214634Sdim  globals = elf32_arm_hash_table (link_info);
4347214634Sdim  /* If blx is available then exported Thumb symbols are OK and there is
4348214634Sdim     nothing to do.  */
4349214634Sdim  if (globals->use_blx)
4350214634Sdim    return;
4351214634Sdim
4352214634Sdim  elf_link_hash_traverse (&globals->root, elf32_arm_to_thumb_export_stub,
4353214634Sdim			  link_info);
4354214634Sdim}
4355214634Sdim
4356214082Sdim/* Some relocations map to different relocations depending on the
4357214082Sdim   target.  Return the real relocation.  */
4358214082Sdimstatic int
4359214082Sdimarm_real_reloc_type (struct elf32_arm_link_hash_table * globals,
4360214082Sdim		     int r_type)
4361214082Sdim{
4362214082Sdim  switch (r_type)
4363214082Sdim    {
4364214082Sdim    case R_ARM_TARGET1:
4365214082Sdim      if (globals->target1_is_rel)
4366214082Sdim	return R_ARM_REL32;
4367214082Sdim      else
4368214082Sdim	return R_ARM_ABS32;
4369214082Sdim
4370214082Sdim    case R_ARM_TARGET2:
4371214082Sdim      return globals->target2_reloc;
4372214082Sdim
4373214082Sdim    default:
4374214082Sdim      return r_type;
4375214082Sdim    }
4376214082Sdim}
4377214082Sdim
4378214082Sdim/* Return the base VMA address which should be subtracted from real addresses
4379214082Sdim   when resolving @dtpoff relocation.
4380214082Sdim   This is PT_TLS segment p_vaddr.  */
4381214082Sdim
4382214082Sdimstatic bfd_vma
4383214082Sdimdtpoff_base (struct bfd_link_info *info)
4384214082Sdim{
4385214082Sdim  /* If tls_sec is NULL, we should have signalled an error already.  */
4386214082Sdim  if (elf_hash_table (info)->tls_sec == NULL)
4387214082Sdim    return 0;
4388214082Sdim  return elf_hash_table (info)->tls_sec->vma;
4389214082Sdim}
4390214082Sdim
4391214082Sdim/* Return the relocation value for @tpoff relocation
4392214082Sdim   if STT_TLS virtual address is ADDRESS.  */
4393214082Sdim
4394214082Sdimstatic bfd_vma
4395214082Sdimtpoff (struct bfd_link_info *info, bfd_vma address)
4396214082Sdim{
4397214082Sdim  struct elf_link_hash_table *htab = elf_hash_table (info);
4398214082Sdim  bfd_vma base;
4399214082Sdim
4400214082Sdim  /* If tls_sec is NULL, we should have signalled an error already.  */
4401214082Sdim  if (htab->tls_sec == NULL)
4402214082Sdim    return 0;
4403214082Sdim  base = align_power ((bfd_vma) TCB_SIZE, htab->tls_sec->alignment_power);
4404214082Sdim  return address - htab->tls_sec->vma + base;
4405214082Sdim}
4406214082Sdim
4407214082Sdim/* Perform an R_ARM_ABS12 relocation on the field pointed to by DATA.
4408214082Sdim   VALUE is the relocation value.  */
4409214082Sdim
4410214082Sdimstatic bfd_reloc_status_type
4411214082Sdimelf32_arm_abs12_reloc (bfd *abfd, void *data, bfd_vma value)
4412214082Sdim{
4413214082Sdim  if (value > 0xfff)
4414214082Sdim    return bfd_reloc_overflow;
4415214082Sdim
4416214082Sdim  value |= bfd_get_32 (abfd, data) & 0xfffff000;
4417214082Sdim  bfd_put_32 (abfd, value, data);
4418214082Sdim  return bfd_reloc_ok;
4419214082Sdim}
4420214082Sdim
4421214634Sdim/* For a given value of n, calculate the value of G_n as required to
4422214634Sdim   deal with group relocations.  We return it in the form of an
4423214634Sdim   encoded constant-and-rotation, together with the final residual.  If n is
4424214634Sdim   specified as less than zero, then final_residual is filled with the
4425214634Sdim   input value and no further action is performed.  */
4426214634Sdim
4427214634Sdimstatic bfd_vma
4428214634Sdimcalculate_group_reloc_mask (bfd_vma value, int n, bfd_vma *final_residual)
4429214634Sdim{
4430214634Sdim  int current_n;
4431214634Sdim  bfd_vma g_n;
4432214634Sdim  bfd_vma encoded_g_n = 0;
4433214634Sdim  bfd_vma residual = value; /* Also known as Y_n.  */
4434214634Sdim
4435214634Sdim  for (current_n = 0; current_n <= n; current_n++)
4436214634Sdim    {
4437214634Sdim      int shift;
4438214634Sdim
4439214634Sdim      /* Calculate which part of the value to mask.  */
4440214634Sdim      if (residual == 0)
4441214634Sdim        shift = 0;
4442214634Sdim      else
4443214634Sdim        {
4444214634Sdim          int msb;
4445214634Sdim
4446214634Sdim          /* Determine the most significant bit in the residual and
4447214634Sdim             align the resulting value to a 2-bit boundary.  */
4448214634Sdim          for (msb = 30; msb >= 0; msb -= 2)
4449214634Sdim            if (residual & (3 << msb))
4450214634Sdim              break;
4451214634Sdim
4452214634Sdim          /* The desired shift is now (msb - 6), or zero, whichever
4453214634Sdim             is the greater.  */
4454214634Sdim          shift = msb - 6;
4455214634Sdim          if (shift < 0)
4456214634Sdim            shift = 0;
4457214634Sdim        }
4458214634Sdim
4459214634Sdim      /* Calculate g_n in 32-bit as well as encoded constant+rotation form.  */
4460214634Sdim      g_n = residual & (0xff << shift);
4461214634Sdim      encoded_g_n = (g_n >> shift)
4462214634Sdim                    | ((g_n <= 0xff ? 0 : (32 - shift) / 2) << 8);
4463214634Sdim
4464214634Sdim      /* Calculate the residual for the next time around.  */
4465214634Sdim      residual &= ~g_n;
4466214634Sdim    }
4467214634Sdim
4468214634Sdim  *final_residual = residual;
4469214634Sdim
4470214634Sdim  return encoded_g_n;
4471214634Sdim}
4472214634Sdim
4473214634Sdim/* Given an ARM instruction, determine whether it is an ADD or a SUB.
4474214634Sdim   Returns 1 if it is an ADD, -1 if it is a SUB, and 0 otherwise.  */
4475214634Sdimstatic int
4476214634Sdimidentify_add_or_sub(bfd_vma insn)
4477214634Sdim{
4478214634Sdim  int opcode = insn & 0x1e00000;
4479214634Sdim
4480214634Sdim  if (opcode == 1 << 23) /* ADD */
4481214634Sdim    return 1;
4482214634Sdim
4483214634Sdim  if (opcode == 1 << 22) /* SUB */
4484214634Sdim    return -1;
4485214634Sdim
4486214634Sdim  return 0;
4487214634Sdim}
4488214634Sdim
4489214634Sdim/* Determine if we're dealing with a Thumb-2 object.  */
4490214634Sdim
4491214634Sdimstatic int using_thumb2 (struct elf32_arm_link_hash_table *globals)
4492214634Sdim{
4493214634Sdim  int arch = bfd_elf_get_obj_attr_int (globals->obfd, OBJ_ATTR_PROC,
4494214634Sdim				       Tag_CPU_arch);
4495214634Sdim  return arch == TAG_CPU_ARCH_V6T2 || arch >= TAG_CPU_ARCH_V7;
4496214634Sdim}
4497214634Sdim
4498214082Sdim/* Perform a relocation as part of a final link.  */
4499214082Sdim
4500214082Sdimstatic bfd_reloc_status_type
4501214082Sdimelf32_arm_final_link_relocate (reloc_howto_type *           howto,
4502214082Sdim			       bfd *                        input_bfd,
4503214082Sdim			       bfd *                        output_bfd,
4504214082Sdim			       asection *                   input_section,
4505214082Sdim			       bfd_byte *                   contents,
4506214082Sdim			       Elf_Internal_Rela *          rel,
4507214082Sdim			       bfd_vma                      value,
4508214082Sdim			       struct bfd_link_info *       info,
4509214082Sdim			       asection *                   sym_sec,
4510214082Sdim			       const char *                 sym_name,
4511214082Sdim			       int		            sym_flags,
4512214082Sdim			       struct elf_link_hash_entry * h,
4513214634Sdim			       bfd_boolean *                unresolved_reloc_p,
4514214634Sdim			       char **error_message)
4515214082Sdim{
4516214082Sdim  unsigned long                 r_type = howto->type;
4517214082Sdim  unsigned long                 r_symndx;
4518214082Sdim  bfd_byte *                    hit_data = contents + rel->r_offset;
4519214082Sdim  bfd *                         dynobj = NULL;
4520214082Sdim  Elf_Internal_Shdr *           symtab_hdr;
4521214082Sdim  struct elf_link_hash_entry ** sym_hashes;
4522214082Sdim  bfd_vma *                     local_got_offsets;
4523214082Sdim  asection *                    sgot = NULL;
4524214082Sdim  asection *                    splt = NULL;
4525214082Sdim  asection *                    sreloc = NULL;
4526214082Sdim  bfd_vma                       addend;
4527214082Sdim  bfd_signed_vma                signed_addend;
4528214082Sdim  struct elf32_arm_link_hash_table * globals;
4529214082Sdim
4530214082Sdim  globals = elf32_arm_hash_table (info);
4531214082Sdim
4532214082Sdim  /* Some relocation type map to different relocations depending on the
4533214082Sdim     target.  We pick the right one here.  */
4534214082Sdim  r_type = arm_real_reloc_type (globals, r_type);
4535214082Sdim  if (r_type != howto->type)
4536214082Sdim    howto = elf32_arm_howto_from_type (r_type);
4537214082Sdim
4538214082Sdim  /* If the start address has been set, then set the EF_ARM_HASENTRY
4539214082Sdim     flag.  Setting this more than once is redundant, but the cost is
4540214082Sdim     not too high, and it keeps the code simple.
4541214082Sdim
4542214082Sdim     The test is done  here, rather than somewhere else, because the
4543214082Sdim     start address is only set just before the final link commences.
4544214082Sdim
4545214082Sdim     Note - if the user deliberately sets a start address of 0, the
4546214082Sdim     flag will not be set.  */
4547214082Sdim  if (bfd_get_start_address (output_bfd) != 0)
4548214082Sdim    elf_elfheader (output_bfd)->e_flags |= EF_ARM_HASENTRY;
4549214082Sdim
4550214082Sdim  dynobj = elf_hash_table (info)->dynobj;
4551214082Sdim  if (dynobj)
4552214082Sdim    {
4553214082Sdim      sgot = bfd_get_section_by_name (dynobj, ".got");
4554214082Sdim      splt = bfd_get_section_by_name (dynobj, ".plt");
4555214082Sdim    }
4556214082Sdim  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
4557214082Sdim  sym_hashes = elf_sym_hashes (input_bfd);
4558214082Sdim  local_got_offsets = elf_local_got_offsets (input_bfd);
4559214082Sdim  r_symndx = ELF32_R_SYM (rel->r_info);
4560214082Sdim
4561214082Sdim  if (globals->use_rel)
4562214082Sdim    {
4563214082Sdim      addend = bfd_get_32 (input_bfd, hit_data) & howto->src_mask;
4564214082Sdim
4565214082Sdim      if (addend & ((howto->src_mask + 1) >> 1))
4566214082Sdim	{
4567214082Sdim	  signed_addend = -1;
4568214082Sdim	  signed_addend &= ~ howto->src_mask;
4569214082Sdim	  signed_addend |= addend;
4570214082Sdim	}
4571214082Sdim      else
4572214082Sdim	signed_addend = addend;
4573214082Sdim    }
4574214082Sdim  else
4575214082Sdim    addend = signed_addend = rel->r_addend;
4576214082Sdim
4577214082Sdim  switch (r_type)
4578214082Sdim    {
4579214082Sdim    case R_ARM_NONE:
4580214082Sdim      /* We don't need to find a value for this symbol.  It's just a
4581214082Sdim	 marker.  */
4582214082Sdim      *unresolved_reloc_p = FALSE;
4583214082Sdim      return bfd_reloc_ok;
4584214082Sdim
4585214082Sdim    case R_ARM_ABS12:
4586214082Sdim      if (!globals->vxworks_p)
4587214082Sdim	return elf32_arm_abs12_reloc (input_bfd, hit_data, value + addend);
4588214082Sdim
4589214082Sdim    case R_ARM_PC24:
4590214082Sdim    case R_ARM_ABS32:
4591214634Sdim    case R_ARM_ABS32_NOI:
4592214082Sdim    case R_ARM_REL32:
4593214634Sdim    case R_ARM_REL32_NOI:
4594214082Sdim    case R_ARM_CALL:
4595214082Sdim    case R_ARM_JUMP24:
4596214082Sdim    case R_ARM_XPC25:
4597214082Sdim    case R_ARM_PREL31:
4598214082Sdim    case R_ARM_PLT32:
4599214082Sdim      /* Handle relocations which should use the PLT entry.  ABS32/REL32
4600214082Sdim	 will use the symbol's value, which may point to a PLT entry, but we
4601214082Sdim	 don't need to handle that here.  If we created a PLT entry, all
4602214082Sdim	 branches in this object should go to it.  */
4603214634Sdim      if ((r_type != R_ARM_ABS32 && r_type != R_ARM_REL32
4604214634Sdim           && r_type != R_ARM_ABS32_NOI && r_type != R_ARM_REL32_NOI)
4605214082Sdim	  && h != NULL
4606214082Sdim	  && splt != NULL
4607214082Sdim	  && h->plt.offset != (bfd_vma) -1)
4608214082Sdim	{
4609214082Sdim	  /* If we've created a .plt section, and assigned a PLT entry to
4610214082Sdim	     this function, it should not be known to bind locally.  If
4611214082Sdim	     it were, we would have cleared the PLT entry.  */
4612214082Sdim	  BFD_ASSERT (!SYMBOL_CALLS_LOCAL (info, h));
4613214082Sdim
4614214082Sdim	  value = (splt->output_section->vma
4615214082Sdim		   + splt->output_offset
4616214082Sdim		   + h->plt.offset);
4617214082Sdim	  *unresolved_reloc_p = FALSE;
4618214082Sdim	  return _bfd_final_link_relocate (howto, input_bfd, input_section,
4619214082Sdim					   contents, rel->r_offset, value,
4620214082Sdim					   rel->r_addend);
4621214082Sdim	}
4622214082Sdim
4623214082Sdim      /* When generating a shared object or relocatable executable, these
4624214082Sdim	 relocations are copied into the output file to be resolved at
4625214082Sdim	 run time.  */
4626214082Sdim      if ((info->shared || globals->root.is_relocatable_executable)
4627214082Sdim	  && (input_section->flags & SEC_ALLOC)
4628214634Sdim	  && ((r_type != R_ARM_REL32 && r_type != R_ARM_REL32_NOI)
4629214082Sdim	      || !SYMBOL_CALLS_LOCAL (info, h))
4630214082Sdim	  && (h == NULL
4631214082Sdim	      || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
4632214082Sdim	      || h->root.type != bfd_link_hash_undefweak)
4633214082Sdim	  && r_type != R_ARM_PC24
4634214082Sdim	  && r_type != R_ARM_CALL
4635214082Sdim	  && r_type != R_ARM_JUMP24
4636214082Sdim	  && r_type != R_ARM_PREL31
4637214082Sdim	  && r_type != R_ARM_PLT32)
4638214082Sdim	{
4639214082Sdim	  Elf_Internal_Rela outrel;
4640214082Sdim	  bfd_byte *loc;
4641214082Sdim	  bfd_boolean skip, relocate;
4642214082Sdim
4643214082Sdim	  *unresolved_reloc_p = FALSE;
4644214082Sdim
4645214082Sdim	  if (sreloc == NULL)
4646214082Sdim	    {
4647214082Sdim	      const char * name;
4648214082Sdim
4649214082Sdim	      name = (bfd_elf_string_from_elf_section
4650214082Sdim		      (input_bfd,
4651214082Sdim		       elf_elfheader (input_bfd)->e_shstrndx,
4652214082Sdim		       elf_section_data (input_section)->rel_hdr.sh_name));
4653214082Sdim	      if (name == NULL)
4654214082Sdim		return bfd_reloc_notsupported;
4655214082Sdim
4656214082Sdim	      BFD_ASSERT (reloc_section_p (globals, name, input_section));
4657214082Sdim
4658214082Sdim	      sreloc = bfd_get_section_by_name (dynobj, name);
4659214082Sdim	      BFD_ASSERT (sreloc != NULL);
4660214082Sdim	    }
4661214082Sdim
4662214082Sdim	  skip = FALSE;
4663214082Sdim	  relocate = FALSE;
4664214082Sdim
4665214082Sdim	  outrel.r_addend = addend;
4666214082Sdim	  outrel.r_offset =
4667214082Sdim	    _bfd_elf_section_offset (output_bfd, info, input_section,
4668214082Sdim				     rel->r_offset);
4669214082Sdim	  if (outrel.r_offset == (bfd_vma) -1)
4670214082Sdim	    skip = TRUE;
4671214082Sdim	  else if (outrel.r_offset == (bfd_vma) -2)
4672214082Sdim	    skip = TRUE, relocate = TRUE;
4673214082Sdim	  outrel.r_offset += (input_section->output_section->vma
4674214082Sdim			      + input_section->output_offset);
4675214082Sdim
4676214082Sdim	  if (skip)
4677214082Sdim	    memset (&outrel, 0, sizeof outrel);
4678214082Sdim	  else if (h != NULL
4679214082Sdim		   && h->dynindx != -1
4680214082Sdim		   && (!info->shared
4681214082Sdim		       || !info->symbolic
4682214082Sdim		       || !h->def_regular))
4683214082Sdim	    outrel.r_info = ELF32_R_INFO (h->dynindx, r_type);
4684214082Sdim	  else
4685214082Sdim	    {
4686214082Sdim	      int symbol;
4687214082Sdim
4688214082Sdim	      /* This symbol is local, or marked to become local.  */
4689214082Sdim	      if (sym_flags == STT_ARM_TFUNC)
4690214082Sdim		value |= 1;
4691214082Sdim	      if (globals->symbian_p)
4692214082Sdim		{
4693214634Sdim		  asection *osec;
4694214634Sdim
4695214082Sdim		  /* On Symbian OS, the data segment and text segement
4696214082Sdim		     can be relocated independently.  Therefore, we
4697214082Sdim		     must indicate the segment to which this
4698214082Sdim		     relocation is relative.  The BPABI allows us to
4699214082Sdim		     use any symbol in the right segment; we just use
4700214082Sdim		     the section symbol as it is convenient.  (We
4701214082Sdim		     cannot use the symbol given by "h" directly as it
4702214634Sdim		     will not appear in the dynamic symbol table.)
4703214634Sdim
4704214634Sdim		     Note that the dynamic linker ignores the section
4705214634Sdim		     symbol value, so we don't subtract osec->vma
4706214634Sdim		     from the emitted reloc addend.  */
4707214082Sdim		  if (sym_sec)
4708214634Sdim		    osec = sym_sec->output_section;
4709214082Sdim		  else
4710214634Sdim		    osec = input_section->output_section;
4711214634Sdim		  symbol = elf_section_data (osec)->dynindx;
4712214634Sdim		  if (symbol == 0)
4713214634Sdim		    {
4714214634Sdim		      struct elf_link_hash_table *htab = elf_hash_table (info);
4715214634Sdim
4716214634Sdim		      if ((osec->flags & SEC_READONLY) == 0
4717214634Sdim			  && htab->data_index_section != NULL)
4718214634Sdim			osec = htab->data_index_section;
4719214634Sdim		      else
4720214634Sdim			osec = htab->text_index_section;
4721214634Sdim		      symbol = elf_section_data (osec)->dynindx;
4722214634Sdim		    }
4723214082Sdim		  BFD_ASSERT (symbol != 0);
4724214082Sdim		}
4725214082Sdim	      else
4726214082Sdim		/* On SVR4-ish systems, the dynamic loader cannot
4727214082Sdim		   relocate the text and data segments independently,
4728214082Sdim		   so the symbol does not matter.  */
4729214082Sdim		symbol = 0;
4730214082Sdim	      outrel.r_info = ELF32_R_INFO (symbol, R_ARM_RELATIVE);
4731214082Sdim	      if (globals->use_rel)
4732214082Sdim		relocate = TRUE;
4733214082Sdim	      else
4734214082Sdim		outrel.r_addend += value;
4735214082Sdim	    }
4736214082Sdim
4737214082Sdim	  loc = sreloc->contents;
4738214082Sdim	  loc += sreloc->reloc_count++ * RELOC_SIZE (globals);
4739214082Sdim	  SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
4740214082Sdim
4741214082Sdim	  /* If this reloc is against an external symbol, we do not want to
4742214082Sdim	     fiddle with the addend.  Otherwise, we need to include the symbol
4743214082Sdim	     value so that it becomes an addend for the dynamic reloc.  */
4744214082Sdim	  if (! relocate)
4745214082Sdim	    return bfd_reloc_ok;
4746214082Sdim
4747214082Sdim	  return _bfd_final_link_relocate (howto, input_bfd, input_section,
4748214082Sdim					   contents, rel->r_offset, value,
4749214082Sdim					   (bfd_vma) 0);
4750214082Sdim	}
4751214082Sdim      else switch (r_type)
4752214082Sdim	{
4753214082Sdim	case R_ARM_ABS12:
4754214082Sdim	  return elf32_arm_abs12_reloc (input_bfd, hit_data, value + addend);
4755214082Sdim
4756214082Sdim	case R_ARM_XPC25:	  /* Arm BLX instruction.  */
4757214082Sdim	case R_ARM_CALL:
4758214082Sdim	case R_ARM_JUMP24:
4759214082Sdim	case R_ARM_PC24:	  /* Arm B/BL instruction */
4760214082Sdim	case R_ARM_PLT32:
4761214082Sdim	  if (r_type == R_ARM_XPC25)
4762214082Sdim	    {
4763214082Sdim	      /* Check for Arm calling Arm function.  */
4764214082Sdim	      /* FIXME: Should we translate the instruction into a BL
4765214082Sdim		 instruction instead ?  */
4766214082Sdim	      if (sym_flags != STT_ARM_TFUNC)
4767214082Sdim		(*_bfd_error_handler)
4768214082Sdim		  (_("\%B: Warning: Arm BLX instruction targets Arm function '%s'."),
4769214082Sdim		   input_bfd,
4770214082Sdim		   h ? h->root.root.string : "(local)");
4771214082Sdim	    }
4772214082Sdim	  else if (r_type != R_ARM_CALL || !globals->use_blx)
4773214082Sdim	    {
4774214082Sdim	      /* Check for Arm calling Thumb function.  */
4775214082Sdim	      if (sym_flags == STT_ARM_TFUNC)
4776214082Sdim		{
4777214634Sdim		  if (elf32_arm_to_thumb_stub (info, sym_name, input_bfd,
4778214634Sdim					       output_bfd, input_section,
4779214634Sdim					       hit_data, sym_sec, rel->r_offset,
4780214634Sdim					       signed_addend, value,
4781214634Sdim					       error_message))
4782214634Sdim		    return bfd_reloc_ok;
4783214634Sdim		  else
4784214634Sdim		    return bfd_reloc_dangerous;
4785214082Sdim		}
4786214082Sdim	    }
4787214082Sdim
4788214082Sdim	  /* The ARM ELF ABI says that this reloc is computed as: S - P + A
4789214082Sdim	     where:
4790214082Sdim	      S is the address of the symbol in the relocation.
4791214082Sdim	      P is address of the instruction being relocated.
4792214082Sdim	      A is the addend (extracted from the instruction) in bytes.
4793214082Sdim
4794214082Sdim	     S is held in 'value'.
4795214082Sdim	     P is the base address of the section containing the
4796214082Sdim	       instruction plus the offset of the reloc into that
4797214082Sdim	       section, ie:
4798214082Sdim		 (input_section->output_section->vma +
4799214082Sdim		  input_section->output_offset +
4800214082Sdim		  rel->r_offset).
4801214082Sdim	     A is the addend, converted into bytes, ie:
4802214082Sdim		 (signed_addend * 4)
4803214082Sdim
4804214082Sdim	     Note: None of these operations have knowledge of the pipeline
4805214082Sdim	     size of the processor, thus it is up to the assembler to
4806214082Sdim	     encode this information into the addend.  */
4807214082Sdim	  value -= (input_section->output_section->vma
4808214082Sdim		    + input_section->output_offset);
4809214082Sdim	  value -= rel->r_offset;
4810214082Sdim	  if (globals->use_rel)
4811214082Sdim	    value += (signed_addend << howto->size);
4812214082Sdim	  else
4813214082Sdim	    /* RELA addends do not have to be adjusted by howto->size.  */
4814214082Sdim	    value += signed_addend;
4815214082Sdim
4816214082Sdim	  signed_addend = value;
4817214082Sdim	  signed_addend >>= howto->rightshift;
4818214082Sdim
4819214634Sdim	  /* A branch to an undefined weak symbol is turned into a jump to
4820214634Sdim	     the next instruction.  */
4821214634Sdim	  if (h && h->root.type == bfd_link_hash_undefweak)
4822214082Sdim	    {
4823214634Sdim	      value = (bfd_get_32 (input_bfd, hit_data) & 0xf0000000)
4824214634Sdim		      | 0x0affffff;
4825214634Sdim	    }
4826214634Sdim	  else
4827214634Sdim	    {
4828214082Sdim	      /* Perform a signed range check.  */
4829214082Sdim	      if (   signed_addend >   ((bfd_signed_vma)  (howto->dst_mask >> 1))
4830214082Sdim		  || signed_addend < - ((bfd_signed_vma) ((howto->dst_mask + 1) >> 1)))
4831214082Sdim		return bfd_reloc_overflow;
4832214082Sdim
4833214634Sdim	      addend = (value & 2);
4834214082Sdim
4835214634Sdim	      value = (signed_addend & howto->dst_mask)
4836214634Sdim		| (bfd_get_32 (input_bfd, hit_data) & (~ howto->dst_mask));
4837214082Sdim
4838214634Sdim	      /* Set the H bit in the BLX instruction.  */
4839214082Sdim	      if (sym_flags == STT_ARM_TFUNC)
4840214082Sdim		{
4841214634Sdim		  if (addend)
4842214634Sdim		    value |= (1 << 24);
4843214634Sdim		  else
4844214634Sdim		    value &= ~(bfd_vma)(1 << 24);
4845214082Sdim		}
4846214634Sdim	      if (r_type == R_ARM_CALL)
4847214634Sdim		{
4848214634Sdim		  /* Select the correct instruction (BL or BLX).  */
4849214634Sdim		  if (sym_flags == STT_ARM_TFUNC)
4850214634Sdim		    value |= (1 << 28);
4851214634Sdim		  else
4852214634Sdim		    {
4853214634Sdim		      value &= ~(bfd_vma)(1 << 28);
4854214634Sdim		      value |= (1 << 24);
4855214634Sdim		    }
4856214634Sdim		}
4857214082Sdim	    }
4858214082Sdim	  break;
4859214082Sdim
4860214082Sdim	case R_ARM_ABS32:
4861214082Sdim	  value += addend;
4862214082Sdim	  if (sym_flags == STT_ARM_TFUNC)
4863214082Sdim	    value |= 1;
4864214082Sdim	  break;
4865214082Sdim
4866214634Sdim	case R_ARM_ABS32_NOI:
4867214634Sdim	  value += addend;
4868214634Sdim	  break;
4869214634Sdim
4870214082Sdim	case R_ARM_REL32:
4871214082Sdim	  value += addend;
4872214082Sdim	  if (sym_flags == STT_ARM_TFUNC)
4873214082Sdim	    value |= 1;
4874214082Sdim	  value -= (input_section->output_section->vma
4875214082Sdim		    + input_section->output_offset + rel->r_offset);
4876214082Sdim	  break;
4877214082Sdim
4878214634Sdim	case R_ARM_REL32_NOI:
4879214634Sdim	  value += addend;
4880214634Sdim	  value -= (input_section->output_section->vma
4881214634Sdim		    + input_section->output_offset + rel->r_offset);
4882214634Sdim	  break;
4883214634Sdim
4884214082Sdim	case R_ARM_PREL31:
4885214082Sdim	  value -= (input_section->output_section->vma
4886214082Sdim		    + input_section->output_offset + rel->r_offset);
4887214082Sdim	  value += signed_addend;
4888214082Sdim	  if (! h || h->root.type != bfd_link_hash_undefweak)
4889214082Sdim	    {
4890214082Sdim	      /* Check for overflow */
4891214082Sdim	      if ((value ^ (value >> 1)) & (1 << 30))
4892214082Sdim		return bfd_reloc_overflow;
4893214082Sdim	    }
4894214082Sdim	  value &= 0x7fffffff;
4895214082Sdim	  value |= (bfd_get_32 (input_bfd, hit_data) & 0x80000000);
4896214082Sdim	  if (sym_flags == STT_ARM_TFUNC)
4897214082Sdim	    value |= 1;
4898214082Sdim	  break;
4899214082Sdim	}
4900214082Sdim
4901214082Sdim      bfd_put_32 (input_bfd, value, hit_data);
4902214082Sdim      return bfd_reloc_ok;
4903214082Sdim
4904214082Sdim    case R_ARM_ABS8:
4905214082Sdim      value += addend;
4906214082Sdim      if ((long) value > 0x7f || (long) value < -0x80)
4907214082Sdim	return bfd_reloc_overflow;
4908214082Sdim
4909214082Sdim      bfd_put_8 (input_bfd, value, hit_data);
4910214082Sdim      return bfd_reloc_ok;
4911214082Sdim
4912214082Sdim    case R_ARM_ABS16:
4913214082Sdim      value += addend;
4914214082Sdim
4915214082Sdim      if ((long) value > 0x7fff || (long) value < -0x8000)
4916214082Sdim	return bfd_reloc_overflow;
4917214082Sdim
4918214082Sdim      bfd_put_16 (input_bfd, value, hit_data);
4919214082Sdim      return bfd_reloc_ok;
4920214082Sdim
4921214082Sdim    case R_ARM_THM_ABS5:
4922214082Sdim      /* Support ldr and str instructions for the thumb.  */
4923214082Sdim      if (globals->use_rel)
4924214082Sdim	{
4925214082Sdim	  /* Need to refetch addend.  */
4926214082Sdim	  addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask;
4927214082Sdim	  /* ??? Need to determine shift amount from operand size.  */
4928214082Sdim	  addend >>= howto->rightshift;
4929214082Sdim	}
4930214082Sdim      value += addend;
4931214082Sdim
4932214082Sdim      /* ??? Isn't value unsigned?  */
4933214082Sdim      if ((long) value > 0x1f || (long) value < -0x10)
4934214082Sdim	return bfd_reloc_overflow;
4935214082Sdim
4936214082Sdim      /* ??? Value needs to be properly shifted into place first.  */
4937214082Sdim      value |= bfd_get_16 (input_bfd, hit_data) & 0xf83f;
4938214082Sdim      bfd_put_16 (input_bfd, value, hit_data);
4939214082Sdim      return bfd_reloc_ok;
4940214082Sdim
4941214634Sdim    case R_ARM_THM_ALU_PREL_11_0:
4942214634Sdim      /* Corresponds to: addw.w reg, pc, #offset (and similarly for subw).  */
4943214634Sdim      {
4944214634Sdim	bfd_vma insn;
4945214634Sdim	bfd_signed_vma relocation;
4946214634Sdim
4947214634Sdim	insn = (bfd_get_16 (input_bfd, hit_data) << 16)
4948214634Sdim             | bfd_get_16 (input_bfd, hit_data + 2);
4949214634Sdim
4950214634Sdim        if (globals->use_rel)
4951214634Sdim          {
4952214634Sdim            signed_addend = (insn & 0xff) | ((insn & 0x7000) >> 4)
4953214634Sdim                          | ((insn & (1 << 26)) >> 15);
4954214634Sdim            if (insn & 0xf00000)
4955214634Sdim              signed_addend = -signed_addend;
4956214634Sdim          }
4957214634Sdim
4958214634Sdim	relocation = value + signed_addend;
4959214634Sdim	relocation -= (input_section->output_section->vma
4960214634Sdim		       + input_section->output_offset
4961214634Sdim		       + rel->r_offset);
4962214634Sdim
4963214634Sdim        value = abs (relocation);
4964214634Sdim
4965214634Sdim        if (value >= 0x1000)
4966214634Sdim          return bfd_reloc_overflow;
4967214634Sdim
4968214634Sdim	insn = (insn & 0xfb0f8f00) | (value & 0xff)
4969214634Sdim             | ((value & 0x700) << 4)
4970214634Sdim             | ((value & 0x800) << 15);
4971214634Sdim        if (relocation < 0)
4972214634Sdim          insn |= 0xa00000;
4973214634Sdim
4974214634Sdim	bfd_put_16 (input_bfd, insn >> 16, hit_data);
4975214634Sdim	bfd_put_16 (input_bfd, insn & 0xffff, hit_data + 2);
4976214634Sdim
4977214634Sdim        return bfd_reloc_ok;
4978214634Sdim      }
4979214634Sdim
4980214634Sdim    case R_ARM_THM_PC12:
4981214634Sdim      /* Corresponds to: ldr.w reg, [pc, #offset].  */
4982214634Sdim      {
4983214634Sdim	bfd_vma insn;
4984214634Sdim	bfd_signed_vma relocation;
4985214634Sdim
4986214634Sdim	insn = (bfd_get_16 (input_bfd, hit_data) << 16)
4987214634Sdim             | bfd_get_16 (input_bfd, hit_data + 2);
4988214634Sdim
4989214634Sdim        if (globals->use_rel)
4990214634Sdim          {
4991214634Sdim            signed_addend = insn & 0xfff;
4992214634Sdim            if (!(insn & (1 << 23)))
4993214634Sdim              signed_addend = -signed_addend;
4994214634Sdim          }
4995214634Sdim
4996214634Sdim	relocation = value + signed_addend;
4997214634Sdim	relocation -= (input_section->output_section->vma
4998214634Sdim		       + input_section->output_offset
4999214634Sdim		       + rel->r_offset);
5000214634Sdim
5001214634Sdim        value = abs (relocation);
5002214634Sdim
5003214634Sdim        if (value >= 0x1000)
5004214634Sdim          return bfd_reloc_overflow;
5005214634Sdim
5006214634Sdim	insn = (insn & 0xff7ff000) | value;
5007214634Sdim        if (relocation >= 0)
5008214634Sdim          insn |= (1 << 23);
5009214634Sdim
5010214634Sdim	bfd_put_16 (input_bfd, insn >> 16, hit_data);
5011214634Sdim	bfd_put_16 (input_bfd, insn & 0xffff, hit_data + 2);
5012214634Sdim
5013214634Sdim        return bfd_reloc_ok;
5014214634Sdim      }
5015214634Sdim
5016214082Sdim    case R_ARM_THM_XPC22:
5017214082Sdim    case R_ARM_THM_CALL:
5018214082Sdim      /* Thumb BL (branch long instruction).  */
5019214082Sdim      {
5020214082Sdim	bfd_vma relocation;
5021214634Sdim        bfd_vma reloc_sign;
5022214082Sdim	bfd_boolean overflow = FALSE;
5023214082Sdim	bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
5024214082Sdim	bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
5025214634Sdim	bfd_signed_vma reloc_signed_max;
5026214634Sdim	bfd_signed_vma reloc_signed_min;
5027214082Sdim	bfd_vma check;
5028214082Sdim	bfd_signed_vma signed_check;
5029214634Sdim	int bitsize;
5030214634Sdim	int thumb2 = using_thumb2 (globals);
5031214082Sdim
5032214634Sdim	/* A branch to an undefined weak symbol is turned into a jump to
5033214634Sdim	   the next instruction.  */
5034214634Sdim	if (h && h->root.type == bfd_link_hash_undefweak)
5035214634Sdim	  {
5036214634Sdim	    bfd_put_16 (input_bfd, 0xe000, hit_data);
5037214634Sdim	    bfd_put_16 (input_bfd, 0xbf00, hit_data + 2);
5038214634Sdim	    return bfd_reloc_ok;
5039214634Sdim	  }
5040214634Sdim
5041214634Sdim	/* Fetch the addend.  We use the Thumb-2 encoding (backwards compatible
5042214634Sdim           with Thumb-1) involving the J1 and J2 bits.  */
5043214082Sdim	if (globals->use_rel)
5044214082Sdim	  {
5045214634Sdim            bfd_vma s = (upper_insn & (1 << 10)) >> 10;
5046214634Sdim            bfd_vma upper = upper_insn & 0x3ff;
5047214634Sdim            bfd_vma lower = lower_insn & 0x7ff;
5048214634Sdim	    bfd_vma j1 = (lower_insn & (1 << 13)) >> 13;
5049214634Sdim	    bfd_vma j2 = (lower_insn & (1 << 11)) >> 11;
5050214634Sdim            bfd_vma i1 = j1 ^ s ? 0 : 1;
5051214634Sdim            bfd_vma i2 = j2 ^ s ? 0 : 1;
5052214634Sdim
5053214634Sdim            addend = (i1 << 23) | (i2 << 22) | (upper << 12) | (lower << 1);
5054214634Sdim            /* Sign extend.  */
5055214634Sdim            addend = (addend | ((s ? 0 : 1) << 24)) - (1 << 24);
5056214634Sdim
5057214082Sdim	    signed_addend = addend;
5058214082Sdim	  }
5059214082Sdim
5060214082Sdim	if (r_type == R_ARM_THM_XPC22)
5061214082Sdim	  {
5062214082Sdim	    /* Check for Thumb to Thumb call.  */
5063214082Sdim	    /* FIXME: Should we translate the instruction into a BL
5064214082Sdim	       instruction instead ?  */
5065214082Sdim	    if (sym_flags == STT_ARM_TFUNC)
5066214082Sdim	      (*_bfd_error_handler)
5067214082Sdim		(_("%B: Warning: Thumb BLX instruction targets thumb function '%s'."),
5068214082Sdim		 input_bfd,
5069214082Sdim		 h ? h->root.root.string : "(local)");
5070214082Sdim	  }
5071214082Sdim	else
5072214082Sdim	  {
5073214082Sdim	    /* If it is not a call to Thumb, assume call to Arm.
5074214082Sdim	       If it is a call relative to a section name, then it is not a
5075214082Sdim	       function call at all, but rather a long jump.  Calls through
5076214082Sdim	       the PLT do not require stubs.  */
5077214082Sdim	    if (sym_flags != STT_ARM_TFUNC && sym_flags != STT_SECTION
5078214082Sdim		&& (h == NULL || splt == NULL
5079214082Sdim		    || h->plt.offset == (bfd_vma) -1))
5080214082Sdim	      {
5081214082Sdim		if (globals->use_blx)
5082214082Sdim		  {
5083214082Sdim		    /* Convert BL to BLX.  */
5084214082Sdim		    lower_insn = (lower_insn & ~0x1000) | 0x0800;
5085214082Sdim		  }
5086214082Sdim		else if (elf32_thumb_to_arm_stub
5087214082Sdim		    (info, sym_name, input_bfd, output_bfd, input_section,
5088214634Sdim		     hit_data, sym_sec, rel->r_offset, signed_addend, value,
5089214634Sdim		     error_message))
5090214082Sdim		  return bfd_reloc_ok;
5091214082Sdim		else
5092214082Sdim		  return bfd_reloc_dangerous;
5093214082Sdim	      }
5094214082Sdim	    else if (sym_flags == STT_ARM_TFUNC && globals->use_blx)
5095214082Sdim	      {
5096214082Sdim		/* Make sure this is a BL.  */
5097214082Sdim		lower_insn |= 0x1800;
5098214082Sdim	      }
5099214082Sdim	  }
5100214082Sdim
5101214082Sdim	/* Handle calls via the PLT.  */
5102214082Sdim	if (h != NULL && splt != NULL && h->plt.offset != (bfd_vma) -1)
5103214082Sdim	  {
5104214082Sdim	    value = (splt->output_section->vma
5105214082Sdim		     + splt->output_offset
5106214082Sdim		     + h->plt.offset);
5107214082Sdim 	    if (globals->use_blx)
5108214082Sdim 	      {
5109214082Sdim 		/* If the Thumb BLX instruction is available, convert the
5110214082Sdim		   BL to a BLX instruction to call the ARM-mode PLT entry.  */
5111214082Sdim		lower_insn = (lower_insn & ~0x1000) | 0x0800;
5112214082Sdim 	      }
5113214082Sdim 	    else
5114214082Sdim 	      /* Target the Thumb stub before the ARM PLT entry.  */
5115214082Sdim 	      value -= PLT_THUMB_STUB_SIZE;
5116214082Sdim	    *unresolved_reloc_p = FALSE;
5117214082Sdim	  }
5118214082Sdim
5119214082Sdim	relocation = value + signed_addend;
5120214082Sdim
5121214082Sdim	relocation -= (input_section->output_section->vma
5122214082Sdim		       + input_section->output_offset
5123214082Sdim		       + rel->r_offset);
5124214082Sdim
5125214082Sdim	check = relocation >> howto->rightshift;
5126214082Sdim
5127214082Sdim	/* If this is a signed value, the rightshift just dropped
5128214082Sdim	   leading 1 bits (assuming twos complement).  */
5129214082Sdim	if ((bfd_signed_vma) relocation >= 0)
5130214082Sdim	  signed_check = check;
5131214082Sdim	else
5132214082Sdim	  signed_check = check | ~((bfd_vma) -1 >> howto->rightshift);
5133214082Sdim
5134214634Sdim	/* Calculate the permissable maximum and minimum values for
5135214634Sdim	   this relocation according to whether we're relocating for
5136214634Sdim	   Thumb-2 or not.  */
5137214634Sdim	bitsize = howto->bitsize;
5138214634Sdim	if (!thumb2)
5139214634Sdim	  bitsize -= 2;
5140214634Sdim	reloc_signed_max = ((1 << (bitsize - 1)) - 1) >> howto->rightshift;
5141214634Sdim	reloc_signed_min = ~reloc_signed_max;
5142214634Sdim
5143214082Sdim	/* Assumes two's complement.  */
5144214082Sdim	if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
5145214082Sdim	  overflow = TRUE;
5146214082Sdim
5147214082Sdim	if ((lower_insn & 0x1800) == 0x0800)
5148214082Sdim	  /* For a BLX instruction, make sure that the relocation is rounded up
5149214082Sdim	     to a word boundary.  This follows the semantics of the instruction
5150214082Sdim	     which specifies that bit 1 of the target address will come from bit
5151214082Sdim	     1 of the base address.  */
5152214082Sdim	  relocation = (relocation + 2) & ~ 3;
5153214082Sdim
5154214634Sdim	/* Put RELOCATION back into the insn.  Assumes two's complement.
5155214634Sdim	   We use the Thumb-2 encoding, which is safe even if dealing with
5156214634Sdim	   a Thumb-1 instruction by virtue of our overflow check above.  */
5157214634Sdim        reloc_sign = (signed_check < 0) ? 1 : 0;
5158214634Sdim	upper_insn = (upper_insn & ~(bfd_vma) 0x7ff)
5159214634Sdim                     | ((relocation >> 12) & 0x3ff)
5160214634Sdim                     | (reloc_sign << 10);
5161214634Sdim	lower_insn = (lower_insn & ~(bfd_vma) 0x2fff)
5162214634Sdim                     | (((!((relocation >> 23) & 1)) ^ reloc_sign) << 13)
5163214634Sdim                     | (((!((relocation >> 22) & 1)) ^ reloc_sign) << 11)
5164214634Sdim                     | ((relocation >> 1) & 0x7ff);
5165214082Sdim
5166214082Sdim	/* Put the relocated value back in the object file:  */
5167214082Sdim	bfd_put_16 (input_bfd, upper_insn, hit_data);
5168214082Sdim	bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
5169214082Sdim
5170214082Sdim	return (overflow ? bfd_reloc_overflow : bfd_reloc_ok);
5171214082Sdim      }
5172214082Sdim      break;
5173214082Sdim
5174214082Sdim    case R_ARM_THM_JUMP24:
5175214082Sdim      /* Thumb32 unconditional branch instruction.  */
5176214082Sdim      {
5177214082Sdim	bfd_vma relocation;
5178214082Sdim	bfd_boolean overflow = FALSE;
5179214082Sdim	bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
5180214082Sdim	bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
5181214082Sdim	bfd_signed_vma reloc_signed_max = ((1 << (howto->bitsize - 1)) - 1) >> howto->rightshift;
5182214082Sdim	bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
5183214082Sdim	bfd_vma check;
5184214082Sdim	bfd_signed_vma signed_check;
5185214082Sdim
5186214082Sdim	/* Need to refetch the addend, reconstruct the top three bits, and glue the
5187214082Sdim	   two pieces together.  */
5188214082Sdim	if (globals->use_rel)
5189214082Sdim	  {
5190214082Sdim	    bfd_vma S  = (upper_insn & 0x0400) >> 10;
5191214082Sdim	    bfd_vma hi = (upper_insn & 0x03ff);
5192214082Sdim	    bfd_vma I1 = (lower_insn & 0x2000) >> 13;
5193214082Sdim	    bfd_vma I2 = (lower_insn & 0x0800) >> 11;
5194214082Sdim	    bfd_vma lo = (lower_insn & 0x07ff);
5195214082Sdim
5196214082Sdim	    I1 = !(I1 ^ S);
5197214082Sdim	    I2 = !(I2 ^ S);
5198214082Sdim	    S  = !S;
5199214082Sdim
5200214082Sdim	    signed_addend = (S << 24) | (I1 << 23) | (I2 << 22) | (hi << 12) | (lo << 1);
5201214082Sdim	    signed_addend -= (1 << 24); /* Sign extend.  */
5202214082Sdim	  }
5203214082Sdim
5204214082Sdim	/* ??? Should handle interworking?  GCC might someday try to
5205214082Sdim	   use this for tail calls.  */
5206214082Sdim
5207214082Sdim      	relocation = value + signed_addend;
5208214082Sdim	relocation -= (input_section->output_section->vma
5209214082Sdim		       + input_section->output_offset
5210214082Sdim		       + rel->r_offset);
5211214082Sdim
5212214082Sdim	check = relocation >> howto->rightshift;
5213214082Sdim
5214214082Sdim	/* If this is a signed value, the rightshift just dropped
5215214082Sdim	   leading 1 bits (assuming twos complement).  */
5216214082Sdim	if ((bfd_signed_vma) relocation >= 0)
5217214082Sdim	  signed_check = check;
5218214082Sdim	else
5219214082Sdim	  signed_check = check | ~((bfd_vma) -1 >> howto->rightshift);
5220214082Sdim
5221214082Sdim	/* Assumes two's complement.  */
5222214082Sdim	if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
5223214082Sdim	  overflow = TRUE;
5224214082Sdim
5225214082Sdim	/* Put RELOCATION back into the insn.  */
5226214082Sdim	{
5227214082Sdim	  bfd_vma S  = (relocation & 0x01000000) >> 24;
5228214082Sdim	  bfd_vma I1 = (relocation & 0x00800000) >> 23;
5229214082Sdim	  bfd_vma I2 = (relocation & 0x00400000) >> 22;
5230214082Sdim	  bfd_vma hi = (relocation & 0x003ff000) >> 12;
5231214082Sdim	  bfd_vma lo = (relocation & 0x00000ffe) >>  1;
5232214082Sdim
5233214082Sdim	  I1 = !(I1 ^ S);
5234214082Sdim	  I2 = !(I2 ^ S);
5235214082Sdim
5236214082Sdim	  upper_insn = (upper_insn & (bfd_vma) 0xf800) | (S << 10) | hi;
5237214082Sdim	  lower_insn = (lower_insn & (bfd_vma) 0xd000) | (I1 << 13) | (I2 << 11) | lo;
5238214082Sdim	}
5239214082Sdim
5240214082Sdim	/* Put the relocated value back in the object file:  */
5241214082Sdim	bfd_put_16 (input_bfd, upper_insn, hit_data);
5242214082Sdim	bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
5243214082Sdim
5244214082Sdim	return (overflow ? bfd_reloc_overflow : bfd_reloc_ok);
5245214082Sdim      }
5246214082Sdim
5247214082Sdim    case R_ARM_THM_JUMP19:
5248214082Sdim      /* Thumb32 conditional branch instruction.  */
5249214082Sdim      {
5250214082Sdim	bfd_vma relocation;
5251214082Sdim	bfd_boolean overflow = FALSE;
5252214082Sdim	bfd_vma upper_insn = bfd_get_16 (input_bfd, hit_data);
5253214082Sdim	bfd_vma lower_insn = bfd_get_16 (input_bfd, hit_data + 2);
5254214634Sdim	bfd_signed_vma reloc_signed_max = 0xffffe;
5255214634Sdim	bfd_signed_vma reloc_signed_min = -0x100000;
5256214082Sdim	bfd_signed_vma signed_check;
5257214082Sdim
5258214082Sdim	/* Need to refetch the addend, reconstruct the top three bits,
5259214082Sdim	   and squish the two 11 bit pieces together.  */
5260214082Sdim	if (globals->use_rel)
5261214082Sdim	  {
5262214082Sdim	    bfd_vma S     = (upper_insn & 0x0400) >> 10;
5263214634Sdim	    bfd_vma upper = (upper_insn & 0x003f);
5264214082Sdim	    bfd_vma J1    = (lower_insn & 0x2000) >> 13;
5265214082Sdim	    bfd_vma J2    = (lower_insn & 0x0800) >> 11;
5266214082Sdim	    bfd_vma lower = (lower_insn & 0x07ff);
5267214082Sdim
5268214634Sdim	    upper |= J1 << 6;
5269214634Sdim	    upper |= J2 << 7;
5270214634Sdim	    upper |= (!S) << 8;
5271214082Sdim	    upper -= 0x0100; /* Sign extend.  */
5272214082Sdim
5273214082Sdim	    addend = (upper << 12) | (lower << 1);
5274214082Sdim	    signed_addend = addend;
5275214082Sdim	  }
5276214082Sdim
5277214082Sdim	/* ??? Should handle interworking?  GCC might someday try to
5278214082Sdim	   use this for tail calls.  */
5279214082Sdim
5280214082Sdim      	relocation = value + signed_addend;
5281214082Sdim	relocation -= (input_section->output_section->vma
5282214082Sdim		       + input_section->output_offset
5283214082Sdim		       + rel->r_offset);
5284214634Sdim	signed_check = (bfd_signed_vma) relocation;
5285214082Sdim
5286214082Sdim	if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
5287214082Sdim	  overflow = TRUE;
5288214082Sdim
5289214082Sdim	/* Put RELOCATION back into the insn.  */
5290214082Sdim	{
5291214082Sdim	  bfd_vma S  = (relocation & 0x00100000) >> 20;
5292214082Sdim	  bfd_vma J2 = (relocation & 0x00080000) >> 19;
5293214082Sdim	  bfd_vma J1 = (relocation & 0x00040000) >> 18;
5294214082Sdim	  bfd_vma hi = (relocation & 0x0003f000) >> 12;
5295214082Sdim	  bfd_vma lo = (relocation & 0x00000ffe) >>  1;
5296214082Sdim
5297214634Sdim	  upper_insn = (upper_insn & 0xfbc0) | (S << 10) | hi;
5298214082Sdim	  lower_insn = (lower_insn & 0xd000) | (J1 << 13) | (J2 << 11) | lo;
5299214082Sdim	}
5300214082Sdim
5301214082Sdim	/* Put the relocated value back in the object file:  */
5302214082Sdim	bfd_put_16 (input_bfd, upper_insn, hit_data);
5303214082Sdim	bfd_put_16 (input_bfd, lower_insn, hit_data + 2);
5304214082Sdim
5305214082Sdim	return (overflow ? bfd_reloc_overflow : bfd_reloc_ok);
5306214082Sdim      }
5307214082Sdim
5308214082Sdim    case R_ARM_THM_JUMP11:
5309214082Sdim    case R_ARM_THM_JUMP8:
5310214082Sdim    case R_ARM_THM_JUMP6:
5311214082Sdim      /* Thumb B (branch) instruction).  */
5312214082Sdim      {
5313214082Sdim	bfd_signed_vma relocation;
5314214082Sdim	bfd_signed_vma reloc_signed_max = (1 << (howto->bitsize - 1)) - 1;
5315214082Sdim	bfd_signed_vma reloc_signed_min = ~ reloc_signed_max;
5316214082Sdim	bfd_signed_vma signed_check;
5317214082Sdim
5318214082Sdim	/* CZB cannot jump backward.  */
5319214082Sdim	if (r_type == R_ARM_THM_JUMP6)
5320214082Sdim	  reloc_signed_min = 0;
5321214082Sdim
5322214082Sdim	if (globals->use_rel)
5323214082Sdim	  {
5324214082Sdim	    /* Need to refetch addend.  */
5325214082Sdim	    addend = bfd_get_16 (input_bfd, hit_data) & howto->src_mask;
5326214082Sdim	    if (addend & ((howto->src_mask + 1) >> 1))
5327214082Sdim	      {
5328214082Sdim		signed_addend = -1;
5329214082Sdim		signed_addend &= ~ howto->src_mask;
5330214082Sdim		signed_addend |= addend;
5331214082Sdim	      }
5332214082Sdim	    else
5333214082Sdim	      signed_addend = addend;
5334214082Sdim	    /* The value in the insn has been right shifted.  We need to
5335214082Sdim	       undo this, so that we can perform the address calculation
5336214082Sdim	       in terms of bytes.  */
5337214082Sdim	    signed_addend <<= howto->rightshift;
5338214082Sdim	  }
5339214082Sdim	relocation = value + signed_addend;
5340214082Sdim
5341214082Sdim	relocation -= (input_section->output_section->vma
5342214082Sdim		       + input_section->output_offset
5343214082Sdim		       + rel->r_offset);
5344214082Sdim
5345214082Sdim	relocation >>= howto->rightshift;
5346214082Sdim	signed_check = relocation;
5347214082Sdim
5348214082Sdim	if (r_type == R_ARM_THM_JUMP6)
5349214082Sdim	  relocation = ((relocation & 0x0020) << 4) | ((relocation & 0x001f) << 3);
5350214082Sdim	else
5351214082Sdim	  relocation &= howto->dst_mask;
5352214082Sdim	relocation |= (bfd_get_16 (input_bfd, hit_data) & (~ howto->dst_mask));
5353214082Sdim
5354214082Sdim	bfd_put_16 (input_bfd, relocation, hit_data);
5355214082Sdim
5356214082Sdim	/* Assumes two's complement.  */
5357214082Sdim	if (signed_check > reloc_signed_max || signed_check < reloc_signed_min)
5358214082Sdim	  return bfd_reloc_overflow;
5359214082Sdim
5360214082Sdim	return bfd_reloc_ok;
5361214082Sdim      }
5362214082Sdim
5363214082Sdim    case R_ARM_ALU_PCREL7_0:
5364214082Sdim    case R_ARM_ALU_PCREL15_8:
5365214082Sdim    case R_ARM_ALU_PCREL23_15:
5366214082Sdim      {
5367214082Sdim	bfd_vma insn;
5368214082Sdim	bfd_vma relocation;
5369214082Sdim
5370214082Sdim	insn = bfd_get_32 (input_bfd, hit_data);
5371214082Sdim	if (globals->use_rel)
5372214082Sdim	  {
5373214082Sdim	    /* Extract the addend.  */
5374214082Sdim	    addend = (insn & 0xff) << ((insn & 0xf00) >> 7);
5375214082Sdim	    signed_addend = addend;
5376214082Sdim	  }
5377214082Sdim	relocation = value + signed_addend;
5378214082Sdim
5379214082Sdim	relocation -= (input_section->output_section->vma
5380214082Sdim		       + input_section->output_offset
5381214082Sdim		       + rel->r_offset);
5382214082Sdim	insn = (insn & ~0xfff)
5383214082Sdim	       | ((howto->bitpos << 7) & 0xf00)
5384214082Sdim	       | ((relocation >> howto->bitpos) & 0xff);
5385214082Sdim	bfd_put_32 (input_bfd, value, hit_data);
5386214082Sdim      }
5387214082Sdim      return bfd_reloc_ok;
5388214082Sdim
5389214082Sdim    case R_ARM_GNU_VTINHERIT:
5390214082Sdim    case R_ARM_GNU_VTENTRY:
5391214082Sdim      return bfd_reloc_ok;
5392214082Sdim
5393214082Sdim    case R_ARM_GOTOFF32:
5394214082Sdim      /* Relocation is relative to the start of the
5395214082Sdim         global offset table.  */
5396214082Sdim
5397214082Sdim      BFD_ASSERT (sgot != NULL);
5398214082Sdim      if (sgot == NULL)
5399214082Sdim        return bfd_reloc_notsupported;
5400214082Sdim
5401214082Sdim      /* If we are addressing a Thumb function, we need to adjust the
5402214082Sdim	 address by one, so that attempts to call the function pointer will
5403214082Sdim	 correctly interpret it as Thumb code.  */
5404214082Sdim      if (sym_flags == STT_ARM_TFUNC)
5405214082Sdim	value += 1;
5406214082Sdim
5407214082Sdim      /* Note that sgot->output_offset is not involved in this
5408214082Sdim         calculation.  We always want the start of .got.  If we
5409214082Sdim         define _GLOBAL_OFFSET_TABLE in a different way, as is
5410214082Sdim         permitted by the ABI, we might have to change this
5411214082Sdim         calculation.  */
5412214082Sdim      value -= sgot->output_section->vma;
5413214082Sdim      return _bfd_final_link_relocate (howto, input_bfd, input_section,
5414214082Sdim				       contents, rel->r_offset, value,
5415214082Sdim				       rel->r_addend);
5416214082Sdim
5417214082Sdim    case R_ARM_GOTPC:
5418214082Sdim      /* Use global offset table as symbol value.  */
5419214082Sdim      BFD_ASSERT (sgot != NULL);
5420214082Sdim
5421214082Sdim      if (sgot == NULL)
5422214082Sdim        return bfd_reloc_notsupported;
5423214082Sdim
5424214082Sdim      *unresolved_reloc_p = FALSE;
5425214082Sdim      value = sgot->output_section->vma;
5426214082Sdim      return _bfd_final_link_relocate (howto, input_bfd, input_section,
5427214082Sdim				       contents, rel->r_offset, value,
5428214082Sdim				       rel->r_addend);
5429214082Sdim
5430214082Sdim    case R_ARM_GOT32:
5431214082Sdim    case R_ARM_GOT_PREL:
5432214082Sdim      /* Relocation is to the entry for this symbol in the
5433214082Sdim         global offset table.  */
5434214082Sdim      if (sgot == NULL)
5435214082Sdim	return bfd_reloc_notsupported;
5436214082Sdim
5437214082Sdim      if (h != NULL)
5438214082Sdim	{
5439214082Sdim	  bfd_vma off;
5440214082Sdim	  bfd_boolean dyn;
5441214082Sdim
5442214082Sdim	  off = h->got.offset;
5443214082Sdim	  BFD_ASSERT (off != (bfd_vma) -1);
5444214082Sdim	  dyn = globals->root.dynamic_sections_created;
5445214082Sdim
5446214082Sdim	  if (! WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
5447214082Sdim	      || (info->shared
5448214082Sdim		  && SYMBOL_REFERENCES_LOCAL (info, h))
5449214082Sdim	      || (ELF_ST_VISIBILITY (h->other)
5450214082Sdim		  && h->root.type == bfd_link_hash_undefweak))
5451214082Sdim	    {
5452214082Sdim	      /* This is actually a static link, or it is a -Bsymbolic link
5453214082Sdim		 and the symbol is defined locally.  We must initialize this
5454214082Sdim		 entry in the global offset table.  Since the offset must
5455214082Sdim		 always be a multiple of 4, we use the least significant bit
5456214082Sdim		 to record whether we have initialized it already.
5457214082Sdim
5458214082Sdim		 When doing a dynamic link, we create a .rel(a).got relocation
5459214082Sdim		 entry to initialize the value.  This is done in the
5460214082Sdim		 finish_dynamic_symbol routine.  */
5461214082Sdim	      if ((off & 1) != 0)
5462214082Sdim		off &= ~1;
5463214082Sdim	      else
5464214082Sdim		{
5465214082Sdim		  /* If we are addressing a Thumb function, we need to
5466214082Sdim		     adjust the address by one, so that attempts to
5467214082Sdim		     call the function pointer will correctly
5468214082Sdim		     interpret it as Thumb code.  */
5469214082Sdim		  if (sym_flags == STT_ARM_TFUNC)
5470214082Sdim		    value |= 1;
5471214082Sdim
5472214082Sdim		  bfd_put_32 (output_bfd, value, sgot->contents + off);
5473214082Sdim		  h->got.offset |= 1;
5474214082Sdim		}
5475214082Sdim	    }
5476214082Sdim	  else
5477214082Sdim	    *unresolved_reloc_p = FALSE;
5478214082Sdim
5479214082Sdim	  value = sgot->output_offset + off;
5480214082Sdim	}
5481214082Sdim      else
5482214082Sdim	{
5483214082Sdim	  bfd_vma off;
5484214082Sdim
5485214082Sdim	  BFD_ASSERT (local_got_offsets != NULL &&
5486214082Sdim		      local_got_offsets[r_symndx] != (bfd_vma) -1);
5487214082Sdim
5488214082Sdim	  off = local_got_offsets[r_symndx];
5489214082Sdim
5490214082Sdim	  /* The offset must always be a multiple of 4.  We use the
5491214082Sdim	     least significant bit to record whether we have already
5492214082Sdim	     generated the necessary reloc.  */
5493214082Sdim	  if ((off & 1) != 0)
5494214082Sdim	    off &= ~1;
5495214082Sdim	  else
5496214082Sdim	    {
5497214082Sdim	      /* If we are addressing a Thumb function, we need to
5498214082Sdim		 adjust the address by one, so that attempts to
5499214082Sdim		 call the function pointer will correctly
5500214082Sdim		 interpret it as Thumb code.  */
5501214082Sdim	      if (sym_flags == STT_ARM_TFUNC)
5502214082Sdim		value |= 1;
5503214082Sdim
5504214082Sdim	      if (globals->use_rel)
5505214082Sdim		bfd_put_32 (output_bfd, value, sgot->contents + off);
5506214082Sdim
5507214082Sdim	      if (info->shared)
5508214082Sdim		{
5509214082Sdim		  asection * srelgot;
5510214082Sdim		  Elf_Internal_Rela outrel;
5511214082Sdim		  bfd_byte *loc;
5512214082Sdim
5513214082Sdim		  srelgot = (bfd_get_section_by_name
5514214082Sdim			     (dynobj, RELOC_SECTION (globals, ".got")));
5515214082Sdim		  BFD_ASSERT (srelgot != NULL);
5516214082Sdim
5517214082Sdim		  outrel.r_addend = addend + value;
5518214082Sdim		  outrel.r_offset = (sgot->output_section->vma
5519214082Sdim				     + sgot->output_offset
5520214082Sdim				     + off);
5521214082Sdim		  outrel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
5522214082Sdim		  loc = srelgot->contents;
5523214082Sdim		  loc += srelgot->reloc_count++ * RELOC_SIZE (globals);
5524214082Sdim		  SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
5525214082Sdim		}
5526214082Sdim
5527214082Sdim	      local_got_offsets[r_symndx] |= 1;
5528214082Sdim	    }
5529214082Sdim
5530214082Sdim	  value = sgot->output_offset + off;
5531214082Sdim	}
5532214082Sdim      if (r_type != R_ARM_GOT32)
5533214082Sdim	value += sgot->output_section->vma;
5534214082Sdim
5535214082Sdim      return _bfd_final_link_relocate (howto, input_bfd, input_section,
5536214082Sdim				       contents, rel->r_offset, value,
5537214082Sdim				       rel->r_addend);
5538214082Sdim
5539214082Sdim    case R_ARM_TLS_LDO32:
5540214082Sdim      value = value - dtpoff_base (info);
5541214082Sdim
5542214082Sdim      return _bfd_final_link_relocate (howto, input_bfd, input_section,
5543214082Sdim				       contents, rel->r_offset, value,
5544214082Sdim				       rel->r_addend);
5545214082Sdim
5546214082Sdim    case R_ARM_TLS_LDM32:
5547214082Sdim      {
5548214082Sdim	bfd_vma off;
5549214082Sdim
5550214082Sdim	if (globals->sgot == NULL)
5551214082Sdim	  abort ();
5552214082Sdim
5553214082Sdim	off = globals->tls_ldm_got.offset;
5554214082Sdim
5555214082Sdim	if ((off & 1) != 0)
5556214082Sdim	  off &= ~1;
5557214082Sdim	else
5558214082Sdim	  {
5559214082Sdim	    /* If we don't know the module number, create a relocation
5560214082Sdim	       for it.  */
5561214082Sdim	    if (info->shared)
5562214082Sdim	      {
5563214082Sdim		Elf_Internal_Rela outrel;
5564214082Sdim		bfd_byte *loc;
5565214082Sdim
5566214082Sdim		if (globals->srelgot == NULL)
5567214082Sdim		  abort ();
5568214082Sdim
5569214082Sdim		outrel.r_addend = 0;
5570214082Sdim		outrel.r_offset = (globals->sgot->output_section->vma
5571214082Sdim				   + globals->sgot->output_offset + off);
5572214082Sdim		outrel.r_info = ELF32_R_INFO (0, R_ARM_TLS_DTPMOD32);
5573214082Sdim
5574214082Sdim		if (globals->use_rel)
5575214082Sdim		  bfd_put_32 (output_bfd, outrel.r_addend,
5576214082Sdim			      globals->sgot->contents + off);
5577214082Sdim
5578214082Sdim		loc = globals->srelgot->contents;
5579214082Sdim		loc += globals->srelgot->reloc_count++ * RELOC_SIZE (globals);
5580214082Sdim		SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
5581214082Sdim	      }
5582214082Sdim	    else
5583214082Sdim	      bfd_put_32 (output_bfd, 1, globals->sgot->contents + off);
5584214082Sdim
5585214082Sdim	    globals->tls_ldm_got.offset |= 1;
5586214082Sdim	  }
5587214082Sdim
5588214082Sdim	value = globals->sgot->output_section->vma + globals->sgot->output_offset + off
5589214082Sdim	  - (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
5590214082Sdim
5591214082Sdim	return _bfd_final_link_relocate (howto, input_bfd, input_section,
5592214082Sdim					 contents, rel->r_offset, value,
5593214082Sdim					 rel->r_addend);
5594214082Sdim      }
5595214082Sdim
5596214082Sdim    case R_ARM_TLS_GD32:
5597214082Sdim    case R_ARM_TLS_IE32:
5598214082Sdim      {
5599214082Sdim	bfd_vma off;
5600214082Sdim	int indx;
5601214082Sdim	char tls_type;
5602214082Sdim
5603214082Sdim	if (globals->sgot == NULL)
5604214082Sdim	  abort ();
5605214082Sdim
5606214082Sdim	indx = 0;
5607214082Sdim	if (h != NULL)
5608214082Sdim	  {
5609214082Sdim	    bfd_boolean dyn;
5610214082Sdim	    dyn = globals->root.dynamic_sections_created;
5611214082Sdim	    if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
5612214082Sdim		&& (!info->shared
5613214082Sdim		    || !SYMBOL_REFERENCES_LOCAL (info, h)))
5614214082Sdim	      {
5615214082Sdim		*unresolved_reloc_p = FALSE;
5616214082Sdim		indx = h->dynindx;
5617214082Sdim	      }
5618214082Sdim	    off = h->got.offset;
5619214082Sdim	    tls_type = ((struct elf32_arm_link_hash_entry *) h)->tls_type;
5620214082Sdim	  }
5621214082Sdim	else
5622214082Sdim	  {
5623214082Sdim	    if (local_got_offsets == NULL)
5624214082Sdim	      abort ();
5625214082Sdim	    off = local_got_offsets[r_symndx];
5626214082Sdim	    tls_type = elf32_arm_local_got_tls_type (input_bfd)[r_symndx];
5627214082Sdim	  }
5628214082Sdim
5629214082Sdim	if (tls_type == GOT_UNKNOWN)
5630214082Sdim	  abort ();
5631214082Sdim
5632214082Sdim	if ((off & 1) != 0)
5633214082Sdim	  off &= ~1;
5634214082Sdim	else
5635214082Sdim	  {
5636214082Sdim	    bfd_boolean need_relocs = FALSE;
5637214082Sdim	    Elf_Internal_Rela outrel;
5638214082Sdim	    bfd_byte *loc = NULL;
5639214082Sdim	    int cur_off = off;
5640214082Sdim
5641214082Sdim	    /* The GOT entries have not been initialized yet.  Do it
5642214082Sdim	       now, and emit any relocations.  If both an IE GOT and a
5643214082Sdim	       GD GOT are necessary, we emit the GD first.  */
5644214082Sdim
5645214082Sdim	    if ((info->shared || indx != 0)
5646214082Sdim		&& (h == NULL
5647214082Sdim		    || ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
5648214082Sdim		    || h->root.type != bfd_link_hash_undefweak))
5649214082Sdim	      {
5650214082Sdim		need_relocs = TRUE;
5651214082Sdim		if (globals->srelgot == NULL)
5652214082Sdim		  abort ();
5653214082Sdim		loc = globals->srelgot->contents;
5654214082Sdim		loc += globals->srelgot->reloc_count * RELOC_SIZE (globals);
5655214082Sdim	      }
5656214082Sdim
5657214082Sdim	    if (tls_type & GOT_TLS_GD)
5658214082Sdim	      {
5659214082Sdim		if (need_relocs)
5660214082Sdim		  {
5661214082Sdim		    outrel.r_addend = 0;
5662214082Sdim		    outrel.r_offset = (globals->sgot->output_section->vma
5663214082Sdim				       + globals->sgot->output_offset
5664214082Sdim				       + cur_off);
5665214082Sdim		    outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_DTPMOD32);
5666214082Sdim
5667214082Sdim		    if (globals->use_rel)
5668214082Sdim		      bfd_put_32 (output_bfd, outrel.r_addend,
5669214082Sdim				  globals->sgot->contents + cur_off);
5670214082Sdim
5671214082Sdim		    SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
5672214082Sdim		    globals->srelgot->reloc_count++;
5673214082Sdim		    loc += RELOC_SIZE (globals);
5674214082Sdim
5675214082Sdim		    if (indx == 0)
5676214082Sdim		      bfd_put_32 (output_bfd, value - dtpoff_base (info),
5677214082Sdim				  globals->sgot->contents + cur_off + 4);
5678214082Sdim		    else
5679214082Sdim		      {
5680214082Sdim			outrel.r_addend = 0;
5681214082Sdim			outrel.r_info = ELF32_R_INFO (indx,
5682214082Sdim						      R_ARM_TLS_DTPOFF32);
5683214082Sdim			outrel.r_offset += 4;
5684214082Sdim
5685214082Sdim			if (globals->use_rel)
5686214082Sdim			  bfd_put_32 (output_bfd, outrel.r_addend,
5687214082Sdim				      globals->sgot->contents + cur_off + 4);
5688214082Sdim
5689214082Sdim
5690214082Sdim			SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
5691214082Sdim			globals->srelgot->reloc_count++;
5692214082Sdim			loc += RELOC_SIZE (globals);
5693214082Sdim		      }
5694214082Sdim		  }
5695214082Sdim		else
5696214082Sdim		  {
5697214082Sdim		    /* If we are not emitting relocations for a
5698214082Sdim		       general dynamic reference, then we must be in a
5699214082Sdim		       static link or an executable link with the
5700214082Sdim		       symbol binding locally.  Mark it as belonging
5701214082Sdim		       to module 1, the executable.  */
5702214082Sdim		    bfd_put_32 (output_bfd, 1,
5703214082Sdim				globals->sgot->contents + cur_off);
5704214082Sdim		    bfd_put_32 (output_bfd, value - dtpoff_base (info),
5705214082Sdim				globals->sgot->contents + cur_off + 4);
5706214082Sdim		  }
5707214082Sdim
5708214082Sdim		cur_off += 8;
5709214082Sdim	      }
5710214082Sdim
5711214082Sdim	    if (tls_type & GOT_TLS_IE)
5712214082Sdim	      {
5713214082Sdim		if (need_relocs)
5714214082Sdim		  {
5715214082Sdim		    if (indx == 0)
5716214082Sdim		      outrel.r_addend = value - dtpoff_base (info);
5717214082Sdim		    else
5718214082Sdim		      outrel.r_addend = 0;
5719214082Sdim		    outrel.r_offset = (globals->sgot->output_section->vma
5720214082Sdim				       + globals->sgot->output_offset
5721214082Sdim				       + cur_off);
5722214082Sdim		    outrel.r_info = ELF32_R_INFO (indx, R_ARM_TLS_TPOFF32);
5723214082Sdim
5724214082Sdim		    if (globals->use_rel)
5725214082Sdim		      bfd_put_32 (output_bfd, outrel.r_addend,
5726214082Sdim				  globals->sgot->contents + cur_off);
5727214082Sdim
5728214082Sdim		    SWAP_RELOC_OUT (globals) (output_bfd, &outrel, loc);
5729214082Sdim		    globals->srelgot->reloc_count++;
5730214082Sdim		    loc += RELOC_SIZE (globals);
5731214082Sdim		  }
5732214082Sdim		else
5733214082Sdim		  bfd_put_32 (output_bfd, tpoff (info, value),
5734214082Sdim			      globals->sgot->contents + cur_off);
5735214082Sdim		cur_off += 4;
5736214082Sdim	      }
5737214082Sdim
5738214082Sdim	    if (h != NULL)
5739214082Sdim	      h->got.offset |= 1;
5740214082Sdim	    else
5741214082Sdim	      local_got_offsets[r_symndx] |= 1;
5742214082Sdim	  }
5743214082Sdim
5744214082Sdim	if ((tls_type & GOT_TLS_GD) && r_type != R_ARM_TLS_GD32)
5745214082Sdim	  off += 8;
5746214082Sdim	value = globals->sgot->output_section->vma + globals->sgot->output_offset + off
5747214082Sdim	  - (input_section->output_section->vma + input_section->output_offset + rel->r_offset);
5748214082Sdim
5749214082Sdim	return _bfd_final_link_relocate (howto, input_bfd, input_section,
5750214082Sdim					 contents, rel->r_offset, value,
5751214082Sdim					 rel->r_addend);
5752214082Sdim      }
5753214082Sdim
5754214082Sdim    case R_ARM_TLS_LE32:
5755214082Sdim      if (info->shared)
5756214082Sdim	{
5757214082Sdim	  (*_bfd_error_handler)
5758214082Sdim	    (_("%B(%A+0x%lx): R_ARM_TLS_LE32 relocation not permitted in shared object"),
5759214082Sdim	     input_bfd, input_section,
5760214082Sdim	     (long) rel->r_offset, howto->name);
5761214082Sdim	  return FALSE;
5762214082Sdim	}
5763214082Sdim      else
5764214082Sdim	value = tpoff (info, value);
5765214082Sdim
5766214082Sdim      return _bfd_final_link_relocate (howto, input_bfd, input_section,
5767214082Sdim				       contents, rel->r_offset, value,
5768214082Sdim				       rel->r_addend);
5769214082Sdim
5770214082Sdim    case R_ARM_V4BX:
5771214082Sdim      if (globals->fix_v4bx)
5772214082Sdim        {
5773214082Sdim          bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
5774214082Sdim
5775214082Sdim          /* Ensure that we have a BX instruction.  */
5776214082Sdim          BFD_ASSERT ((insn & 0x0ffffff0) == 0x012fff10);
5777214082Sdim
5778214082Sdim          /* Preserve Rm (lowest four bits) and the condition code
5779214082Sdim             (highest four bits). Other bits encode MOV PC,Rm.  */
5780214082Sdim          insn = (insn & 0xf000000f) | 0x01a0f000;
5781214082Sdim
5782214082Sdim          bfd_put_32 (input_bfd, insn, hit_data);
5783214082Sdim        }
5784214082Sdim      return bfd_reloc_ok;
5785214082Sdim
5786214634Sdim    case R_ARM_MOVW_ABS_NC:
5787214634Sdim    case R_ARM_MOVT_ABS:
5788214634Sdim    case R_ARM_MOVW_PREL_NC:
5789214634Sdim    case R_ARM_MOVT_PREL:
5790214634Sdim    /* Until we properly support segment-base-relative addressing then
5791214634Sdim       we assume the segment base to be zero, as for the group relocations.
5792214634Sdim       Thus R_ARM_MOVW_BREL_NC has the same semantics as R_ARM_MOVW_ABS_NC
5793214634Sdim       and R_ARM_MOVT_BREL has the same semantics as R_ARM_MOVT_ABS.  */
5794214634Sdim    case R_ARM_MOVW_BREL_NC:
5795214634Sdim    case R_ARM_MOVW_BREL:
5796214634Sdim    case R_ARM_MOVT_BREL:
5797214634Sdim      {
5798214634Sdim	bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
5799214082Sdim
5800214634Sdim	if (globals->use_rel)
5801214634Sdim	  {
5802214634Sdim	    addend = ((insn >> 4) & 0xf000) | (insn & 0xfff);
5803214634Sdim	    signed_addend = (addend ^ 0x10000) - 0x10000;
5804214634Sdim	  }
5805214082Sdim
5806214634Sdim	value += signed_addend;
5807214082Sdim
5808214634Sdim	if (r_type == R_ARM_MOVW_PREL_NC || r_type == R_ARM_MOVT_PREL)
5809214634Sdim	  value -= (input_section->output_section->vma
5810214634Sdim		    + input_section->output_offset + rel->r_offset);
5811214082Sdim
5812214634Sdim	if (r_type == R_ARM_MOVW_BREL && value >= 0x10000)
5813214634Sdim          return bfd_reloc_overflow;
5814214082Sdim
5815214634Sdim	if (sym_flags == STT_ARM_TFUNC)
5816214634Sdim	  value |= 1;
5817214082Sdim
5818214634Sdim	if (r_type == R_ARM_MOVT_ABS || r_type == R_ARM_MOVT_PREL
5819214634Sdim            || r_type == R_ARM_MOVT_BREL)
5820214634Sdim	  value >>= 16;
5821214082Sdim
5822214634Sdim	insn &= 0xfff0f000;
5823214634Sdim	insn |= value & 0xfff;
5824214634Sdim	insn |= (value & 0xf000) << 4;
5825214634Sdim	bfd_put_32 (input_bfd, insn, hit_data);
5826214634Sdim      }
5827214634Sdim      return bfd_reloc_ok;
5828214082Sdim
5829214634Sdim    case R_ARM_THM_MOVW_ABS_NC:
5830214634Sdim    case R_ARM_THM_MOVT_ABS:
5831214634Sdim    case R_ARM_THM_MOVW_PREL_NC:
5832214634Sdim    case R_ARM_THM_MOVT_PREL:
5833214634Sdim    /* Until we properly support segment-base-relative addressing then
5834214634Sdim       we assume the segment base to be zero, as for the above relocations.
5835214634Sdim       Thus R_ARM_THM_MOVW_BREL_NC has the same semantics as
5836214634Sdim       R_ARM_THM_MOVW_ABS_NC and R_ARM_THM_MOVT_BREL has the same semantics
5837214634Sdim       as R_ARM_THM_MOVT_ABS.  */
5838214634Sdim    case R_ARM_THM_MOVW_BREL_NC:
5839214634Sdim    case R_ARM_THM_MOVW_BREL:
5840214634Sdim    case R_ARM_THM_MOVT_BREL:
5841214634Sdim      {
5842214634Sdim	bfd_vma insn;
5843214634Sdim
5844214634Sdim	insn = bfd_get_16 (input_bfd, hit_data) << 16;
5845214634Sdim	insn |= bfd_get_16 (input_bfd, hit_data + 2);
5846214082Sdim
5847214634Sdim	if (globals->use_rel)
5848214634Sdim	  {
5849214634Sdim	    addend = ((insn >> 4)  & 0xf000)
5850214634Sdim		   | ((insn >> 15) & 0x0800)
5851214634Sdim		   | ((insn >> 4)  & 0x0700)
5852214634Sdim		   | (insn         & 0x00ff);
5853214634Sdim	    signed_addend = (addend ^ 0x10000) - 0x10000;
5854214634Sdim	  }
5855214082Sdim
5856214634Sdim	value += signed_addend;
5857214082Sdim
5858214634Sdim	if (r_type == R_ARM_THM_MOVW_PREL_NC || r_type == R_ARM_THM_MOVT_PREL)
5859214634Sdim	  value -= (input_section->output_section->vma
5860214634Sdim		    + input_section->output_offset + rel->r_offset);
5861214082Sdim
5862214634Sdim	if (r_type == R_ARM_THM_MOVW_BREL && value >= 0x10000)
5863214634Sdim          return bfd_reloc_overflow;
5864214082Sdim
5865214634Sdim	if (sym_flags == STT_ARM_TFUNC)
5866214634Sdim	  value |= 1;
5867214082Sdim
5868214634Sdim	if (r_type == R_ARM_THM_MOVT_ABS || r_type == R_ARM_THM_MOVT_PREL
5869214634Sdim            || r_type == R_ARM_THM_MOVT_BREL)
5870214634Sdim	  value >>= 16;
5871214082Sdim
5872214634Sdim	insn &= 0xfbf08f00;
5873214634Sdim	insn |= (value & 0xf000) << 4;
5874214634Sdim	insn |= (value & 0x0800) << 15;
5875214634Sdim	insn |= (value & 0x0700) << 4;
5876214634Sdim	insn |= (value & 0x00ff);
5877214082Sdim
5878214634Sdim	bfd_put_16 (input_bfd, insn >> 16, hit_data);
5879214634Sdim	bfd_put_16 (input_bfd, insn & 0xffff, hit_data + 2);
5880214634Sdim      }
5881214634Sdim      return bfd_reloc_ok;
5882214082Sdim
5883214634Sdim    case R_ARM_ALU_PC_G0_NC:
5884214634Sdim    case R_ARM_ALU_PC_G1_NC:
5885214634Sdim    case R_ARM_ALU_PC_G0:
5886214634Sdim    case R_ARM_ALU_PC_G1:
5887214634Sdim    case R_ARM_ALU_PC_G2:
5888214634Sdim    case R_ARM_ALU_SB_G0_NC:
5889214634Sdim    case R_ARM_ALU_SB_G1_NC:
5890214634Sdim    case R_ARM_ALU_SB_G0:
5891214634Sdim    case R_ARM_ALU_SB_G1:
5892214634Sdim    case R_ARM_ALU_SB_G2:
5893214634Sdim      {
5894214634Sdim	bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
5895214634Sdim        bfd_vma pc = input_section->output_section->vma
5896214634Sdim		     + input_section->output_offset + rel->r_offset;
5897214634Sdim        /* sb should be the origin of the *segment* containing the symbol.
5898214634Sdim           It is not clear how to obtain this OS-dependent value, so we
5899214634Sdim           make an arbitrary choice of zero.  */
5900214634Sdim        bfd_vma sb = 0;
5901214634Sdim        bfd_vma residual;
5902214634Sdim        bfd_vma g_n;
5903214634Sdim	bfd_signed_vma signed_value;
5904214634Sdim        int group = 0;
5905214082Sdim
5906214634Sdim        /* Determine which group of bits to select.  */
5907214634Sdim        switch (r_type)
5908214634Sdim          {
5909214634Sdim          case R_ARM_ALU_PC_G0_NC:
5910214634Sdim          case R_ARM_ALU_PC_G0:
5911214634Sdim          case R_ARM_ALU_SB_G0_NC:
5912214634Sdim          case R_ARM_ALU_SB_G0:
5913214634Sdim            group = 0;
5914214634Sdim            break;
5915214082Sdim
5916214634Sdim          case R_ARM_ALU_PC_G1_NC:
5917214634Sdim          case R_ARM_ALU_PC_G1:
5918214634Sdim          case R_ARM_ALU_SB_G1_NC:
5919214634Sdim          case R_ARM_ALU_SB_G1:
5920214634Sdim            group = 1;
5921214634Sdim            break;
5922214082Sdim
5923214634Sdim          case R_ARM_ALU_PC_G2:
5924214634Sdim          case R_ARM_ALU_SB_G2:
5925214634Sdim            group = 2;
5926214634Sdim            break;
5927214082Sdim
5928214634Sdim          default:
5929214634Sdim            abort();
5930214634Sdim          }
5931214082Sdim
5932214634Sdim        /* If REL, extract the addend from the insn.  If RELA, it will
5933214634Sdim           have already been fetched for us.  */
5934214634Sdim	if (globals->use_rel)
5935214634Sdim          {
5936214634Sdim            int negative;
5937214634Sdim            bfd_vma constant = insn & 0xff;
5938214634Sdim            bfd_vma rotation = (insn & 0xf00) >> 8;
5939214082Sdim
5940214634Sdim            if (rotation == 0)
5941214634Sdim              signed_addend = constant;
5942214634Sdim            else
5943214634Sdim              {
5944214634Sdim                /* Compensate for the fact that in the instruction, the
5945214634Sdim                   rotation is stored in multiples of 2 bits.  */
5946214634Sdim                rotation *= 2;
5947214082Sdim
5948214634Sdim                /* Rotate "constant" right by "rotation" bits.  */
5949214634Sdim                signed_addend = (constant >> rotation) |
5950214634Sdim                                (constant << (8 * sizeof (bfd_vma) - rotation));
5951214634Sdim              }
5952214634Sdim
5953214634Sdim            /* Determine if the instruction is an ADD or a SUB.
5954214634Sdim               (For REL, this determines the sign of the addend.)  */
5955214634Sdim            negative = identify_add_or_sub (insn);
5956214634Sdim            if (negative == 0)
5957214634Sdim              {
5958214634Sdim                (*_bfd_error_handler)
5959214634Sdim                  (_("%B(%A+0x%lx): Only ADD or SUB instructions are allowed for ALU group relocations"),
5960214634Sdim                  input_bfd, input_section,
5961214634Sdim                  (long) rel->r_offset, howto->name);
5962214634Sdim                return bfd_reloc_overflow;
5963214634Sdim    	      }
5964214634Sdim
5965214634Sdim            signed_addend *= negative;
5966214634Sdim          }
5967214634Sdim
5968214634Sdim	/* Compute the value (X) to go in the place.  */
5969214634Sdim        if (r_type == R_ARM_ALU_PC_G0_NC
5970214634Sdim            || r_type == R_ARM_ALU_PC_G1_NC
5971214634Sdim            || r_type == R_ARM_ALU_PC_G0
5972214634Sdim            || r_type == R_ARM_ALU_PC_G1
5973214634Sdim            || r_type == R_ARM_ALU_PC_G2)
5974214634Sdim          /* PC relative.  */
5975214634Sdim          signed_value = value - pc + signed_addend;
5976214634Sdim        else
5977214634Sdim          /* Section base relative.  */
5978214634Sdim          signed_value = value - sb + signed_addend;
5979214634Sdim
5980214634Sdim        /* If the target symbol is a Thumb function, then set the
5981214634Sdim           Thumb bit in the address.  */
5982214634Sdim	if (sym_flags == STT_ARM_TFUNC)
5983214634Sdim	  signed_value |= 1;
5984214634Sdim
5985214634Sdim        /* Calculate the value of the relevant G_n, in encoded
5986214634Sdim           constant-with-rotation format.  */
5987214634Sdim        g_n = calculate_group_reloc_mask (abs (signed_value), group,
5988214634Sdim                                          &residual);
5989214634Sdim
5990214634Sdim        /* Check for overflow if required.  */
5991214634Sdim        if ((r_type == R_ARM_ALU_PC_G0
5992214634Sdim             || r_type == R_ARM_ALU_PC_G1
5993214634Sdim             || r_type == R_ARM_ALU_PC_G2
5994214634Sdim             || r_type == R_ARM_ALU_SB_G0
5995214634Sdim             || r_type == R_ARM_ALU_SB_G1
5996214634Sdim             || r_type == R_ARM_ALU_SB_G2) && residual != 0)
5997214634Sdim          {
5998214634Sdim            (*_bfd_error_handler)
5999214634Sdim              (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
6000214634Sdim              input_bfd, input_section,
6001214634Sdim              (long) rel->r_offset, abs (signed_value), howto->name);
6002214634Sdim            return bfd_reloc_overflow;
6003214634Sdim          }
6004214634Sdim
6005214634Sdim        /* Mask out the value and the ADD/SUB part of the opcode; take care
6006214634Sdim           not to destroy the S bit.  */
6007214634Sdim        insn &= 0xff1ff000;
6008214634Sdim
6009214634Sdim        /* Set the opcode according to whether the value to go in the
6010214634Sdim           place is negative.  */
6011214634Sdim        if (signed_value < 0)
6012214634Sdim          insn |= 1 << 22;
6013214634Sdim        else
6014214634Sdim          insn |= 1 << 23;
6015214634Sdim
6016214634Sdim        /* Encode the offset.  */
6017214634Sdim        insn |= g_n;
6018214634Sdim
6019214634Sdim	bfd_put_32 (input_bfd, insn, hit_data);
6020214634Sdim      }
6021214634Sdim      return bfd_reloc_ok;
6022214634Sdim
6023214634Sdim    case R_ARM_LDR_PC_G0:
6024214634Sdim    case R_ARM_LDR_PC_G1:
6025214634Sdim    case R_ARM_LDR_PC_G2:
6026214634Sdim    case R_ARM_LDR_SB_G0:
6027214634Sdim    case R_ARM_LDR_SB_G1:
6028214634Sdim    case R_ARM_LDR_SB_G2:
6029214634Sdim      {
6030214634Sdim	bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
6031214634Sdim        bfd_vma pc = input_section->output_section->vma
6032214634Sdim		     + input_section->output_offset + rel->r_offset;
6033214634Sdim        bfd_vma sb = 0; /* See note above.  */
6034214634Sdim        bfd_vma residual;
6035214634Sdim	bfd_signed_vma signed_value;
6036214634Sdim        int group = 0;
6037214634Sdim
6038214634Sdim        /* Determine which groups of bits to calculate.  */
6039214634Sdim        switch (r_type)
6040214634Sdim          {
6041214634Sdim          case R_ARM_LDR_PC_G0:
6042214634Sdim          case R_ARM_LDR_SB_G0:
6043214634Sdim            group = 0;
6044214634Sdim            break;
6045214634Sdim
6046214634Sdim          case R_ARM_LDR_PC_G1:
6047214634Sdim          case R_ARM_LDR_SB_G1:
6048214634Sdim            group = 1;
6049214634Sdim            break;
6050214634Sdim
6051214634Sdim          case R_ARM_LDR_PC_G2:
6052214634Sdim          case R_ARM_LDR_SB_G2:
6053214634Sdim            group = 2;
6054214634Sdim            break;
6055214634Sdim
6056214634Sdim          default:
6057214634Sdim            abort();
6058214634Sdim          }
6059214634Sdim
6060214634Sdim        /* If REL, extract the addend from the insn.  If RELA, it will
6061214634Sdim           have already been fetched for us.  */
6062214634Sdim	if (globals->use_rel)
6063214634Sdim          {
6064214634Sdim            int negative = (insn & (1 << 23)) ? 1 : -1;
6065214634Sdim            signed_addend = negative * (insn & 0xfff);
6066214634Sdim          }
6067214634Sdim
6068214634Sdim	/* Compute the value (X) to go in the place.  */
6069214634Sdim        if (r_type == R_ARM_LDR_PC_G0
6070214634Sdim            || r_type == R_ARM_LDR_PC_G1
6071214634Sdim            || r_type == R_ARM_LDR_PC_G2)
6072214634Sdim          /* PC relative.  */
6073214634Sdim          signed_value = value - pc + signed_addend;
6074214634Sdim        else
6075214634Sdim          /* Section base relative.  */
6076214634Sdim          signed_value = value - sb + signed_addend;
6077214634Sdim
6078214634Sdim        /* Calculate the value of the relevant G_{n-1} to obtain
6079214634Sdim           the residual at that stage.  */
6080214634Sdim        calculate_group_reloc_mask (abs (signed_value), group - 1, &residual);
6081214634Sdim
6082214634Sdim        /* Check for overflow.  */
6083214634Sdim        if (residual >= 0x1000)
6084214634Sdim          {
6085214634Sdim            (*_bfd_error_handler)
6086214634Sdim              (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
6087214634Sdim              input_bfd, input_section,
6088214634Sdim              (long) rel->r_offset, abs (signed_value), howto->name);
6089214634Sdim            return bfd_reloc_overflow;
6090214634Sdim          }
6091214634Sdim
6092214634Sdim        /* Mask out the value and U bit.  */
6093214634Sdim        insn &= 0xff7ff000;
6094214634Sdim
6095214634Sdim        /* Set the U bit if the value to go in the place is non-negative.  */
6096214634Sdim        if (signed_value >= 0)
6097214634Sdim          insn |= 1 << 23;
6098214634Sdim
6099214634Sdim        /* Encode the offset.  */
6100214634Sdim        insn |= residual;
6101214634Sdim
6102214634Sdim	bfd_put_32 (input_bfd, insn, hit_data);
6103214634Sdim      }
6104214634Sdim      return bfd_reloc_ok;
6105214634Sdim
6106214634Sdim    case R_ARM_LDRS_PC_G0:
6107214634Sdim    case R_ARM_LDRS_PC_G1:
6108214634Sdim    case R_ARM_LDRS_PC_G2:
6109214634Sdim    case R_ARM_LDRS_SB_G0:
6110214634Sdim    case R_ARM_LDRS_SB_G1:
6111214634Sdim    case R_ARM_LDRS_SB_G2:
6112214634Sdim      {
6113214634Sdim	bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
6114214634Sdim        bfd_vma pc = input_section->output_section->vma
6115214634Sdim		     + input_section->output_offset + rel->r_offset;
6116214634Sdim        bfd_vma sb = 0; /* See note above.  */
6117214634Sdim        bfd_vma residual;
6118214634Sdim	bfd_signed_vma signed_value;
6119214634Sdim        int group = 0;
6120214634Sdim
6121214634Sdim        /* Determine which groups of bits to calculate.  */
6122214634Sdim        switch (r_type)
6123214634Sdim          {
6124214634Sdim          case R_ARM_LDRS_PC_G0:
6125214634Sdim          case R_ARM_LDRS_SB_G0:
6126214634Sdim            group = 0;
6127214634Sdim            break;
6128214634Sdim
6129214634Sdim          case R_ARM_LDRS_PC_G1:
6130214634Sdim          case R_ARM_LDRS_SB_G1:
6131214634Sdim            group = 1;
6132214634Sdim            break;
6133214634Sdim
6134214634Sdim          case R_ARM_LDRS_PC_G2:
6135214634Sdim          case R_ARM_LDRS_SB_G2:
6136214634Sdim            group = 2;
6137214634Sdim            break;
6138214634Sdim
6139214634Sdim          default:
6140214634Sdim            abort();
6141214634Sdim          }
6142214634Sdim
6143214634Sdim        /* If REL, extract the addend from the insn.  If RELA, it will
6144214634Sdim           have already been fetched for us.  */
6145214634Sdim	if (globals->use_rel)
6146214634Sdim          {
6147214634Sdim            int negative = (insn & (1 << 23)) ? 1 : -1;
6148214634Sdim            signed_addend = negative * (((insn & 0xf00) >> 4) + (insn & 0xf));
6149214634Sdim          }
6150214634Sdim
6151214634Sdim	/* Compute the value (X) to go in the place.  */
6152214634Sdim        if (r_type == R_ARM_LDRS_PC_G0
6153214634Sdim            || r_type == R_ARM_LDRS_PC_G1
6154214634Sdim            || r_type == R_ARM_LDRS_PC_G2)
6155214634Sdim          /* PC relative.  */
6156214634Sdim          signed_value = value - pc + signed_addend;
6157214634Sdim        else
6158214634Sdim          /* Section base relative.  */
6159214634Sdim          signed_value = value - sb + signed_addend;
6160214634Sdim
6161214634Sdim        /* Calculate the value of the relevant G_{n-1} to obtain
6162214634Sdim           the residual at that stage.  */
6163214634Sdim        calculate_group_reloc_mask (abs (signed_value), group - 1, &residual);
6164214634Sdim
6165214634Sdim        /* Check for overflow.  */
6166214634Sdim        if (residual >= 0x100)
6167214634Sdim          {
6168214634Sdim            (*_bfd_error_handler)
6169214634Sdim              (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
6170214634Sdim              input_bfd, input_section,
6171214634Sdim              (long) rel->r_offset, abs (signed_value), howto->name);
6172214634Sdim            return bfd_reloc_overflow;
6173214634Sdim          }
6174214634Sdim
6175214634Sdim        /* Mask out the value and U bit.  */
6176214634Sdim        insn &= 0xff7ff0f0;
6177214634Sdim
6178214634Sdim        /* Set the U bit if the value to go in the place is non-negative.  */
6179214634Sdim        if (signed_value >= 0)
6180214634Sdim          insn |= 1 << 23;
6181214634Sdim
6182214634Sdim        /* Encode the offset.  */
6183214634Sdim        insn |= ((residual & 0xf0) << 4) | (residual & 0xf);
6184214634Sdim
6185214634Sdim	bfd_put_32 (input_bfd, insn, hit_data);
6186214634Sdim      }
6187214634Sdim      return bfd_reloc_ok;
6188214634Sdim
6189214634Sdim    case R_ARM_LDC_PC_G0:
6190214634Sdim    case R_ARM_LDC_PC_G1:
6191214634Sdim    case R_ARM_LDC_PC_G2:
6192214634Sdim    case R_ARM_LDC_SB_G0:
6193214634Sdim    case R_ARM_LDC_SB_G1:
6194214634Sdim    case R_ARM_LDC_SB_G2:
6195214634Sdim      {
6196214634Sdim	bfd_vma insn = bfd_get_32 (input_bfd, hit_data);
6197214634Sdim        bfd_vma pc = input_section->output_section->vma
6198214634Sdim		     + input_section->output_offset + rel->r_offset;
6199214634Sdim        bfd_vma sb = 0; /* See note above.  */
6200214634Sdim        bfd_vma residual;
6201214634Sdim	bfd_signed_vma signed_value;
6202214634Sdim        int group = 0;
6203214634Sdim
6204214634Sdim        /* Determine which groups of bits to calculate.  */
6205214634Sdim        switch (r_type)
6206214634Sdim          {
6207214634Sdim          case R_ARM_LDC_PC_G0:
6208214634Sdim          case R_ARM_LDC_SB_G0:
6209214634Sdim            group = 0;
6210214634Sdim            break;
6211214634Sdim
6212214634Sdim          case R_ARM_LDC_PC_G1:
6213214634Sdim          case R_ARM_LDC_SB_G1:
6214214634Sdim            group = 1;
6215214634Sdim            break;
6216214634Sdim
6217214634Sdim          case R_ARM_LDC_PC_G2:
6218214634Sdim          case R_ARM_LDC_SB_G2:
6219214634Sdim            group = 2;
6220214634Sdim            break;
6221214634Sdim
6222214634Sdim          default:
6223214634Sdim            abort();
6224214634Sdim          }
6225214634Sdim
6226214634Sdim        /* If REL, extract the addend from the insn.  If RELA, it will
6227214634Sdim           have already been fetched for us.  */
6228214634Sdim	if (globals->use_rel)
6229214634Sdim          {
6230214634Sdim            int negative = (insn & (1 << 23)) ? 1 : -1;
6231214634Sdim            signed_addend = negative * ((insn & 0xff) << 2);
6232214634Sdim          }
6233214634Sdim
6234214634Sdim	/* Compute the value (X) to go in the place.  */
6235214634Sdim        if (r_type == R_ARM_LDC_PC_G0
6236214634Sdim            || r_type == R_ARM_LDC_PC_G1
6237214634Sdim            || r_type == R_ARM_LDC_PC_G2)
6238214634Sdim          /* PC relative.  */
6239214634Sdim          signed_value = value - pc + signed_addend;
6240214634Sdim        else
6241214634Sdim          /* Section base relative.  */
6242214634Sdim          signed_value = value - sb + signed_addend;
6243214634Sdim
6244214634Sdim        /* Calculate the value of the relevant G_{n-1} to obtain
6245214634Sdim           the residual at that stage.  */
6246214634Sdim        calculate_group_reloc_mask (abs (signed_value), group - 1, &residual);
6247214634Sdim
6248214634Sdim        /* Check for overflow.  (The absolute value to go in the place must be
6249214634Sdim           divisible by four and, after having been divided by four, must
6250214634Sdim           fit in eight bits.)  */
6251214634Sdim        if ((residual & 0x3) != 0 || residual >= 0x400)
6252214634Sdim          {
6253214634Sdim            (*_bfd_error_handler)
6254214634Sdim              (_("%B(%A+0x%lx): Overflow whilst splitting 0x%lx for group relocation %s"),
6255214634Sdim              input_bfd, input_section,
6256214634Sdim              (long) rel->r_offset, abs (signed_value), howto->name);
6257214634Sdim            return bfd_reloc_overflow;
6258214634Sdim          }
6259214634Sdim
6260214634Sdim        /* Mask out the value and U bit.  */
6261214634Sdim        insn &= 0xff7fff00;
6262214634Sdim
6263214634Sdim        /* Set the U bit if the value to go in the place is non-negative.  */
6264214634Sdim        if (signed_value >= 0)
6265214634Sdim          insn |= 1 << 23;
6266214634Sdim
6267214634Sdim        /* Encode the offset.  */
6268214634Sdim        insn |= residual >> 2;
6269214634Sdim
6270214634Sdim	bfd_put_32 (input_bfd, insn, hit_data);
6271214634Sdim      }
6272214634Sdim      return bfd_reloc_ok;
6273214634Sdim
6274214634Sdim    default:
6275214634Sdim      return bfd_reloc_notsupported;
6276214082Sdim    }
6277214082Sdim}
6278214082Sdim
6279214082Sdim/* Add INCREMENT to the reloc (of type HOWTO) at ADDRESS.  */
6280214082Sdimstatic void
6281214082Sdimarm_add_to_rel (bfd *              abfd,
6282214082Sdim		bfd_byte *         address,
6283214082Sdim		reloc_howto_type * howto,
6284214082Sdim		bfd_signed_vma     increment)
6285214082Sdim{
6286214082Sdim  bfd_signed_vma addend;
6287214082Sdim
6288214082Sdim  if (howto->type == R_ARM_THM_CALL)
6289214082Sdim    {
6290214082Sdim      int upper_insn, lower_insn;
6291214082Sdim      int upper, lower;
6292214082Sdim
6293214082Sdim      upper_insn = bfd_get_16 (abfd, address);
6294214082Sdim      lower_insn = bfd_get_16 (abfd, address + 2);
6295214082Sdim      upper = upper_insn & 0x7ff;
6296214082Sdim      lower = lower_insn & 0x7ff;
6297214082Sdim
6298214082Sdim      addend = (upper << 12) | (lower << 1);
6299214082Sdim      addend += increment;
6300214082Sdim      addend >>= 1;
6301214082Sdim
6302214082Sdim      upper_insn = (upper_insn & 0xf800) | ((addend >> 11) & 0x7ff);
6303214082Sdim      lower_insn = (lower_insn & 0xf800) | (addend & 0x7ff);
6304214082Sdim
6305214082Sdim      bfd_put_16 (abfd, (bfd_vma) upper_insn, address);
6306214082Sdim      bfd_put_16 (abfd, (bfd_vma) lower_insn, address + 2);
6307214082Sdim    }
6308214082Sdim  else
6309214082Sdim    {
6310214082Sdim      bfd_vma        contents;
6311214082Sdim
6312214082Sdim      contents = bfd_get_32 (abfd, address);
6313214082Sdim
6314214082Sdim      /* Get the (signed) value from the instruction.  */
6315214082Sdim      addend = contents & howto->src_mask;
6316214082Sdim      if (addend & ((howto->src_mask + 1) >> 1))
6317214082Sdim	{
6318214082Sdim	  bfd_signed_vma mask;
6319214082Sdim
6320214082Sdim	  mask = -1;
6321214082Sdim	  mask &= ~ howto->src_mask;
6322214082Sdim	  addend |= mask;
6323214082Sdim	}
6324214082Sdim
6325214082Sdim      /* Add in the increment, (which is a byte value).  */
6326214082Sdim      switch (howto->type)
6327214082Sdim	{
6328214082Sdim	default:
6329214082Sdim	  addend += increment;
6330214082Sdim	  break;
6331214082Sdim
6332214082Sdim	case R_ARM_PC24:
6333214082Sdim	case R_ARM_PLT32:
6334214082Sdim	case R_ARM_CALL:
6335214082Sdim	case R_ARM_JUMP24:
6336214082Sdim	  addend <<= howto->size;
6337214082Sdim	  addend += increment;
6338214082Sdim
6339214082Sdim	  /* Should we check for overflow here ?  */
6340214082Sdim
6341214082Sdim	  /* Drop any undesired bits.  */
6342214082Sdim	  addend >>= howto->rightshift;
6343214082Sdim	  break;
6344214082Sdim	}
6345214082Sdim
6346214082Sdim      contents = (contents & ~ howto->dst_mask) | (addend & howto->dst_mask);
6347214082Sdim
6348214082Sdim      bfd_put_32 (abfd, contents, address);
6349214082Sdim    }
6350214082Sdim}
6351214082Sdim
6352214082Sdim#define IS_ARM_TLS_RELOC(R_TYPE)	\
6353214082Sdim  ((R_TYPE) == R_ARM_TLS_GD32		\
6354214082Sdim   || (R_TYPE) == R_ARM_TLS_LDO32	\
6355214082Sdim   || (R_TYPE) == R_ARM_TLS_LDM32	\
6356214082Sdim   || (R_TYPE) == R_ARM_TLS_DTPOFF32	\
6357214082Sdim   || (R_TYPE) == R_ARM_TLS_DTPMOD32	\
6358214082Sdim   || (R_TYPE) == R_ARM_TLS_TPOFF32	\
6359214082Sdim   || (R_TYPE) == R_ARM_TLS_LE32	\
6360214082Sdim   || (R_TYPE) == R_ARM_TLS_IE32)
6361214082Sdim
6362214082Sdim/* Relocate an ARM ELF section.  */
6363214082Sdimstatic bfd_boolean
6364214082Sdimelf32_arm_relocate_section (bfd *                  output_bfd,
6365214082Sdim			    struct bfd_link_info * info,
6366214082Sdim			    bfd *                  input_bfd,
6367214082Sdim			    asection *             input_section,
6368214082Sdim			    bfd_byte *             contents,
6369214082Sdim			    Elf_Internal_Rela *    relocs,
6370214082Sdim			    Elf_Internal_Sym *     local_syms,
6371214082Sdim			    asection **            local_sections)
6372214082Sdim{
6373214082Sdim  Elf_Internal_Shdr *symtab_hdr;
6374214082Sdim  struct elf_link_hash_entry **sym_hashes;
6375214082Sdim  Elf_Internal_Rela *rel;
6376214082Sdim  Elf_Internal_Rela *relend;
6377214082Sdim  const char *name;
6378214082Sdim  struct elf32_arm_link_hash_table * globals;
6379214082Sdim
6380214082Sdim  globals = elf32_arm_hash_table (info);
6381214082Sdim
6382214082Sdim  symtab_hdr = & elf_tdata (input_bfd)->symtab_hdr;
6383214082Sdim  sym_hashes = elf_sym_hashes (input_bfd);
6384214082Sdim
6385214082Sdim  rel = relocs;
6386214082Sdim  relend = relocs + input_section->reloc_count;
6387214082Sdim  for (; rel < relend; rel++)
6388214082Sdim    {
6389214082Sdim      int                          r_type;
6390214082Sdim      reloc_howto_type *           howto;
6391214082Sdim      unsigned long                r_symndx;
6392214082Sdim      Elf_Internal_Sym *           sym;
6393214082Sdim      asection *                   sec;
6394214082Sdim      struct elf_link_hash_entry * h;
6395214082Sdim      bfd_vma                      relocation;
6396214082Sdim      bfd_reloc_status_type        r;
6397214082Sdim      arelent                      bfd_reloc;
6398214082Sdim      char                         sym_type;
6399214082Sdim      bfd_boolean                  unresolved_reloc = FALSE;
6400214634Sdim      char *error_message = NULL;
6401214082Sdim
6402214082Sdim      r_symndx = ELF32_R_SYM (rel->r_info);
6403214082Sdim      r_type   = ELF32_R_TYPE (rel->r_info);
6404214082Sdim      r_type   = arm_real_reloc_type (globals, r_type);
6405214082Sdim
6406214082Sdim      if (   r_type == R_ARM_GNU_VTENTRY
6407214082Sdim          || r_type == R_ARM_GNU_VTINHERIT)
6408214082Sdim        continue;
6409214082Sdim
6410214082Sdim      bfd_reloc.howto = elf32_arm_howto_from_type (r_type);
6411214082Sdim      howto = bfd_reloc.howto;
6412214082Sdim
6413214082Sdim      h = NULL;
6414214082Sdim      sym = NULL;
6415214082Sdim      sec = NULL;
6416214082Sdim
6417214082Sdim      if (r_symndx < symtab_hdr->sh_info)
6418214082Sdim	{
6419214082Sdim	  sym = local_syms + r_symndx;
6420214082Sdim	  sym_type = ELF32_ST_TYPE (sym->st_info);
6421214082Sdim	  sec = local_sections[r_symndx];
6422214082Sdim	  if (globals->use_rel)
6423214082Sdim	    {
6424214082Sdim	      relocation = (sec->output_section->vma
6425214082Sdim			    + sec->output_offset
6426214082Sdim			    + sym->st_value);
6427214634Sdim	      if (!info->relocatable
6428214634Sdim		  && (sec->flags & SEC_MERGE)
6429214634Sdim		  && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
6430214082Sdim		{
6431214082Sdim		  asection *msec;
6432214082Sdim		  bfd_vma addend, value;
6433214082Sdim
6434214082Sdim		  if (howto->rightshift)
6435214082Sdim		    {
6436214082Sdim		      (*_bfd_error_handler)
6437214082Sdim			(_("%B(%A+0x%lx): %s relocation against SEC_MERGE section"),
6438214082Sdim			 input_bfd, input_section,
6439214082Sdim			 (long) rel->r_offset, howto->name);
6440214082Sdim		      return FALSE;
6441214082Sdim		    }
6442214082Sdim
6443214082Sdim		  value = bfd_get_32 (input_bfd, contents + rel->r_offset);
6444214082Sdim
6445214082Sdim		  /* Get the (signed) value from the instruction.  */
6446214082Sdim		  addend = value & howto->src_mask;
6447214082Sdim		  if (addend & ((howto->src_mask + 1) >> 1))
6448214082Sdim		    {
6449214082Sdim		      bfd_signed_vma mask;
6450214082Sdim
6451214082Sdim		      mask = -1;
6452214082Sdim		      mask &= ~ howto->src_mask;
6453214082Sdim		      addend |= mask;
6454214082Sdim		    }
6455214082Sdim		  msec = sec;
6456214082Sdim		  addend =
6457214082Sdim		    _bfd_elf_rel_local_sym (output_bfd, sym, &msec, addend)
6458214082Sdim		    - relocation;
6459214082Sdim		  addend += msec->output_section->vma + msec->output_offset;
6460214082Sdim		  value = (value & ~ howto->dst_mask) | (addend & howto->dst_mask);
6461214082Sdim		  bfd_put_32 (input_bfd, value, contents + rel->r_offset);
6462214082Sdim		}
6463214082Sdim	    }
6464214082Sdim	  else
6465214082Sdim	    relocation = _bfd_elf_rela_local_sym (output_bfd, sym, &sec, rel);
6466214082Sdim	}
6467214082Sdim      else
6468214082Sdim	{
6469214082Sdim	  bfd_boolean warned;
6470214082Sdim
6471214082Sdim	  RELOC_FOR_GLOBAL_SYMBOL (info, input_bfd, input_section, rel,
6472214082Sdim				   r_symndx, symtab_hdr, sym_hashes,
6473214082Sdim				   h, sec, relocation,
6474214082Sdim				   unresolved_reloc, warned);
6475214082Sdim
6476214082Sdim	  sym_type = h->type;
6477214082Sdim	}
6478214082Sdim
6479214634Sdim      if (sec != NULL && elf_discarded_section (sec))
6480214634Sdim	{
6481214634Sdim	  /* For relocs against symbols from removed linkonce sections,
6482214634Sdim	     or sections discarded by a linker script, we just want the
6483214634Sdim	     section contents zeroed.  Avoid any special processing.  */
6484214634Sdim	  _bfd_clear_contents (howto, input_bfd, contents + rel->r_offset);
6485214634Sdim	  rel->r_info = 0;
6486214634Sdim	  rel->r_addend = 0;
6487214634Sdim	  continue;
6488214634Sdim	}
6489214634Sdim
6490214634Sdim      if (info->relocatable)
6491214634Sdim	{
6492214634Sdim	  /* This is a relocatable link.  We don't have to change
6493214634Sdim	     anything, unless the reloc is against a section symbol,
6494214634Sdim	     in which case we have to adjust according to where the
6495214634Sdim	     section symbol winds up in the output section.  */
6496214634Sdim	  if (sym != NULL && ELF_ST_TYPE (sym->st_info) == STT_SECTION)
6497214634Sdim	    {
6498214634Sdim	      if (globals->use_rel)
6499214634Sdim		arm_add_to_rel (input_bfd, contents + rel->r_offset,
6500214634Sdim				howto, (bfd_signed_vma) sec->output_offset);
6501214634Sdim	      else
6502214634Sdim		rel->r_addend += sec->output_offset;
6503214634Sdim	    }
6504214634Sdim	  continue;
6505214634Sdim	}
6506214634Sdim
6507214082Sdim      if (h != NULL)
6508214082Sdim	name = h->root.root.string;
6509214082Sdim      else
6510214082Sdim	{
6511214082Sdim	  name = (bfd_elf_string_from_elf_section
6512214082Sdim		  (input_bfd, symtab_hdr->sh_link, sym->st_name));
6513214082Sdim	  if (name == NULL || *name == '\0')
6514214082Sdim	    name = bfd_section_name (input_bfd, sec);
6515214082Sdim	}
6516214082Sdim
6517214082Sdim      if (r_symndx != 0
6518214082Sdim	  && r_type != R_ARM_NONE
6519214082Sdim	  && (h == NULL
6520214082Sdim	      || h->root.type == bfd_link_hash_defined
6521214082Sdim	      || h->root.type == bfd_link_hash_defweak)
6522214082Sdim	  && IS_ARM_TLS_RELOC (r_type) != (sym_type == STT_TLS))
6523214082Sdim	{
6524214082Sdim	  (*_bfd_error_handler)
6525214082Sdim	    ((sym_type == STT_TLS
6526214082Sdim	      ? _("%B(%A+0x%lx): %s used with TLS symbol %s")
6527214082Sdim	      : _("%B(%A+0x%lx): %s used with non-TLS symbol %s")),
6528214082Sdim	     input_bfd,
6529214082Sdim	     input_section,
6530214082Sdim	     (long) rel->r_offset,
6531214082Sdim	     howto->name,
6532214082Sdim	     name);
6533214082Sdim	}
6534214082Sdim
6535214082Sdim      r = elf32_arm_final_link_relocate (howto, input_bfd, output_bfd,
6536214082Sdim					 input_section, contents, rel,
6537214082Sdim					 relocation, info, sec, name,
6538214082Sdim					 (h ? ELF_ST_TYPE (h->type) :
6539214082Sdim					  ELF_ST_TYPE (sym->st_info)), h,
6540214634Sdim					 &unresolved_reloc, &error_message);
6541214082Sdim
6542214082Sdim      /* Dynamic relocs are not propagated for SEC_DEBUGGING sections
6543214082Sdim	 because such sections are not SEC_ALLOC and thus ld.so will
6544214082Sdim	 not process them.  */
6545214082Sdim      if (unresolved_reloc
6546214082Sdim          && !((input_section->flags & SEC_DEBUGGING) != 0
6547214082Sdim               && h->def_dynamic))
6548214082Sdim	{
6549214082Sdim	  (*_bfd_error_handler)
6550214082Sdim	    (_("%B(%A+0x%lx): unresolvable %s relocation against symbol `%s'"),
6551214082Sdim	     input_bfd,
6552214082Sdim	     input_section,
6553214082Sdim	     (long) rel->r_offset,
6554214082Sdim	     howto->name,
6555214082Sdim	     h->root.root.string);
6556214082Sdim	  return FALSE;
6557214082Sdim	}
6558214082Sdim
6559214082Sdim      if (r != bfd_reloc_ok)
6560214082Sdim	{
6561214082Sdim	  switch (r)
6562214082Sdim	    {
6563214082Sdim	    case bfd_reloc_overflow:
6564214082Sdim	      /* If the overflowing reloc was to an undefined symbol,
6565214082Sdim		 we have already printed one error message and there
6566214082Sdim		 is no point complaining again.  */
6567214082Sdim	      if ((! h ||
6568214082Sdim		   h->root.type != bfd_link_hash_undefined)
6569214082Sdim		  && (!((*info->callbacks->reloc_overflow)
6570214082Sdim			(info, (h ? &h->root : NULL), name, howto->name,
6571214082Sdim			 (bfd_vma) 0, input_bfd, input_section,
6572214082Sdim			 rel->r_offset))))
6573214082Sdim		  return FALSE;
6574214082Sdim	      break;
6575214082Sdim
6576214082Sdim	    case bfd_reloc_undefined:
6577214082Sdim	      if (!((*info->callbacks->undefined_symbol)
6578214082Sdim		    (info, name, input_bfd, input_section,
6579214082Sdim		     rel->r_offset, TRUE)))
6580214082Sdim		return FALSE;
6581214082Sdim	      break;
6582214082Sdim
6583214082Sdim	    case bfd_reloc_outofrange:
6584214634Sdim	      error_message = _("out of range");
6585214082Sdim	      goto common_error;
6586214082Sdim
6587214082Sdim	    case bfd_reloc_notsupported:
6588214634Sdim	      error_message = _("unsupported relocation");
6589214082Sdim	      goto common_error;
6590214082Sdim
6591214082Sdim	    case bfd_reloc_dangerous:
6592214634Sdim	      /* error_message should already be set.  */
6593214082Sdim	      goto common_error;
6594214082Sdim
6595214082Sdim	    default:
6596214634Sdim	      error_message = _("unknown error");
6597214082Sdim	      /* fall through */
6598214082Sdim
6599214082Sdim	    common_error:
6600214634Sdim	      BFD_ASSERT (error_message != NULL);
6601214634Sdim	      if (!((*info->callbacks->reloc_dangerous)
6602214634Sdim		    (info, error_message, input_bfd, input_section,
6603214082Sdim		     rel->r_offset)))
6604214082Sdim		return FALSE;
6605214082Sdim	      break;
6606214082Sdim	    }
6607214082Sdim	}
6608214082Sdim    }
6609214082Sdim
6610214082Sdim  return TRUE;
6611214082Sdim}
6612214082Sdim
6613214082Sdim/* Set the right machine number.  */
6614214082Sdim
6615214082Sdimstatic bfd_boolean
6616214082Sdimelf32_arm_object_p (bfd *abfd)
6617214082Sdim{
6618214082Sdim  unsigned int mach;
6619214082Sdim
6620214082Sdim  mach = bfd_arm_get_mach_from_notes (abfd, ARM_NOTE_SECTION);
6621214082Sdim
6622214082Sdim  if (mach != bfd_mach_arm_unknown)
6623214082Sdim    bfd_default_set_arch_mach (abfd, bfd_arch_arm, mach);
6624214082Sdim
6625214082Sdim  else if (elf_elfheader (abfd)->e_flags & EF_ARM_MAVERICK_FLOAT)
6626214082Sdim    bfd_default_set_arch_mach (abfd, bfd_arch_arm, bfd_mach_arm_ep9312);
6627214082Sdim
6628214082Sdim  else
6629214082Sdim    bfd_default_set_arch_mach (abfd, bfd_arch_arm, mach);
6630214082Sdim
6631214082Sdim  return TRUE;
6632214082Sdim}
6633214082Sdim
6634214082Sdim/* Function to keep ARM specific flags in the ELF header.  */
6635214082Sdim
6636214082Sdimstatic bfd_boolean
6637214082Sdimelf32_arm_set_private_flags (bfd *abfd, flagword flags)
6638214082Sdim{
6639214082Sdim  if (elf_flags_init (abfd)
6640214082Sdim      && elf_elfheader (abfd)->e_flags != flags)
6641214082Sdim    {
6642214082Sdim      if (EF_ARM_EABI_VERSION (flags) == EF_ARM_EABI_UNKNOWN)
6643214082Sdim	{
6644214082Sdim	  if (flags & EF_ARM_INTERWORK)
6645214082Sdim	    (*_bfd_error_handler)
6646214082Sdim	      (_("Warning: Not setting interworking flag of %B since it has already been specified as non-interworking"),
6647214082Sdim	       abfd);
6648214082Sdim	  else
6649214082Sdim	    _bfd_error_handler
6650214082Sdim	      (_("Warning: Clearing the interworking flag of %B due to outside request"),
6651214082Sdim	       abfd);
6652214082Sdim	}
6653214082Sdim    }
6654214082Sdim  else
6655214082Sdim    {
6656214082Sdim      elf_elfheader (abfd)->e_flags = flags;
6657214082Sdim      elf_flags_init (abfd) = TRUE;
6658214082Sdim    }
6659214082Sdim
6660214082Sdim  return TRUE;
6661214082Sdim}
6662214082Sdim
6663214082Sdim/* Copy backend specific data from one object module to another.  */
6664214082Sdim
6665214082Sdimstatic bfd_boolean
6666214082Sdimelf32_arm_copy_private_bfd_data (bfd *ibfd, bfd *obfd)
6667214082Sdim{
6668214082Sdim  flagword in_flags;
6669214082Sdim  flagword out_flags;
6670214082Sdim
6671214082Sdim  if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
6672214082Sdim      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
6673214082Sdim    return TRUE;
6674214082Sdim
6675214082Sdim  in_flags  = elf_elfheader (ibfd)->e_flags;
6676214082Sdim  out_flags = elf_elfheader (obfd)->e_flags;
6677214082Sdim
6678214082Sdim  if (elf_flags_init (obfd)
6679214082Sdim      && EF_ARM_EABI_VERSION (out_flags) == EF_ARM_EABI_UNKNOWN
6680214082Sdim      && in_flags != out_flags)
6681214082Sdim    {
6682214082Sdim      /* Cannot mix APCS26 and APCS32 code.  */
6683214082Sdim      if ((in_flags & EF_ARM_APCS_26) != (out_flags & EF_ARM_APCS_26))
6684214082Sdim	return FALSE;
6685214082Sdim
6686214082Sdim      /* Cannot mix float APCS and non-float APCS code.  */
6687214082Sdim      if ((in_flags & EF_ARM_APCS_FLOAT) != (out_flags & EF_ARM_APCS_FLOAT))
6688214082Sdim	return FALSE;
6689214082Sdim
6690214082Sdim      /* If the src and dest have different interworking flags
6691214082Sdim         then turn off the interworking bit.  */
6692214082Sdim      if ((in_flags & EF_ARM_INTERWORK) != (out_flags & EF_ARM_INTERWORK))
6693214082Sdim	{
6694214082Sdim	  if (out_flags & EF_ARM_INTERWORK)
6695214082Sdim	    _bfd_error_handler
6696214082Sdim	      (_("Warning: Clearing the interworking flag of %B because non-interworking code in %B has been linked with it"),
6697214082Sdim	       obfd, ibfd);
6698214082Sdim
6699214082Sdim	  in_flags &= ~EF_ARM_INTERWORK;
6700214082Sdim	}
6701214082Sdim
6702214082Sdim      /* Likewise for PIC, though don't warn for this case.  */
6703214082Sdim      if ((in_flags & EF_ARM_PIC) != (out_flags & EF_ARM_PIC))
6704214082Sdim	in_flags &= ~EF_ARM_PIC;
6705214082Sdim    }
6706214082Sdim
6707214082Sdim  elf_elfheader (obfd)->e_flags = in_flags;
6708214082Sdim  elf_flags_init (obfd) = TRUE;
6709214082Sdim
6710214082Sdim  /* Also copy the EI_OSABI field.  */
6711214082Sdim  elf_elfheader (obfd)->e_ident[EI_OSABI] =
6712214082Sdim    elf_elfheader (ibfd)->e_ident[EI_OSABI];
6713214082Sdim
6714214634Sdim  /* Copy object attributes.  */
6715214634Sdim  _bfd_elf_copy_obj_attributes (ibfd, obfd);
6716214082Sdim
6717214082Sdim  return TRUE;
6718214082Sdim}
6719214082Sdim
6720214082Sdim/* Values for Tag_ABI_PCS_R9_use.  */
6721214082Sdimenum
6722214082Sdim{
6723214082Sdim  AEABI_R9_V6,
6724214082Sdim  AEABI_R9_SB,
6725214082Sdim  AEABI_R9_TLS,
6726214082Sdim  AEABI_R9_unused
6727214082Sdim};
6728214082Sdim
6729214082Sdim/* Values for Tag_ABI_PCS_RW_data.  */
6730214082Sdimenum
6731214082Sdim{
6732214082Sdim  AEABI_PCS_RW_data_absolute,
6733214082Sdim  AEABI_PCS_RW_data_PCrel,
6734214082Sdim  AEABI_PCS_RW_data_SBrel,
6735214082Sdim  AEABI_PCS_RW_data_unused
6736214082Sdim};
6737214082Sdim
6738214082Sdim/* Values for Tag_ABI_enum_size.  */
6739214082Sdimenum
6740214082Sdim{
6741214082Sdim  AEABI_enum_unused,
6742214082Sdim  AEABI_enum_short,
6743214082Sdim  AEABI_enum_wide,
6744214082Sdim  AEABI_enum_forced_wide
6745214082Sdim};
6746214082Sdim
6747214634Sdim/* Determine whether an object attribute tag takes an integer, a
6748214634Sdim   string or both.  */
6749214634Sdimstatic int
6750214634Sdimelf32_arm_obj_attrs_arg_type (int tag)
6751214634Sdim{
6752214634Sdim  if (tag == Tag_compatibility)
6753214634Sdim    return 3;
6754214634Sdim  else if (tag == 4 || tag == 5)
6755214634Sdim    return 2;
6756214634Sdim  else if (tag < 32)
6757214634Sdim    return 1;
6758214634Sdim  else
6759214634Sdim    return (tag & 1) != 0 ? 2 : 1;
6760214634Sdim}
6761214634Sdim
6762214082Sdim/* Merge EABI object attributes from IBFD into OBFD.  Raise an error if there
6763214082Sdim   are conflicting attributes.  */
6764214082Sdimstatic bfd_boolean
6765214082Sdimelf32_arm_merge_eabi_attributes (bfd *ibfd, bfd *obfd)
6766214082Sdim{
6767214634Sdim  obj_attribute *in_attr;
6768214634Sdim  obj_attribute *out_attr;
6769214634Sdim  obj_attribute_list *in_list;
6770214082Sdim  /* Some tags have 0 = don't care, 1 = strong requirement,
6771214082Sdim     2 = weak requirement.  */
6772214082Sdim  static const int order_312[3] = {3, 1, 2};
6773214082Sdim  int i;
6774214082Sdim
6775214634Sdim  if (!elf_known_obj_attributes_proc (obfd)[0].i)
6776214082Sdim    {
6777214082Sdim      /* This is the first object.  Copy the attributes.  */
6778214634Sdim      _bfd_elf_copy_obj_attributes (ibfd, obfd);
6779214634Sdim
6780214634Sdim      /* Use the Tag_null value to indicate the attributes have been
6781214634Sdim	 initialized.  */
6782214634Sdim      elf_known_obj_attributes_proc (obfd)[0].i = 1;
6783214634Sdim
6784214082Sdim      return TRUE;
6785214082Sdim    }
6786214082Sdim
6787214634Sdim  in_attr = elf_known_obj_attributes_proc (ibfd);
6788214634Sdim  out_attr = elf_known_obj_attributes_proc (obfd);
6789214082Sdim  /* This needs to happen before Tag_ABI_FP_number_model is merged.  */
6790214082Sdim  if (in_attr[Tag_ABI_VFP_args].i != out_attr[Tag_ABI_VFP_args].i)
6791214082Sdim    {
6792214082Sdim      /* Ignore mismatches if teh object doesn't use floating point.  */
6793214082Sdim      if (out_attr[Tag_ABI_FP_number_model].i == 0)
6794214082Sdim	out_attr[Tag_ABI_VFP_args].i = in_attr[Tag_ABI_VFP_args].i;
6795214082Sdim      else if (in_attr[Tag_ABI_FP_number_model].i != 0)
6796214082Sdim	{
6797214082Sdim	  _bfd_error_handler
6798214082Sdim	    (_("ERROR: %B uses VFP register arguments, %B does not"),
6799214082Sdim	     ibfd, obfd);
6800214082Sdim	  return FALSE;
6801214082Sdim	}
6802214082Sdim    }
6803214082Sdim
6804214634Sdim  for (i = 4; i < NUM_KNOWN_OBJ_ATTRIBUTES; i++)
6805214082Sdim    {
6806214082Sdim      /* Merge this attribute with existing attributes.  */
6807214082Sdim      switch (i)
6808214082Sdim	{
6809214082Sdim	case Tag_CPU_raw_name:
6810214082Sdim	case Tag_CPU_name:
6811214634Sdim	  /* Use whichever has the greatest architecture requirements.  We
6812214634Sdim	     won't necessarily have both the above tags, so make sure input
6813214634Sdim	     name is non-NULL.  */
6814214634Sdim	  if (in_attr[Tag_CPU_arch].i > out_attr[Tag_CPU_arch].i
6815214634Sdim	      && in_attr[i].s)
6816214634Sdim	    out_attr[i].s = _bfd_elf_attr_strdup (obfd, in_attr[i].s);
6817214082Sdim	  break;
6818214082Sdim
6819214082Sdim	case Tag_ABI_optimization_goals:
6820214082Sdim	case Tag_ABI_FP_optimization_goals:
6821214082Sdim	  /* Use the first value seen.  */
6822214082Sdim	  break;
6823214082Sdim
6824214082Sdim	case Tag_CPU_arch:
6825214082Sdim	case Tag_ARM_ISA_use:
6826214082Sdim	case Tag_THUMB_ISA_use:
6827214082Sdim	case Tag_VFP_arch:
6828214082Sdim	case Tag_WMMX_arch:
6829214082Sdim	case Tag_NEON_arch:
6830214082Sdim	  /* ??? Do NEON and WMMX conflict?  */
6831214082Sdim	case Tag_ABI_FP_rounding:
6832214082Sdim	case Tag_ABI_FP_denormal:
6833214082Sdim	case Tag_ABI_FP_exceptions:
6834214082Sdim	case Tag_ABI_FP_user_exceptions:
6835214082Sdim	case Tag_ABI_FP_number_model:
6836214082Sdim	case Tag_ABI_align8_preserved:
6837214082Sdim	case Tag_ABI_HardFP_use:
6838214082Sdim	  /* Use the largest value specified.  */
6839214082Sdim	  if (in_attr[i].i > out_attr[i].i)
6840214082Sdim	    out_attr[i].i = in_attr[i].i;
6841214082Sdim	  break;
6842214082Sdim
6843214082Sdim	case Tag_CPU_arch_profile:
6844214082Sdim	  /* Warn if conflicting architecture profiles used.  */
6845214082Sdim	  if (out_attr[i].i && in_attr[i].i && in_attr[i].i != out_attr[i].i)
6846214082Sdim	    {
6847214082Sdim	      _bfd_error_handler
6848214082Sdim		(_("ERROR: %B: Conflicting architecture profiles %c/%c"),
6849214082Sdim		 ibfd, in_attr[i].i, out_attr[i].i);
6850214082Sdim	      return FALSE;
6851214082Sdim	    }
6852214082Sdim	  if (in_attr[i].i)
6853214082Sdim	    out_attr[i].i = in_attr[i].i;
6854214082Sdim	  break;
6855214082Sdim	case Tag_PCS_config:
6856214082Sdim	  if (out_attr[i].i == 0)
6857214082Sdim	    out_attr[i].i = in_attr[i].i;
6858214082Sdim	  else if (in_attr[i].i != 0 && out_attr[i].i != 0)
6859214082Sdim	    {
6860214082Sdim	      /* It's sometimes ok to mix different configs, so this is only
6861214082Sdim	         a warning.  */
6862214082Sdim	      _bfd_error_handler
6863214082Sdim		(_("Warning: %B: Conflicting platform configuration"), ibfd);
6864214082Sdim	    }
6865214082Sdim	  break;
6866214082Sdim	case Tag_ABI_PCS_R9_use:
6867214634Sdim	  if (in_attr[i].i != out_attr[i].i
6868214634Sdim	      && out_attr[i].i != AEABI_R9_unused
6869214082Sdim	      && in_attr[i].i != AEABI_R9_unused)
6870214082Sdim	    {
6871214082Sdim	      _bfd_error_handler
6872214082Sdim		(_("ERROR: %B: Conflicting use of R9"), ibfd);
6873214082Sdim	      return FALSE;
6874214082Sdim	    }
6875214082Sdim	  if (out_attr[i].i == AEABI_R9_unused)
6876214082Sdim	    out_attr[i].i = in_attr[i].i;
6877214082Sdim	  break;
6878214082Sdim	case Tag_ABI_PCS_RW_data:
6879214082Sdim	  if (in_attr[i].i == AEABI_PCS_RW_data_SBrel
6880214082Sdim	      && out_attr[Tag_ABI_PCS_R9_use].i != AEABI_R9_SB
6881214082Sdim	      && out_attr[Tag_ABI_PCS_R9_use].i != AEABI_R9_unused)
6882214082Sdim	    {
6883214082Sdim	      _bfd_error_handler
6884214082Sdim		(_("ERROR: %B: SB relative addressing conflicts with use of R9"),
6885214082Sdim		 ibfd);
6886214082Sdim	      return FALSE;
6887214082Sdim	    }
6888214082Sdim	  /* Use the smallest value specified.  */
6889214082Sdim	  if (in_attr[i].i < out_attr[i].i)
6890214082Sdim	    out_attr[i].i = in_attr[i].i;
6891214082Sdim	  break;
6892214082Sdim	case Tag_ABI_PCS_RO_data:
6893214082Sdim	  /* Use the smallest value specified.  */
6894214082Sdim	  if (in_attr[i].i < out_attr[i].i)
6895214082Sdim	    out_attr[i].i = in_attr[i].i;
6896214082Sdim	  break;
6897214082Sdim	case Tag_ABI_PCS_GOT_use:
6898214082Sdim	  if (in_attr[i].i > 2 || out_attr[i].i > 2
6899214082Sdim	      || order_312[in_attr[i].i] < order_312[out_attr[i].i])
6900214082Sdim	    out_attr[i].i = in_attr[i].i;
6901214082Sdim	  break;
6902214082Sdim	case Tag_ABI_PCS_wchar_t:
6903214082Sdim	  if (out_attr[i].i && in_attr[i].i && out_attr[i].i != in_attr[i].i)
6904214082Sdim	    {
6905214082Sdim	      _bfd_error_handler
6906214082Sdim		(_("ERROR: %B: Conflicting definitions of wchar_t"), ibfd);
6907214082Sdim	      return FALSE;
6908214082Sdim	    }
6909214082Sdim	  if (in_attr[i].i)
6910214082Sdim	    out_attr[i].i = in_attr[i].i;
6911214082Sdim	  break;
6912214082Sdim	case Tag_ABI_align8_needed:
6913214082Sdim	  /* ??? Check against Tag_ABI_align8_preserved.  */
6914214082Sdim	  if (in_attr[i].i > 2 || out_attr[i].i > 2
6915214082Sdim	      || order_312[in_attr[i].i] < order_312[out_attr[i].i])
6916214082Sdim	    out_attr[i].i = in_attr[i].i;
6917214082Sdim	  break;
6918214082Sdim	case Tag_ABI_enum_size:
6919214082Sdim	  if (in_attr[i].i != AEABI_enum_unused)
6920214082Sdim	    {
6921214082Sdim	      if (out_attr[i].i == AEABI_enum_unused
6922214082Sdim		  || out_attr[i].i == AEABI_enum_forced_wide)
6923214082Sdim		{
6924214082Sdim		  /* The existing object is compatible with anything.
6925214082Sdim		     Use whatever requirements the new object has.  */
6926214082Sdim		  out_attr[i].i = in_attr[i].i;
6927214082Sdim		}
6928214082Sdim	      else if (in_attr[i].i != AEABI_enum_forced_wide
6929214634Sdim		       && out_attr[i].i != in_attr[i].i
6930214634Sdim		       && !elf32_arm_tdata (obfd)->no_enum_size_warning)
6931214082Sdim		{
6932214634Sdim		  const char *aeabi_enum_names[] =
6933214634Sdim		    { "", "variable-size", "32-bit", "" };
6934214082Sdim		  _bfd_error_handler
6935214634Sdim		    (_("warning: %B uses %s enums yet the output is to use %s enums; use of enum values across objects may fail"),
6936214634Sdim		     ibfd, aeabi_enum_names[in_attr[i].i],
6937214634Sdim		     aeabi_enum_names[out_attr[i].i]);
6938214082Sdim		}
6939214082Sdim	    }
6940214082Sdim	  break;
6941214082Sdim	case Tag_ABI_VFP_args:
6942214082Sdim	  /* Aready done.  */
6943214082Sdim	  break;
6944214082Sdim	case Tag_ABI_WMMX_args:
6945214082Sdim	  if (in_attr[i].i != out_attr[i].i)
6946214082Sdim	    {
6947214082Sdim	      _bfd_error_handler
6948214082Sdim		(_("ERROR: %B uses iWMMXt register arguments, %B does not"),
6949214082Sdim		 ibfd, obfd);
6950214082Sdim	      return FALSE;
6951214082Sdim	    }
6952214082Sdim	  break;
6953214082Sdim	default: /* All known attributes should be explicitly covered.   */
6954214082Sdim	  abort ();
6955214082Sdim	}
6956214082Sdim    }
6957214082Sdim
6958214634Sdim  /* Merge Tag_compatibility attributes and any common GNU ones.  */
6959214634Sdim  _bfd_elf_merge_object_attributes (ibfd, obfd);
6960214634Sdim
6961214634Sdim  /* Check for any attributes not known on ARM.  */
6962214634Sdim  in_list = elf_other_obj_attributes_proc (ibfd);
6963214082Sdim  while (in_list && in_list->tag == Tag_compatibility)
6964214634Sdim    in_list = in_list->next;
6965214082Sdim
6966214082Sdim  for (; in_list; in_list = in_list->next)
6967214082Sdim    {
6968214082Sdim      if ((in_list->tag & 128) < 64)
6969214082Sdim	{
6970214082Sdim	  _bfd_error_handler
6971214082Sdim	    (_("Warning: %B: Unknown EABI object attribute %d"),
6972214082Sdim	     ibfd, in_list->tag);
6973214082Sdim	  break;
6974214082Sdim	}
6975214082Sdim    }
6976214082Sdim  return TRUE;
6977214082Sdim}
6978214082Sdim
6979214082Sdim
6980214082Sdim/* Return TRUE if the two EABI versions are incompatible.  */
6981214082Sdim
6982214082Sdimstatic bfd_boolean
6983214082Sdimelf32_arm_versions_compatible (unsigned iver, unsigned over)
6984214082Sdim{
6985214082Sdim  /* v4 and v5 are the same spec before and after it was released,
6986214082Sdim     so allow mixing them.  */
6987214082Sdim  if ((iver == EF_ARM_EABI_VER4 && over == EF_ARM_EABI_VER5)
6988214082Sdim      || (iver == EF_ARM_EABI_VER5 && over == EF_ARM_EABI_VER4))
6989214082Sdim    return TRUE;
6990214082Sdim
6991214082Sdim  return (iver == over);
6992214082Sdim}
6993214082Sdim
6994214082Sdim/* Merge backend specific data from an object file to the output
6995214082Sdim   object file when linking.  */
6996214082Sdim
6997214082Sdimstatic bfd_boolean
6998214082Sdimelf32_arm_merge_private_bfd_data (bfd * ibfd, bfd * obfd)
6999214082Sdim{
7000214082Sdim  flagword out_flags;
7001214082Sdim  flagword in_flags;
7002214082Sdim  bfd_boolean flags_compatible = TRUE;
7003214082Sdim  asection *sec;
7004214082Sdim
7005214082Sdim  /* Check if we have the same endianess.  */
7006214082Sdim  if (! _bfd_generic_verify_endian_match (ibfd, obfd))
7007214082Sdim    return FALSE;
7008214082Sdim
7009214082Sdim  if (   bfd_get_flavour (ibfd) != bfd_target_elf_flavour
7010214082Sdim      || bfd_get_flavour (obfd) != bfd_target_elf_flavour)
7011214082Sdim    return TRUE;
7012214082Sdim
7013214082Sdim  if (!elf32_arm_merge_eabi_attributes (ibfd, obfd))
7014214082Sdim    return FALSE;
7015214082Sdim
7016214082Sdim  /* The input BFD must have had its flags initialised.  */
7017214082Sdim  /* The following seems bogus to me -- The flags are initialized in
7018214082Sdim     the assembler but I don't think an elf_flags_init field is
7019214082Sdim     written into the object.  */
7020214082Sdim  /* BFD_ASSERT (elf_flags_init (ibfd)); */
7021214082Sdim
7022214082Sdim  in_flags  = elf_elfheader (ibfd)->e_flags;
7023214082Sdim  out_flags = elf_elfheader (obfd)->e_flags;
7024214082Sdim
7025214082Sdim  if (!elf_flags_init (obfd))
7026214082Sdim    {
7027214082Sdim      /* If the input is the default architecture and had the default
7028214082Sdim	 flags then do not bother setting the flags for the output
7029214082Sdim	 architecture, instead allow future merges to do this.  If no
7030214082Sdim	 future merges ever set these flags then they will retain their
7031214082Sdim         uninitialised values, which surprise surprise, correspond
7032214082Sdim         to the default values.  */
7033214082Sdim      if (bfd_get_arch_info (ibfd)->the_default
7034214082Sdim	  && elf_elfheader (ibfd)->e_flags == 0)
7035214082Sdim	return TRUE;
7036214082Sdim
7037214082Sdim      elf_flags_init (obfd) = TRUE;
7038214082Sdim      elf_elfheader (obfd)->e_flags = in_flags;
7039214082Sdim
7040214082Sdim      if (bfd_get_arch (obfd) == bfd_get_arch (ibfd)
7041214082Sdim	  && bfd_get_arch_info (obfd)->the_default)
7042214082Sdim	return bfd_set_arch_mach (obfd, bfd_get_arch (ibfd), bfd_get_mach (ibfd));
7043214082Sdim
7044214082Sdim      return TRUE;
7045214082Sdim    }
7046214082Sdim
7047214082Sdim  /* Determine what should happen if the input ARM architecture
7048214082Sdim     does not match the output ARM architecture.  */
7049214082Sdim  if (! bfd_arm_merge_machines (ibfd, obfd))
7050214082Sdim    return FALSE;
7051214082Sdim
7052214082Sdim  /* Identical flags must be compatible.  */
7053214082Sdim  if (in_flags == out_flags)
7054214082Sdim    return TRUE;
7055214082Sdim
7056214082Sdim  /* Check to see if the input BFD actually contains any sections.  If
7057214082Sdim     not, its flags may not have been initialised either, but it
7058214082Sdim     cannot actually cause any incompatiblity.  Do not short-circuit
7059214082Sdim     dynamic objects; their section list may be emptied by
7060214082Sdim    elf_link_add_object_symbols.
7061214082Sdim
7062214082Sdim    Also check to see if there are no code sections in the input.
7063214082Sdim    In this case there is no need to check for code specific flags.
7064214082Sdim    XXX - do we need to worry about floating-point format compatability
7065214082Sdim    in data sections ?  */
7066214082Sdim  if (!(ibfd->flags & DYNAMIC))
7067214082Sdim    {
7068214082Sdim      bfd_boolean null_input_bfd = TRUE;
7069214082Sdim      bfd_boolean only_data_sections = TRUE;
7070214082Sdim
7071214082Sdim      for (sec = ibfd->sections; sec != NULL; sec = sec->next)
7072214082Sdim	{
7073214082Sdim	  /* Ignore synthetic glue sections.  */
7074214082Sdim	  if (strcmp (sec->name, ".glue_7")
7075214082Sdim	      && strcmp (sec->name, ".glue_7t"))
7076214082Sdim	    {
7077214082Sdim	      if ((bfd_get_section_flags (ibfd, sec)
7078214082Sdim		   & (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
7079214082Sdim		  == (SEC_LOAD | SEC_CODE | SEC_HAS_CONTENTS))
7080214082Sdim	    	only_data_sections = FALSE;
7081214082Sdim
7082214082Sdim	      null_input_bfd = FALSE;
7083214082Sdim	      break;
7084214082Sdim	    }
7085214082Sdim	}
7086214082Sdim
7087214082Sdim      if (null_input_bfd || only_data_sections)
7088214082Sdim	return TRUE;
7089214082Sdim    }
7090214082Sdim
7091214082Sdim  /* Complain about various flag mismatches.  */
7092214082Sdim  if (!elf32_arm_versions_compatible (EF_ARM_EABI_VERSION (in_flags),
7093214082Sdim				      EF_ARM_EABI_VERSION (out_flags)))
7094214082Sdim    {
7095214082Sdim      _bfd_error_handler
7096214082Sdim	(_("ERROR: Source object %B has EABI version %d, but target %B has EABI version %d"),
7097214082Sdim	 ibfd, obfd,
7098214082Sdim	 (in_flags & EF_ARM_EABIMASK) >> 24,
7099214082Sdim	 (out_flags & EF_ARM_EABIMASK) >> 24);
7100214082Sdim      return FALSE;
7101214082Sdim    }
7102214082Sdim
7103214082Sdim  /* Not sure what needs to be checked for EABI versions >= 1.  */
7104214082Sdim  /* VxWorks libraries do not use these flags.  */
7105214082Sdim  if (get_elf_backend_data (obfd) != &elf32_arm_vxworks_bed
7106214082Sdim      && get_elf_backend_data (ibfd) != &elf32_arm_vxworks_bed
7107214082Sdim      && EF_ARM_EABI_VERSION (in_flags) == EF_ARM_EABI_UNKNOWN)
7108214082Sdim    {
7109214082Sdim      if ((in_flags & EF_ARM_APCS_26) != (out_flags & EF_ARM_APCS_26))
7110214082Sdim	{
7111214082Sdim	  _bfd_error_handler
7112214082Sdim	    (_("ERROR: %B is compiled for APCS-%d, whereas target %B uses APCS-%d"),
7113214082Sdim	     ibfd, obfd,
7114214082Sdim	     in_flags & EF_ARM_APCS_26 ? 26 : 32,
7115214082Sdim	     out_flags & EF_ARM_APCS_26 ? 26 : 32);
7116214082Sdim	  flags_compatible = FALSE;
7117214082Sdim	}
7118214082Sdim
7119214082Sdim      if ((in_flags & EF_ARM_APCS_FLOAT) != (out_flags & EF_ARM_APCS_FLOAT))
7120214082Sdim	{
7121214082Sdim	  if (in_flags & EF_ARM_APCS_FLOAT)
7122214082Sdim	    _bfd_error_handler
7123214082Sdim	      (_("ERROR: %B passes floats in float registers, whereas %B passes them in integer registers"),
7124214082Sdim	       ibfd, obfd);
7125214082Sdim	  else
7126214082Sdim	    _bfd_error_handler
7127214082Sdim	      (_("ERROR: %B passes floats in integer registers, whereas %B passes them in float registers"),
7128214082Sdim	       ibfd, obfd);
7129214082Sdim
7130214082Sdim	  flags_compatible = FALSE;
7131214082Sdim	}
7132214082Sdim
7133214082Sdim      if ((in_flags & EF_ARM_VFP_FLOAT) != (out_flags & EF_ARM_VFP_FLOAT))
7134214082Sdim	{
7135214082Sdim	  if (in_flags & EF_ARM_VFP_FLOAT)
7136214082Sdim	    _bfd_error_handler
7137214082Sdim	      (_("ERROR: %B uses VFP instructions, whereas %B does not"),
7138214082Sdim	       ibfd, obfd);
7139214082Sdim	  else
7140214082Sdim	    _bfd_error_handler
7141214082Sdim	      (_("ERROR: %B uses FPA instructions, whereas %B does not"),
7142214082Sdim	       ibfd, obfd);
7143214082Sdim
7144214082Sdim	  flags_compatible = FALSE;
7145214082Sdim	}
7146214082Sdim
7147214082Sdim      if ((in_flags & EF_ARM_MAVERICK_FLOAT) != (out_flags & EF_ARM_MAVERICK_FLOAT))
7148214082Sdim	{
7149214082Sdim	  if (in_flags & EF_ARM_MAVERICK_FLOAT)
7150214082Sdim	    _bfd_error_handler
7151214082Sdim	      (_("ERROR: %B uses Maverick instructions, whereas %B does not"),
7152214082Sdim	       ibfd, obfd);
7153214082Sdim	  else
7154214082Sdim	    _bfd_error_handler
7155214082Sdim	      (_("ERROR: %B does not use Maverick instructions, whereas %B does"),
7156214082Sdim	       ibfd, obfd);
7157214082Sdim
7158214082Sdim	  flags_compatible = FALSE;
7159214082Sdim	}
7160214082Sdim
7161214082Sdim#ifdef EF_ARM_SOFT_FLOAT
7162214082Sdim      if ((in_flags & EF_ARM_SOFT_FLOAT) != (out_flags & EF_ARM_SOFT_FLOAT))
7163214082Sdim	{
7164214082Sdim	  /* We can allow interworking between code that is VFP format
7165214082Sdim	     layout, and uses either soft float or integer regs for
7166214082Sdim	     passing floating point arguments and results.  We already
7167214082Sdim	     know that the APCS_FLOAT flags match; similarly for VFP
7168214082Sdim	     flags.  */
7169214082Sdim	  if ((in_flags & EF_ARM_APCS_FLOAT) != 0
7170214082Sdim	      || (in_flags & EF_ARM_VFP_FLOAT) == 0)
7171214082Sdim	    {
7172214082Sdim	      if (in_flags & EF_ARM_SOFT_FLOAT)
7173214082Sdim		_bfd_error_handler
7174214082Sdim		  (_("ERROR: %B uses software FP, whereas %B uses hardware FP"),
7175214082Sdim		   ibfd, obfd);
7176214082Sdim	      else
7177214082Sdim		_bfd_error_handler
7178214082Sdim		  (_("ERROR: %B uses hardware FP, whereas %B uses software FP"),
7179214082Sdim		   ibfd, obfd);
7180214082Sdim
7181214082Sdim	      flags_compatible = FALSE;
7182214082Sdim	    }
7183214082Sdim	}
7184214082Sdim#endif
7185214082Sdim
7186214082Sdim      /* Interworking mismatch is only a warning.  */
7187214082Sdim      if ((in_flags & EF_ARM_INTERWORK) != (out_flags & EF_ARM_INTERWORK))
7188214082Sdim	{
7189214082Sdim	  if (in_flags & EF_ARM_INTERWORK)
7190214082Sdim	    {
7191214082Sdim	      _bfd_error_handler
7192214082Sdim		(_("Warning: %B supports interworking, whereas %B does not"),
7193214082Sdim		 ibfd, obfd);
7194214082Sdim	    }
7195214082Sdim	  else
7196214082Sdim	    {
7197214082Sdim	      _bfd_error_handler
7198214082Sdim		(_("Warning: %B does not support interworking, whereas %B does"),
7199214082Sdim		 ibfd, obfd);
7200214082Sdim	    }
7201214082Sdim	}
7202214082Sdim    }
7203214082Sdim
7204214082Sdim  return flags_compatible;
7205214082Sdim}
7206214082Sdim
7207214082Sdim/* Display the flags field.  */
7208214082Sdim
7209214082Sdimstatic bfd_boolean
7210214082Sdimelf32_arm_print_private_bfd_data (bfd *abfd, void * ptr)
7211214082Sdim{
7212214082Sdim  FILE * file = (FILE *) ptr;
7213214082Sdim  unsigned long flags;
7214214082Sdim
7215214082Sdim  BFD_ASSERT (abfd != NULL && ptr != NULL);
7216214082Sdim
7217214082Sdim  /* Print normal ELF private data.  */
7218214082Sdim  _bfd_elf_print_private_bfd_data (abfd, ptr);
7219214082Sdim
7220214082Sdim  flags = elf_elfheader (abfd)->e_flags;
7221214082Sdim  /* Ignore init flag - it may not be set, despite the flags field
7222214082Sdim     containing valid data.  */
7223214082Sdim
7224214082Sdim  /* xgettext:c-format */
7225214082Sdim  fprintf (file, _("private flags = %lx:"), elf_elfheader (abfd)->e_flags);
7226214082Sdim
7227214082Sdim  switch (EF_ARM_EABI_VERSION (flags))
7228214082Sdim    {
7229214082Sdim    case EF_ARM_EABI_UNKNOWN:
7230214082Sdim      /* The following flag bits are GNU extensions and not part of the
7231214082Sdim	 official ARM ELF extended ABI.  Hence they are only decoded if
7232214082Sdim	 the EABI version is not set.  */
7233214082Sdim      if (flags & EF_ARM_INTERWORK)
7234214082Sdim	fprintf (file, _(" [interworking enabled]"));
7235214082Sdim
7236214082Sdim      if (flags & EF_ARM_APCS_26)
7237214082Sdim	fprintf (file, " [APCS-26]");
7238214082Sdim      else
7239214082Sdim	fprintf (file, " [APCS-32]");
7240214082Sdim
7241214082Sdim      if (flags & EF_ARM_VFP_FLOAT)
7242214082Sdim	fprintf (file, _(" [VFP float format]"));
7243214082Sdim      else if (flags & EF_ARM_MAVERICK_FLOAT)
7244214082Sdim	fprintf (file, _(" [Maverick float format]"));
7245214082Sdim      else
7246214082Sdim	fprintf (file, _(" [FPA float format]"));
7247214082Sdim
7248214082Sdim      if (flags & EF_ARM_APCS_FLOAT)
7249214082Sdim	fprintf (file, _(" [floats passed in float registers]"));
7250214082Sdim
7251214082Sdim      if (flags & EF_ARM_PIC)
7252214082Sdim	fprintf (file, _(" [position independent]"));
7253214082Sdim
7254214082Sdim      if (flags & EF_ARM_NEW_ABI)
7255214082Sdim	fprintf (file, _(" [new ABI]"));
7256214082Sdim
7257214082Sdim      if (flags & EF_ARM_OLD_ABI)
7258214082Sdim	fprintf (file, _(" [old ABI]"));
7259214082Sdim
7260214082Sdim      if (flags & EF_ARM_SOFT_FLOAT)
7261214082Sdim	fprintf (file, _(" [software FP]"));
7262214082Sdim
7263214082Sdim      flags &= ~(EF_ARM_INTERWORK | EF_ARM_APCS_26 | EF_ARM_APCS_FLOAT
7264214082Sdim		 | EF_ARM_PIC | EF_ARM_NEW_ABI | EF_ARM_OLD_ABI
7265214082Sdim		 | EF_ARM_SOFT_FLOAT | EF_ARM_VFP_FLOAT
7266214082Sdim		 | EF_ARM_MAVERICK_FLOAT);
7267214082Sdim      break;
7268214082Sdim
7269214082Sdim    case EF_ARM_EABI_VER1:
7270214082Sdim      fprintf (file, _(" [Version1 EABI]"));
7271214082Sdim
7272214082Sdim      if (flags & EF_ARM_SYMSARESORTED)
7273214082Sdim	fprintf (file, _(" [sorted symbol table]"));
7274214082Sdim      else
7275214082Sdim	fprintf (file, _(" [unsorted symbol table]"));
7276214082Sdim
7277214082Sdim      flags &= ~ EF_ARM_SYMSARESORTED;
7278214082Sdim      break;
7279214082Sdim
7280214082Sdim    case EF_ARM_EABI_VER2:
7281214082Sdim      fprintf (file, _(" [Version2 EABI]"));
7282214082Sdim
7283214082Sdim      if (flags & EF_ARM_SYMSARESORTED)
7284214082Sdim	fprintf (file, _(" [sorted symbol table]"));
7285214082Sdim      else
7286214082Sdim	fprintf (file, _(" [unsorted symbol table]"));
7287214082Sdim
7288214082Sdim      if (flags & EF_ARM_DYNSYMSUSESEGIDX)
7289214082Sdim	fprintf (file, _(" [dynamic symbols use segment index]"));
7290214082Sdim
7291214082Sdim      if (flags & EF_ARM_MAPSYMSFIRST)
7292214082Sdim	fprintf (file, _(" [mapping symbols precede others]"));
7293214082Sdim
7294214082Sdim      flags &= ~(EF_ARM_SYMSARESORTED | EF_ARM_DYNSYMSUSESEGIDX
7295214082Sdim		 | EF_ARM_MAPSYMSFIRST);
7296214082Sdim      break;
7297214082Sdim
7298214082Sdim    case EF_ARM_EABI_VER3:
7299214082Sdim      fprintf (file, _(" [Version3 EABI]"));
7300214082Sdim      break;
7301214082Sdim
7302214082Sdim    case EF_ARM_EABI_VER4:
7303214082Sdim      fprintf (file, _(" [Version4 EABI]"));
7304214082Sdim      goto eabi;
7305214082Sdim
7306214082Sdim    case EF_ARM_EABI_VER5:
7307214082Sdim      fprintf (file, _(" [Version5 EABI]"));
7308214082Sdim    eabi:
7309214082Sdim      if (flags & EF_ARM_BE8)
7310214082Sdim	fprintf (file, _(" [BE8]"));
7311214082Sdim
7312214082Sdim      if (flags & EF_ARM_LE8)
7313214082Sdim	fprintf (file, _(" [LE8]"));
7314214082Sdim
7315214082Sdim      flags &= ~(EF_ARM_LE8 | EF_ARM_BE8);
7316214082Sdim      break;
7317214082Sdim
7318214082Sdim    default:
7319214082Sdim      fprintf (file, _(" <EABI version unrecognised>"));
7320214082Sdim      break;
7321214082Sdim    }
7322214082Sdim
7323214082Sdim  flags &= ~ EF_ARM_EABIMASK;
7324214082Sdim
7325214082Sdim  if (flags & EF_ARM_RELEXEC)
7326214082Sdim    fprintf (file, _(" [relocatable executable]"));
7327214082Sdim
7328214082Sdim  if (flags & EF_ARM_HASENTRY)
7329214082Sdim    fprintf (file, _(" [has entry point]"));
7330214082Sdim
7331214082Sdim  flags &= ~ (EF_ARM_RELEXEC | EF_ARM_HASENTRY);
7332214082Sdim
7333214082Sdim  if (flags)
7334214082Sdim    fprintf (file, _("<Unrecognised flag bits set>"));
7335214082Sdim
7336214082Sdim  fputc ('\n', file);
7337214082Sdim
7338214082Sdim  return TRUE;
7339214082Sdim}
7340214082Sdim
7341214082Sdimstatic int
7342214082Sdimelf32_arm_get_symbol_type (Elf_Internal_Sym * elf_sym, int type)
7343214082Sdim{
7344214082Sdim  switch (ELF_ST_TYPE (elf_sym->st_info))
7345214082Sdim    {
7346214082Sdim    case STT_ARM_TFUNC:
7347214082Sdim      return ELF_ST_TYPE (elf_sym->st_info);
7348214082Sdim
7349214082Sdim    case STT_ARM_16BIT:
7350214082Sdim      /* If the symbol is not an object, return the STT_ARM_16BIT flag.
7351214082Sdim	 This allows us to distinguish between data used by Thumb instructions
7352214082Sdim	 and non-data (which is probably code) inside Thumb regions of an
7353214082Sdim	 executable.  */
7354214082Sdim      if (type != STT_OBJECT && type != STT_TLS)
7355214082Sdim	return ELF_ST_TYPE (elf_sym->st_info);
7356214082Sdim      break;
7357214082Sdim
7358214082Sdim    default:
7359214082Sdim      break;
7360214082Sdim    }
7361214082Sdim
7362214082Sdim  return type;
7363214082Sdim}
7364214082Sdim
7365214082Sdimstatic asection *
7366214634Sdimelf32_arm_gc_mark_hook (asection *sec,
7367214634Sdim			struct bfd_link_info *info,
7368214634Sdim			Elf_Internal_Rela *rel,
7369214634Sdim			struct elf_link_hash_entry *h,
7370214634Sdim			Elf_Internal_Sym *sym)
7371214082Sdim{
7372214082Sdim  if (h != NULL)
7373214634Sdim    switch (ELF32_R_TYPE (rel->r_info))
7374214082Sdim      {
7375214082Sdim      case R_ARM_GNU_VTINHERIT:
7376214082Sdim      case R_ARM_GNU_VTENTRY:
7377214634Sdim	return NULL;
7378214634Sdim      }
7379214082Sdim
7380214634Sdim  return _bfd_elf_gc_mark_hook (sec, info, rel, h, sym);
7381214082Sdim}
7382214082Sdim
7383214082Sdim/* Update the got entry reference counts for the section being removed.  */
7384214082Sdim
7385214082Sdimstatic bfd_boolean
7386214082Sdimelf32_arm_gc_sweep_hook (bfd *                     abfd,
7387214082Sdim			 struct bfd_link_info *    info,
7388214082Sdim			 asection *                sec,
7389214082Sdim			 const Elf_Internal_Rela * relocs)
7390214082Sdim{
7391214082Sdim  Elf_Internal_Shdr *symtab_hdr;
7392214082Sdim  struct elf_link_hash_entry **sym_hashes;
7393214082Sdim  bfd_signed_vma *local_got_refcounts;
7394214082Sdim  const Elf_Internal_Rela *rel, *relend;
7395214082Sdim  struct elf32_arm_link_hash_table * globals;
7396214082Sdim
7397214082Sdim  globals = elf32_arm_hash_table (info);
7398214082Sdim
7399214082Sdim  elf_section_data (sec)->local_dynrel = NULL;
7400214082Sdim
7401214082Sdim  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
7402214082Sdim  sym_hashes = elf_sym_hashes (abfd);
7403214082Sdim  local_got_refcounts = elf_local_got_refcounts (abfd);
7404214082Sdim
7405214082Sdim  relend = relocs + sec->reloc_count;
7406214082Sdim  for (rel = relocs; rel < relend; rel++)
7407214082Sdim    {
7408214082Sdim      unsigned long r_symndx;
7409214082Sdim      struct elf_link_hash_entry *h = NULL;
7410214082Sdim      int r_type;
7411214082Sdim
7412214082Sdim      r_symndx = ELF32_R_SYM (rel->r_info);
7413214082Sdim      if (r_symndx >= symtab_hdr->sh_info)
7414214082Sdim	{
7415214082Sdim	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
7416214082Sdim	  while (h->root.type == bfd_link_hash_indirect
7417214082Sdim		 || h->root.type == bfd_link_hash_warning)
7418214082Sdim	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
7419214082Sdim	}
7420214082Sdim
7421214082Sdim      r_type = ELF32_R_TYPE (rel->r_info);
7422214082Sdim      r_type = arm_real_reloc_type (globals, r_type);
7423214082Sdim      switch (r_type)
7424214082Sdim	{
7425214082Sdim	case R_ARM_GOT32:
7426214082Sdim	case R_ARM_GOT_PREL:
7427214082Sdim	case R_ARM_TLS_GD32:
7428214082Sdim	case R_ARM_TLS_IE32:
7429214082Sdim	  if (h != NULL)
7430214082Sdim	    {
7431214082Sdim	      if (h->got.refcount > 0)
7432214082Sdim		h->got.refcount -= 1;
7433214082Sdim	    }
7434214082Sdim	  else if (local_got_refcounts != NULL)
7435214082Sdim	    {
7436214082Sdim	      if (local_got_refcounts[r_symndx] > 0)
7437214082Sdim		local_got_refcounts[r_symndx] -= 1;
7438214082Sdim	    }
7439214082Sdim	  break;
7440214082Sdim
7441214082Sdim	case R_ARM_TLS_LDM32:
7442214082Sdim	  elf32_arm_hash_table (info)->tls_ldm_got.refcount -= 1;
7443214082Sdim	  break;
7444214082Sdim
7445214082Sdim	case R_ARM_ABS32:
7446214634Sdim	case R_ARM_ABS32_NOI:
7447214082Sdim	case R_ARM_REL32:
7448214634Sdim	case R_ARM_REL32_NOI:
7449214082Sdim	case R_ARM_PC24:
7450214082Sdim	case R_ARM_PLT32:
7451214082Sdim	case R_ARM_CALL:
7452214082Sdim	case R_ARM_JUMP24:
7453214082Sdim	case R_ARM_PREL31:
7454214082Sdim	case R_ARM_THM_CALL:
7455214634Sdim	case R_ARM_MOVW_ABS_NC:
7456214634Sdim	case R_ARM_MOVT_ABS:
7457214634Sdim	case R_ARM_MOVW_PREL_NC:
7458214634Sdim	case R_ARM_MOVT_PREL:
7459214634Sdim	case R_ARM_THM_MOVW_ABS_NC:
7460214634Sdim	case R_ARM_THM_MOVT_ABS:
7461214634Sdim	case R_ARM_THM_MOVW_PREL_NC:
7462214634Sdim	case R_ARM_THM_MOVT_PREL:
7463214082Sdim	  /* Should the interworking branches be here also?  */
7464214082Sdim
7465214082Sdim	  if (h != NULL)
7466214082Sdim	    {
7467214082Sdim	      struct elf32_arm_link_hash_entry *eh;
7468214082Sdim	      struct elf32_arm_relocs_copied **pp;
7469214082Sdim	      struct elf32_arm_relocs_copied *p;
7470214082Sdim
7471214082Sdim	      eh = (struct elf32_arm_link_hash_entry *) h;
7472214082Sdim
7473214082Sdim	      if (h->plt.refcount > 0)
7474214082Sdim		{
7475214082Sdim		  h->plt.refcount -= 1;
7476214082Sdim		  if (ELF32_R_TYPE (rel->r_info) == R_ARM_THM_CALL)
7477214082Sdim		    eh->plt_thumb_refcount--;
7478214082Sdim		}
7479214082Sdim
7480214082Sdim	      if (r_type == R_ARM_ABS32
7481214634Sdim		  || r_type == R_ARM_REL32
7482214634Sdim                  || r_type == R_ARM_ABS32_NOI
7483214634Sdim                  || r_type == R_ARM_REL32_NOI)
7484214082Sdim		{
7485214082Sdim		  for (pp = &eh->relocs_copied; (p = *pp) != NULL;
7486214082Sdim		       pp = &p->next)
7487214082Sdim		  if (p->section == sec)
7488214082Sdim		    {
7489214082Sdim		      p->count -= 1;
7490214634Sdim		      if (ELF32_R_TYPE (rel->r_info) == R_ARM_REL32
7491214634Sdim                          || ELF32_R_TYPE (rel->r_info) == R_ARM_REL32_NOI)
7492214082Sdim			p->pc_count -= 1;
7493214082Sdim		      if (p->count == 0)
7494214082Sdim			*pp = p->next;
7495214082Sdim		      break;
7496214082Sdim		    }
7497214082Sdim		}
7498214082Sdim	    }
7499214082Sdim	  break;
7500214082Sdim
7501214082Sdim	default:
7502214082Sdim	  break;
7503214082Sdim	}
7504214082Sdim    }
7505214082Sdim
7506214082Sdim  return TRUE;
7507214082Sdim}
7508214082Sdim
7509214082Sdim/* Look through the relocs for a section during the first phase.  */
7510214082Sdim
7511214082Sdimstatic bfd_boolean
7512214082Sdimelf32_arm_check_relocs (bfd *abfd, struct bfd_link_info *info,
7513214082Sdim			asection *sec, const Elf_Internal_Rela *relocs)
7514214082Sdim{
7515214082Sdim  Elf_Internal_Shdr *symtab_hdr;
7516214082Sdim  struct elf_link_hash_entry **sym_hashes;
7517214082Sdim  struct elf_link_hash_entry **sym_hashes_end;
7518214082Sdim  const Elf_Internal_Rela *rel;
7519214082Sdim  const Elf_Internal_Rela *rel_end;
7520214082Sdim  bfd *dynobj;
7521214082Sdim  asection *sreloc;
7522214082Sdim  bfd_vma *local_got_offsets;
7523214082Sdim  struct elf32_arm_link_hash_table *htab;
7524214082Sdim
7525214082Sdim  if (info->relocatable)
7526214082Sdim    return TRUE;
7527214082Sdim
7528214082Sdim  htab = elf32_arm_hash_table (info);
7529214082Sdim  sreloc = NULL;
7530214082Sdim
7531214082Sdim  /* Create dynamic sections for relocatable executables so that we can
7532214082Sdim     copy relocations.  */
7533214082Sdim  if (htab->root.is_relocatable_executable
7534214082Sdim      && ! htab->root.dynamic_sections_created)
7535214082Sdim    {
7536214082Sdim      if (! _bfd_elf_link_create_dynamic_sections (abfd, info))
7537214082Sdim	return FALSE;
7538214082Sdim    }
7539214082Sdim
7540214082Sdim  dynobj = elf_hash_table (info)->dynobj;
7541214082Sdim  local_got_offsets = elf_local_got_offsets (abfd);
7542214082Sdim
7543214082Sdim  symtab_hdr = &elf_tdata (abfd)->symtab_hdr;
7544214082Sdim  sym_hashes = elf_sym_hashes (abfd);
7545214082Sdim  sym_hashes_end = sym_hashes
7546214082Sdim    + symtab_hdr->sh_size / sizeof (Elf32_External_Sym);
7547214082Sdim
7548214082Sdim  if (!elf_bad_symtab (abfd))
7549214082Sdim    sym_hashes_end -= symtab_hdr->sh_info;
7550214082Sdim
7551214082Sdim  rel_end = relocs + sec->reloc_count;
7552214082Sdim  for (rel = relocs; rel < rel_end; rel++)
7553214082Sdim    {
7554214082Sdim      struct elf_link_hash_entry *h;
7555214082Sdim      struct elf32_arm_link_hash_entry *eh;
7556214082Sdim      unsigned long r_symndx;
7557214082Sdim      int r_type;
7558214082Sdim
7559214082Sdim      r_symndx = ELF32_R_SYM (rel->r_info);
7560214082Sdim      r_type = ELF32_R_TYPE (rel->r_info);
7561214082Sdim      r_type = arm_real_reloc_type (htab, r_type);
7562214082Sdim
7563214082Sdim      if (r_symndx >= NUM_SHDR_ENTRIES (symtab_hdr))
7564214082Sdim	{
7565214082Sdim	  (*_bfd_error_handler) (_("%B: bad symbol index: %d"), abfd,
7566214082Sdim				 r_symndx);
7567214082Sdim	  return FALSE;
7568214082Sdim	}
7569214082Sdim
7570214082Sdim      if (r_symndx < symtab_hdr->sh_info)
7571214082Sdim        h = NULL;
7572214082Sdim      else
7573214082Sdim	{
7574214082Sdim	  h = sym_hashes[r_symndx - symtab_hdr->sh_info];
7575214082Sdim	  while (h->root.type == bfd_link_hash_indirect
7576214082Sdim		 || h->root.type == bfd_link_hash_warning)
7577214082Sdim	    h = (struct elf_link_hash_entry *) h->root.u.i.link;
7578214082Sdim	}
7579214082Sdim
7580214082Sdim      eh = (struct elf32_arm_link_hash_entry *) h;
7581214082Sdim
7582214082Sdim      switch (r_type)
7583214082Sdim        {
7584214082Sdim	  case R_ARM_GOT32:
7585214082Sdim	  case R_ARM_GOT_PREL:
7586214082Sdim	  case R_ARM_TLS_GD32:
7587214082Sdim	  case R_ARM_TLS_IE32:
7588214082Sdim	    /* This symbol requires a global offset table entry.  */
7589214082Sdim	    {
7590214082Sdim	      int tls_type, old_tls_type;
7591214082Sdim
7592214082Sdim	      switch (r_type)
7593214082Sdim		{
7594214082Sdim		case R_ARM_TLS_GD32: tls_type = GOT_TLS_GD; break;
7595214082Sdim		case R_ARM_TLS_IE32: tls_type = GOT_TLS_IE; break;
7596214082Sdim		default: tls_type = GOT_NORMAL; break;
7597214082Sdim		}
7598214082Sdim
7599214082Sdim	      if (h != NULL)
7600214082Sdim		{
7601214082Sdim		  h->got.refcount++;
7602214082Sdim		  old_tls_type = elf32_arm_hash_entry (h)->tls_type;
7603214082Sdim		}
7604214082Sdim	      else
7605214082Sdim		{
7606214082Sdim		  bfd_signed_vma *local_got_refcounts;
7607214082Sdim
7608214082Sdim		  /* This is a global offset table entry for a local symbol.  */
7609214082Sdim		  local_got_refcounts = elf_local_got_refcounts (abfd);
7610214082Sdim		  if (local_got_refcounts == NULL)
7611214082Sdim		    {
7612214082Sdim		      bfd_size_type size;
7613214082Sdim
7614214082Sdim		      size = symtab_hdr->sh_info;
7615214082Sdim		      size *= (sizeof (bfd_signed_vma) + sizeof(char));
7616214082Sdim		      local_got_refcounts = bfd_zalloc (abfd, size);
7617214082Sdim		      if (local_got_refcounts == NULL)
7618214082Sdim			return FALSE;
7619214082Sdim		      elf_local_got_refcounts (abfd) = local_got_refcounts;
7620214082Sdim		      elf32_arm_local_got_tls_type (abfd)
7621214082Sdim			= (char *) (local_got_refcounts + symtab_hdr->sh_info);
7622214082Sdim		    }
7623214082Sdim		  local_got_refcounts[r_symndx] += 1;
7624214082Sdim		  old_tls_type = elf32_arm_local_got_tls_type (abfd) [r_symndx];
7625214082Sdim		}
7626214082Sdim
7627214082Sdim	      /* We will already have issued an error message if there is a
7628214082Sdim		 TLS / non-TLS mismatch, based on the symbol type.  We don't
7629214082Sdim		 support any linker relaxations.  So just combine any TLS
7630214082Sdim		 types needed.  */
7631214082Sdim	      if (old_tls_type != GOT_UNKNOWN && old_tls_type != GOT_NORMAL
7632214082Sdim		  && tls_type != GOT_NORMAL)
7633214082Sdim		tls_type |= old_tls_type;
7634214082Sdim
7635214082Sdim	      if (old_tls_type != tls_type)
7636214082Sdim		{
7637214082Sdim		  if (h != NULL)
7638214082Sdim		    elf32_arm_hash_entry (h)->tls_type = tls_type;
7639214082Sdim		  else
7640214082Sdim		    elf32_arm_local_got_tls_type (abfd) [r_symndx] = tls_type;
7641214082Sdim		}
7642214082Sdim	    }
7643214082Sdim	    /* Fall through */
7644214082Sdim
7645214082Sdim	  case R_ARM_TLS_LDM32:
7646214082Sdim	    if (r_type == R_ARM_TLS_LDM32)
7647214082Sdim		htab->tls_ldm_got.refcount++;
7648214082Sdim	    /* Fall through */
7649214082Sdim
7650214082Sdim	  case R_ARM_GOTOFF32:
7651214082Sdim	  case R_ARM_GOTPC:
7652214082Sdim	    if (htab->sgot == NULL)
7653214082Sdim	      {
7654214082Sdim		if (htab->root.dynobj == NULL)
7655214082Sdim		  htab->root.dynobj = abfd;
7656214082Sdim		if (!create_got_section (htab->root.dynobj, info))
7657214082Sdim		  return FALSE;
7658214082Sdim	      }
7659214082Sdim	    break;
7660214082Sdim
7661214082Sdim	  case R_ARM_ABS12:
7662214082Sdim	    /* VxWorks uses dynamic R_ARM_ABS12 relocations for
7663214082Sdim	       ldr __GOTT_INDEX__ offsets.  */
7664214082Sdim	    if (!htab->vxworks_p)
7665214082Sdim	      break;
7666214082Sdim	    /* Fall through */
7667214082Sdim
7668214082Sdim	  case R_ARM_ABS32:
7669214634Sdim	  case R_ARM_ABS32_NOI:
7670214082Sdim	  case R_ARM_REL32:
7671214634Sdim	  case R_ARM_REL32_NOI:
7672214082Sdim	  case R_ARM_PC24:
7673214082Sdim	  case R_ARM_PLT32:
7674214082Sdim	  case R_ARM_CALL:
7675214082Sdim	  case R_ARM_JUMP24:
7676214082Sdim	  case R_ARM_PREL31:
7677214082Sdim	  case R_ARM_THM_CALL:
7678214634Sdim	  case R_ARM_MOVW_ABS_NC:
7679214634Sdim	  case R_ARM_MOVT_ABS:
7680214634Sdim	  case R_ARM_MOVW_PREL_NC:
7681214634Sdim	  case R_ARM_MOVT_PREL:
7682214634Sdim	  case R_ARM_THM_MOVW_ABS_NC:
7683214634Sdim	  case R_ARM_THM_MOVT_ABS:
7684214634Sdim	  case R_ARM_THM_MOVW_PREL_NC:
7685214634Sdim	  case R_ARM_THM_MOVT_PREL:
7686214082Sdim	    /* Should the interworking branches be listed here?  */
7687214082Sdim	    if (h != NULL)
7688214082Sdim	      {
7689214082Sdim		/* If this reloc is in a read-only section, we might
7690214082Sdim		   need a copy reloc.  We can't check reliably at this
7691214082Sdim		   stage whether the section is read-only, as input
7692214082Sdim		   sections have not yet been mapped to output sections.
7693214082Sdim		   Tentatively set the flag for now, and correct in
7694214082Sdim		   adjust_dynamic_symbol.  */
7695214082Sdim		if (!info->shared)
7696214082Sdim		  h->non_got_ref = 1;
7697214082Sdim
7698214082Sdim		/* We may need a .plt entry if the function this reloc
7699214082Sdim		   refers to is in a different object.  We can't tell for
7700214082Sdim		   sure yet, because something later might force the
7701214082Sdim		   symbol local.  */
7702214634Sdim		if (r_type != R_ARM_ABS32
7703214634Sdim                    && r_type != R_ARM_REL32
7704214634Sdim                    && r_type != R_ARM_ABS32_NOI
7705214634Sdim                    && r_type != R_ARM_REL32_NOI
7706214634Sdim                    && r_type != R_ARM_ABS12)
7707214082Sdim		  h->needs_plt = 1;
7708214082Sdim
7709214082Sdim		/* If we create a PLT entry, this relocation will reference
7710214082Sdim		   it, even if it's an ABS32 relocation.  */
7711214082Sdim		h->plt.refcount += 1;
7712214082Sdim
7713214082Sdim		if (r_type == R_ARM_THM_CALL)
7714214082Sdim		  eh->plt_thumb_refcount += 1;
7715214082Sdim	      }
7716214082Sdim
7717214082Sdim	    /* If we are creating a shared library or relocatable executable,
7718214082Sdim	       and this is a reloc against a global symbol, or a non PC
7719214082Sdim	       relative reloc against a local symbol, then we need to copy
7720214082Sdim	       the reloc into the shared library.  However, if we are linking
7721214082Sdim	       with -Bsymbolic, we do not need to copy a reloc against a
7722214082Sdim               global symbol which is defined in an object we are
7723214082Sdim               including in the link (i.e., DEF_REGULAR is set).  At
7724214082Sdim               this point we have not seen all the input files, so it is
7725214082Sdim               possible that DEF_REGULAR is not set now but will be set
7726214082Sdim               later (it is never cleared).  We account for that
7727214082Sdim               possibility below by storing information in the
7728214082Sdim               relocs_copied field of the hash table entry.  */
7729214082Sdim	    if ((info->shared || htab->root.is_relocatable_executable)
7730214082Sdim		&& (sec->flags & SEC_ALLOC) != 0
7731214634Sdim		&& ((r_type == R_ARM_ABS32 || r_type == R_ARM_ABS32_NOI)
7732214082Sdim		    || (h != NULL && ! h->needs_plt
7733214082Sdim			&& (! info->symbolic || ! h->def_regular))))
7734214082Sdim	      {
7735214082Sdim		struct elf32_arm_relocs_copied *p, **head;
7736214082Sdim
7737214082Sdim	        /* When creating a shared object, we must copy these
7738214082Sdim                   reloc types into the output file.  We create a reloc
7739214082Sdim                   section in dynobj and make room for this reloc.  */
7740214082Sdim	        if (sreloc == NULL)
7741214082Sdim		  {
7742214082Sdim		    const char * name;
7743214082Sdim
7744214082Sdim		    name = (bfd_elf_string_from_elf_section
7745214082Sdim			    (abfd,
7746214082Sdim			     elf_elfheader (abfd)->e_shstrndx,
7747214082Sdim			     elf_section_data (sec)->rel_hdr.sh_name));
7748214082Sdim		    if (name == NULL)
7749214082Sdim		      return FALSE;
7750214082Sdim
7751214082Sdim		    BFD_ASSERT (reloc_section_p (htab, name, sec));
7752214082Sdim
7753214082Sdim		    sreloc = bfd_get_section_by_name (dynobj, name);
7754214082Sdim		    if (sreloc == NULL)
7755214082Sdim		      {
7756214082Sdim		        flagword flags;
7757214082Sdim
7758214082Sdim		        flags = (SEC_HAS_CONTENTS | SEC_READONLY
7759214082Sdim			         | SEC_IN_MEMORY | SEC_LINKER_CREATED);
7760214082Sdim		        if ((sec->flags & SEC_ALLOC) != 0
7761214082Sdim			    /* BPABI objects never have dynamic
7762214082Sdim			       relocations mapped.  */
7763214082Sdim			    && !htab->symbian_p)
7764214082Sdim			  flags |= SEC_ALLOC | SEC_LOAD;
7765214082Sdim		        sreloc = bfd_make_section_with_flags (dynobj,
7766214082Sdim							      name,
7767214082Sdim							      flags);
7768214082Sdim		        if (sreloc == NULL
7769214082Sdim			    || ! bfd_set_section_alignment (dynobj, sreloc, 2))
7770214082Sdim			  return FALSE;
7771214082Sdim		      }
7772214082Sdim
7773214082Sdim		    elf_section_data (sec)->sreloc = sreloc;
7774214082Sdim		  }
7775214082Sdim
7776214082Sdim		/* If this is a global symbol, we count the number of
7777214082Sdim		   relocations we need for this symbol.  */
7778214082Sdim		if (h != NULL)
7779214082Sdim		  {
7780214082Sdim		    head = &((struct elf32_arm_link_hash_entry *) h)->relocs_copied;
7781214082Sdim		  }
7782214082Sdim		else
7783214082Sdim		  {
7784214082Sdim		    /* Track dynamic relocs needed for local syms too.
7785214082Sdim		       We really need local syms available to do this
7786214082Sdim		       easily.  Oh well.  */
7787214082Sdim
7788214082Sdim		    asection *s;
7789214082Sdim		    void *vpp;
7790214082Sdim
7791214082Sdim		    s = bfd_section_from_r_symndx (abfd, &htab->sym_sec,
7792214082Sdim						   sec, r_symndx);
7793214082Sdim		    if (s == NULL)
7794214082Sdim		      return FALSE;
7795214082Sdim
7796214082Sdim		    vpp = &elf_section_data (s)->local_dynrel;
7797214082Sdim		    head = (struct elf32_arm_relocs_copied **) vpp;
7798214082Sdim		  }
7799214082Sdim
7800214082Sdim		p = *head;
7801214082Sdim		if (p == NULL || p->section != sec)
7802214082Sdim		  {
7803214082Sdim		    bfd_size_type amt = sizeof *p;
7804214082Sdim
7805214082Sdim		    p = bfd_alloc (htab->root.dynobj, amt);
7806214082Sdim		    if (p == NULL)
7807214082Sdim		      return FALSE;
7808214082Sdim		    p->next = *head;
7809214082Sdim		    *head = p;
7810214082Sdim		    p->section = sec;
7811214082Sdim		    p->count = 0;
7812214082Sdim		    p->pc_count = 0;
7813214082Sdim		  }
7814214082Sdim
7815214634Sdim		if (r_type == R_ARM_REL32 || r_type == R_ARM_REL32_NOI)
7816214082Sdim		  p->pc_count += 1;
7817214082Sdim		p->count += 1;
7818214082Sdim	      }
7819214082Sdim	    break;
7820214082Sdim
7821214082Sdim        /* This relocation describes the C++ object vtable hierarchy.
7822214082Sdim           Reconstruct it for later use during GC.  */
7823214082Sdim        case R_ARM_GNU_VTINHERIT:
7824214082Sdim          if (!bfd_elf_gc_record_vtinherit (abfd, sec, h, rel->r_offset))
7825214082Sdim            return FALSE;
7826214082Sdim          break;
7827214082Sdim
7828214082Sdim        /* This relocation describes which C++ vtable entries are actually
7829214082Sdim           used.  Record for later use during GC.  */
7830214082Sdim        case R_ARM_GNU_VTENTRY:
7831214082Sdim          if (!bfd_elf_gc_record_vtentry (abfd, sec, h, rel->r_offset))
7832214082Sdim            return FALSE;
7833214082Sdim          break;
7834214082Sdim        }
7835214082Sdim    }
7836214082Sdim
7837214082Sdim  return TRUE;
7838214082Sdim}
7839214082Sdim
7840214634Sdim/* Unwinding tables are not referenced directly.  This pass marks them as
7841214634Sdim   required if the corresponding code section is marked.  */
7842214634Sdim
7843214634Sdimstatic bfd_boolean
7844214634Sdimelf32_arm_gc_mark_extra_sections(struct bfd_link_info *info,
7845214634Sdim				 elf_gc_mark_hook_fn gc_mark_hook)
7846214634Sdim{
7847214634Sdim  bfd *sub;
7848214634Sdim  Elf_Internal_Shdr **elf_shdrp;
7849214634Sdim  bfd_boolean again;
7850214634Sdim
7851214634Sdim  /* Marking EH data may cause additional code sections to be marked,
7852214634Sdim     requiring multiple passes.  */
7853214634Sdim  again = TRUE;
7854214634Sdim  while (again)
7855214634Sdim    {
7856214634Sdim      again = FALSE;
7857214634Sdim      for (sub = info->input_bfds; sub != NULL; sub = sub->link_next)
7858214634Sdim	{
7859214634Sdim	  asection *o;
7860214634Sdim
7861214634Sdim	  if (bfd_get_flavour (sub) != bfd_target_elf_flavour)
7862214634Sdim	    continue;
7863214634Sdim
7864214634Sdim	  elf_shdrp = elf_elfsections (sub);
7865214634Sdim	  for (o = sub->sections; o != NULL; o = o->next)
7866214634Sdim	    {
7867214634Sdim	      Elf_Internal_Shdr *hdr;
7868214634Sdim	      hdr = &elf_section_data (o)->this_hdr;
7869214634Sdim	      if (hdr->sh_type == SHT_ARM_EXIDX && hdr->sh_link
7870214634Sdim		  && !o->gc_mark
7871214634Sdim		  && elf_shdrp[hdr->sh_link]->bfd_section->gc_mark)
7872214634Sdim		{
7873214634Sdim		  again = TRUE;
7874214634Sdim		  if (!_bfd_elf_gc_mark (info, o, gc_mark_hook))
7875214634Sdim		    return FALSE;
7876214634Sdim		}
7877214634Sdim	    }
7878214634Sdim	}
7879214634Sdim    }
7880214634Sdim
7881214634Sdim  return TRUE;
7882214634Sdim}
7883214634Sdim
7884214082Sdim/* Treat mapping symbols as special target symbols.  */
7885214082Sdim
7886214082Sdimstatic bfd_boolean
7887214082Sdimelf32_arm_is_target_special_symbol (bfd * abfd ATTRIBUTE_UNUSED, asymbol * sym)
7888214082Sdim{
7889214634Sdim  return bfd_is_arm_special_symbol_name (sym->name,
7890214634Sdim					 BFD_ARM_SPECIAL_SYM_TYPE_ANY);
7891214082Sdim}
7892214082Sdim
7893214082Sdim/* This is a copy of elf_find_function() from elf.c except that
7894214082Sdim   ARM mapping symbols are ignored when looking for function names
7895214082Sdim   and STT_ARM_TFUNC is considered to a function type.  */
7896214082Sdim
7897214082Sdimstatic bfd_boolean
7898214082Sdimarm_elf_find_function (bfd *         abfd ATTRIBUTE_UNUSED,
7899214082Sdim		       asection *    section,
7900214082Sdim		       asymbol **    symbols,
7901214082Sdim		       bfd_vma       offset,
7902214082Sdim		       const char ** filename_ptr,
7903214082Sdim		       const char ** functionname_ptr)
7904214082Sdim{
7905214082Sdim  const char * filename = NULL;
7906214082Sdim  asymbol * func = NULL;
7907214082Sdim  bfd_vma low_func = 0;
7908214082Sdim  asymbol ** p;
7909214082Sdim
7910214082Sdim  for (p = symbols; *p != NULL; p++)
7911214082Sdim    {
7912214082Sdim      elf_symbol_type *q;
7913214082Sdim
7914214082Sdim      q = (elf_symbol_type *) *p;
7915214082Sdim
7916214082Sdim      switch (ELF_ST_TYPE (q->internal_elf_sym.st_info))
7917214082Sdim	{
7918214082Sdim	default:
7919214082Sdim	  break;
7920214082Sdim	case STT_FILE:
7921214082Sdim	  filename = bfd_asymbol_name (&q->symbol);
7922214082Sdim	  break;
7923214082Sdim	case STT_FUNC:
7924214082Sdim	case STT_ARM_TFUNC:
7925214082Sdim	case STT_NOTYPE:
7926214634Sdim	  /* Skip mapping symbols.  */
7927214082Sdim	  if ((q->symbol.flags & BSF_LOCAL)
7928214634Sdim	      && bfd_is_arm_special_symbol_name (q->symbol.name,
7929214634Sdim		    BFD_ARM_SPECIAL_SYM_TYPE_ANY))
7930214082Sdim	    continue;
7931214082Sdim	  /* Fall through.  */
7932214082Sdim	  if (bfd_get_section (&q->symbol) == section
7933214082Sdim	      && q->symbol.value >= low_func
7934214082Sdim	      && q->symbol.value <= offset)
7935214082Sdim	    {
7936214082Sdim	      func = (asymbol *) q;
7937214082Sdim	      low_func = q->symbol.value;
7938214082Sdim	    }
7939214082Sdim	  break;
7940214082Sdim	}
7941214082Sdim    }
7942214082Sdim
7943214082Sdim  if (func == NULL)
7944214082Sdim    return FALSE;
7945214082Sdim
7946214082Sdim  if (filename_ptr)
7947214082Sdim    *filename_ptr = filename;
7948214082Sdim  if (functionname_ptr)
7949214082Sdim    *functionname_ptr = bfd_asymbol_name (func);
7950214082Sdim
7951214082Sdim  return TRUE;
7952214082Sdim}
7953214082Sdim
7954214082Sdim
7955214082Sdim/* Find the nearest line to a particular section and offset, for error
7956214082Sdim   reporting.   This code is a duplicate of the code in elf.c, except
7957214082Sdim   that it uses arm_elf_find_function.  */
7958214082Sdim
7959214082Sdimstatic bfd_boolean
7960214082Sdimelf32_arm_find_nearest_line (bfd *          abfd,
7961214082Sdim			     asection *     section,
7962214082Sdim			     asymbol **     symbols,
7963214082Sdim			     bfd_vma        offset,
7964214082Sdim			     const char **  filename_ptr,
7965214082Sdim			     const char **  functionname_ptr,
7966214082Sdim			     unsigned int * line_ptr)
7967214082Sdim{
7968214082Sdim  bfd_boolean found = FALSE;
7969214082Sdim
7970214082Sdim  /* We skip _bfd_dwarf1_find_nearest_line since no known ARM toolchain uses it.  */
7971214082Sdim
7972214082Sdim  if (_bfd_dwarf2_find_nearest_line (abfd, section, symbols, offset,
7973214082Sdim				     filename_ptr, functionname_ptr,
7974214082Sdim				     line_ptr, 0,
7975214082Sdim				     & elf_tdata (abfd)->dwarf2_find_line_info))
7976214082Sdim    {
7977214082Sdim      if (!*functionname_ptr)
7978214082Sdim	arm_elf_find_function (abfd, section, symbols, offset,
7979214082Sdim			       *filename_ptr ? NULL : filename_ptr,
7980214082Sdim			       functionname_ptr);
7981214082Sdim
7982214082Sdim      return TRUE;
7983214082Sdim    }
7984214082Sdim
7985214082Sdim  if (! _bfd_stab_section_find_nearest_line (abfd, symbols, section, offset,
7986214082Sdim					     & found, filename_ptr,
7987214082Sdim					     functionname_ptr, line_ptr,
7988214082Sdim					     & elf_tdata (abfd)->line_info))
7989214082Sdim    return FALSE;
7990214082Sdim
7991214082Sdim  if (found && (*functionname_ptr || *line_ptr))
7992214082Sdim    return TRUE;
7993214082Sdim
7994214082Sdim  if (symbols == NULL)
7995214082Sdim    return FALSE;
7996214082Sdim
7997214082Sdim  if (! arm_elf_find_function (abfd, section, symbols, offset,
7998214082Sdim			       filename_ptr, functionname_ptr))
7999214082Sdim    return FALSE;
8000214082Sdim
8001214082Sdim  *line_ptr = 0;
8002214082Sdim  return TRUE;
8003214082Sdim}
8004214082Sdim
8005214082Sdimstatic bfd_boolean
8006214082Sdimelf32_arm_find_inliner_info (bfd *          abfd,
8007214082Sdim			     const char **  filename_ptr,
8008214082Sdim			     const char **  functionname_ptr,
8009214082Sdim			     unsigned int * line_ptr)
8010214082Sdim{
8011214082Sdim  bfd_boolean found;
8012214082Sdim  found = _bfd_dwarf2_find_inliner_info (abfd, filename_ptr,
8013214082Sdim					 functionname_ptr, line_ptr,
8014214082Sdim					 & elf_tdata (abfd)->dwarf2_find_line_info);
8015214082Sdim  return found;
8016214082Sdim}
8017214082Sdim
8018214082Sdim/* Adjust a symbol defined by a dynamic object and referenced by a
8019214082Sdim   regular object.  The current definition is in some section of the
8020214082Sdim   dynamic object, but we're not including those sections.  We have to
8021214082Sdim   change the definition to something the rest of the link can
8022214082Sdim   understand.  */
8023214082Sdim
8024214082Sdimstatic bfd_boolean
8025214082Sdimelf32_arm_adjust_dynamic_symbol (struct bfd_link_info * info,
8026214082Sdim				 struct elf_link_hash_entry * h)
8027214082Sdim{
8028214082Sdim  bfd * dynobj;
8029214082Sdim  asection * s;
8030214082Sdim  struct elf32_arm_link_hash_entry * eh;
8031214082Sdim  struct elf32_arm_link_hash_table *globals;
8032214082Sdim
8033214082Sdim  globals = elf32_arm_hash_table (info);
8034214082Sdim  dynobj = elf_hash_table (info)->dynobj;
8035214082Sdim
8036214082Sdim  /* Make sure we know what is going on here.  */
8037214082Sdim  BFD_ASSERT (dynobj != NULL
8038214082Sdim	      && (h->needs_plt
8039214082Sdim		  || h->u.weakdef != NULL
8040214082Sdim		  || (h->def_dynamic
8041214082Sdim		      && h->ref_regular
8042214082Sdim		      && !h->def_regular)));
8043214082Sdim
8044214082Sdim  eh = (struct elf32_arm_link_hash_entry *) h;
8045214082Sdim
8046214082Sdim  /* If this is a function, put it in the procedure linkage table.  We
8047214082Sdim     will fill in the contents of the procedure linkage table later,
8048214082Sdim     when we know the address of the .got section.  */
8049214082Sdim  if (h->type == STT_FUNC || h->type == STT_ARM_TFUNC
8050214082Sdim      || h->needs_plt)
8051214082Sdim    {
8052214082Sdim      if (h->plt.refcount <= 0
8053214082Sdim	  || SYMBOL_CALLS_LOCAL (info, h)
8054214082Sdim	  || (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT
8055214082Sdim	      && h->root.type == bfd_link_hash_undefweak))
8056214082Sdim	{
8057214082Sdim	  /* This case can occur if we saw a PLT32 reloc in an input
8058214082Sdim	     file, but the symbol was never referred to by a dynamic
8059214082Sdim	     object, or if all references were garbage collected.  In
8060214082Sdim	     such a case, we don't actually need to build a procedure
8061214082Sdim	     linkage table, and we can just do a PC24 reloc instead.  */
8062214082Sdim	  h->plt.offset = (bfd_vma) -1;
8063214082Sdim	  eh->plt_thumb_refcount = 0;
8064214082Sdim	  h->needs_plt = 0;
8065214082Sdim	}
8066214082Sdim
8067214082Sdim      return TRUE;
8068214082Sdim    }
8069214082Sdim  else
8070214082Sdim    {
8071214082Sdim      /* It's possible that we incorrectly decided a .plt reloc was
8072214082Sdim	 needed for an R_ARM_PC24 or similar reloc to a non-function sym
8073214082Sdim	 in check_relocs.  We can't decide accurately between function
8074214082Sdim	 and non-function syms in check-relocs; Objects loaded later in
8075214082Sdim	 the link may change h->type.  So fix it now.  */
8076214082Sdim      h->plt.offset = (bfd_vma) -1;
8077214082Sdim      eh->plt_thumb_refcount = 0;
8078214082Sdim    }
8079214082Sdim
8080214082Sdim  /* If this is a weak symbol, and there is a real definition, the
8081214082Sdim     processor independent code will have arranged for us to see the
8082214082Sdim     real definition first, and we can just use the same value.  */
8083214082Sdim  if (h->u.weakdef != NULL)
8084214082Sdim    {
8085214082Sdim      BFD_ASSERT (h->u.weakdef->root.type == bfd_link_hash_defined
8086214082Sdim		  || h->u.weakdef->root.type == bfd_link_hash_defweak);
8087214082Sdim      h->root.u.def.section = h->u.weakdef->root.u.def.section;
8088214082Sdim      h->root.u.def.value = h->u.weakdef->root.u.def.value;
8089214082Sdim      return TRUE;
8090214082Sdim    }
8091214082Sdim
8092214082Sdim  /* If there are no non-GOT references, we do not need a copy
8093214082Sdim     relocation.  */
8094214082Sdim  if (!h->non_got_ref)
8095214082Sdim    return TRUE;
8096214082Sdim
8097214082Sdim  /* This is a reference to a symbol defined by a dynamic object which
8098214082Sdim     is not a function.  */
8099214082Sdim
8100214082Sdim  /* If we are creating a shared library, we must presume that the
8101214082Sdim     only references to the symbol are via the global offset table.
8102214082Sdim     For such cases we need not do anything here; the relocations will
8103214082Sdim     be handled correctly by relocate_section.  Relocatable executables
8104214082Sdim     can reference data in shared objects directly, so we don't need to
8105214082Sdim     do anything here.  */
8106214082Sdim  if (info->shared || globals->root.is_relocatable_executable)
8107214082Sdim    return TRUE;
8108214082Sdim
8109214082Sdim  if (h->size == 0)
8110214082Sdim    {
8111214082Sdim      (*_bfd_error_handler) (_("dynamic variable `%s' is zero size"),
8112214082Sdim			     h->root.root.string);
8113214082Sdim      return TRUE;
8114214082Sdim    }
8115214082Sdim
8116214082Sdim  /* We must allocate the symbol in our .dynbss section, which will
8117214082Sdim     become part of the .bss section of the executable.  There will be
8118214082Sdim     an entry for this symbol in the .dynsym section.  The dynamic
8119214082Sdim     object will contain position independent code, so all references
8120214082Sdim     from the dynamic object to this symbol will go through the global
8121214082Sdim     offset table.  The dynamic linker will use the .dynsym entry to
8122214082Sdim     determine the address it must put in the global offset table, so
8123214082Sdim     both the dynamic object and the regular object will refer to the
8124214082Sdim     same memory location for the variable.  */
8125214082Sdim  s = bfd_get_section_by_name (dynobj, ".dynbss");
8126214082Sdim  BFD_ASSERT (s != NULL);
8127214082Sdim
8128214082Sdim  /* We must generate a R_ARM_COPY reloc to tell the dynamic linker to
8129214082Sdim     copy the initial value out of the dynamic object and into the
8130214082Sdim     runtime process image.  We need to remember the offset into the
8131214082Sdim     .rel(a).bss section we are going to use.  */
8132214082Sdim  if ((h->root.u.def.section->flags & SEC_ALLOC) != 0)
8133214082Sdim    {
8134214082Sdim      asection *srel;
8135214082Sdim
8136214082Sdim      srel = bfd_get_section_by_name (dynobj, RELOC_SECTION (globals, ".bss"));
8137214082Sdim      BFD_ASSERT (srel != NULL);
8138214082Sdim      srel->size += RELOC_SIZE (globals);
8139214082Sdim      h->needs_copy = 1;
8140214082Sdim    }
8141214082Sdim
8142214634Sdim  return _bfd_elf_adjust_dynamic_copy (h, s);
8143214082Sdim}
8144214082Sdim
8145214082Sdim/* Allocate space in .plt, .got and associated reloc sections for
8146214082Sdim   dynamic relocs.  */
8147214082Sdim
8148214082Sdimstatic bfd_boolean
8149214082Sdimallocate_dynrelocs (struct elf_link_hash_entry *h, void * inf)
8150214082Sdim{
8151214082Sdim  struct bfd_link_info *info;
8152214082Sdim  struct elf32_arm_link_hash_table *htab;
8153214082Sdim  struct elf32_arm_link_hash_entry *eh;
8154214082Sdim  struct elf32_arm_relocs_copied *p;
8155214082Sdim
8156214082Sdim  eh = (struct elf32_arm_link_hash_entry *) h;
8157214082Sdim
8158214082Sdim  if (h->root.type == bfd_link_hash_indirect)
8159214082Sdim    return TRUE;
8160214082Sdim
8161214082Sdim  if (h->root.type == bfd_link_hash_warning)
8162214082Sdim    /* When warning symbols are created, they **replace** the "real"
8163214082Sdim       entry in the hash table, thus we never get to see the real
8164214082Sdim       symbol in a hash traversal.  So look at it now.  */
8165214082Sdim    h = (struct elf_link_hash_entry *) h->root.u.i.link;
8166214082Sdim
8167214082Sdim  info = (struct bfd_link_info *) inf;
8168214082Sdim  htab = elf32_arm_hash_table (info);
8169214082Sdim
8170214082Sdim  if (htab->root.dynamic_sections_created
8171214082Sdim      && h->plt.refcount > 0)
8172214082Sdim    {
8173214082Sdim      /* Make sure this symbol is output as a dynamic symbol.
8174214082Sdim	 Undefined weak syms won't yet be marked as dynamic.  */
8175214082Sdim      if (h->dynindx == -1
8176214082Sdim	  && !h->forced_local)
8177214082Sdim	{
8178214082Sdim	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
8179214082Sdim	    return FALSE;
8180214082Sdim	}
8181214082Sdim
8182214082Sdim      if (info->shared
8183214082Sdim	  || WILL_CALL_FINISH_DYNAMIC_SYMBOL (1, 0, h))
8184214082Sdim	{
8185214082Sdim	  asection *s = htab->splt;
8186214082Sdim
8187214082Sdim	  /* If this is the first .plt entry, make room for the special
8188214082Sdim	     first entry.  */
8189214082Sdim	  if (s->size == 0)
8190214082Sdim	    s->size += htab->plt_header_size;
8191214082Sdim
8192214082Sdim	  h->plt.offset = s->size;
8193214082Sdim
8194214082Sdim	  /* If we will insert a Thumb trampoline before this PLT, leave room
8195214082Sdim	     for it.  */
8196214082Sdim	  if (!htab->use_blx && eh->plt_thumb_refcount > 0)
8197214082Sdim	    {
8198214082Sdim	      h->plt.offset += PLT_THUMB_STUB_SIZE;
8199214082Sdim	      s->size += PLT_THUMB_STUB_SIZE;
8200214082Sdim	    }
8201214082Sdim
8202214082Sdim	  /* If this symbol is not defined in a regular file, and we are
8203214082Sdim	     not generating a shared library, then set the symbol to this
8204214082Sdim	     location in the .plt.  This is required to make function
8205214082Sdim	     pointers compare as equal between the normal executable and
8206214082Sdim	     the shared library.  */
8207214082Sdim	  if (! info->shared
8208214082Sdim	      && !h->def_regular)
8209214082Sdim	    {
8210214082Sdim	      h->root.u.def.section = s;
8211214082Sdim	      h->root.u.def.value = h->plt.offset;
8212214082Sdim
8213214082Sdim	      /* Make sure the function is not marked as Thumb, in case
8214214082Sdim		 it is the target of an ABS32 relocation, which will
8215214082Sdim		 point to the PLT entry.  */
8216214082Sdim	      if (ELF_ST_TYPE (h->type) == STT_ARM_TFUNC)
8217214082Sdim		h->type = ELF_ST_INFO (ELF_ST_BIND (h->type), STT_FUNC);
8218214082Sdim	    }
8219214082Sdim
8220214082Sdim	  /* Make room for this entry.  */
8221214082Sdim	  s->size += htab->plt_entry_size;
8222214082Sdim
8223214082Sdim	  if (!htab->symbian_p)
8224214082Sdim	    {
8225214082Sdim	      /* We also need to make an entry in the .got.plt section, which
8226214082Sdim		 will be placed in the .got section by the linker script.  */
8227214082Sdim	      eh->plt_got_offset = htab->sgotplt->size;
8228214082Sdim	      htab->sgotplt->size += 4;
8229214082Sdim	    }
8230214082Sdim
8231214082Sdim	  /* We also need to make an entry in the .rel(a).plt section.  */
8232214082Sdim	  htab->srelplt->size += RELOC_SIZE (htab);
8233214082Sdim
8234214082Sdim	  /* VxWorks executables have a second set of relocations for
8235214082Sdim	     each PLT entry.  They go in a separate relocation section,
8236214082Sdim	     which is processed by the kernel loader.  */
8237214082Sdim	  if (htab->vxworks_p && !info->shared)
8238214082Sdim	    {
8239214082Sdim	      /* There is a relocation for the initial PLT entry:
8240214082Sdim		 an R_ARM_32 relocation for _GLOBAL_OFFSET_TABLE_.  */
8241214082Sdim	      if (h->plt.offset == htab->plt_header_size)
8242214082Sdim		htab->srelplt2->size += RELOC_SIZE (htab);
8243214082Sdim
8244214082Sdim	      /* There are two extra relocations for each subsequent
8245214082Sdim		 PLT entry: an R_ARM_32 relocation for the GOT entry,
8246214082Sdim		 and an R_ARM_32 relocation for the PLT entry.  */
8247214082Sdim	      htab->srelplt2->size += RELOC_SIZE (htab) * 2;
8248214082Sdim	    }
8249214082Sdim	}
8250214082Sdim      else
8251214082Sdim	{
8252214082Sdim	  h->plt.offset = (bfd_vma) -1;
8253214082Sdim	  h->needs_plt = 0;
8254214082Sdim	}
8255214082Sdim    }
8256214082Sdim  else
8257214082Sdim    {
8258214082Sdim      h->plt.offset = (bfd_vma) -1;
8259214082Sdim      h->needs_plt = 0;
8260214082Sdim    }
8261214082Sdim
8262214082Sdim  if (h->got.refcount > 0)
8263214082Sdim    {
8264214082Sdim      asection *s;
8265214082Sdim      bfd_boolean dyn;
8266214082Sdim      int tls_type = elf32_arm_hash_entry (h)->tls_type;
8267214082Sdim      int indx;
8268214082Sdim
8269214082Sdim      /* Make sure this symbol is output as a dynamic symbol.
8270214082Sdim	 Undefined weak syms won't yet be marked as dynamic.  */
8271214082Sdim      if (h->dynindx == -1
8272214082Sdim	  && !h->forced_local)
8273214082Sdim	{
8274214082Sdim	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
8275214082Sdim	    return FALSE;
8276214082Sdim	}
8277214082Sdim
8278214082Sdim      if (!htab->symbian_p)
8279214082Sdim	{
8280214082Sdim	  s = htab->sgot;
8281214082Sdim	  h->got.offset = s->size;
8282214082Sdim
8283214082Sdim	  if (tls_type == GOT_UNKNOWN)
8284214082Sdim	    abort ();
8285214082Sdim
8286214082Sdim	  if (tls_type == GOT_NORMAL)
8287214082Sdim	    /* Non-TLS symbols need one GOT slot.  */
8288214082Sdim	    s->size += 4;
8289214082Sdim	  else
8290214082Sdim	    {
8291214082Sdim	      if (tls_type & GOT_TLS_GD)
8292214082Sdim		/* R_ARM_TLS_GD32 needs 2 consecutive GOT slots.  */
8293214082Sdim		s->size += 8;
8294214082Sdim	      if (tls_type & GOT_TLS_IE)
8295214082Sdim		/* R_ARM_TLS_IE32 needs one GOT slot.  */
8296214082Sdim		s->size += 4;
8297214082Sdim	    }
8298214082Sdim
8299214082Sdim	  dyn = htab->root.dynamic_sections_created;
8300214082Sdim
8301214082Sdim	  indx = 0;
8302214082Sdim	  if (WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, info->shared, h)
8303214082Sdim	      && (!info->shared
8304214082Sdim		  || !SYMBOL_REFERENCES_LOCAL (info, h)))
8305214082Sdim	    indx = h->dynindx;
8306214082Sdim
8307214082Sdim	  if (tls_type != GOT_NORMAL
8308214082Sdim	      && (info->shared || indx != 0)
8309214082Sdim	      && (ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
8310214082Sdim		  || h->root.type != bfd_link_hash_undefweak))
8311214082Sdim	    {
8312214082Sdim	      if (tls_type & GOT_TLS_IE)
8313214082Sdim		htab->srelgot->size += RELOC_SIZE (htab);
8314214082Sdim
8315214082Sdim	      if (tls_type & GOT_TLS_GD)
8316214082Sdim		htab->srelgot->size += RELOC_SIZE (htab);
8317214082Sdim
8318214082Sdim	      if ((tls_type & GOT_TLS_GD) && indx != 0)
8319214082Sdim		htab->srelgot->size += RELOC_SIZE (htab);
8320214082Sdim	    }
8321214082Sdim	  else if ((ELF_ST_VISIBILITY (h->other) == STV_DEFAULT
8322214082Sdim		    || h->root.type != bfd_link_hash_undefweak)
8323214082Sdim		   && (info->shared
8324214082Sdim	    	   || WILL_CALL_FINISH_DYNAMIC_SYMBOL (dyn, 0, h)))
8325214082Sdim	    htab->srelgot->size += RELOC_SIZE (htab);
8326214082Sdim	}
8327214082Sdim    }
8328214082Sdim  else
8329214082Sdim    h->got.offset = (bfd_vma) -1;
8330214082Sdim
8331214634Sdim  /* Allocate stubs for exported Thumb functions on v4t.  */
8332214634Sdim  if (!htab->use_blx && h->dynindx != -1
8333214634Sdim      && h->def_regular
8334214634Sdim      && ELF_ST_TYPE (h->type) == STT_ARM_TFUNC
8335214634Sdim      && ELF_ST_VISIBILITY (h->other) == STV_DEFAULT)
8336214634Sdim    {
8337214634Sdim      struct elf_link_hash_entry * th;
8338214634Sdim      struct bfd_link_hash_entry * bh;
8339214634Sdim      struct elf_link_hash_entry * myh;
8340214634Sdim      char name[1024];
8341214634Sdim      asection *s;
8342214634Sdim      bh = NULL;
8343214634Sdim      /* Create a new symbol to regist the real location of the function.  */
8344214634Sdim      s = h->root.u.def.section;
8345214634Sdim      sprintf(name, "__real_%s", h->root.root.string);
8346214634Sdim      _bfd_generic_link_add_one_symbol (info, s->owner,
8347214634Sdim					name, BSF_GLOBAL, s,
8348214634Sdim					h->root.u.def.value,
8349214634Sdim					NULL, TRUE, FALSE, &bh);
8350214634Sdim
8351214634Sdim      myh = (struct elf_link_hash_entry *) bh;
8352214634Sdim      myh->type = ELF_ST_INFO (STB_LOCAL, STT_ARM_TFUNC);
8353214634Sdim      myh->forced_local = 1;
8354214634Sdim      eh->export_glue = myh;
8355214634Sdim      th = record_arm_to_thumb_glue (info, h);
8356214634Sdim      /* Point the symbol at the stub.  */
8357214634Sdim      h->type = ELF_ST_INFO (ELF_ST_BIND (h->type), STT_FUNC);
8358214634Sdim      h->root.u.def.section = th->root.u.def.section;
8359214634Sdim      h->root.u.def.value = th->root.u.def.value & ~1;
8360214634Sdim    }
8361214634Sdim
8362214082Sdim  if (eh->relocs_copied == NULL)
8363214082Sdim    return TRUE;
8364214082Sdim
8365214082Sdim  /* In the shared -Bsymbolic case, discard space allocated for
8366214082Sdim     dynamic pc-relative relocs against symbols which turn out to be
8367214082Sdim     defined in regular objects.  For the normal shared case, discard
8368214082Sdim     space for pc-relative relocs that have become local due to symbol
8369214082Sdim     visibility changes.  */
8370214082Sdim
8371214082Sdim  if (info->shared || htab->root.is_relocatable_executable)
8372214082Sdim    {
8373214634Sdim      /* The only relocs that use pc_count are R_ARM_REL32 and
8374214634Sdim         R_ARM_REL32_NOI, which will appear on something like
8375214634Sdim         ".long foo - .".  We want calls to protected symbols to resolve
8376214634Sdim         directly to the function rather than going via the plt.  If people
8377214634Sdim         want function pointer comparisons to work as expected then they
8378214634Sdim         should avoid writing assembly like ".long foo - .".  */
8379214082Sdim      if (SYMBOL_CALLS_LOCAL (info, h))
8380214082Sdim	{
8381214082Sdim	  struct elf32_arm_relocs_copied **pp;
8382214082Sdim
8383214082Sdim	  for (pp = &eh->relocs_copied; (p = *pp) != NULL; )
8384214082Sdim	    {
8385214082Sdim	      p->count -= p->pc_count;
8386214082Sdim	      p->pc_count = 0;
8387214082Sdim	      if (p->count == 0)
8388214082Sdim		*pp = p->next;
8389214082Sdim	      else
8390214082Sdim		pp = &p->next;
8391214082Sdim	    }
8392214082Sdim	}
8393214082Sdim
8394214082Sdim      /* Also discard relocs on undefined weak syms with non-default
8395214082Sdim         visibility.  */
8396214082Sdim      if (eh->relocs_copied != NULL
8397214082Sdim	  && h->root.type == bfd_link_hash_undefweak)
8398214082Sdim	{
8399214082Sdim	  if (ELF_ST_VISIBILITY (h->other) != STV_DEFAULT)
8400214082Sdim	    eh->relocs_copied = NULL;
8401214082Sdim
8402214082Sdim	  /* Make sure undefined weak symbols are output as a dynamic
8403214082Sdim	     symbol in PIEs.  */
8404214082Sdim	  else if (h->dynindx == -1
8405214082Sdim		   && !h->forced_local)
8406214082Sdim	    {
8407214082Sdim	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
8408214082Sdim		return FALSE;
8409214082Sdim	    }
8410214082Sdim	}
8411214082Sdim
8412214082Sdim      else if (htab->root.is_relocatable_executable && h->dynindx == -1
8413214082Sdim	       && h->root.type == bfd_link_hash_new)
8414214082Sdim	{
8415214082Sdim	  /* Output absolute symbols so that we can create relocations
8416214082Sdim	     against them.  For normal symbols we output a relocation
8417214082Sdim	     against the section that contains them.  */
8418214082Sdim	  if (! bfd_elf_link_record_dynamic_symbol (info, h))
8419214082Sdim	    return FALSE;
8420214082Sdim	}
8421214082Sdim
8422214082Sdim    }
8423214082Sdim  else
8424214082Sdim    {
8425214082Sdim      /* For the non-shared case, discard space for relocs against
8426214082Sdim	 symbols which turn out to need copy relocs or are not
8427214082Sdim	 dynamic.  */
8428214082Sdim
8429214082Sdim      if (!h->non_got_ref
8430214082Sdim	  && ((h->def_dynamic
8431214082Sdim	       && !h->def_regular)
8432214082Sdim	      || (htab->root.dynamic_sections_created
8433214082Sdim		  && (h->root.type == bfd_link_hash_undefweak
8434214082Sdim		      || h->root.type == bfd_link_hash_undefined))))
8435214082Sdim	{
8436214082Sdim	  /* Make sure this symbol is output as a dynamic symbol.
8437214082Sdim	     Undefined weak syms won't yet be marked as dynamic.  */
8438214082Sdim	  if (h->dynindx == -1
8439214082Sdim	      && !h->forced_local)
8440214082Sdim	    {
8441214082Sdim	      if (! bfd_elf_link_record_dynamic_symbol (info, h))
8442214082Sdim		return FALSE;
8443214082Sdim	    }
8444214082Sdim
8445214082Sdim	  /* If that succeeded, we know we'll be keeping all the
8446214082Sdim	     relocs.  */
8447214082Sdim	  if (h->dynindx != -1)
8448214082Sdim	    goto keep;
8449214082Sdim	}
8450214082Sdim
8451214082Sdim      eh->relocs_copied = NULL;
8452214082Sdim
8453214082Sdim    keep: ;
8454214082Sdim    }
8455214082Sdim
8456214082Sdim  /* Finally, allocate space.  */
8457214082Sdim  for (p = eh->relocs_copied; p != NULL; p = p->next)
8458214082Sdim    {
8459214082Sdim      asection *sreloc = elf_section_data (p->section)->sreloc;
8460214082Sdim      sreloc->size += p->count * RELOC_SIZE (htab);
8461214082Sdim    }
8462214082Sdim
8463214082Sdim  return TRUE;
8464214082Sdim}
8465214082Sdim
8466214082Sdim/* Find any dynamic relocs that apply to read-only sections.  */
8467214082Sdim
8468214082Sdimstatic bfd_boolean
8469214082Sdimelf32_arm_readonly_dynrelocs (struct elf_link_hash_entry *h, PTR inf)
8470214082Sdim{
8471214082Sdim  struct elf32_arm_link_hash_entry *eh;
8472214082Sdim  struct elf32_arm_relocs_copied *p;
8473214082Sdim
8474214082Sdim  if (h->root.type == bfd_link_hash_warning)
8475214082Sdim    h = (struct elf_link_hash_entry *) h->root.u.i.link;
8476214082Sdim
8477214082Sdim  eh = (struct elf32_arm_link_hash_entry *) h;
8478214082Sdim  for (p = eh->relocs_copied; p != NULL; p = p->next)
8479214082Sdim    {
8480214082Sdim      asection *s = p->section;
8481214082Sdim
8482214082Sdim      if (s != NULL && (s->flags & SEC_READONLY) != 0)
8483214082Sdim	{
8484214082Sdim	  struct bfd_link_info *info = (struct bfd_link_info *) inf;
8485214082Sdim
8486214082Sdim	  info->flags |= DF_TEXTREL;
8487214082Sdim
8488214082Sdim	  /* Not an error, just cut short the traversal.  */
8489214082Sdim	  return FALSE;
8490214082Sdim	}
8491214082Sdim    }
8492214082Sdim  return TRUE;
8493214082Sdim}
8494214082Sdim
8495214634Sdimvoid
8496214634Sdimbfd_elf32_arm_set_byteswap_code (struct bfd_link_info *info,
8497214634Sdim				 int byteswap_code)
8498214634Sdim{
8499214634Sdim  struct elf32_arm_link_hash_table *globals;
8500214634Sdim
8501214634Sdim  globals = elf32_arm_hash_table (info);
8502214634Sdim  globals->byteswap_code = byteswap_code;
8503214634Sdim}
8504214634Sdim
8505214082Sdim/* Set the sizes of the dynamic sections.  */
8506214082Sdim
8507214082Sdimstatic bfd_boolean
8508214082Sdimelf32_arm_size_dynamic_sections (bfd * output_bfd ATTRIBUTE_UNUSED,
8509214082Sdim				 struct bfd_link_info * info)
8510214082Sdim{
8511214082Sdim  bfd * dynobj;
8512214082Sdim  asection * s;
8513214082Sdim  bfd_boolean plt;
8514214082Sdim  bfd_boolean relocs;
8515214082Sdim  bfd *ibfd;
8516214082Sdim  struct elf32_arm_link_hash_table *htab;
8517214082Sdim
8518214082Sdim  htab = elf32_arm_hash_table (info);
8519214082Sdim  dynobj = elf_hash_table (info)->dynobj;
8520214082Sdim  BFD_ASSERT (dynobj != NULL);
8521214082Sdim  check_use_blx (htab);
8522214082Sdim
8523214082Sdim  if (elf_hash_table (info)->dynamic_sections_created)
8524214082Sdim    {
8525214082Sdim      /* Set the contents of the .interp section to the interpreter.  */
8526214082Sdim      if (info->executable)
8527214082Sdim	{
8528214082Sdim	  s = bfd_get_section_by_name (dynobj, ".interp");
8529214082Sdim	  BFD_ASSERT (s != NULL);
8530214082Sdim	  s->size = sizeof ELF_DYNAMIC_INTERPRETER;
8531214082Sdim	  s->contents = (unsigned char *) ELF_DYNAMIC_INTERPRETER;
8532214082Sdim	}
8533214082Sdim    }
8534214082Sdim
8535214082Sdim  /* Set up .got offsets for local syms, and space for local dynamic
8536214082Sdim     relocs.  */
8537214082Sdim  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
8538214082Sdim    {
8539214082Sdim      bfd_signed_vma *local_got;
8540214082Sdim      bfd_signed_vma *end_local_got;
8541214082Sdim      char *local_tls_type;
8542214082Sdim      bfd_size_type locsymcount;
8543214082Sdim      Elf_Internal_Shdr *symtab_hdr;
8544214082Sdim      asection *srel;
8545214082Sdim
8546214082Sdim      if (bfd_get_flavour (ibfd) != bfd_target_elf_flavour)
8547214082Sdim	continue;
8548214082Sdim
8549214082Sdim      for (s = ibfd->sections; s != NULL; s = s->next)
8550214082Sdim	{
8551214082Sdim	  struct elf32_arm_relocs_copied *p;
8552214082Sdim
8553214082Sdim	  for (p = elf_section_data (s)->local_dynrel; p != NULL; p = p->next)
8554214082Sdim	    {
8555214082Sdim	      if (!bfd_is_abs_section (p->section)
8556214082Sdim		  && bfd_is_abs_section (p->section->output_section))
8557214082Sdim		{
8558214082Sdim		  /* Input section has been discarded, either because
8559214082Sdim		     it is a copy of a linkonce section or due to
8560214082Sdim		     linker script /DISCARD/, so we'll be discarding
8561214082Sdim		     the relocs too.  */
8562214082Sdim		}
8563214082Sdim	      else if (p->count != 0)
8564214082Sdim		{
8565214082Sdim		  srel = elf_section_data (p->section)->sreloc;
8566214082Sdim		  srel->size += p->count * RELOC_SIZE (htab);
8567214082Sdim		  if ((p->section->output_section->flags & SEC_READONLY) != 0)
8568214082Sdim		    info->flags |= DF_TEXTREL;
8569214082Sdim		}
8570214082Sdim	    }
8571214082Sdim	}
8572214082Sdim
8573214082Sdim      local_got = elf_local_got_refcounts (ibfd);
8574214082Sdim      if (!local_got)
8575214082Sdim	continue;
8576214082Sdim
8577214082Sdim      symtab_hdr = &elf_tdata (ibfd)->symtab_hdr;
8578214082Sdim      locsymcount = symtab_hdr->sh_info;
8579214082Sdim      end_local_got = local_got + locsymcount;
8580214082Sdim      local_tls_type = elf32_arm_local_got_tls_type (ibfd);
8581214082Sdim      s = htab->sgot;
8582214082Sdim      srel = htab->srelgot;
8583214082Sdim      for (; local_got < end_local_got; ++local_got, ++local_tls_type)
8584214082Sdim	{
8585214082Sdim	  if (*local_got > 0)
8586214082Sdim	    {
8587214082Sdim	      *local_got = s->size;
8588214082Sdim	      if (*local_tls_type & GOT_TLS_GD)
8589214082Sdim		/* TLS_GD relocs need an 8-byte structure in the GOT.  */
8590214082Sdim		s->size += 8;
8591214082Sdim	      if (*local_tls_type & GOT_TLS_IE)
8592214082Sdim		s->size += 4;
8593214082Sdim	      if (*local_tls_type == GOT_NORMAL)
8594214082Sdim		s->size += 4;
8595214082Sdim
8596214082Sdim	      if (info->shared || *local_tls_type == GOT_TLS_GD)
8597214082Sdim		srel->size += RELOC_SIZE (htab);
8598214082Sdim	    }
8599214082Sdim	  else
8600214082Sdim	    *local_got = (bfd_vma) -1;
8601214082Sdim	}
8602214082Sdim    }
8603214082Sdim
8604214082Sdim  if (htab->tls_ldm_got.refcount > 0)
8605214082Sdim    {
8606214082Sdim      /* Allocate two GOT entries and one dynamic relocation (if necessary)
8607214082Sdim	 for R_ARM_TLS_LDM32 relocations.  */
8608214082Sdim      htab->tls_ldm_got.offset = htab->sgot->size;
8609214082Sdim      htab->sgot->size += 8;
8610214082Sdim      if (info->shared)
8611214082Sdim	htab->srelgot->size += RELOC_SIZE (htab);
8612214082Sdim    }
8613214082Sdim  else
8614214082Sdim    htab->tls_ldm_got.offset = -1;
8615214082Sdim
8616214082Sdim  /* Allocate global sym .plt and .got entries, and space for global
8617214082Sdim     sym dynamic relocs.  */
8618214082Sdim  elf_link_hash_traverse (& htab->root, allocate_dynrelocs, info);
8619214082Sdim
8620214634Sdim  /* Here we rummage through the found bfds to collect glue information.  */
8621214634Sdim  for (ibfd = info->input_bfds; ibfd != NULL; ibfd = ibfd->link_next)
8622214634Sdim    {
8623214634Sdim      /* Initialise mapping tables for code/data.  */
8624214634Sdim      bfd_elf32_arm_init_maps (ibfd);
8625214634Sdim
8626214634Sdim      if (!bfd_elf32_arm_process_before_allocation (ibfd, info)
8627214634Sdim	  || !bfd_elf32_arm_vfp11_erratum_scan (ibfd, info))
8628214634Sdim        /* xgettext:c-format */
8629214634Sdim        _bfd_error_handler (_("Errors encountered processing file %s"),
8630214634Sdim			    ibfd->filename);
8631214634Sdim    }
8632214634Sdim
8633214082Sdim  /* The check_relocs and adjust_dynamic_symbol entry points have
8634214082Sdim     determined the sizes of the various dynamic sections.  Allocate
8635214082Sdim     memory for them.  */
8636214082Sdim  plt = FALSE;
8637214082Sdim  relocs = FALSE;
8638214082Sdim  for (s = dynobj->sections; s != NULL; s = s->next)
8639214082Sdim    {
8640214082Sdim      const char * name;
8641214082Sdim
8642214082Sdim      if ((s->flags & SEC_LINKER_CREATED) == 0)
8643214082Sdim	continue;
8644214082Sdim
8645214082Sdim      /* It's OK to base decisions on the section name, because none
8646214082Sdim	 of the dynobj section names depend upon the input files.  */
8647214082Sdim      name = bfd_get_section_name (dynobj, s);
8648214082Sdim
8649214082Sdim      if (strcmp (name, ".plt") == 0)
8650214082Sdim	{
8651214082Sdim	  /* Remember whether there is a PLT.  */
8652214082Sdim	  plt = s->size != 0;
8653214082Sdim	}
8654214634Sdim      else if (CONST_STRNEQ (name, ".rel"))
8655214082Sdim	{
8656214082Sdim	  if (s->size != 0)
8657214082Sdim	    {
8658214082Sdim	      /* Remember whether there are any reloc sections other
8659214082Sdim		 than .rel(a).plt and .rela.plt.unloaded.  */
8660214082Sdim	      if (s != htab->srelplt && s != htab->srelplt2)
8661214082Sdim		relocs = TRUE;
8662214082Sdim
8663214082Sdim	      /* We use the reloc_count field as a counter if we need
8664214082Sdim		 to copy relocs into the output file.  */
8665214082Sdim	      s->reloc_count = 0;
8666214082Sdim	    }
8667214082Sdim	}
8668214634Sdim      else if (! CONST_STRNEQ (name, ".got")
8669214082Sdim	       && strcmp (name, ".dynbss") != 0)
8670214082Sdim	{
8671214082Sdim	  /* It's not one of our sections, so don't allocate space.  */
8672214082Sdim	  continue;
8673214082Sdim	}
8674214082Sdim
8675214082Sdim      if (s->size == 0)
8676214082Sdim	{
8677214082Sdim	  /* If we don't need this section, strip it from the
8678214082Sdim	     output file.  This is mostly to handle .rel(a).bss and
8679214082Sdim	     .rel(a).plt.  We must create both sections in
8680214082Sdim	     create_dynamic_sections, because they must be created
8681214082Sdim	     before the linker maps input sections to output
8682214082Sdim	     sections.  The linker does that before
8683214082Sdim	     adjust_dynamic_symbol is called, and it is that
8684214082Sdim	     function which decides whether anything needs to go
8685214082Sdim	     into these sections.  */
8686214082Sdim	  s->flags |= SEC_EXCLUDE;
8687214082Sdim	  continue;
8688214082Sdim	}
8689214082Sdim
8690214082Sdim      if ((s->flags & SEC_HAS_CONTENTS) == 0)
8691214082Sdim	continue;
8692214082Sdim
8693214082Sdim      /* Allocate memory for the section contents.  */
8694214082Sdim      s->contents = (bfd_byte *) bfd_zalloc (dynobj, s->size);
8695214082Sdim      if (s->contents == NULL)
8696214082Sdim	return FALSE;
8697214082Sdim    }
8698214082Sdim
8699214082Sdim  if (elf_hash_table (info)->dynamic_sections_created)
8700214082Sdim    {
8701214082Sdim      /* Add some entries to the .dynamic section.  We fill in the
8702214082Sdim	 values later, in elf32_arm_finish_dynamic_sections, but we
8703214082Sdim	 must add the entries now so that we get the correct size for
8704214082Sdim	 the .dynamic section.  The DT_DEBUG entry is filled in by the
8705214082Sdim	 dynamic linker and used by the debugger.  */
8706214082Sdim#define add_dynamic_entry(TAG, VAL) \
8707214082Sdim  _bfd_elf_add_dynamic_entry (info, TAG, VAL)
8708214082Sdim
8709214082Sdim     if (info->executable)
8710214082Sdim	{
8711214082Sdim	  if (!add_dynamic_entry (DT_DEBUG, 0))
8712214082Sdim	    return FALSE;
8713214082Sdim	}
8714214082Sdim
8715214082Sdim      if (plt)
8716214082Sdim	{
8717214082Sdim	  if (   !add_dynamic_entry (DT_PLTGOT, 0)
8718214082Sdim	      || !add_dynamic_entry (DT_PLTRELSZ, 0)
8719214082Sdim	      || !add_dynamic_entry (DT_PLTREL,
8720214082Sdim				     htab->use_rel ? DT_REL : DT_RELA)
8721214082Sdim	      || !add_dynamic_entry (DT_JMPREL, 0))
8722214082Sdim	    return FALSE;
8723214082Sdim	}
8724214082Sdim
8725214082Sdim      if (relocs)
8726214082Sdim	{
8727214082Sdim	  if (htab->use_rel)
8728214082Sdim	    {
8729214082Sdim	      if (!add_dynamic_entry (DT_REL, 0)
8730214082Sdim		  || !add_dynamic_entry (DT_RELSZ, 0)
8731214082Sdim		  || !add_dynamic_entry (DT_RELENT, RELOC_SIZE (htab)))
8732214082Sdim		return FALSE;
8733214082Sdim	    }
8734214082Sdim	  else
8735214082Sdim	    {
8736214082Sdim	      if (!add_dynamic_entry (DT_RELA, 0)
8737214082Sdim		  || !add_dynamic_entry (DT_RELASZ, 0)
8738214082Sdim		  || !add_dynamic_entry (DT_RELAENT, RELOC_SIZE (htab)))
8739214082Sdim		return FALSE;
8740214082Sdim	    }
8741214082Sdim	}
8742214082Sdim
8743214082Sdim      /* If any dynamic relocs apply to a read-only section,
8744214082Sdim	 then we need a DT_TEXTREL entry.  */
8745214082Sdim      if ((info->flags & DF_TEXTREL) == 0)
8746214082Sdim	elf_link_hash_traverse (&htab->root, elf32_arm_readonly_dynrelocs,
8747214082Sdim				(PTR) info);
8748214082Sdim
8749214082Sdim      if ((info->flags & DF_TEXTREL) != 0)
8750214082Sdim	{
8751214082Sdim	  if (!add_dynamic_entry (DT_TEXTREL, 0))
8752214082Sdim	    return FALSE;
8753214082Sdim	}
8754214082Sdim    }
8755214082Sdim#undef add_dynamic_entry
8756214082Sdim
8757214082Sdim  return TRUE;
8758214082Sdim}
8759214082Sdim
8760214082Sdim/* Finish up dynamic symbol handling.  We set the contents of various
8761214082Sdim   dynamic sections here.  */
8762214082Sdim
8763214082Sdimstatic bfd_boolean
8764214082Sdimelf32_arm_finish_dynamic_symbol (bfd * output_bfd, struct bfd_link_info * info,
8765214082Sdim				 struct elf_link_hash_entry * h, Elf_Internal_Sym * sym)
8766214082Sdim{
8767214082Sdim  bfd * dynobj;
8768214082Sdim  struct elf32_arm_link_hash_table *htab;
8769214082Sdim  struct elf32_arm_link_hash_entry *eh;
8770214082Sdim
8771214082Sdim  dynobj = elf_hash_table (info)->dynobj;
8772214082Sdim  htab = elf32_arm_hash_table (info);
8773214082Sdim  eh = (struct elf32_arm_link_hash_entry *) h;
8774214082Sdim
8775214082Sdim  if (h->plt.offset != (bfd_vma) -1)
8776214082Sdim    {
8777214082Sdim      asection * splt;
8778214082Sdim      asection * srel;
8779214082Sdim      bfd_byte *loc;
8780214082Sdim      bfd_vma plt_index;
8781214082Sdim      Elf_Internal_Rela rel;
8782214082Sdim
8783214082Sdim      /* This symbol has an entry in the procedure linkage table.  Set
8784214082Sdim	 it up.  */
8785214082Sdim
8786214082Sdim      BFD_ASSERT (h->dynindx != -1);
8787214082Sdim
8788214082Sdim      splt = bfd_get_section_by_name (dynobj, ".plt");
8789214082Sdim      srel = bfd_get_section_by_name (dynobj, RELOC_SECTION (htab, ".plt"));
8790214082Sdim      BFD_ASSERT (splt != NULL && srel != NULL);
8791214082Sdim
8792214082Sdim      /* Fill in the entry in the procedure linkage table.  */
8793214082Sdim      if (htab->symbian_p)
8794214082Sdim	{
8795214634Sdim	  put_arm_insn (htab, output_bfd,
8796214634Sdim		      elf32_arm_symbian_plt_entry[0],
8797214634Sdim		      splt->contents + h->plt.offset);
8798214634Sdim	  bfd_put_32 (output_bfd,
8799214634Sdim		      elf32_arm_symbian_plt_entry[1],
8800214634Sdim		      splt->contents + h->plt.offset + 4);
8801214082Sdim
8802214082Sdim	  /* Fill in the entry in the .rel.plt section.  */
8803214082Sdim	  rel.r_offset = (splt->output_section->vma
8804214082Sdim			  + splt->output_offset
8805214634Sdim			  + h->plt.offset + 4);
8806214082Sdim	  rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT);
8807214082Sdim
8808214082Sdim	  /* Get the index in the procedure linkage table which
8809214082Sdim	     corresponds to this symbol.  This is the index of this symbol
8810214082Sdim	     in all the symbols for which we are making plt entries.  The
8811214082Sdim	     first entry in the procedure linkage table is reserved.  */
8812214082Sdim	  plt_index = ((h->plt.offset - htab->plt_header_size)
8813214082Sdim		       / htab->plt_entry_size);
8814214082Sdim	}
8815214082Sdim      else
8816214082Sdim	{
8817214082Sdim	  bfd_vma got_offset, got_address, plt_address;
8818214082Sdim	  bfd_vma got_displacement;
8819214082Sdim	  asection * sgot;
8820214634Sdim	  bfd_byte * ptr;
8821214082Sdim
8822214082Sdim	  sgot = bfd_get_section_by_name (dynobj, ".got.plt");
8823214082Sdim	  BFD_ASSERT (sgot != NULL);
8824214082Sdim
8825214082Sdim	  /* Get the offset into the .got.plt table of the entry that
8826214082Sdim	     corresponds to this function.  */
8827214082Sdim	  got_offset = eh->plt_got_offset;
8828214082Sdim
8829214082Sdim	  /* Get the index in the procedure linkage table which
8830214082Sdim	     corresponds to this symbol.  This is the index of this symbol
8831214082Sdim	     in all the symbols for which we are making plt entries.  The
8832214082Sdim	     first three entries in .got.plt are reserved; after that
8833214082Sdim	     symbols appear in the same order as in .plt.  */
8834214082Sdim	  plt_index = (got_offset - 12) / 4;
8835214082Sdim
8836214082Sdim	  /* Calculate the address of the GOT entry.  */
8837214082Sdim	  got_address = (sgot->output_section->vma
8838214082Sdim			 + sgot->output_offset
8839214082Sdim			 + got_offset);
8840214082Sdim
8841214082Sdim	  /* ...and the address of the PLT entry.  */
8842214082Sdim	  plt_address = (splt->output_section->vma
8843214082Sdim			 + splt->output_offset
8844214082Sdim			 + h->plt.offset);
8845214082Sdim
8846214634Sdim	  ptr = htab->splt->contents + h->plt.offset;
8847214082Sdim	  if (htab->vxworks_p && info->shared)
8848214082Sdim	    {
8849214082Sdim	      unsigned int i;
8850214082Sdim	      bfd_vma val;
8851214082Sdim
8852214634Sdim	      for (i = 0; i != htab->plt_entry_size / 4; i++, ptr += 4)
8853214082Sdim		{
8854214082Sdim		  val = elf32_arm_vxworks_shared_plt_entry[i];
8855214082Sdim		  if (i == 2)
8856214082Sdim		    val |= got_address - sgot->output_section->vma;
8857214082Sdim		  if (i == 5)
8858214082Sdim		    val |= plt_index * RELOC_SIZE (htab);
8859214634Sdim		  if (i == 2 || i == 5)
8860214634Sdim		    bfd_put_32 (output_bfd, val, ptr);
8861214634Sdim		  else
8862214634Sdim		    put_arm_insn (htab, output_bfd, val, ptr);
8863214082Sdim		}
8864214082Sdim	    }
8865214082Sdim	  else if (htab->vxworks_p)
8866214082Sdim	    {
8867214082Sdim	      unsigned int i;
8868214082Sdim	      bfd_vma val;
8869214082Sdim
8870214634Sdim	      for (i = 0; i != htab->plt_entry_size / 4; i++, ptr += 4)
8871214082Sdim		{
8872214082Sdim		  val = elf32_arm_vxworks_exec_plt_entry[i];
8873214082Sdim		  if (i == 2)
8874214082Sdim		    val |= got_address;
8875214082Sdim		  if (i == 4)
8876214082Sdim		    val |= 0xffffff & -((h->plt.offset + i * 4 + 8) >> 2);
8877214082Sdim		  if (i == 5)
8878214082Sdim		    val |= plt_index * RELOC_SIZE (htab);
8879214634Sdim		  if (i == 2 || i == 5)
8880214634Sdim		    bfd_put_32 (output_bfd, val, ptr);
8881214634Sdim		  else
8882214634Sdim		    put_arm_insn (htab, output_bfd, val, ptr);
8883214082Sdim		}
8884214082Sdim
8885214082Sdim	      loc = (htab->srelplt2->contents
8886214082Sdim		     + (plt_index * 2 + 1) * RELOC_SIZE (htab));
8887214082Sdim
8888214082Sdim	      /* Create the .rela.plt.unloaded R_ARM_ABS32 relocation
8889214082Sdim		 referencing the GOT for this PLT entry.  */
8890214082Sdim	      rel.r_offset = plt_address + 8;
8891214082Sdim	      rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_ARM_ABS32);
8892214082Sdim	      rel.r_addend = got_offset;
8893214082Sdim	      SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc);
8894214082Sdim	      loc += RELOC_SIZE (htab);
8895214082Sdim
8896214082Sdim	      /* Create the R_ARM_ABS32 relocation referencing the
8897214082Sdim		 beginning of the PLT for this GOT entry.  */
8898214082Sdim	      rel.r_offset = got_address;
8899214082Sdim	      rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, R_ARM_ABS32);
8900214082Sdim	      rel.r_addend = 0;
8901214082Sdim	      SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc);
8902214082Sdim	    }
8903214082Sdim	  else
8904214082Sdim	    {
8905214082Sdim	      /* Calculate the displacement between the PLT slot and the
8906214082Sdim		 entry in the GOT.  The eight-byte offset accounts for the
8907214082Sdim		 value produced by adding to pc in the first instruction
8908214082Sdim		 of the PLT stub.  */
8909214082Sdim	      got_displacement = got_address - (plt_address + 8);
8910214082Sdim
8911214082Sdim	      BFD_ASSERT ((got_displacement & 0xf0000000) == 0);
8912214082Sdim
8913214082Sdim	      if (!htab->use_blx && eh->plt_thumb_refcount > 0)
8914214082Sdim		{
8915214634Sdim		  put_thumb_insn (htab, output_bfd,
8916214634Sdim				  elf32_arm_plt_thumb_stub[0], ptr - 4);
8917214634Sdim		  put_thumb_insn (htab, output_bfd,
8918214634Sdim				  elf32_arm_plt_thumb_stub[1], ptr - 2);
8919214082Sdim		}
8920214082Sdim
8921214634Sdim	      put_arm_insn (htab, output_bfd,
8922214634Sdim			    elf32_arm_plt_entry[0]
8923214634Sdim			    | ((got_displacement & 0x0ff00000) >> 20),
8924214634Sdim			    ptr + 0);
8925214634Sdim	      put_arm_insn (htab, output_bfd,
8926214634Sdim			    elf32_arm_plt_entry[1]
8927214634Sdim			    | ((got_displacement & 0x000ff000) >> 12),
8928214634Sdim			    ptr+ 4);
8929214634Sdim	      put_arm_insn (htab, output_bfd,
8930214634Sdim			    elf32_arm_plt_entry[2]
8931214634Sdim			    | (got_displacement & 0x00000fff),
8932214634Sdim			    ptr + 8);
8933214082Sdim#ifdef FOUR_WORD_PLT
8934214634Sdim	      bfd_put_32 (output_bfd, elf32_arm_plt_entry[3], ptr + 12);
8935214082Sdim#endif
8936214082Sdim	    }
8937214082Sdim
8938214082Sdim	  /* Fill in the entry in the global offset table.  */
8939214082Sdim	  bfd_put_32 (output_bfd,
8940214082Sdim		      (splt->output_section->vma
8941214082Sdim		       + splt->output_offset),
8942214082Sdim		      sgot->contents + got_offset);
8943214082Sdim
8944214082Sdim	  /* Fill in the entry in the .rel(a).plt section.  */
8945214082Sdim	  rel.r_addend = 0;
8946214082Sdim	  rel.r_offset = got_address;
8947214082Sdim	  rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_JUMP_SLOT);
8948214082Sdim	}
8949214082Sdim
8950214082Sdim      loc = srel->contents + plt_index * RELOC_SIZE (htab);
8951214082Sdim      SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc);
8952214082Sdim
8953214082Sdim      if (!h->def_regular)
8954214082Sdim	{
8955214082Sdim	  /* Mark the symbol as undefined, rather than as defined in
8956214082Sdim	     the .plt section.  Leave the value alone.  */
8957214082Sdim	  sym->st_shndx = SHN_UNDEF;
8958214082Sdim	  /* If the symbol is weak, we do need to clear the value.
8959214082Sdim	     Otherwise, the PLT entry would provide a definition for
8960214082Sdim	     the symbol even if the symbol wasn't defined anywhere,
8961214082Sdim	     and so the symbol would never be NULL.  */
8962214082Sdim	  if (!h->ref_regular_nonweak)
8963214082Sdim	    sym->st_value = 0;
8964214082Sdim	}
8965214082Sdim    }
8966214082Sdim
8967214082Sdim  if (h->got.offset != (bfd_vma) -1
8968214082Sdim      && (elf32_arm_hash_entry (h)->tls_type & GOT_TLS_GD) == 0
8969214082Sdim      && (elf32_arm_hash_entry (h)->tls_type & GOT_TLS_IE) == 0)
8970214082Sdim    {
8971214082Sdim      asection * sgot;
8972214082Sdim      asection * srel;
8973214082Sdim      Elf_Internal_Rela rel;
8974214082Sdim      bfd_byte *loc;
8975214082Sdim      bfd_vma offset;
8976214082Sdim
8977214082Sdim      /* This symbol has an entry in the global offset table.  Set it
8978214082Sdim	 up.  */
8979214082Sdim      sgot = bfd_get_section_by_name (dynobj, ".got");
8980214082Sdim      srel = bfd_get_section_by_name (dynobj, RELOC_SECTION (htab, ".got"));
8981214082Sdim      BFD_ASSERT (sgot != NULL && srel != NULL);
8982214082Sdim
8983214082Sdim      offset = (h->got.offset & ~(bfd_vma) 1);
8984214082Sdim      rel.r_addend = 0;
8985214082Sdim      rel.r_offset = (sgot->output_section->vma
8986214082Sdim		      + sgot->output_offset
8987214082Sdim		      + offset);
8988214082Sdim
8989214082Sdim      /* If this is a static link, or it is a -Bsymbolic link and the
8990214082Sdim	 symbol is defined locally or was forced to be local because
8991214082Sdim	 of a version file, we just want to emit a RELATIVE reloc.
8992214082Sdim	 The entry in the global offset table will already have been
8993214082Sdim	 initialized in the relocate_section function.  */
8994214082Sdim      if (info->shared
8995214082Sdim	  && SYMBOL_REFERENCES_LOCAL (info, h))
8996214082Sdim	{
8997214082Sdim	  BFD_ASSERT((h->got.offset & 1) != 0);
8998214082Sdim	  rel.r_info = ELF32_R_INFO (0, R_ARM_RELATIVE);
8999214082Sdim	  if (!htab->use_rel)
9000214082Sdim	    {
9001214082Sdim	      rel.r_addend = bfd_get_32 (output_bfd, sgot->contents + offset);
9002214082Sdim	      bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + offset);
9003214082Sdim	    }
9004214082Sdim	}
9005214082Sdim      else
9006214082Sdim	{
9007214082Sdim	  BFD_ASSERT((h->got.offset & 1) == 0);
9008214082Sdim	  bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + offset);
9009214082Sdim	  rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_GLOB_DAT);
9010214082Sdim	}
9011214082Sdim
9012214082Sdim      loc = srel->contents + srel->reloc_count++ * RELOC_SIZE (htab);
9013214082Sdim      SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc);
9014214082Sdim    }
9015214082Sdim
9016214082Sdim  if (h->needs_copy)
9017214082Sdim    {
9018214082Sdim      asection * s;
9019214082Sdim      Elf_Internal_Rela rel;
9020214082Sdim      bfd_byte *loc;
9021214082Sdim
9022214082Sdim      /* This symbol needs a copy reloc.  Set it up.  */
9023214082Sdim      BFD_ASSERT (h->dynindx != -1
9024214082Sdim		  && (h->root.type == bfd_link_hash_defined
9025214082Sdim		      || h->root.type == bfd_link_hash_defweak));
9026214082Sdim
9027214082Sdim      s = bfd_get_section_by_name (h->root.u.def.section->owner,
9028214082Sdim				   RELOC_SECTION (htab, ".bss"));
9029214082Sdim      BFD_ASSERT (s != NULL);
9030214082Sdim
9031214082Sdim      rel.r_addend = 0;
9032214082Sdim      rel.r_offset = (h->root.u.def.value
9033214082Sdim		      + h->root.u.def.section->output_section->vma
9034214082Sdim		      + h->root.u.def.section->output_offset);
9035214082Sdim      rel.r_info = ELF32_R_INFO (h->dynindx, R_ARM_COPY);
9036214082Sdim      loc = s->contents + s->reloc_count++ * RELOC_SIZE (htab);
9037214082Sdim      SWAP_RELOC_OUT (htab) (output_bfd, &rel, loc);
9038214082Sdim    }
9039214082Sdim
9040214082Sdim  /* Mark _DYNAMIC and _GLOBAL_OFFSET_TABLE_ as absolute.  On VxWorks,
9041214082Sdim     the _GLOBAL_OFFSET_TABLE_ symbol is not absolute: it is relative
9042214082Sdim     to the ".got" section.  */
9043214082Sdim  if (strcmp (h->root.root.string, "_DYNAMIC") == 0
9044214082Sdim      || (!htab->vxworks_p && h == htab->root.hgot))
9045214082Sdim    sym->st_shndx = SHN_ABS;
9046214082Sdim
9047214082Sdim  return TRUE;
9048214082Sdim}
9049214082Sdim
9050214082Sdim/* Finish up the dynamic sections.  */
9051214082Sdim
9052214082Sdimstatic bfd_boolean
9053214082Sdimelf32_arm_finish_dynamic_sections (bfd * output_bfd, struct bfd_link_info * info)
9054214082Sdim{
9055214082Sdim  bfd * dynobj;
9056214082Sdim  asection * sgot;
9057214082Sdim  asection * sdyn;
9058214082Sdim
9059214082Sdim  dynobj = elf_hash_table (info)->dynobj;
9060214082Sdim
9061214082Sdim  sgot = bfd_get_section_by_name (dynobj, ".got.plt");
9062214082Sdim  BFD_ASSERT (elf32_arm_hash_table (info)->symbian_p || sgot != NULL);
9063214082Sdim  sdyn = bfd_get_section_by_name (dynobj, ".dynamic");
9064214082Sdim
9065214082Sdim  if (elf_hash_table (info)->dynamic_sections_created)
9066214082Sdim    {
9067214082Sdim      asection *splt;
9068214082Sdim      Elf32_External_Dyn *dyncon, *dynconend;
9069214082Sdim      struct elf32_arm_link_hash_table *htab;
9070214082Sdim
9071214082Sdim      htab = elf32_arm_hash_table (info);
9072214082Sdim      splt = bfd_get_section_by_name (dynobj, ".plt");
9073214082Sdim      BFD_ASSERT (splt != NULL && sdyn != NULL);
9074214082Sdim
9075214082Sdim      dyncon = (Elf32_External_Dyn *) sdyn->contents;
9076214082Sdim      dynconend = (Elf32_External_Dyn *) (sdyn->contents + sdyn->size);
9077214082Sdim
9078214082Sdim      for (; dyncon < dynconend; dyncon++)
9079214082Sdim	{
9080214082Sdim	  Elf_Internal_Dyn dyn;
9081214082Sdim	  const char * name;
9082214082Sdim	  asection * s;
9083214082Sdim
9084214082Sdim	  bfd_elf32_swap_dyn_in (dynobj, dyncon, &dyn);
9085214082Sdim
9086214082Sdim	  switch (dyn.d_tag)
9087214082Sdim	    {
9088214082Sdim	      unsigned int type;
9089214082Sdim
9090214082Sdim	    default:
9091214082Sdim	      break;
9092214082Sdim
9093214082Sdim	    case DT_HASH:
9094214082Sdim	      name = ".hash";
9095214082Sdim	      goto get_vma_if_bpabi;
9096214082Sdim	    case DT_STRTAB:
9097214082Sdim	      name = ".dynstr";
9098214082Sdim	      goto get_vma_if_bpabi;
9099214082Sdim	    case DT_SYMTAB:
9100214082Sdim	      name = ".dynsym";
9101214082Sdim	      goto get_vma_if_bpabi;
9102214082Sdim	    case DT_VERSYM:
9103214082Sdim	      name = ".gnu.version";
9104214082Sdim	      goto get_vma_if_bpabi;
9105214082Sdim	    case DT_VERDEF:
9106214082Sdim	      name = ".gnu.version_d";
9107214082Sdim	      goto get_vma_if_bpabi;
9108214082Sdim	    case DT_VERNEED:
9109214082Sdim	      name = ".gnu.version_r";
9110214082Sdim	      goto get_vma_if_bpabi;
9111214082Sdim
9112214082Sdim	    case DT_PLTGOT:
9113214082Sdim	      name = ".got";
9114214082Sdim	      goto get_vma;
9115214082Sdim	    case DT_JMPREL:
9116214082Sdim	      name = RELOC_SECTION (htab, ".plt");
9117214082Sdim	    get_vma:
9118214082Sdim	      s = bfd_get_section_by_name (output_bfd, name);
9119214082Sdim	      BFD_ASSERT (s != NULL);
9120214082Sdim	      if (!htab->symbian_p)
9121214082Sdim		dyn.d_un.d_ptr = s->vma;
9122214082Sdim	      else
9123214082Sdim		/* In the BPABI, tags in the PT_DYNAMIC section point
9124214082Sdim		   at the file offset, not the memory address, for the
9125214082Sdim		   convenience of the post linker.  */
9126214082Sdim		dyn.d_un.d_ptr = s->filepos;
9127214082Sdim	      bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
9128214082Sdim	      break;
9129214082Sdim
9130214082Sdim	    get_vma_if_bpabi:
9131214082Sdim	      if (htab->symbian_p)
9132214082Sdim		goto get_vma;
9133214082Sdim	      break;
9134214082Sdim
9135214082Sdim	    case DT_PLTRELSZ:
9136214082Sdim	      s = bfd_get_section_by_name (output_bfd,
9137214082Sdim					   RELOC_SECTION (htab, ".plt"));
9138214082Sdim	      BFD_ASSERT (s != NULL);
9139214082Sdim	      dyn.d_un.d_val = s->size;
9140214082Sdim	      bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
9141214082Sdim	      break;
9142214082Sdim
9143214082Sdim	    case DT_RELSZ:
9144214082Sdim	    case DT_RELASZ:
9145214082Sdim	      if (!htab->symbian_p)
9146214082Sdim		{
9147214082Sdim		  /* My reading of the SVR4 ABI indicates that the
9148214082Sdim		     procedure linkage table relocs (DT_JMPREL) should be
9149214082Sdim		     included in the overall relocs (DT_REL).  This is
9150214082Sdim		     what Solaris does.  However, UnixWare can not handle
9151214082Sdim		     that case.  Therefore, we override the DT_RELSZ entry
9152214082Sdim		     here to make it not include the JMPREL relocs.  Since
9153214082Sdim		     the linker script arranges for .rel(a).plt to follow all
9154214082Sdim		     other relocation sections, we don't have to worry
9155214082Sdim		     about changing the DT_REL entry.  */
9156214082Sdim		  s = bfd_get_section_by_name (output_bfd,
9157214082Sdim					       RELOC_SECTION (htab, ".plt"));
9158214082Sdim		  if (s != NULL)
9159214082Sdim		    dyn.d_un.d_val -= s->size;
9160214082Sdim		  bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
9161214082Sdim		  break;
9162214082Sdim		}
9163214082Sdim	      /* Fall through */
9164214082Sdim
9165214082Sdim	    case DT_REL:
9166214082Sdim	    case DT_RELA:
9167214082Sdim	      /* In the BPABI, the DT_REL tag must point at the file
9168214082Sdim		 offset, not the VMA, of the first relocation
9169214082Sdim		 section.  So, we use code similar to that in
9170214082Sdim		 elflink.c, but do not check for SHF_ALLOC on the
9171214082Sdim		 relcoation section, since relocations sections are
9172214082Sdim		 never allocated under the BPABI.  The comments above
9173214082Sdim		 about Unixware notwithstanding, we include all of the
9174214082Sdim		 relocations here.  */
9175214082Sdim	      if (htab->symbian_p)
9176214082Sdim		{
9177214082Sdim		  unsigned int i;
9178214082Sdim		  type = ((dyn.d_tag == DT_REL || dyn.d_tag == DT_RELSZ)
9179214082Sdim			  ? SHT_REL : SHT_RELA);
9180214082Sdim		  dyn.d_un.d_val = 0;
9181214082Sdim		  for (i = 1; i < elf_numsections (output_bfd); i++)
9182214082Sdim		    {
9183214082Sdim		      Elf_Internal_Shdr *hdr
9184214082Sdim			= elf_elfsections (output_bfd)[i];
9185214082Sdim		      if (hdr->sh_type == type)
9186214082Sdim			{
9187214082Sdim			  if (dyn.d_tag == DT_RELSZ
9188214082Sdim			      || dyn.d_tag == DT_RELASZ)
9189214082Sdim			    dyn.d_un.d_val += hdr->sh_size;
9190214082Sdim			  else if ((ufile_ptr) hdr->sh_offset
9191214082Sdim				   <= dyn.d_un.d_val - 1)
9192214082Sdim			    dyn.d_un.d_val = hdr->sh_offset;
9193214082Sdim			}
9194214082Sdim		    }
9195214082Sdim		  bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
9196214082Sdim		}
9197214082Sdim	      break;
9198214082Sdim
9199214082Sdim	      /* Set the bottom bit of DT_INIT/FINI if the
9200214082Sdim		 corresponding function is Thumb.  */
9201214082Sdim	    case DT_INIT:
9202214082Sdim	      name = info->init_function;
9203214082Sdim	      goto get_sym;
9204214082Sdim	    case DT_FINI:
9205214082Sdim	      name = info->fini_function;
9206214082Sdim	    get_sym:
9207214082Sdim	      /* If it wasn't set by elf_bfd_final_link
9208214082Sdim		 then there is nothing to adjust.  */
9209214082Sdim	      if (dyn.d_un.d_val != 0)
9210214082Sdim		{
9211214082Sdim		  struct elf_link_hash_entry * eh;
9212214082Sdim
9213214082Sdim		  eh = elf_link_hash_lookup (elf_hash_table (info), name,
9214214082Sdim					     FALSE, FALSE, TRUE);
9215214082Sdim		  if (eh != (struct elf_link_hash_entry *) NULL
9216214082Sdim		      && ELF_ST_TYPE (eh->type) == STT_ARM_TFUNC)
9217214082Sdim		    {
9218214082Sdim		      dyn.d_un.d_val |= 1;
9219214082Sdim		      bfd_elf32_swap_dyn_out (output_bfd, &dyn, dyncon);
9220214082Sdim		    }
9221214082Sdim		}
9222214082Sdim	      break;
9223214082Sdim	    }
9224214082Sdim	}
9225214082Sdim
9226214082Sdim      /* Fill in the first entry in the procedure linkage table.  */
9227214082Sdim      if (splt->size > 0 && elf32_arm_hash_table (info)->plt_header_size)
9228214082Sdim	{
9229214082Sdim	  const bfd_vma *plt0_entry;
9230214082Sdim	  bfd_vma got_address, plt_address, got_displacement;
9231214082Sdim
9232214082Sdim	  /* Calculate the addresses of the GOT and PLT.  */
9233214082Sdim	  got_address = sgot->output_section->vma + sgot->output_offset;
9234214082Sdim	  plt_address = splt->output_section->vma + splt->output_offset;
9235214082Sdim
9236214082Sdim	  if (htab->vxworks_p)
9237214082Sdim	    {
9238214082Sdim	      /* The VxWorks GOT is relocated by the dynamic linker.
9239214082Sdim		 Therefore, we must emit relocations rather than simply
9240214082Sdim		 computing the values now.  */
9241214082Sdim	      Elf_Internal_Rela rel;
9242214082Sdim
9243214082Sdim	      plt0_entry = elf32_arm_vxworks_exec_plt0_entry;
9244214634Sdim	      put_arm_insn (htab, output_bfd, plt0_entry[0],
9245214634Sdim			    splt->contents + 0);
9246214634Sdim	      put_arm_insn (htab, output_bfd, plt0_entry[1],
9247214634Sdim			    splt->contents + 4);
9248214634Sdim	      put_arm_insn (htab, output_bfd, plt0_entry[2],
9249214634Sdim			    splt->contents + 8);
9250214082Sdim	      bfd_put_32 (output_bfd, got_address, splt->contents + 12);
9251214082Sdim
9252214082Sdim	      /* Generate a relocation for _GLOBAL_OFFSET_TABLE_. */
9253214082Sdim	      rel.r_offset = plt_address + 12;
9254214082Sdim	      rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_ARM_ABS32);
9255214082Sdim	      rel.r_addend = 0;
9256214082Sdim	      SWAP_RELOC_OUT (htab) (output_bfd, &rel,
9257214082Sdim				     htab->srelplt2->contents);
9258214082Sdim	    }
9259214082Sdim	  else
9260214082Sdim	    {
9261214082Sdim	      got_displacement = got_address - (plt_address + 16);
9262214082Sdim
9263214082Sdim	      plt0_entry = elf32_arm_plt0_entry;
9264214634Sdim	      put_arm_insn (htab, output_bfd, plt0_entry[0],
9265214634Sdim			    splt->contents + 0);
9266214634Sdim	      put_arm_insn (htab, output_bfd, plt0_entry[1],
9267214634Sdim			    splt->contents + 4);
9268214634Sdim	      put_arm_insn (htab, output_bfd, plt0_entry[2],
9269214634Sdim			    splt->contents + 8);
9270214634Sdim	      put_arm_insn (htab, output_bfd, plt0_entry[3],
9271214634Sdim			    splt->contents + 12);
9272214082Sdim
9273214082Sdim#ifdef FOUR_WORD_PLT
9274214082Sdim	      /* The displacement value goes in the otherwise-unused
9275214082Sdim		 last word of the second entry.  */
9276214082Sdim	      bfd_put_32 (output_bfd, got_displacement, splt->contents + 28);
9277214082Sdim#else
9278214082Sdim	      bfd_put_32 (output_bfd, got_displacement, splt->contents + 16);
9279214082Sdim#endif
9280214082Sdim	    }
9281214082Sdim	}
9282214082Sdim
9283214082Sdim      /* UnixWare sets the entsize of .plt to 4, although that doesn't
9284214082Sdim	 really seem like the right value.  */
9285214634Sdim      if (splt->output_section->owner == output_bfd)
9286214634Sdim	elf_section_data (splt->output_section)->this_hdr.sh_entsize = 4;
9287214082Sdim
9288214082Sdim      if (htab->vxworks_p && !info->shared && htab->splt->size > 0)
9289214082Sdim	{
9290214082Sdim	  /* Correct the .rel(a).plt.unloaded relocations.  They will have
9291214082Sdim	     incorrect symbol indexes.  */
9292214082Sdim	  int num_plts;
9293214082Sdim	  unsigned char *p;
9294214082Sdim
9295214082Sdim	  num_plts = ((htab->splt->size - htab->plt_header_size)
9296214082Sdim		      / htab->plt_entry_size);
9297214082Sdim	  p = htab->srelplt2->contents + RELOC_SIZE (htab);
9298214082Sdim
9299214082Sdim	  for (; num_plts; num_plts--)
9300214082Sdim	    {
9301214082Sdim	      Elf_Internal_Rela rel;
9302214082Sdim
9303214082Sdim	      SWAP_RELOC_IN (htab) (output_bfd, p, &rel);
9304214082Sdim	      rel.r_info = ELF32_R_INFO (htab->root.hgot->indx, R_ARM_ABS32);
9305214082Sdim	      SWAP_RELOC_OUT (htab) (output_bfd, &rel, p);
9306214082Sdim	      p += RELOC_SIZE (htab);
9307214082Sdim
9308214082Sdim	      SWAP_RELOC_IN (htab) (output_bfd, p, &rel);
9309214082Sdim	      rel.r_info = ELF32_R_INFO (htab->root.hplt->indx, R_ARM_ABS32);
9310214082Sdim	      SWAP_RELOC_OUT (htab) (output_bfd, &rel, p);
9311214082Sdim	      p += RELOC_SIZE (htab);
9312214082Sdim	    }
9313214082Sdim	}
9314214082Sdim    }
9315214082Sdim
9316214082Sdim  /* Fill in the first three entries in the global offset table.  */
9317214082Sdim  if (sgot)
9318214082Sdim    {
9319214082Sdim      if (sgot->size > 0)
9320214082Sdim	{
9321214082Sdim	  if (sdyn == NULL)
9322214082Sdim	    bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents);
9323214082Sdim	  else
9324214082Sdim	    bfd_put_32 (output_bfd,
9325214082Sdim			sdyn->output_section->vma + sdyn->output_offset,
9326214082Sdim			sgot->contents);
9327214082Sdim	  bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 4);
9328214082Sdim	  bfd_put_32 (output_bfd, (bfd_vma) 0, sgot->contents + 8);
9329214082Sdim	}
9330214082Sdim
9331214082Sdim      elf_section_data (sgot->output_section)->this_hdr.sh_entsize = 4;
9332214082Sdim    }
9333214082Sdim
9334214082Sdim  return TRUE;
9335214082Sdim}
9336214082Sdim
9337214082Sdimstatic void
9338214082Sdimelf32_arm_post_process_headers (bfd * abfd, struct bfd_link_info * link_info ATTRIBUTE_UNUSED)
9339214082Sdim{
9340214082Sdim  Elf_Internal_Ehdr * i_ehdrp;	/* ELF file header, internal form.  */
9341214082Sdim  struct elf32_arm_link_hash_table *globals;
9342214082Sdim
9343214082Sdim  i_ehdrp = elf_elfheader (abfd);
9344214082Sdim
9345214082Sdim  if (EF_ARM_EABI_VERSION (i_ehdrp->e_flags) == EF_ARM_EABI_UNKNOWN)
9346214157Sdim    i_ehdrp->e_ident[EI_OSABI] = ARM_ELF_OS_ABI_VERSION;
9347214082Sdim  else
9348214082Sdim    i_ehdrp->e_ident[EI_OSABI] = 0;
9349214082Sdim  i_ehdrp->e_ident[EI_ABIVERSION] = ARM_ELF_ABI_VERSION;
9350214082Sdim
9351214082Sdim  if (link_info)
9352214082Sdim    {
9353214082Sdim      globals = elf32_arm_hash_table (link_info);
9354214082Sdim      if (globals->byteswap_code)
9355214082Sdim	i_ehdrp->e_flags |= EF_ARM_BE8;
9356214082Sdim    }
9357214082Sdim}
9358214082Sdim
9359214082Sdimstatic enum elf_reloc_type_class
9360214082Sdimelf32_arm_reloc_type_class (const Elf_Internal_Rela *rela)
9361214082Sdim{
9362214082Sdim  switch ((int) ELF32_R_TYPE (rela->r_info))
9363214082Sdim    {
9364214082Sdim    case R_ARM_RELATIVE:
9365214082Sdim      return reloc_class_relative;
9366214082Sdim    case R_ARM_JUMP_SLOT:
9367214082Sdim      return reloc_class_plt;
9368214082Sdim    case R_ARM_COPY:
9369214082Sdim      return reloc_class_copy;
9370214082Sdim    default:
9371214082Sdim      return reloc_class_normal;
9372214082Sdim    }
9373214082Sdim}
9374214082Sdim
9375214082Sdim/* Set the right machine number for an Arm ELF file.  */
9376214082Sdim
9377214082Sdimstatic bfd_boolean
9378214082Sdimelf32_arm_section_flags (flagword *flags, const Elf_Internal_Shdr *hdr)
9379214082Sdim{
9380214082Sdim  if (hdr->sh_type == SHT_NOTE)
9381214082Sdim    *flags |= SEC_LINK_ONCE | SEC_LINK_DUPLICATES_SAME_CONTENTS;
9382214082Sdim
9383214082Sdim  return TRUE;
9384214082Sdim}
9385214082Sdim
9386214082Sdimstatic void
9387214082Sdimelf32_arm_final_write_processing (bfd *abfd, bfd_boolean linker ATTRIBUTE_UNUSED)
9388214082Sdim{
9389214082Sdim  bfd_arm_update_notes (abfd, ARM_NOTE_SECTION);
9390214082Sdim}
9391214082Sdim
9392214082Sdim/* Return TRUE if this is an unwinding table entry.  */
9393214082Sdim
9394214082Sdimstatic bfd_boolean
9395214082Sdimis_arm_elf_unwind_section_name (bfd * abfd ATTRIBUTE_UNUSED, const char * name)
9396214082Sdim{
9397214634Sdim  return (CONST_STRNEQ (name, ELF_STRING_ARM_unwind)
9398214634Sdim	  || CONST_STRNEQ (name, ELF_STRING_ARM_unwind_once));
9399214082Sdim}
9400214082Sdim
9401214082Sdim
9402214082Sdim/* Set the type and flags for an ARM section.  We do this by
9403214082Sdim   the section name, which is a hack, but ought to work.  */
9404214082Sdim
9405214082Sdimstatic bfd_boolean
9406214082Sdimelf32_arm_fake_sections (bfd * abfd, Elf_Internal_Shdr * hdr, asection * sec)
9407214082Sdim{
9408214082Sdim  const char * name;
9409214082Sdim
9410214082Sdim  name = bfd_get_section_name (abfd, sec);
9411214082Sdim
9412214082Sdim  if (is_arm_elf_unwind_section_name (abfd, name))
9413214082Sdim    {
9414214082Sdim      hdr->sh_type = SHT_ARM_EXIDX;
9415214082Sdim      hdr->sh_flags |= SHF_LINK_ORDER;
9416214082Sdim    }
9417214082Sdim  return TRUE;
9418214082Sdim}
9419214082Sdim
9420214082Sdim/* Handle an ARM specific section when reading an object file.  This is
9421214082Sdim   called when bfd_section_from_shdr finds a section with an unknown
9422214082Sdim   type.  */
9423214082Sdim
9424214082Sdimstatic bfd_boolean
9425214082Sdimelf32_arm_section_from_shdr (bfd *abfd,
9426214082Sdim			     Elf_Internal_Shdr * hdr,
9427214082Sdim			     const char *name,
9428214082Sdim			     int shindex)
9429214082Sdim{
9430214082Sdim  /* There ought to be a place to keep ELF backend specific flags, but
9431214082Sdim     at the moment there isn't one.  We just keep track of the
9432214082Sdim     sections by their name, instead.  Fortunately, the ABI gives
9433214082Sdim     names for all the ARM specific sections, so we will probably get
9434214082Sdim     away with this.  */
9435214082Sdim  switch (hdr->sh_type)
9436214082Sdim    {
9437214082Sdim    case SHT_ARM_EXIDX:
9438214082Sdim    case SHT_ARM_PREEMPTMAP:
9439214082Sdim    case SHT_ARM_ATTRIBUTES:
9440214082Sdim      break;
9441214082Sdim
9442214082Sdim    default:
9443214082Sdim      return FALSE;
9444214082Sdim    }
9445214082Sdim
9446214082Sdim  if (! _bfd_elf_make_section_from_shdr (abfd, hdr, name, shindex))
9447214082Sdim    return FALSE;
9448214082Sdim
9449214082Sdim  return TRUE;
9450214082Sdim}
9451214082Sdim
9452214082Sdim/* A structure used to record a list of sections, independently
9453214082Sdim   of the next and prev fields in the asection structure.  */
9454214082Sdimtypedef struct section_list
9455214082Sdim{
9456214082Sdim  asection * sec;
9457214082Sdim  struct section_list * next;
9458214082Sdim  struct section_list * prev;
9459214082Sdim}
9460214082Sdimsection_list;
9461214082Sdim
9462214082Sdim/* Unfortunately we need to keep a list of sections for which
9463214082Sdim   an _arm_elf_section_data structure has been allocated.  This
9464214082Sdim   is because it is possible for functions like elf32_arm_write_section
9465214082Sdim   to be called on a section which has had an elf_data_structure
9466214082Sdim   allocated for it (and so the used_by_bfd field is valid) but
9467214082Sdim   for which the ARM extended version of this structure - the
9468214082Sdim   _arm_elf_section_data structure - has not been allocated.  */
9469214082Sdimstatic section_list * sections_with_arm_elf_section_data = NULL;
9470214082Sdim
9471214082Sdimstatic void
9472214082Sdimrecord_section_with_arm_elf_section_data (asection * sec)
9473214082Sdim{
9474214082Sdim  struct section_list * entry;
9475214082Sdim
9476214082Sdim  entry = bfd_malloc (sizeof (* entry));
9477214082Sdim  if (entry == NULL)
9478214082Sdim    return;
9479214082Sdim  entry->sec = sec;
9480214082Sdim  entry->next = sections_with_arm_elf_section_data;
9481214082Sdim  entry->prev = NULL;
9482214082Sdim  if (entry->next != NULL)
9483214082Sdim    entry->next->prev = entry;
9484214082Sdim  sections_with_arm_elf_section_data = entry;
9485214082Sdim}
9486214082Sdim
9487214082Sdimstatic struct section_list *
9488214082Sdimfind_arm_elf_section_entry (asection * sec)
9489214082Sdim{
9490214082Sdim  struct section_list * entry;
9491214082Sdim  static struct section_list * last_entry = NULL;
9492214082Sdim
9493214082Sdim  /* This is a short cut for the typical case where the sections are added
9494214082Sdim     to the sections_with_arm_elf_section_data list in forward order and
9495214082Sdim     then looked up here in backwards order.  This makes a real difference
9496214082Sdim     to the ld-srec/sec64k.exp linker test.  */
9497214082Sdim  entry = sections_with_arm_elf_section_data;
9498214082Sdim  if (last_entry != NULL)
9499214082Sdim    {
9500214082Sdim      if (last_entry->sec == sec)
9501214082Sdim	entry = last_entry;
9502214082Sdim      else if (last_entry->next != NULL
9503214082Sdim	       && last_entry->next->sec == sec)
9504214082Sdim	entry = last_entry->next;
9505214082Sdim    }
9506214082Sdim
9507214082Sdim  for (; entry; entry = entry->next)
9508214082Sdim    if (entry->sec == sec)
9509214082Sdim      break;
9510214082Sdim
9511214082Sdim  if (entry)
9512214082Sdim    /* Record the entry prior to this one - it is the entry we are most
9513214082Sdim       likely to want to locate next time.  Also this way if we have been
9514214082Sdim       called from unrecord_section_with_arm_elf_section_data() we will not
9515214082Sdim       be caching a pointer that is about to be freed.  */
9516214082Sdim    last_entry = entry->prev;
9517214082Sdim
9518214082Sdim  return entry;
9519214082Sdim}
9520214082Sdim
9521214082Sdimstatic _arm_elf_section_data *
9522214082Sdimget_arm_elf_section_data (asection * sec)
9523214082Sdim{
9524214082Sdim  struct section_list * entry;
9525214082Sdim
9526214082Sdim  entry = find_arm_elf_section_entry (sec);
9527214082Sdim
9528214082Sdim  if (entry)
9529214082Sdim    return elf32_arm_section_data (entry->sec);
9530214082Sdim  else
9531214082Sdim    return NULL;
9532214082Sdim}
9533214082Sdim
9534214082Sdimstatic void
9535214082Sdimunrecord_section_with_arm_elf_section_data (asection * sec)
9536214082Sdim{
9537214082Sdim  struct section_list * entry;
9538214082Sdim
9539214082Sdim  entry = find_arm_elf_section_entry (sec);
9540214082Sdim
9541214082Sdim  if (entry)
9542214082Sdim    {
9543214082Sdim      if (entry->prev != NULL)
9544214082Sdim	entry->prev->next = entry->next;
9545214082Sdim      if (entry->next != NULL)
9546214082Sdim	entry->next->prev = entry->prev;
9547214082Sdim      if (entry == sections_with_arm_elf_section_data)
9548214082Sdim	sections_with_arm_elf_section_data = entry->next;
9549214082Sdim      free (entry);
9550214082Sdim    }
9551214082Sdim}
9552214082Sdim
9553214082Sdim
9554214634Sdimtypedef struct
9555214634Sdim{
9556214634Sdim  void *finfo;
9557214634Sdim  struct bfd_link_info *info;
9558214634Sdim  asection *sec;
9559214634Sdim  int sec_shndx;
9560214634Sdim  bfd_boolean (*func) (void *, const char *, Elf_Internal_Sym *,
9561214634Sdim		       asection *, struct elf_link_hash_entry *);
9562214634Sdim} output_arch_syminfo;
9563214634Sdim
9564214634Sdimenum map_symbol_type
9565214634Sdim{
9566214634Sdim  ARM_MAP_ARM,
9567214634Sdim  ARM_MAP_THUMB,
9568214634Sdim  ARM_MAP_DATA
9569214634Sdim};
9570214634Sdim
9571214634Sdim
9572214634Sdim/* Output a single PLT mapping symbol.  */
9573214634Sdim
9574214082Sdimstatic bfd_boolean
9575214634Sdimelf32_arm_ouput_plt_map_sym (output_arch_syminfo *osi,
9576214634Sdim			     enum map_symbol_type type,
9577214634Sdim			     bfd_vma offset)
9578214082Sdim{
9579214634Sdim  static const char *names[3] = {"$a", "$t", "$d"};
9580214634Sdim  struct elf32_arm_link_hash_table *htab;
9581214634Sdim  Elf_Internal_Sym sym;
9582214082Sdim
9583214634Sdim  htab = elf32_arm_hash_table (osi->info);
9584214634Sdim  sym.st_value = osi->sec->output_section->vma
9585214634Sdim		 + osi->sec->output_offset
9586214634Sdim		 + offset;
9587214634Sdim  sym.st_size = 0;
9588214634Sdim  sym.st_other = 0;
9589214634Sdim  sym.st_info = ELF_ST_INFO (STB_LOCAL, STT_NOTYPE);
9590214634Sdim  sym.st_shndx = osi->sec_shndx;
9591214634Sdim  if (!osi->func (osi->finfo, names[type], &sym, osi->sec, NULL))
9592214082Sdim    return FALSE;
9593214634Sdim  return TRUE;
9594214634Sdim}
9595214082Sdim
9596214082Sdim
9597214634Sdim/* Output mapping symbols for PLT entries associated with H.  */
9598214082Sdim
9599214634Sdimstatic bfd_boolean
9600214634Sdimelf32_arm_output_plt_map (struct elf_link_hash_entry *h, void *inf)
9601214634Sdim{
9602214634Sdim  output_arch_syminfo *osi = (output_arch_syminfo *) inf;
9603214634Sdim  struct elf32_arm_link_hash_table *htab;
9604214634Sdim  struct elf32_arm_link_hash_entry *eh;
9605214634Sdim  bfd_vma addr;
9606214634Sdim
9607214634Sdim  htab = elf32_arm_hash_table (osi->info);
9608214634Sdim
9609214634Sdim  if (h->root.type == bfd_link_hash_indirect)
9610214082Sdim    return TRUE;
9611214082Sdim
9612214634Sdim  if (h->root.type == bfd_link_hash_warning)
9613214634Sdim    /* When warning symbols are created, they **replace** the "real"
9614214634Sdim       entry in the hash table, thus we never get to see the real
9615214634Sdim       symbol in a hash traversal.  So look at it now.  */
9616214634Sdim    h = (struct elf_link_hash_entry *) h->root.u.i.link;
9617214634Sdim
9618214634Sdim  if (h->plt.offset == (bfd_vma) -1)
9619214082Sdim    return TRUE;
9620214082Sdim
9621214634Sdim  eh = (struct elf32_arm_link_hash_entry *) h;
9622214634Sdim  addr = h->plt.offset;
9623214634Sdim  if (htab->symbian_p)
9624214634Sdim    {
9625214634Sdim      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
9626214634Sdim	return FALSE;
9627214634Sdim      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_DATA, addr + 4))
9628214634Sdim	return FALSE;
9629214634Sdim    }
9630214634Sdim  else if (htab->vxworks_p)
9631214634Sdim    {
9632214634Sdim      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
9633214634Sdim	return FALSE;
9634214634Sdim      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_DATA, addr + 8))
9635214634Sdim	return FALSE;
9636214634Sdim      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr + 12))
9637214634Sdim	return FALSE;
9638214634Sdim      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_DATA, addr + 20))
9639214634Sdim	return FALSE;
9640214634Sdim    }
9641214634Sdim  else
9642214634Sdim    {
9643214634Sdim      bfd_boolean thumb_stub;
9644214082Sdim
9645214634Sdim      thumb_stub = eh->plt_thumb_refcount > 0 && !htab->use_blx;
9646214634Sdim      if (thumb_stub)
9647214634Sdim	{
9648214634Sdim	  if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_THUMB, addr - 4))
9649214634Sdim	    return FALSE;
9650214634Sdim	}
9651214634Sdim#ifdef FOUR_WORD_PLT
9652214634Sdim      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
9653214634Sdim	return FALSE;
9654214634Sdim      if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_DATA, addr + 12))
9655214634Sdim	return FALSE;
9656214634Sdim#else
9657214634Sdim      /* A three-word PLT with no Thumb thunk contains only Arm code,
9658214634Sdim	 so only need to output a mapping symbol for the first PLT entry and
9659214634Sdim	 entries with thumb thunks.  */
9660214634Sdim      if (thumb_stub || addr == 20)
9661214634Sdim	{
9662214634Sdim	  if (!elf32_arm_ouput_plt_map_sym (osi, ARM_MAP_ARM, addr))
9663214634Sdim	    return FALSE;
9664214634Sdim	}
9665214634Sdim#endif
9666214634Sdim    }
9667214634Sdim
9668214634Sdim  return TRUE;
9669214634Sdim}
9670214634Sdim
9671214634Sdim
9672214634Sdim/* Output mapping symbols for linker generated sections.  */
9673214634Sdim
9674214634Sdimstatic bfd_boolean
9675214634Sdimelf32_arm_output_arch_local_syms (bfd *output_bfd,
9676214634Sdim    struct bfd_link_info *info,
9677214634Sdim    void *finfo, bfd_boolean (*func) (void *, const char *,
9678214634Sdim				    Elf_Internal_Sym *,
9679214634Sdim				    asection *,
9680214634Sdim				    struct elf_link_hash_entry *))
9681214634Sdim{
9682214634Sdim  output_arch_syminfo osi;
9683214634Sdim  struct elf32_arm_link_hash_table *htab;
9684214634Sdim  bfd_vma offset;
9685214634Sdim  bfd_size_type size;
9686214634Sdim
9687214634Sdim  htab = elf32_arm_hash_table (info);
9688214634Sdim  check_use_blx(htab);
9689214634Sdim
9690214634Sdim  osi.finfo = finfo;
9691214634Sdim  osi.info = info;
9692214634Sdim  osi.func = func;
9693214634Sdim
9694214634Sdim  /* ARM->Thumb glue.  */
9695214634Sdim  if (htab->arm_glue_size > 0)
9696214082Sdim    {
9697214634Sdim      osi.sec = bfd_get_section_by_name (htab->bfd_of_glue_owner,
9698214634Sdim					 ARM2THUMB_GLUE_SECTION_NAME);
9699214082Sdim
9700214634Sdim      osi.sec_shndx = _bfd_elf_section_from_bfd_section
9701214634Sdim	  (output_bfd, osi.sec->output_section);
9702214634Sdim      if (info->shared || htab->root.is_relocatable_executable
9703214634Sdim	  || htab->pic_veneer)
9704214634Sdim	size = ARM2THUMB_PIC_GLUE_SIZE;
9705214634Sdim      else if (htab->use_blx)
9706214634Sdim	size = ARM2THUMB_V5_STATIC_GLUE_SIZE;
9707214634Sdim      else
9708214634Sdim	size = ARM2THUMB_STATIC_GLUE_SIZE;
9709214634Sdim
9710214634Sdim      for (offset = 0; offset < htab->arm_glue_size; offset += size)
9711214634Sdim	{
9712214634Sdim	  elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, offset);
9713214634Sdim	  elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_DATA, offset + size - 4);
9714214634Sdim	}
9715214082Sdim    }
9716214082Sdim
9717214634Sdim  /* Thumb->ARM glue.  */
9718214634Sdim  if (htab->thumb_glue_size > 0)
9719214634Sdim    {
9720214634Sdim      osi.sec = bfd_get_section_by_name (htab->bfd_of_glue_owner,
9721214634Sdim					 THUMB2ARM_GLUE_SECTION_NAME);
9722214634Sdim
9723214634Sdim      osi.sec_shndx = _bfd_elf_section_from_bfd_section
9724214634Sdim	  (output_bfd, osi.sec->output_section);
9725214634Sdim      size = THUMB2ARM_GLUE_SIZE;
9726214634Sdim
9727214634Sdim      for (offset = 0; offset < htab->thumb_glue_size; offset += size)
9728214634Sdim	{
9729214634Sdim	  elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_THUMB, offset);
9730214634Sdim	  elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, offset + 4);
9731214634Sdim	}
9732214634Sdim    }
9733214634Sdim
9734214634Sdim  /* Finally, output mapping symbols for the PLT.  */
9735214634Sdim  if (!htab->splt || htab->splt->size == 0)
9736214634Sdim    return TRUE;
9737214634Sdim
9738214634Sdim  osi.sec_shndx = _bfd_elf_section_from_bfd_section (output_bfd,
9739214634Sdim      htab->splt->output_section);
9740214634Sdim  osi.sec = htab->splt;
9741214634Sdim  /* Output mapping symbols for the plt header.  SymbianOS does not have a
9742214634Sdim     plt header.  */
9743214634Sdim  if (htab->vxworks_p)
9744214634Sdim    {
9745214634Sdim      /* VxWorks shared libraries have no PLT header.  */
9746214634Sdim      if (!info->shared)
9747214634Sdim	{
9748214634Sdim	  if (!elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, 0))
9749214634Sdim	    return FALSE;
9750214634Sdim	  if (!elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_DATA, 12))
9751214634Sdim	    return FALSE;
9752214634Sdim	}
9753214634Sdim    }
9754214634Sdim  else if (!htab->symbian_p)
9755214634Sdim    {
9756214634Sdim      if (!elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_ARM, 0))
9757214634Sdim	return FALSE;
9758214634Sdim#ifndef FOUR_WORD_PLT
9759214634Sdim      if (!elf32_arm_ouput_plt_map_sym (&osi, ARM_MAP_DATA, 16))
9760214634Sdim	return FALSE;
9761214634Sdim#endif
9762214634Sdim    }
9763214634Sdim
9764214634Sdim  elf_link_hash_traverse (&htab->root, elf32_arm_output_plt_map, (void *) &osi);
9765214082Sdim  return TRUE;
9766214082Sdim}
9767214082Sdim
9768214082Sdim/* Allocate target specific section data.  */
9769214082Sdim
9770214082Sdimstatic bfd_boolean
9771214082Sdimelf32_arm_new_section_hook (bfd *abfd, asection *sec)
9772214082Sdim{
9773214634Sdim  if (!sec->used_by_bfd)
9774214634Sdim    {
9775214634Sdim      _arm_elf_section_data *sdata;
9776214634Sdim      bfd_size_type amt = sizeof (*sdata);
9777214082Sdim
9778214634Sdim      sdata = bfd_zalloc (abfd, amt);
9779214634Sdim      if (sdata == NULL)
9780214634Sdim	return FALSE;
9781214634Sdim      sec->used_by_bfd = sdata;
9782214634Sdim    }
9783214082Sdim
9784214082Sdim  record_section_with_arm_elf_section_data (sec);
9785214082Sdim
9786214082Sdim  return _bfd_elf_new_section_hook (abfd, sec);
9787214082Sdim}
9788214082Sdim
9789214082Sdim
9790214082Sdim/* Used to order a list of mapping symbols by address.  */
9791214082Sdim
9792214082Sdimstatic int
9793214082Sdimelf32_arm_compare_mapping (const void * a, const void * b)
9794214082Sdim{
9795214082Sdim  return ((const elf32_arm_section_map *) a)->vma
9796214082Sdim	 > ((const elf32_arm_section_map *) b)->vma;
9797214082Sdim}
9798214082Sdim
9799214082Sdim
9800214082Sdim/* Do code byteswapping.  Return FALSE afterwards so that the section is
9801214082Sdim   written out as normal.  */
9802214082Sdim
9803214082Sdimstatic bfd_boolean
9804214634Sdimelf32_arm_write_section (bfd *output_bfd,
9805214634Sdim			 struct bfd_link_info *link_info, asection *sec,
9806214082Sdim			 bfd_byte *contents)
9807214082Sdim{
9808214634Sdim  int mapcount, errcount;
9809214082Sdim  _arm_elf_section_data *arm_data;
9810214634Sdim  struct elf32_arm_link_hash_table *globals = elf32_arm_hash_table (link_info);
9811214082Sdim  elf32_arm_section_map *map;
9812214634Sdim  elf32_vfp11_erratum_list *errnode;
9813214082Sdim  bfd_vma ptr;
9814214082Sdim  bfd_vma end;
9815214634Sdim  bfd_vma offset = sec->output_section->vma + sec->output_offset;
9816214082Sdim  bfd_byte tmp;
9817214082Sdim  int i;
9818214082Sdim
9819214082Sdim  /* If this section has not been allocated an _arm_elf_section_data
9820214082Sdim     structure then we cannot record anything.  */
9821214082Sdim  arm_data = get_arm_elf_section_data (sec);
9822214082Sdim  if (arm_data == NULL)
9823214082Sdim    return FALSE;
9824214082Sdim
9825214082Sdim  mapcount = arm_data->mapcount;
9826214082Sdim  map = arm_data->map;
9827214634Sdim  errcount = arm_data->erratumcount;
9828214082Sdim
9829214634Sdim  if (errcount != 0)
9830214634Sdim    {
9831214634Sdim      unsigned int endianflip = bfd_big_endian (output_bfd) ? 3 : 0;
9832214634Sdim
9833214634Sdim      for (errnode = arm_data->erratumlist; errnode != 0;
9834214634Sdim           errnode = errnode->next)
9835214634Sdim        {
9836214634Sdim          bfd_vma index = errnode->vma - offset;
9837214634Sdim
9838214634Sdim          switch (errnode->type)
9839214634Sdim            {
9840214634Sdim            case VFP11_ERRATUM_BRANCH_TO_ARM_VENEER:
9841214634Sdim              {
9842214634Sdim                bfd_vma branch_to_veneer;
9843214634Sdim                /* Original condition code of instruction, plus bit mask for
9844214634Sdim                   ARM B instruction.  */
9845214634Sdim                unsigned int insn = (errnode->u.b.vfp_insn & 0xf0000000)
9846214634Sdim                                  | 0x0a000000;
9847214634Sdim
9848214634Sdim		/* The instruction is before the label.  */
9849214634Sdim		index -= 4;
9850214634Sdim
9851214634Sdim		/* Above offset included in -4 below.  */
9852214634Sdim		branch_to_veneer = errnode->u.b.veneer->vma
9853214634Sdim                                   - errnode->vma - 4;
9854214634Sdim
9855214634Sdim		if ((signed) branch_to_veneer < -(1 << 25)
9856214634Sdim		    || (signed) branch_to_veneer >= (1 << 25))
9857214634Sdim		  (*_bfd_error_handler) (_("%B: error: VFP11 veneer out of "
9858214634Sdim					   "range"), output_bfd);
9859214634Sdim
9860214634Sdim                insn |= (branch_to_veneer >> 2) & 0xffffff;
9861214634Sdim                contents[endianflip ^ index] = insn & 0xff;
9862214634Sdim                contents[endianflip ^ (index + 1)] = (insn >> 8) & 0xff;
9863214634Sdim                contents[endianflip ^ (index + 2)] = (insn >> 16) & 0xff;
9864214634Sdim                contents[endianflip ^ (index + 3)] = (insn >> 24) & 0xff;
9865214634Sdim              }
9866214634Sdim              break;
9867214634Sdim
9868214634Sdim	    case VFP11_ERRATUM_ARM_VENEER:
9869214634Sdim              {
9870214634Sdim                bfd_vma branch_from_veneer;
9871214634Sdim                unsigned int insn;
9872214634Sdim
9873214634Sdim                /* Take size of veneer into account.  */
9874214634Sdim                branch_from_veneer = errnode->u.v.branch->vma
9875214634Sdim                                     - errnode->vma - 12;
9876214634Sdim
9877214634Sdim		if ((signed) branch_from_veneer < -(1 << 25)
9878214634Sdim		    || (signed) branch_from_veneer >= (1 << 25))
9879214634Sdim		  (*_bfd_error_handler) (_("%B: error: VFP11 veneer out of "
9880214634Sdim					   "range"), output_bfd);
9881214634Sdim
9882214634Sdim                /* Original instruction.  */
9883214634Sdim                insn = errnode->u.v.branch->u.b.vfp_insn;
9884214634Sdim                contents[endianflip ^ index] = insn & 0xff;
9885214634Sdim                contents[endianflip ^ (index + 1)] = (insn >> 8) & 0xff;
9886214634Sdim                contents[endianflip ^ (index + 2)] = (insn >> 16) & 0xff;
9887214634Sdim                contents[endianflip ^ (index + 3)] = (insn >> 24) & 0xff;
9888214634Sdim
9889214634Sdim                /* Branch back to insn after original insn.  */
9890214634Sdim                insn = 0xea000000 | ((branch_from_veneer >> 2) & 0xffffff);
9891214634Sdim                contents[endianflip ^ (index + 4)] = insn & 0xff;
9892214634Sdim                contents[endianflip ^ (index + 5)] = (insn >> 8) & 0xff;
9893214634Sdim                contents[endianflip ^ (index + 6)] = (insn >> 16) & 0xff;
9894214634Sdim                contents[endianflip ^ (index + 7)] = (insn >> 24) & 0xff;
9895214634Sdim              }
9896214634Sdim              break;
9897214634Sdim
9898214634Sdim            default:
9899214634Sdim              abort ();
9900214634Sdim            }
9901214634Sdim        }
9902214634Sdim    }
9903214634Sdim
9904214082Sdim  if (mapcount == 0)
9905214082Sdim    return FALSE;
9906214082Sdim
9907214634Sdim  if (globals->byteswap_code)
9908214082Sdim    {
9909214634Sdim      qsort (map, mapcount, sizeof (* map), elf32_arm_compare_mapping);
9910214082Sdim
9911214634Sdim      ptr = map[0].vma;
9912214634Sdim      for (i = 0; i < mapcount; i++)
9913214634Sdim        {
9914214634Sdim          if (i == mapcount - 1)
9915214634Sdim	    end = sec->size;
9916214634Sdim          else
9917214634Sdim            end = map[i + 1].vma;
9918214634Sdim
9919214634Sdim          switch (map[i].type)
9920214082Sdim	    {
9921214634Sdim	    case 'a':
9922214634Sdim	      /* Byte swap code words.  */
9923214634Sdim	      while (ptr + 3 < end)
9924214634Sdim	        {
9925214634Sdim	          tmp = contents[ptr];
9926214634Sdim	          contents[ptr] = contents[ptr + 3];
9927214634Sdim	          contents[ptr + 3] = tmp;
9928214634Sdim	          tmp = contents[ptr + 1];
9929214634Sdim	          contents[ptr + 1] = contents[ptr + 2];
9930214634Sdim	          contents[ptr + 2] = tmp;
9931214634Sdim	          ptr += 4;
9932214634Sdim	        }
9933214634Sdim	      break;
9934214082Sdim
9935214634Sdim	    case 't':
9936214634Sdim	      /* Byte swap code halfwords.  */
9937214634Sdim	      while (ptr + 1 < end)
9938214634Sdim	        {
9939214634Sdim	          tmp = contents[ptr];
9940214634Sdim	          contents[ptr] = contents[ptr + 1];
9941214634Sdim	          contents[ptr + 1] = tmp;
9942214634Sdim	          ptr += 2;
9943214634Sdim	        }
9944214634Sdim	      break;
9945214634Sdim
9946214634Sdim	    case 'd':
9947214634Sdim	      /* Leave data alone.  */
9948214634Sdim	      break;
9949214082Sdim	    }
9950214634Sdim          ptr = end;
9951214634Sdim        }
9952214082Sdim    }
9953214082Sdim
9954214082Sdim  free (map);
9955214082Sdim  arm_data->mapcount = 0;
9956214634Sdim  arm_data->mapsize = 0;
9957214082Sdim  arm_data->map = NULL;
9958214082Sdim  unrecord_section_with_arm_elf_section_data (sec);
9959214082Sdim
9960214082Sdim  return FALSE;
9961214082Sdim}
9962214082Sdim
9963214082Sdimstatic void
9964214082Sdimunrecord_section_via_map_over_sections (bfd * abfd ATTRIBUTE_UNUSED,
9965214082Sdim					asection * sec,
9966214082Sdim					void * ignore ATTRIBUTE_UNUSED)
9967214082Sdim{
9968214082Sdim  unrecord_section_with_arm_elf_section_data (sec);
9969214082Sdim}
9970214082Sdim
9971214082Sdimstatic bfd_boolean
9972214082Sdimelf32_arm_close_and_cleanup (bfd * abfd)
9973214082Sdim{
9974214634Sdim  if (abfd->sections)
9975214634Sdim    bfd_map_over_sections (abfd,
9976214634Sdim			   unrecord_section_via_map_over_sections,
9977214634Sdim			   NULL);
9978214082Sdim
9979214082Sdim  return _bfd_elf_close_and_cleanup (abfd);
9980214082Sdim}
9981214082Sdim
9982214634Sdimstatic bfd_boolean
9983214634Sdimelf32_arm_bfd_free_cached_info (bfd * abfd)
9984214634Sdim{
9985214634Sdim  if (abfd->sections)
9986214634Sdim    bfd_map_over_sections (abfd,
9987214634Sdim			   unrecord_section_via_map_over_sections,
9988214634Sdim			   NULL);
9989214634Sdim
9990214634Sdim  return _bfd_free_cached_info (abfd);
9991214634Sdim}
9992214634Sdim
9993214082Sdim/* Display STT_ARM_TFUNC symbols as functions.  */
9994214082Sdim
9995214082Sdimstatic void
9996214082Sdimelf32_arm_symbol_processing (bfd *abfd ATTRIBUTE_UNUSED,
9997214082Sdim			     asymbol *asym)
9998214082Sdim{
9999214082Sdim  elf_symbol_type *elfsym = (elf_symbol_type *) asym;
10000214082Sdim
10001214082Sdim  if (ELF_ST_TYPE (elfsym->internal_elf_sym.st_info) == STT_ARM_TFUNC)
10002214082Sdim    elfsym->symbol.flags |= BSF_FUNCTION;
10003214082Sdim}
10004214082Sdim
10005214082Sdim
10006214082Sdim/* Mangle thumb function symbols as we read them in.  */
10007214082Sdim
10008214634Sdimstatic bfd_boolean
10009214082Sdimelf32_arm_swap_symbol_in (bfd * abfd,
10010214082Sdim			  const void *psrc,
10011214082Sdim			  const void *pshn,
10012214082Sdim			  Elf_Internal_Sym *dst)
10013214082Sdim{
10014214634Sdim  if (!bfd_elf32_swap_symbol_in (abfd, psrc, pshn, dst))
10015214634Sdim    return FALSE;
10016214082Sdim
10017214082Sdim  /* New EABI objects mark thumb function symbols by setting the low bit of
10018214082Sdim     the address.  Turn these into STT_ARM_TFUNC.  */
10019214082Sdim  if (ELF_ST_TYPE (dst->st_info) == STT_FUNC
10020214082Sdim      && (dst->st_value & 1))
10021214082Sdim    {
10022214082Sdim      dst->st_info = ELF_ST_INFO (ELF_ST_BIND (dst->st_info), STT_ARM_TFUNC);
10023214082Sdim      dst->st_value &= ~(bfd_vma) 1;
10024214082Sdim    }
10025214634Sdim  return TRUE;
10026214082Sdim}
10027214082Sdim
10028214082Sdim
10029214082Sdim/* Mangle thumb function symbols as we write them out.  */
10030214082Sdim
10031214082Sdimstatic void
10032214082Sdimelf32_arm_swap_symbol_out (bfd *abfd,
10033214082Sdim			   const Elf_Internal_Sym *src,
10034214082Sdim			   void *cdst,
10035214082Sdim			   void *shndx)
10036214082Sdim{
10037214082Sdim  Elf_Internal_Sym newsym;
10038214082Sdim
10039214082Sdim  /* We convert STT_ARM_TFUNC symbols into STT_FUNC with the low bit
10040214082Sdim     of the address set, as per the new EABI.  We do this unconditionally
10041214082Sdim     because objcopy does not set the elf header flags until after
10042214082Sdim     it writes out the symbol table.  */
10043214082Sdim  if (ELF_ST_TYPE (src->st_info) == STT_ARM_TFUNC)
10044214082Sdim    {
10045214082Sdim      newsym = *src;
10046214082Sdim      newsym.st_info = ELF_ST_INFO (ELF_ST_BIND (src->st_info), STT_FUNC);
10047214634Sdim      if (newsym.st_shndx != SHN_UNDEF)
10048214634Sdim        {
10049214634Sdim          /* Do this only for defined symbols. At link type, the static
10050214634Sdim             linker will simulate the work of dynamic linker of resolving
10051214634Sdim             symbols and will carry over the thumbness of found symbols to
10052214634Sdim             the output symbol table. It's not clear how it happens, but
10053214634Sdim             the thumbness of undefined symbols can well be different at
10054214634Sdim             runtime, and writing '1' for them will be confusing for users
10055214634Sdim             and possibly for dynamic linker itself.
10056214634Sdim          */
10057214634Sdim          newsym.st_value |= 1;
10058214634Sdim        }
10059214082Sdim
10060214082Sdim      src = &newsym;
10061214082Sdim    }
10062214082Sdim  bfd_elf32_swap_symbol_out (abfd, src, cdst, shndx);
10063214082Sdim}
10064214082Sdim
10065214082Sdim/* Add the PT_ARM_EXIDX program header.  */
10066214082Sdim
10067214082Sdimstatic bfd_boolean
10068214082Sdimelf32_arm_modify_segment_map (bfd *abfd,
10069214082Sdim			      struct bfd_link_info *info ATTRIBUTE_UNUSED)
10070214082Sdim{
10071214082Sdim  struct elf_segment_map *m;
10072214082Sdim  asection *sec;
10073214082Sdim
10074214082Sdim  sec = bfd_get_section_by_name (abfd, ".ARM.exidx");
10075214082Sdim  if (sec != NULL && (sec->flags & SEC_LOAD) != 0)
10076214082Sdim    {
10077214082Sdim      /* If there is already a PT_ARM_EXIDX header, then we do not
10078214082Sdim	 want to add another one.  This situation arises when running
10079214082Sdim	 "strip"; the input binary already has the header.  */
10080214082Sdim      m = elf_tdata (abfd)->segment_map;
10081214082Sdim      while (m && m->p_type != PT_ARM_EXIDX)
10082214082Sdim	m = m->next;
10083214082Sdim      if (!m)
10084214082Sdim	{
10085214082Sdim	  m = bfd_zalloc (abfd, sizeof (struct elf_segment_map));
10086214082Sdim	  if (m == NULL)
10087214082Sdim	    return FALSE;
10088214082Sdim	  m->p_type = PT_ARM_EXIDX;
10089214082Sdim	  m->count = 1;
10090214082Sdim	  m->sections[0] = sec;
10091214082Sdim
10092214082Sdim	  m->next = elf_tdata (abfd)->segment_map;
10093214082Sdim	  elf_tdata (abfd)->segment_map = m;
10094214082Sdim	}
10095214082Sdim    }
10096214082Sdim
10097214082Sdim  return TRUE;
10098214082Sdim}
10099214082Sdim
10100214082Sdim/* We may add a PT_ARM_EXIDX program header.  */
10101214082Sdim
10102214082Sdimstatic int
10103214634Sdimelf32_arm_additional_program_headers (bfd *abfd,
10104214634Sdim				      struct bfd_link_info *info ATTRIBUTE_UNUSED)
10105214082Sdim{
10106214082Sdim  asection *sec;
10107214082Sdim
10108214082Sdim  sec = bfd_get_section_by_name (abfd, ".ARM.exidx");
10109214082Sdim  if (sec != NULL && (sec->flags & SEC_LOAD) != 0)
10110214082Sdim    return 1;
10111214082Sdim  else
10112214082Sdim    return 0;
10113214082Sdim}
10114214082Sdim
10115214634Sdim/* We have two function types: STT_FUNC and STT_ARM_TFUNC.  */
10116214634Sdimstatic bfd_boolean
10117214634Sdimelf32_arm_is_function_type (unsigned int type)
10118214634Sdim{
10119214634Sdim  return (type == STT_FUNC) || (type == STT_ARM_TFUNC);
10120214634Sdim}
10121214634Sdim
10122214082Sdim/* We use this to override swap_symbol_in and swap_symbol_out.  */
10123214082Sdimconst struct elf_size_info elf32_arm_size_info = {
10124214082Sdim  sizeof (Elf32_External_Ehdr),
10125214082Sdim  sizeof (Elf32_External_Phdr),
10126214082Sdim  sizeof (Elf32_External_Shdr),
10127214082Sdim  sizeof (Elf32_External_Rel),
10128214082Sdim  sizeof (Elf32_External_Rela),
10129214082Sdim  sizeof (Elf32_External_Sym),
10130214082Sdim  sizeof (Elf32_External_Dyn),
10131214082Sdim  sizeof (Elf_External_Note),
10132214082Sdim  4,
10133214082Sdim  1,
10134214082Sdim  32, 2,
10135214082Sdim  ELFCLASS32, EV_CURRENT,
10136214082Sdim  bfd_elf32_write_out_phdrs,
10137214082Sdim  bfd_elf32_write_shdrs_and_ehdr,
10138214082Sdim  bfd_elf32_write_relocs,
10139214082Sdim  elf32_arm_swap_symbol_in,
10140214082Sdim  elf32_arm_swap_symbol_out,
10141214082Sdim  bfd_elf32_slurp_reloc_table,
10142214082Sdim  bfd_elf32_slurp_symbol_table,
10143214082Sdim  bfd_elf32_swap_dyn_in,
10144214082Sdim  bfd_elf32_swap_dyn_out,
10145214082Sdim  bfd_elf32_swap_reloc_in,
10146214082Sdim  bfd_elf32_swap_reloc_out,
10147214082Sdim  bfd_elf32_swap_reloca_in,
10148214082Sdim  bfd_elf32_swap_reloca_out
10149214082Sdim};
10150214082Sdim
10151214082Sdim#define ELF_ARCH			bfd_arch_arm
10152214082Sdim#define ELF_MACHINE_CODE		EM_ARM
10153214082Sdim#ifdef __QNXTARGET__
10154214082Sdim#define ELF_MAXPAGESIZE			0x1000
10155214082Sdim#else
10156214082Sdim#define ELF_MAXPAGESIZE			0x8000
10157214082Sdim#endif
10158214082Sdim#define ELF_MINPAGESIZE			0x1000
10159214634Sdim#define ELF_COMMONPAGESIZE		0x1000
10160214082Sdim
10161214082Sdim#define bfd_elf32_mkobject		        elf32_arm_mkobject
10162214082Sdim
10163214082Sdim#define bfd_elf32_bfd_copy_private_bfd_data	elf32_arm_copy_private_bfd_data
10164214082Sdim#define bfd_elf32_bfd_merge_private_bfd_data	elf32_arm_merge_private_bfd_data
10165214082Sdim#define bfd_elf32_bfd_set_private_flags		elf32_arm_set_private_flags
10166214082Sdim#define bfd_elf32_bfd_print_private_bfd_data	elf32_arm_print_private_bfd_data
10167214082Sdim#define bfd_elf32_bfd_link_hash_table_create    elf32_arm_link_hash_table_create
10168214082Sdim#define bfd_elf32_bfd_reloc_type_lookup		elf32_arm_reloc_type_lookup
10169214634Sdim#define bfd_elf32_bfd_reloc_name_lookup	elf32_arm_reloc_name_lookup
10170214082Sdim#define bfd_elf32_find_nearest_line	        elf32_arm_find_nearest_line
10171214082Sdim#define bfd_elf32_find_inliner_info	        elf32_arm_find_inliner_info
10172214082Sdim#define bfd_elf32_new_section_hook		elf32_arm_new_section_hook
10173214082Sdim#define bfd_elf32_bfd_is_target_special_symbol	elf32_arm_is_target_special_symbol
10174214082Sdim#define bfd_elf32_close_and_cleanup             elf32_arm_close_and_cleanup
10175214634Sdim#define bfd_elf32_bfd_free_cached_info          elf32_arm_bfd_free_cached_info
10176214082Sdim
10177214082Sdim#define elf_backend_get_symbol_type             elf32_arm_get_symbol_type
10178214082Sdim#define elf_backend_gc_mark_hook                elf32_arm_gc_mark_hook
10179214634Sdim#define elf_backend_gc_mark_extra_sections	elf32_arm_gc_mark_extra_sections
10180214082Sdim#define elf_backend_gc_sweep_hook               elf32_arm_gc_sweep_hook
10181214082Sdim#define elf_backend_check_relocs                elf32_arm_check_relocs
10182214082Sdim#define elf_backend_relocate_section		elf32_arm_relocate_section
10183214082Sdim#define elf_backend_write_section		elf32_arm_write_section
10184214082Sdim#define elf_backend_adjust_dynamic_symbol	elf32_arm_adjust_dynamic_symbol
10185214082Sdim#define elf_backend_create_dynamic_sections     elf32_arm_create_dynamic_sections
10186214082Sdim#define elf_backend_finish_dynamic_symbol	elf32_arm_finish_dynamic_symbol
10187214082Sdim#define elf_backend_finish_dynamic_sections	elf32_arm_finish_dynamic_sections
10188214082Sdim#define elf_backend_size_dynamic_sections	elf32_arm_size_dynamic_sections
10189214634Sdim#define elf_backend_init_index_section		_bfd_elf_init_2_index_sections
10190214082Sdim#define elf_backend_post_process_headers	elf32_arm_post_process_headers
10191214082Sdim#define elf_backend_reloc_type_class		elf32_arm_reloc_type_class
10192214082Sdim#define elf_backend_object_p			elf32_arm_object_p
10193214082Sdim#define elf_backend_section_flags		elf32_arm_section_flags
10194214082Sdim#define elf_backend_fake_sections  		elf32_arm_fake_sections
10195214082Sdim#define elf_backend_section_from_shdr  		elf32_arm_section_from_shdr
10196214082Sdim#define elf_backend_final_write_processing      elf32_arm_final_write_processing
10197214082Sdim#define elf_backend_copy_indirect_symbol        elf32_arm_copy_indirect_symbol
10198214082Sdim#define elf_backend_symbol_processing		elf32_arm_symbol_processing
10199214082Sdim#define elf_backend_size_info			elf32_arm_size_info
10200214082Sdim#define elf_backend_modify_segment_map		elf32_arm_modify_segment_map
10201214082Sdim#define elf_backend_additional_program_headers \
10202214082Sdim  elf32_arm_additional_program_headers
10203214634Sdim#define elf_backend_output_arch_local_syms \
10204214634Sdim  elf32_arm_output_arch_local_syms
10205214634Sdim#define elf_backend_begin_write_processing \
10206214634Sdim    elf32_arm_begin_write_processing
10207214634Sdim#define elf_backend_is_function_type		elf32_arm_is_function_type
10208214082Sdim
10209214082Sdim#define elf_backend_can_refcount    1
10210214082Sdim#define elf_backend_can_gc_sections 1
10211214082Sdim#define elf_backend_plt_readonly    1
10212214082Sdim#define elf_backend_want_got_plt    1
10213214082Sdim#define elf_backend_want_plt_sym    0
10214214082Sdim#define elf_backend_may_use_rel_p   1
10215214082Sdim#define elf_backend_may_use_rela_p  0
10216214082Sdim#define elf_backend_default_use_rela_p 0
10217214082Sdim
10218214082Sdim#define elf_backend_got_header_size	12
10219214082Sdim
10220214634Sdim#undef elf_backend_obj_attrs_vendor
10221214634Sdim#define elf_backend_obj_attrs_vendor	"aeabi"
10222214634Sdim#undef elf_backend_obj_attrs_section
10223214634Sdim#define elf_backend_obj_attrs_section	".ARM.attributes"
10224214634Sdim#undef elf_backend_obj_attrs_arg_type
10225214634Sdim#define elf_backend_obj_attrs_arg_type	elf32_arm_obj_attrs_arg_type
10226214634Sdim#undef elf_backend_obj_attrs_section_type
10227214634Sdim#define elf_backend_obj_attrs_section_type	SHT_ARM_ATTRIBUTES
10228214634Sdim
10229214082Sdim#include "elf32-target.h"
10230214082Sdim
10231214082Sdim/* VxWorks Targets */
10232214082Sdim
10233214082Sdim#undef TARGET_LITTLE_SYM
10234214082Sdim#define TARGET_LITTLE_SYM               bfd_elf32_littlearm_vxworks_vec
10235214082Sdim#undef TARGET_LITTLE_NAME
10236214082Sdim#define TARGET_LITTLE_NAME              "elf32-littlearm-vxworks"
10237214082Sdim#undef TARGET_BIG_SYM
10238214082Sdim#define TARGET_BIG_SYM                  bfd_elf32_bigarm_vxworks_vec
10239214082Sdim#undef TARGET_BIG_NAME
10240214082Sdim#define TARGET_BIG_NAME                 "elf32-bigarm-vxworks"
10241214082Sdim
10242214082Sdim/* Like elf32_arm_link_hash_table_create -- but overrides
10243214082Sdim   appropriately for VxWorks.  */
10244214082Sdimstatic struct bfd_link_hash_table *
10245214082Sdimelf32_arm_vxworks_link_hash_table_create (bfd *abfd)
10246214082Sdim{
10247214082Sdim  struct bfd_link_hash_table *ret;
10248214082Sdim
10249214082Sdim  ret = elf32_arm_link_hash_table_create (abfd);
10250214082Sdim  if (ret)
10251214082Sdim    {
10252214082Sdim      struct elf32_arm_link_hash_table *htab
10253214082Sdim	= (struct elf32_arm_link_hash_table *) ret;
10254214082Sdim      htab->use_rel = 0;
10255214082Sdim      htab->vxworks_p = 1;
10256214082Sdim    }
10257214082Sdim  return ret;
10258214082Sdim}
10259214082Sdim
10260214082Sdimstatic void
10261214082Sdimelf32_arm_vxworks_final_write_processing (bfd *abfd, bfd_boolean linker)
10262214082Sdim{
10263214082Sdim  elf32_arm_final_write_processing (abfd, linker);
10264214082Sdim  elf_vxworks_final_write_processing (abfd, linker);
10265214082Sdim}
10266214082Sdim
10267214082Sdim#undef elf32_bed
10268214082Sdim#define elf32_bed elf32_arm_vxworks_bed
10269214082Sdim
10270214082Sdim#undef bfd_elf32_bfd_link_hash_table_create
10271214082Sdim#define bfd_elf32_bfd_link_hash_table_create \
10272214082Sdim  elf32_arm_vxworks_link_hash_table_create
10273214082Sdim#undef elf_backend_add_symbol_hook
10274214082Sdim#define elf_backend_add_symbol_hook \
10275214082Sdim  elf_vxworks_add_symbol_hook
10276214082Sdim#undef elf_backend_final_write_processing
10277214082Sdim#define elf_backend_final_write_processing \
10278214082Sdim  elf32_arm_vxworks_final_write_processing
10279214082Sdim#undef elf_backend_emit_relocs
10280214082Sdim#define elf_backend_emit_relocs \
10281214082Sdim  elf_vxworks_emit_relocs
10282214082Sdim
10283214082Sdim#undef elf_backend_may_use_rel_p
10284214082Sdim#define elf_backend_may_use_rel_p	0
10285214082Sdim#undef elf_backend_may_use_rela_p
10286214082Sdim#define elf_backend_may_use_rela_p	1
10287214082Sdim#undef elf_backend_default_use_rela_p
10288214082Sdim#define elf_backend_default_use_rela_p	1
10289214082Sdim#undef elf_backend_want_plt_sym
10290214082Sdim#define elf_backend_want_plt_sym	1
10291214082Sdim#undef ELF_MAXPAGESIZE
10292214082Sdim#define ELF_MAXPAGESIZE			0x1000
10293214082Sdim
10294214082Sdim#include "elf32-target.h"
10295214082Sdim
10296214082Sdim
10297214082Sdim/* Symbian OS Targets */
10298214082Sdim
10299214082Sdim#undef TARGET_LITTLE_SYM
10300214082Sdim#define TARGET_LITTLE_SYM               bfd_elf32_littlearm_symbian_vec
10301214082Sdim#undef TARGET_LITTLE_NAME
10302214082Sdim#define TARGET_LITTLE_NAME              "elf32-littlearm-symbian"
10303214082Sdim#undef TARGET_BIG_SYM
10304214082Sdim#define TARGET_BIG_SYM                  bfd_elf32_bigarm_symbian_vec
10305214082Sdim#undef TARGET_BIG_NAME
10306214082Sdim#define TARGET_BIG_NAME                 "elf32-bigarm-symbian"
10307214082Sdim
10308214082Sdim/* Like elf32_arm_link_hash_table_create -- but overrides
10309214082Sdim   appropriately for Symbian OS.  */
10310214082Sdimstatic struct bfd_link_hash_table *
10311214082Sdimelf32_arm_symbian_link_hash_table_create (bfd *abfd)
10312214082Sdim{
10313214082Sdim  struct bfd_link_hash_table *ret;
10314214082Sdim
10315214082Sdim  ret = elf32_arm_link_hash_table_create (abfd);
10316214082Sdim  if (ret)
10317214082Sdim    {
10318214082Sdim      struct elf32_arm_link_hash_table *htab
10319214082Sdim	= (struct elf32_arm_link_hash_table *)ret;
10320214082Sdim      /* There is no PLT header for Symbian OS.  */
10321214082Sdim      htab->plt_header_size = 0;
10322214082Sdim      /* The PLT entries are each three instructions.  */
10323214082Sdim      htab->plt_entry_size = 4 * NUM_ELEM (elf32_arm_symbian_plt_entry);
10324214082Sdim      htab->symbian_p = 1;
10325214082Sdim      /* Symbian uses armv5t or above, so use_blx is always true.  */
10326214082Sdim      htab->use_blx = 1;
10327214082Sdim      htab->root.is_relocatable_executable = 1;
10328214082Sdim    }
10329214082Sdim  return ret;
10330214082Sdim}
10331214082Sdim
10332214082Sdimstatic const struct bfd_elf_special_section
10333214082Sdimelf32_arm_symbian_special_sections[] =
10334214082Sdim{
10335214082Sdim  /* In a BPABI executable, the dynamic linking sections do not go in
10336214082Sdim     the loadable read-only segment.  The post-linker may wish to
10337214082Sdim     refer to these sections, but they are not part of the final
10338214082Sdim     program image.  */
10339214634Sdim  { STRING_COMMA_LEN (".dynamic"),       0, SHT_DYNAMIC,  0 },
10340214634Sdim  { STRING_COMMA_LEN (".dynstr"),        0, SHT_STRTAB,   0 },
10341214634Sdim  { STRING_COMMA_LEN (".dynsym"),        0, SHT_DYNSYM,   0 },
10342214634Sdim  { STRING_COMMA_LEN (".got"),           0, SHT_PROGBITS, 0 },
10343214634Sdim  { STRING_COMMA_LEN (".hash"),          0, SHT_HASH,     0 },
10344214082Sdim  /* These sections do not need to be writable as the SymbianOS
10345214082Sdim     postlinker will arrange things so that no dynamic relocation is
10346214082Sdim     required.  */
10347214634Sdim  { STRING_COMMA_LEN (".init_array"),    0, SHT_INIT_ARRAY,    SHF_ALLOC },
10348214634Sdim  { STRING_COMMA_LEN (".fini_array"),    0, SHT_FINI_ARRAY,    SHF_ALLOC },
10349214634Sdim  { STRING_COMMA_LEN (".preinit_array"), 0, SHT_PREINIT_ARRAY, SHF_ALLOC },
10350214634Sdim  { NULL,                             0, 0, 0,                 0 }
10351214082Sdim};
10352214082Sdim
10353214082Sdimstatic void
10354214082Sdimelf32_arm_symbian_begin_write_processing (bfd *abfd,
10355214634Sdim					  struct bfd_link_info *link_info)
10356214082Sdim{
10357214082Sdim  /* BPABI objects are never loaded directly by an OS kernel; they are
10358214082Sdim     processed by a postlinker first, into an OS-specific format.  If
10359214082Sdim     the D_PAGED bit is set on the file, BFD will align segments on
10360214082Sdim     page boundaries, so that an OS can directly map the file.  With
10361214082Sdim     BPABI objects, that just results in wasted space.  In addition,
10362214082Sdim     because we clear the D_PAGED bit, map_sections_to_segments will
10363214082Sdim     recognize that the program headers should not be mapped into any
10364214082Sdim     loadable segment.  */
10365214082Sdim  abfd->flags &= ~D_PAGED;
10366214634Sdim  elf32_arm_begin_write_processing(abfd, link_info);
10367214082Sdim}
10368214082Sdim
10369214082Sdimstatic bfd_boolean
10370214082Sdimelf32_arm_symbian_modify_segment_map (bfd *abfd,
10371214082Sdim				      struct bfd_link_info *info)
10372214082Sdim{
10373214082Sdim  struct elf_segment_map *m;
10374214082Sdim  asection *dynsec;
10375214082Sdim
10376214082Sdim  /* BPABI shared libraries and executables should have a PT_DYNAMIC
10377214082Sdim     segment.  However, because the .dynamic section is not marked
10378214082Sdim     with SEC_LOAD, the generic ELF code will not create such a
10379214082Sdim     segment.  */
10380214082Sdim  dynsec = bfd_get_section_by_name (abfd, ".dynamic");
10381214082Sdim  if (dynsec)
10382214082Sdim    {
10383214634Sdim      for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
10384214634Sdim	if (m->p_type == PT_DYNAMIC)
10385214634Sdim	  break;
10386214634Sdim
10387214634Sdim      if (m == NULL)
10388214634Sdim	{
10389214634Sdim	  m = _bfd_elf_make_dynamic_segment (abfd, dynsec);
10390214634Sdim	  m->next = elf_tdata (abfd)->segment_map;
10391214634Sdim	  elf_tdata (abfd)->segment_map = m;
10392214634Sdim	}
10393214082Sdim    }
10394214082Sdim
10395214082Sdim  /* Also call the generic arm routine.  */
10396214082Sdim  return elf32_arm_modify_segment_map (abfd, info);
10397214082Sdim}
10398214082Sdim
10399214082Sdim#undef elf32_bed
10400214082Sdim#define elf32_bed elf32_arm_symbian_bed
10401214082Sdim
10402214082Sdim/* The dynamic sections are not allocated on SymbianOS; the postlinker
10403214082Sdim   will process them and then discard them.  */
10404214082Sdim#undef ELF_DYNAMIC_SEC_FLAGS
10405214082Sdim#define ELF_DYNAMIC_SEC_FLAGS \
10406214082Sdim  (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED)
10407214082Sdim
10408214082Sdim#undef bfd_elf32_bfd_link_hash_table_create
10409214082Sdim#define bfd_elf32_bfd_link_hash_table_create \
10410214082Sdim  elf32_arm_symbian_link_hash_table_create
10411214082Sdim#undef elf_backend_add_symbol_hook
10412214082Sdim
10413214082Sdim#undef elf_backend_special_sections
10414214082Sdim#define elf_backend_special_sections elf32_arm_symbian_special_sections
10415214082Sdim
10416214082Sdim#undef elf_backend_begin_write_processing
10417214082Sdim#define elf_backend_begin_write_processing \
10418214082Sdim    elf32_arm_symbian_begin_write_processing
10419214082Sdim#undef elf_backend_final_write_processing
10420214082Sdim#define elf_backend_final_write_processing \
10421214082Sdim  elf32_arm_final_write_processing
10422214082Sdim#undef elf_backend_emit_relocs
10423214082Sdim
10424214082Sdim#undef elf_backend_modify_segment_map
10425214082Sdim#define elf_backend_modify_segment_map elf32_arm_symbian_modify_segment_map
10426214082Sdim
10427214082Sdim/* There is no .got section for BPABI objects, and hence no header.  */
10428214082Sdim#undef elf_backend_got_header_size
10429214082Sdim#define elf_backend_got_header_size 0
10430214082Sdim
10431214082Sdim/* Similarly, there is no .got.plt section.  */
10432214082Sdim#undef elf_backend_want_got_plt
10433214082Sdim#define elf_backend_want_got_plt 0
10434214082Sdim
10435214082Sdim#undef elf_backend_may_use_rel_p
10436214082Sdim#define elf_backend_may_use_rel_p	1
10437214082Sdim#undef elf_backend_may_use_rela_p
10438214082Sdim#define elf_backend_may_use_rela_p	0
10439214082Sdim#undef elf_backend_default_use_rela_p
10440214082Sdim#define elf_backend_default_use_rela_p	0
10441214082Sdim#undef elf_backend_want_plt_sym
10442214082Sdim#define elf_backend_want_plt_sym	0
10443214082Sdim#undef ELF_MAXPAGESIZE
10444214082Sdim#define ELF_MAXPAGESIZE			0x8000
10445214082Sdim
10446214082Sdim#include "elf32-target.h"
10447