1/* 32-bit ELF support for ARM new abi option.
2   Copyright 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3
4   This file is part of BFD, the Binary File Descriptor library.
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
19
20#include "elf/arm.h"
21#include "bfd.h"
22#include "sysdep.h"
23#include "libbfd.h"
24#include "elf-bfd.h"
25
26#ifndef NUM_ELEM
27#define NUM_ELEM(a)  (sizeof (a) / (sizeof (a)[0]))
28#endif
29
30#define USE_REL	1
31
32#define elf_info_to_howto               0
33#define elf_info_to_howto_rel           elf32_arm_info_to_howto
34
35#define ARM_ELF_ABI_VERSION		0
36#define ARM_ELF_OS_ABI_VERSION		ELFOSABI_ARM
37
38static reloc_howto_type * elf32_arm_reloc_type_lookup
39  PARAMS ((bfd * abfd, bfd_reloc_code_real_type code));
40static bfd_boolean elf32_arm_nabi_grok_prstatus
41  PARAMS ((bfd *abfd, Elf_Internal_Note *note));
42static bfd_boolean elf32_arm_nabi_grok_psinfo
43  PARAMS ((bfd *abfd, Elf_Internal_Note *note));
44
45/* Note: code such as elf32_arm_reloc_type_lookup expect to use e.g.
46   R_ARM_PC24 as an index into this, and find the R_ARM_PC24 HOWTO
47   in that slot.  */
48
49static reloc_howto_type elf32_arm_howto_table[] =
50{
51  /* No relocation */
52  HOWTO (R_ARM_NONE,		/* type */
53	 0,			/* rightshift */
54	 0,			/* size (0 = byte, 1 = short, 2 = long) */
55	 0,			/* bitsize */
56	 FALSE,			/* pc_relative */
57	 0,			/* bitpos */
58	 complain_overflow_dont,/* complain_on_overflow */
59	 bfd_elf_generic_reloc,	/* special_function */
60	 "R_ARM_NONE",		/* name */
61	 FALSE,			/* partial_inplace */
62	 0,			/* src_mask */
63	 0,			/* dst_mask */
64	 FALSE),		/* pcrel_offset */
65
66  HOWTO (R_ARM_PC24,		/* type */
67	 2,			/* rightshift */
68	 2,			/* size (0 = byte, 1 = short, 2 = long) */
69	 24,			/* bitsize */
70	 TRUE,			/* pc_relative */
71	 0,			/* bitpos */
72	 complain_overflow_signed,/* complain_on_overflow */
73	 bfd_elf_generic_reloc,	/* special_function */
74	 "R_ARM_PC24",		/* name */
75	 FALSE,			/* partial_inplace */
76	 0x00ffffff,		/* src_mask */
77	 0x00ffffff,		/* dst_mask */
78	 TRUE),			/* pcrel_offset */
79
80  /* 32 bit absolute */
81  HOWTO (R_ARM_ABS32,		/* type */
82	 0,			/* rightshift */
83	 2,			/* size (0 = byte, 1 = short, 2 = long) */
84	 32,			/* bitsize */
85	 FALSE,			/* pc_relative */
86	 0,			/* bitpos */
87	 complain_overflow_bitfield,/* complain_on_overflow */
88	 bfd_elf_generic_reloc,	/* special_function */
89	 "R_ARM_ABS32",		/* name */
90	 FALSE,			/* partial_inplace */
91	 0xffffffff,		/* src_mask */
92	 0xffffffff,		/* dst_mask */
93	 FALSE),		/* pcrel_offset */
94
95  /* standard 32bit pc-relative reloc */
96  HOWTO (R_ARM_REL32,		/* type */
97	 0,			/* rightshift */
98	 2,			/* size (0 = byte, 1 = short, 2 = long) */
99	 32,			/* bitsize */
100	 TRUE,			/* pc_relative */
101	 0,			/* bitpos */
102	 complain_overflow_bitfield,/* complain_on_overflow */
103	 bfd_elf_generic_reloc,	/* special_function */
104	 "R_ARM_REL32",		/* name */
105	 FALSE,			/* partial_inplace */
106	 0xffffffff,		/* src_mask */
107	 0xffffffff,		/* dst_mask */
108	 TRUE),			/* pcrel_offset */
109
110  /* 8 bit absolute */
111  HOWTO (R_ARM_PC13,		/* type */
112	 0,			/* rightshift */
113	 0,			/* size (0 = byte, 1 = short, 2 = long) */
114	 8,			/* bitsize */
115	 FALSE,			/* pc_relative */
116	 0,			/* bitpos */
117	 complain_overflow_bitfield,/* complain_on_overflow */
118	 bfd_elf_generic_reloc,	/* special_function */
119	 "R_ARM_PC13",		/* name */
120	 FALSE,			/* partial_inplace */
121	 0x000000ff,		/* src_mask */
122	 0x000000ff,		/* dst_mask */
123	 FALSE),		/* pcrel_offset */
124
125   /* 16 bit absolute */
126  HOWTO (R_ARM_ABS16,		/* type */
127	 0,			/* rightshift */
128	 1,			/* size (0 = byte, 1 = short, 2 = long) */
129	 16,			/* bitsize */
130	 FALSE,			/* pc_relative */
131	 0,			/* bitpos */
132	 complain_overflow_bitfield,/* complain_on_overflow */
133	 bfd_elf_generic_reloc,	/* special_function */
134	 "R_ARM_ABS16",		/* name */
135	 FALSE,			/* partial_inplace */
136	 0x0000ffff,		/* src_mask */
137	 0x0000ffff,		/* dst_mask */
138	 FALSE),		/* pcrel_offset */
139
140  /* 12 bit absolute */
141  HOWTO (R_ARM_ABS12,		/* type */
142	 0,			/* rightshift */
143	 2,			/* size (0 = byte, 1 = short, 2 = long) */
144	 12,			/* bitsize */
145	 FALSE,			/* pc_relative */
146	 0,			/* bitpos */
147	 complain_overflow_bitfield,/* complain_on_overflow */
148	 bfd_elf_generic_reloc,	/* special_function */
149	 "R_ARM_ABS12",		/* name */
150	 FALSE,			/* partial_inplace */
151	 0x000008ff,		/* src_mask */
152	 0x000008ff,		/* dst_mask */
153	 FALSE),		/* pcrel_offset */
154
155  HOWTO (R_ARM_THM_ABS5,	/* type */
156	 6,			/* rightshift */
157	 1,			/* size (0 = byte, 1 = short, 2 = long) */
158	 5,			/* bitsize */
159	 FALSE,			/* pc_relative */
160	 0,			/* bitpos */
161	 complain_overflow_bitfield,/* complain_on_overflow */
162	 bfd_elf_generic_reloc,	/* special_function */
163	 "R_ARM_THM_ABS5",	/* name */
164	 FALSE,			/* partial_inplace */
165	 0x000007e0,		/* src_mask */
166	 0x000007e0,		/* dst_mask */
167	 FALSE),		/* pcrel_offset */
168
169  /* 8 bit absolute */
170  HOWTO (R_ARM_ABS8,		/* type */
171	 0,			/* rightshift */
172	 0,			/* size (0 = byte, 1 = short, 2 = long) */
173	 8,			/* bitsize */
174	 FALSE,			/* pc_relative */
175	 0,			/* bitpos */
176	 complain_overflow_bitfield,/* complain_on_overflow */
177	 bfd_elf_generic_reloc,	/* special_function */
178	 "R_ARM_ABS8",		/* name */
179	 FALSE,			/* partial_inplace */
180	 0x000000ff,		/* src_mask */
181	 0x000000ff,		/* dst_mask */
182	 FALSE),		/* pcrel_offset */
183
184  HOWTO (R_ARM_SBREL32,		/* type */
185	 0,			/* rightshift */
186	 2,			/* size (0 = byte, 1 = short, 2 = long) */
187	 32,			/* bitsize */
188	 FALSE,			/* pc_relative */
189	 0,			/* bitpos */
190	 complain_overflow_dont,/* complain_on_overflow */
191	 bfd_elf_generic_reloc,	/* special_function */
192	 "R_ARM_SBREL32",	/* name */
193	 FALSE,			/* partial_inplace */
194	 0xffffffff,		/* src_mask */
195	 0xffffffff,		/* dst_mask */
196	 FALSE),		/* pcrel_offset */
197
198  HOWTO (R_ARM_THM_PC22,	/* type */
199	 1,			/* rightshift */
200	 2,			/* size (0 = byte, 1 = short, 2 = long) */
201	 23,			/* bitsize */
202	 TRUE,			/* pc_relative */
203	 0,			/* bitpos */
204	 complain_overflow_signed,/* complain_on_overflow */
205	 bfd_elf_generic_reloc,	/* special_function */
206	 "R_ARM_THM_PC22",	/* name */
207	 FALSE,			/* partial_inplace */
208	 0x07ff07ff,		/* src_mask */
209	 0x07ff07ff,		/* dst_mask */
210	 TRUE),			/* pcrel_offset */
211
212  HOWTO (R_ARM_THM_PC8,	        /* type */
213	 1,			/* rightshift */
214	 1,			/* size (0 = byte, 1 = short, 2 = long) */
215	 8,			/* bitsize */
216	 TRUE,			/* pc_relative */
217	 0,			/* bitpos */
218	 complain_overflow_signed,/* complain_on_overflow */
219	 bfd_elf_generic_reloc,	/* special_function */
220	 "R_ARM_THM_PC8",	/* name */
221	 FALSE,			/* partial_inplace */
222	 0x000000ff,		/* src_mask */
223	 0x000000ff,		/* dst_mask */
224	 TRUE),			/* pcrel_offset */
225
226  HOWTO (R_ARM_AMP_VCALL9,	/* type */
227	 1,			/* rightshift */
228	 1,			/* size (0 = byte, 1 = short, 2 = long) */
229	 8,			/* bitsize */
230	 TRUE,			/* pc_relative */
231	 0,			/* bitpos */
232	 complain_overflow_signed,/* complain_on_overflow */
233	 bfd_elf_generic_reloc,	/* special_function */
234	 "R_ARM_AMP_VCALL9",	/* name */
235	 FALSE,			/* partial_inplace */
236	 0x000000ff,		/* src_mask */
237	 0x000000ff,		/* dst_mask */
238	 TRUE),			/* pcrel_offset */
239
240  HOWTO (R_ARM_SWI24,		/* type */
241	 0,			/* rightshift */
242	 0,			/* size (0 = byte, 1 = short, 2 = long) */
243	 0,			/* bitsize */
244	 FALSE,			/* pc_relative */
245	 0,			/* bitpos */
246	 complain_overflow_signed,/* complain_on_overflow */
247	 bfd_elf_generic_reloc,	/* special_function */
248	 "R_ARM_SWI24",		/* name */
249	 FALSE,			/* partial_inplace */
250	 0x00000000,		/* src_mask */
251	 0x00000000,		/* dst_mask */
252	 FALSE),		/* pcrel_offset */
253
254  HOWTO (R_ARM_THM_SWI8,	/* type */
255	 0,			/* rightshift */
256	 0,			/* size (0 = byte, 1 = short, 2 = long) */
257	 0,			/* bitsize */
258	 FALSE,			/* pc_relative */
259	 0,			/* bitpos */
260	 complain_overflow_signed,/* complain_on_overflow */
261	 bfd_elf_generic_reloc,	/* special_function */
262	 "R_ARM_SWI8",		/* name */
263	 FALSE,			/* partial_inplace */
264	 0x00000000,		/* src_mask */
265	 0x00000000,		/* dst_mask */
266	 FALSE),		/* pcrel_offset */
267
268  /* BLX instruction for the ARM.  */
269  HOWTO (R_ARM_XPC25,		/* type */
270	 2,			/* rightshift */
271	 2,			/* size (0 = byte, 1 = short, 2 = long) */
272	 25,			/* bitsize */
273	 TRUE,			/* pc_relative */
274	 0,			/* bitpos */
275	 complain_overflow_signed,/* complain_on_overflow */
276	 bfd_elf_generic_reloc,	/* special_function */
277	 "R_ARM_XPC25",		/* name */
278	 FALSE,			/* partial_inplace */
279	 0x00ffffff,		/* src_mask */
280	 0x00ffffff,		/* dst_mask */
281	 TRUE),			/* pcrel_offset */
282
283  /* BLX instruction for the Thumb.  */
284  HOWTO (R_ARM_THM_XPC22,	/* type */
285	 2,			/* rightshift */
286	 2,			/* size (0 = byte, 1 = short, 2 = long) */
287	 22,			/* bitsize */
288	 TRUE,			/* pc_relative */
289	 0,			/* bitpos */
290	 complain_overflow_signed,/* complain_on_overflow */
291	 bfd_elf_generic_reloc,	/* special_function */
292	 "R_ARM_THM_XPC22",	/* name */
293	 FALSE,			/* partial_inplace */
294	 0x07ff07ff,		/* src_mask */
295	 0x07ff07ff,		/* dst_mask */
296	 TRUE),			/* pcrel_offset */
297
298  /* These next three relocs are not defined, but we need to fill the space.  */
299
300  HOWTO (R_ARM_NONE,		/* type */
301	 0,			/* rightshift */
302	 0,			/* size (0 = byte, 1 = short, 2 = long) */
303	 0,			/* bitsize */
304	 FALSE,			/* pc_relative */
305	 0,			/* bitpos */
306	 complain_overflow_dont,/* complain_on_overflow */
307	 bfd_elf_generic_reloc,	/* special_function */
308	 "R_ARM_unknown_17",	/* name */
309	 FALSE,			/* partial_inplace */
310	 0,			/* src_mask */
311	 0,			/* dst_mask */
312	 FALSE),		/* pcrel_offset */
313
314  HOWTO (R_ARM_NONE,		/* type */
315	 0,			/* rightshift */
316	 0,			/* size (0 = byte, 1 = short, 2 = long) */
317	 0,			/* bitsize */
318	 FALSE,			/* pc_relative */
319	 0,			/* bitpos */
320	 complain_overflow_dont,/* complain_on_overflow */
321	 bfd_elf_generic_reloc,	/* special_function */
322	 "R_ARM_unknown_18",	/* name */
323	 FALSE,			/* partial_inplace */
324	 0,			/* src_mask */
325	 0,			/* dst_mask */
326	 FALSE),		/* pcrel_offset */
327
328  HOWTO (R_ARM_NONE,		/* type */
329	 0,			/* rightshift */
330	 0,			/* size (0 = byte, 1 = short, 2 = long) */
331	 0,			/* bitsize */
332	 FALSE,			/* pc_relative */
333	 0,			/* bitpos */
334	 complain_overflow_dont,/* complain_on_overflow */
335	 bfd_elf_generic_reloc,	/* special_function */
336	 "R_ARM_unknown_19",	/* name */
337	 FALSE,			/* partial_inplace */
338	 0,			/* src_mask */
339	 0,			/* dst_mask */
340	 FALSE),		/* pcrel_offset */
341
342  /* Relocs used in ARM Linux */
343
344  HOWTO (R_ARM_COPY,		/* type */
345         0,                     /* rightshift */
346         2,                     /* size (0 = byte, 1 = short, 2 = long) */
347         32,                    /* bitsize */
348         FALSE,                 /* pc_relative */
349         0,                     /* bitpos */
350         complain_overflow_bitfield,/* complain_on_overflow */
351         bfd_elf_generic_reloc, /* special_function */
352         "R_ARM_COPY",		/* name */
353         TRUE,			/* partial_inplace */
354         0xffffffff,		/* src_mask */
355         0xffffffff,		/* dst_mask */
356         FALSE),                /* pcrel_offset */
357
358  HOWTO (R_ARM_GLOB_DAT,	/* type */
359         0,                     /* rightshift */
360         2,                     /* size (0 = byte, 1 = short, 2 = long) */
361         32,                    /* bitsize */
362         FALSE,                 /* pc_relative */
363         0,                     /* bitpos */
364         complain_overflow_bitfield,/* complain_on_overflow */
365         bfd_elf_generic_reloc, /* special_function */
366         "R_ARM_GLOB_DAT",	/* name */
367         TRUE,			/* partial_inplace */
368         0xffffffff,		/* src_mask */
369         0xffffffff,		/* dst_mask */
370         FALSE),                /* pcrel_offset */
371
372  HOWTO (R_ARM_JUMP_SLOT,	/* type */
373         0,                     /* rightshift */
374         2,                     /* size (0 = byte, 1 = short, 2 = long) */
375         32,                    /* bitsize */
376         FALSE,                 /* pc_relative */
377         0,                     /* bitpos */
378         complain_overflow_bitfield,/* complain_on_overflow */
379         bfd_elf_generic_reloc, /* special_function */
380         "R_ARM_JUMP_SLOT",	/* name */
381         TRUE,			/* partial_inplace */
382         0xffffffff,		/* src_mask */
383         0xffffffff,		/* dst_mask */
384         FALSE),                /* pcrel_offset */
385
386  HOWTO (R_ARM_RELATIVE,	/* type */
387         0,                     /* rightshift */
388         2,                     /* size (0 = byte, 1 = short, 2 = long) */
389         32,                    /* bitsize */
390         FALSE,                 /* pc_relative */
391         0,                     /* bitpos */
392         complain_overflow_bitfield,/* complain_on_overflow */
393         bfd_elf_generic_reloc, /* special_function */
394         "R_ARM_RELATIVE",	/* name */
395         TRUE,			/* partial_inplace */
396         0xffffffff,		/* src_mask */
397         0xffffffff,		/* dst_mask */
398         FALSE),                /* pcrel_offset */
399
400  HOWTO (R_ARM_GOTOFF,		/* type */
401         0,                     /* rightshift */
402         2,                     /* size (0 = byte, 1 = short, 2 = long) */
403         32,                    /* bitsize */
404         FALSE,                 /* pc_relative */
405         0,                     /* bitpos */
406         complain_overflow_bitfield,/* complain_on_overflow */
407         bfd_elf_generic_reloc, /* special_function */
408         "R_ARM_GOTOFF",	/* name */
409         TRUE,			/* partial_inplace */
410         0xffffffff,		/* src_mask */
411         0xffffffff,		/* dst_mask */
412         FALSE),                /* pcrel_offset */
413
414  HOWTO (R_ARM_GOTPC,		/* type */
415         0,                     /* rightshift */
416         2,                     /* size (0 = byte, 1 = short, 2 = long) */
417         32,                    /* bitsize */
418         TRUE,			/* pc_relative */
419         0,                     /* bitpos */
420         complain_overflow_bitfield,/* complain_on_overflow */
421         bfd_elf_generic_reloc, /* special_function */
422         "R_ARM_GOTPC",		/* name */
423         TRUE,			/* partial_inplace */
424         0xffffffff,		/* src_mask */
425         0xffffffff,		/* dst_mask */
426         TRUE),			/* pcrel_offset */
427
428  HOWTO (R_ARM_GOT32,		/* type */
429         0,                     /* rightshift */
430         2,                     /* size (0 = byte, 1 = short, 2 = long) */
431         32,                    /* bitsize */
432         FALSE,			/* pc_relative */
433         0,                     /* bitpos */
434         complain_overflow_bitfield,/* complain_on_overflow */
435         bfd_elf_generic_reloc, /* special_function */
436         "R_ARM_GOT32",		/* name */
437         TRUE,			/* partial_inplace */
438         0xffffffff,		/* src_mask */
439         0xffffffff,		/* dst_mask */
440         FALSE),		/* pcrel_offset */
441
442  HOWTO (R_ARM_PLT32,		/* type */
443         2,                     /* rightshift */
444         2,                     /* size (0 = byte, 1 = short, 2 = long) */
445         26,                    /* bitsize */
446         TRUE,			/* pc_relative */
447         0,                     /* bitpos */
448         complain_overflow_bitfield,/* complain_on_overflow */
449         bfd_elf_generic_reloc, /* special_function */
450         "R_ARM_PLT32",		/* name */
451         TRUE,			/* partial_inplace */
452         0x00ffffff,		/* src_mask */
453         0x00ffffff,		/* dst_mask */
454         TRUE),			/* pcrel_offset */
455
456  /* End of relocs used in ARM Linux */
457
458  HOWTO (R_ARM_RREL32,		/* type */
459	 0,			/* rightshift */
460	 0,			/* size (0 = byte, 1 = short, 2 = long) */
461	 0,			/* bitsize */
462	 FALSE,			/* pc_relative */
463	 0,			/* bitpos */
464	 complain_overflow_dont,/* complain_on_overflow */
465	 bfd_elf_generic_reloc,	/* special_function */
466	 "R_ARM_RREL32",	/* name */
467	 FALSE,			/* partial_inplace */
468	 0,			/* src_mask */
469	 0,			/* dst_mask */
470	 FALSE),		/* pcrel_offset */
471
472  HOWTO (R_ARM_RABS32,		/* type */
473	 0,			/* rightshift */
474	 0,			/* size (0 = byte, 1 = short, 2 = long) */
475	 0,			/* bitsize */
476	 FALSE,			/* pc_relative */
477	 0,			/* bitpos */
478	 complain_overflow_dont,/* complain_on_overflow */
479	 bfd_elf_generic_reloc,	/* special_function */
480	 "R_ARM_RABS32",	/* name */
481	 FALSE,			/* partial_inplace */
482	 0,			/* src_mask */
483	 0,			/* dst_mask */
484	 FALSE),		/* pcrel_offset */
485
486  HOWTO (R_ARM_RPC24,		/* type */
487	 0,			/* rightshift */
488	 0,			/* size (0 = byte, 1 = short, 2 = long) */
489	 0,			/* bitsize */
490	 FALSE,			/* pc_relative */
491	 0,			/* bitpos */
492	 complain_overflow_dont,/* complain_on_overflow */
493	 bfd_elf_generic_reloc,	/* special_function */
494	 "R_ARM_RPC24",		/* name */
495	 FALSE,			/* partial_inplace */
496	 0,			/* src_mask */
497	 0,			/* dst_mask */
498	 FALSE),		/* pcrel_offset */
499
500  HOWTO (R_ARM_RBASE,		/* type */
501	 0,			/* rightshift */
502	 0,			/* size (0 = byte, 1 = short, 2 = long) */
503	 0,			/* bitsize */
504	 FALSE,			/* pc_relative */
505	 0,			/* bitpos */
506	 complain_overflow_dont,/* complain_on_overflow */
507	 bfd_elf_generic_reloc,	/* special_function */
508	 "R_ARM_RBASE",		/* name */
509	 FALSE,			/* partial_inplace */
510	 0,			/* src_mask */
511	 0,			/* dst_mask */
512	 FALSE),		/* pcrel_offset */
513
514  HOWTO (R_ARM_ALU_PCREL7_0,	/* type */
515	 0,			/* rightshift */
516	 2,			/* size (0 = byte, 1 = short, 2 = long) */
517	 12,			/* bitsize */
518	 TRUE,			/* pc_relative */
519	 0,			/* bitpos */
520	 complain_overflow_dont,/* complain_on_overflow */
521	 bfd_elf_generic_reloc,	/* special_function */
522	 "R_ARM_ALU_PCREL_7_0",	/* name */
523	 FALSE,			/* partial_inplace */
524	 0x00000fff,		/* src_mask */
525	 0x00000fff,		/* dst_mask */
526	 TRUE),			/* pcrel_offset */
527
528  HOWTO (R_ARM_ALU_PCREL15_8,	/* type */
529	 0,			/* rightshift */
530	 2,			/* size (0 = byte, 1 = short, 2 = long) */
531	 12,			/* bitsize */
532	 TRUE,			/* pc_relative */
533	 8,			/* bitpos */
534	 complain_overflow_dont,/* complain_on_overflow */
535	 bfd_elf_generic_reloc,	/* special_function */
536	 "R_ARM_ALU_PCREL_15_8",/* name */
537	 FALSE,			/* partial_inplace */
538	 0x00000fff,		/* src_mask */
539	 0x00000fff,		/* dst_mask */
540	 TRUE),			/* pcrel_offset */
541
542  HOWTO (R_ARM_ALU_PCREL23_15,	/* type */
543	 0,			/* rightshift */
544	 2,			/* size (0 = byte, 1 = short, 2 = long) */
545	 12,			/* bitsize */
546	 TRUE,			/* pc_relative */
547	 16,			/* bitpos */
548	 complain_overflow_dont,/* complain_on_overflow */
549	 bfd_elf_generic_reloc,	/* special_function */
550	 "R_ARM_ALU_PCREL_23_15",/* name */
551	 FALSE,			/* partial_inplace */
552	 0x00000fff,		/* src_mask */
553	 0x00000fff,		/* dst_mask */
554	 TRUE),			/* pcrel_offset */
555
556  HOWTO (R_ARM_LDR_SBREL_11_0,	/* type */
557	 0,			/* rightshift */
558	 2,			/* size (0 = byte, 1 = short, 2 = long) */
559	 12,			/* bitsize */
560	 FALSE,			/* pc_relative */
561	 0,			/* bitpos */
562	 complain_overflow_dont,/* complain_on_overflow */
563	 bfd_elf_generic_reloc,	/* special_function */
564	 "R_ARM_LDR_SBREL_11_0",/* name */
565	 FALSE,			/* partial_inplace */
566	 0x00000fff,		/* src_mask */
567	 0x00000fff,		/* dst_mask */
568	 FALSE),		/* pcrel_offset */
569
570  HOWTO (R_ARM_ALU_SBREL_19_12,	/* type */
571	 0,			/* rightshift */
572	 2,			/* size (0 = byte, 1 = short, 2 = long) */
573	 8,			/* bitsize */
574	 FALSE,			/* pc_relative */
575	 12,			/* bitpos */
576	 complain_overflow_dont,/* complain_on_overflow */
577	 bfd_elf_generic_reloc,	/* special_function */
578	 "R_ARM_ALU_SBREL_19_12",/* name */
579	 FALSE,			/* partial_inplace */
580	 0x000ff000,		/* src_mask */
581	 0x000ff000,		/* dst_mask */
582	 FALSE),		/* pcrel_offset */
583
584  HOWTO (R_ARM_ALU_SBREL_27_20,	/* type */
585	 0,			/* rightshift */
586	 2,			/* size (0 = byte, 1 = short, 2 = long) */
587	 8,			/* bitsize */
588	 FALSE,			/* pc_relative */
589	 20,			/* bitpos */
590	 complain_overflow_dont,/* complain_on_overflow */
591	 bfd_elf_generic_reloc,	/* special_function */
592	 "R_ARM_ALU_SBREL_27_20",/* name */
593	 FALSE,			/* partial_inplace */
594	 0x0ff00000,		/* src_mask */
595	 0x0ff00000,		/* dst_mask */
596	 FALSE),		/* pcrel_offset */
597
598  HOWTO (R_ARM_TARGET1,		/* type */
599	 0,			/* rightshift */
600	 2,			/* size (0 = byte, 1 = short, 2 = long) */
601	 32,			/* bitsize */
602	 FALSE,			/* pc_relative */
603	 0,			/* bitpos */
604	 complain_overflow_dont,/* complain_on_overflow */
605	 bfd_elf_generic_reloc,	/* special_function */
606	 "R_ARM_TARGET1",	/* name */
607	 FALSE,			/* partial_inplace */
608	 0xffffffff,		/* src_mask */
609	 0xffffffff,		/* dst_mask */
610	 FALSE),		/* pcrel_offset */
611
612  HOWTO (R_ARM_ROSEGREL32,	/* type */
613	 0,			/* rightshift */
614	 2,			/* size (0 = byte, 1 = short, 2 = long) */
615	 32,			/* bitsize */
616	 FALSE,			/* pc_relative */
617	 0,			/* bitpos */
618	 complain_overflow_dont,/* complain_on_overflow */
619	 bfd_elf_generic_reloc,	/* special_function */
620	 "R_ARM_ROSEGREL32",	/* name */
621	 FALSE,			/* partial_inplace */
622	 0xffffffff,		/* src_mask */
623	 0xffffffff,		/* dst_mask */
624	 FALSE),		/* pcrel_offset */
625
626  HOWTO (R_ARM_V4BX,		/* type */
627	 0,			/* rightshift */
628	 2,			/* size (0 = byte, 1 = short, 2 = long) */
629	 32,			/* bitsize */
630	 FALSE,			/* pc_relative */
631	 0,			/* bitpos */
632	 complain_overflow_dont,/* complain_on_overflow */
633	 bfd_elf_generic_reloc,	/* special_function */
634	 "R_ARM_V4BX",		/* name */
635	 FALSE,			/* partial_inplace */
636	 0xffffffff,		/* src_mask */
637	 0xffffffff,		/* dst_mask */
638	 FALSE),		/* pcrel_offset */
639
640  HOWTO (R_ARM_TARGET2,		/* type */
641	 0,			/* rightshift */
642	 2,			/* size (0 = byte, 1 = short, 2 = long) */
643	 32,			/* bitsize */
644	 FALSE,			/* pc_relative */
645	 0,			/* bitpos */
646	 complain_overflow_signed,/* complain_on_overflow */
647	 bfd_elf_generic_reloc,	/* special_function */
648	 "R_ARM_TARGET2",	/* name */
649	 FALSE,			/* partial_inplace */
650	 0xffffffff,		/* src_mask */
651	 0xffffffff,		/* dst_mask */
652	 TRUE),			/* pcrel_offset */
653
654  HOWTO (R_ARM_PREL31,		/* type */
655	 0,			/* rightshift */
656	 2,			/* size (0 = byte, 1 = short, 2 = long) */
657	 31,			/* bitsize */
658	 TRUE,			/* pc_relative */
659	 0,			/* bitpos */
660	 complain_overflow_signed,/* complain_on_overflow */
661	 bfd_elf_generic_reloc,	/* special_function */
662	 "R_ARM_PREL31",	/* name */
663	 FALSE,			/* partial_inplace */
664	 0x7fffffff,		/* src_mask */
665	 0x7fffffff,		/* dst_mask */
666	 TRUE),			/* pcrel_offset */
667};
668
669  /* GNU extension to record C++ vtable hierarchy */
670static reloc_howto_type elf32_arm_vtinherit_howto =
671  HOWTO (R_ARM_GNU_VTINHERIT, /* type */
672         0,                     /* rightshift */
673         2,                     /* size (0 = byte, 1 = short, 2 = long) */
674         0,                     /* bitsize */
675         FALSE,                 /* pc_relative */
676         0,                     /* bitpos */
677         complain_overflow_dont, /* complain_on_overflow */
678         NULL,                  /* special_function */
679         "R_ARM_GNU_VTINHERIT", /* name */
680         FALSE,                 /* partial_inplace */
681         0,                     /* src_mask */
682         0,                     /* dst_mask */
683         FALSE);                /* pcrel_offset */
684
685  /* GNU extension to record C++ vtable member usage */
686static reloc_howto_type elf32_arm_vtentry_howto =
687  HOWTO (R_ARM_GNU_VTENTRY,     /* type */
688         0,                     /* rightshift */
689         2,                     /* size (0 = byte, 1 = short, 2 = long) */
690         0,                     /* bitsize */
691         FALSE,                 /* pc_relative */
692         0,                     /* bitpos */
693         complain_overflow_dont, /* complain_on_overflow */
694         _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
695         "R_ARM_GNU_VTENTRY",   /* name */
696         FALSE,                 /* partial_inplace */
697         0,                     /* src_mask */
698         0,                     /* dst_mask */
699         FALSE);                /* pcrel_offset */
700
701  /* 12 bit pc relative */
702static reloc_howto_type elf32_arm_thm_pc11_howto =
703  HOWTO (R_ARM_THM_PC11,	/* type */
704	 1,			/* rightshift */
705	 1,			/* size (0 = byte, 1 = short, 2 = long) */
706	 11,			/* bitsize */
707	 TRUE,			/* pc_relative */
708	 0,			/* bitpos */
709	 complain_overflow_signed,	/* complain_on_overflow */
710	 bfd_elf_generic_reloc,	/* special_function */
711	 "R_ARM_THM_PC11",	/* name */
712	 FALSE,			/* partial_inplace */
713	 0x000007ff,		/* src_mask */
714	 0x000007ff,		/* dst_mask */
715	 TRUE);			/* pcrel_offset */
716
717  /* 12 bit pc relative */
718static reloc_howto_type elf32_arm_thm_pc9_howto =
719  HOWTO (R_ARM_THM_PC9,		/* type */
720	 1,			/* rightshift */
721	 1,			/* size (0 = byte, 1 = short, 2 = long) */
722	 8,			/* bitsize */
723	 TRUE,			/* pc_relative */
724	 0,			/* bitpos */
725	 complain_overflow_signed,	/* complain_on_overflow */
726	 bfd_elf_generic_reloc,	/* special_function */
727	 "R_ARM_THM_PC9",	/* name */
728	 FALSE,			/* partial_inplace */
729	 0x000000ff,		/* src_mask */
730	 0x000000ff,		/* dst_mask */
731	 TRUE);			/* pcrel_offset */
732
733/* Place relative GOT-indirect.  */
734static reloc_howto_type elf32_arm_got_prel =
735  HOWTO (R_ARM_GOT_PREL,	/* type */
736	 0,			/* rightshift */
737	 2,			/* size (0 = byte, 1 = short, 2 = long) */
738	 32,			/* bitsize */
739	 TRUE,			/* pc_relative */
740	 0,			/* bitpos */
741	 complain_overflow_dont,	/* complain_on_overflow */
742	 bfd_elf_generic_reloc,	/* special_function */
743	 "R_ARM_GOT_PREL",	/* name */
744	 FALSE,			/* partial_inplace */
745	 0xffffffff,		/* src_mask */
746	 0xffffffff,		/* dst_mask */
747	 TRUE);			/* pcrel_offset */
748
749static reloc_howto_type *
750elf32_arm_howto_from_type (unsigned int r_type)
751{
752  if (r_type < NUM_ELEM (elf32_arm_howto_table))
753    return &elf32_arm_howto_table[r_type];
754
755  switch (r_type)
756    {
757    case R_ARM_GOT_PREL:
758      return &elf32_arm_got_prel;
759
760    case R_ARM_GNU_VTINHERIT:
761      return &elf32_arm_vtinherit_howto;
762
763    case R_ARM_GNU_VTENTRY:
764      return &elf32_arm_vtentry_howto;
765
766    case R_ARM_THM_PC11:
767      return &elf32_arm_thm_pc11_howto;
768
769    case R_ARM_THM_PC9:
770      return &elf32_arm_thm_pc9_howto;
771
772    default:
773      return NULL;
774    }
775}
776
777static void
778elf32_arm_info_to_howto (bfd * abfd ATTRIBUTE_UNUSED, arelent * bfd_reloc,
779			 Elf_Internal_Rela * elf_reloc)
780{
781  unsigned int r_type;
782
783  r_type = ELF32_R_TYPE (elf_reloc->r_info);
784  bfd_reloc->howto = elf32_arm_howto_from_type (r_type);
785}
786
787struct elf32_arm_reloc_map
788  {
789    bfd_reloc_code_real_type  bfd_reloc_val;
790    unsigned char             elf_reloc_val;
791  };
792
793/* All entries in this list must also be present in elf32_arm_howto_table.  */
794static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
795  {
796    {BFD_RELOC_NONE,                 R_ARM_NONE},
797    {BFD_RELOC_ARM_PCREL_BRANCH,     R_ARM_PC24},
798    {BFD_RELOC_ARM_PCREL_BLX,        R_ARM_XPC25},
799    {BFD_RELOC_THUMB_PCREL_BLX,      R_ARM_THM_XPC22},
800    {BFD_RELOC_32,                   R_ARM_ABS32},
801    {BFD_RELOC_32_PCREL,             R_ARM_REL32},
802    {BFD_RELOC_8,                    R_ARM_ABS8},
803    {BFD_RELOC_16,                   R_ARM_ABS16},
804    {BFD_RELOC_ARM_OFFSET_IMM,       R_ARM_ABS12},
805    {BFD_RELOC_ARM_THUMB_OFFSET,     R_ARM_THM_ABS5},
806    {BFD_RELOC_THUMB_PCREL_BRANCH23, R_ARM_THM_PC22},
807    {BFD_RELOC_ARM_COPY,             R_ARM_COPY},
808    {BFD_RELOC_ARM_GLOB_DAT,         R_ARM_GLOB_DAT},
809    {BFD_RELOC_ARM_JUMP_SLOT,        R_ARM_JUMP_SLOT},
810    {BFD_RELOC_ARM_RELATIVE,         R_ARM_RELATIVE},
811    {BFD_RELOC_ARM_GOTOFF,           R_ARM_GOTOFF},
812    {BFD_RELOC_ARM_GOTPC,            R_ARM_GOTPC},
813    {BFD_RELOC_ARM_GOT32,            R_ARM_GOT32},
814    {BFD_RELOC_ARM_PLT32,            R_ARM_PLT32},
815    {BFD_RELOC_ARM_TARGET1,	     R_ARM_TARGET1},
816    {BFD_RELOC_ARM_ROSEGREL32,	     R_ARM_ROSEGREL32},
817    {BFD_RELOC_ARM_SBREL32,	     R_ARM_SBREL32},
818    {BFD_RELOC_ARM_PREL31,	     R_ARM_PREL31},
819    {BFD_RELOC_ARM_TARGET2,	     R_ARM_TARGET2}
820  };
821
822static reloc_howto_type *
823elf32_arm_reloc_type_lookup (abfd, code)
824     bfd *abfd ATTRIBUTE_UNUSED;
825     bfd_reloc_code_real_type code;
826{
827  unsigned int i;
828
829  switch (code)
830    {
831    case BFD_RELOC_VTABLE_INHERIT:
832      return & elf32_arm_vtinherit_howto;
833
834    case BFD_RELOC_VTABLE_ENTRY:
835      return & elf32_arm_vtentry_howto;
836
837    case BFD_RELOC_THUMB_PCREL_BRANCH12:
838      return & elf32_arm_thm_pc11_howto;
839
840    case BFD_RELOC_THUMB_PCREL_BRANCH9:
841      return & elf32_arm_thm_pc9_howto;
842
843    default:
844      for (i = 0; i < NUM_ELEM (elf32_arm_reloc_map); i ++)
845	if (elf32_arm_reloc_map[i].bfd_reloc_val == code)
846	  return & elf32_arm_howto_table[elf32_arm_reloc_map[i].elf_reloc_val];
847
848      return NULL;
849   }
850}
851
852/* Support for core dump NOTE sections */
853static bfd_boolean
854elf32_arm_nabi_grok_prstatus (abfd, note)
855     bfd *abfd;
856     Elf_Internal_Note *note;
857{
858  int offset;
859  size_t size;
860
861  switch (note->descsz)
862    {
863      default:
864	return FALSE;
865
866      case 148:		/* Linux/ARM 32-bit*/
867	/* pr_cursig */
868	elf_tdata (abfd)->core_signal = bfd_get_16 (abfd, note->descdata + 12);
869
870	/* pr_pid */
871	elf_tdata (abfd)->core_pid = bfd_get_32 (abfd, note->descdata + 24);
872
873	/* pr_reg */
874	offset = 72;
875	size = 72;
876
877	break;
878    }
879
880  /* Make a ".reg/999" section.  */
881  return _bfd_elfcore_make_pseudosection (abfd, ".reg",
882					  size, note->descpos + offset);
883}
884
885static bfd_boolean
886elf32_arm_nabi_grok_psinfo (abfd, note)
887     bfd *abfd;
888     Elf_Internal_Note *note;
889{
890  switch (note->descsz)
891    {
892      default:
893	return FALSE;
894
895      case 124:		/* Linux/ARM elf_prpsinfo */
896	elf_tdata (abfd)->core_program
897	 = _bfd_elfcore_strndup (abfd, note->descdata + 28, 16);
898	elf_tdata (abfd)->core_command
899	 = _bfd_elfcore_strndup (abfd, note->descdata + 44, 80);
900    }
901
902  /* Note that for some reason, a spurious space is tacked
903     onto the end of the args in some (at least one anyway)
904     implementations, so strip it off if it exists.  */
905
906  {
907    char *command = elf_tdata (abfd)->core_command;
908    int n = strlen (command);
909
910    if (0 < n && command[n - 1] == ' ')
911      command[n - 1] = '\0';
912  }
913
914  return TRUE;
915}
916
917#define TARGET_LITTLE_SYM               bfd_elf32_littlearm_vec
918#define TARGET_LITTLE_NAME              "elf32-littlearm"
919#define TARGET_BIG_SYM                  bfd_elf32_bigarm_vec
920#define TARGET_BIG_NAME                 "elf32-bigarm"
921
922#define elf_backend_grok_prstatus	elf32_arm_nabi_grok_prstatus
923#define elf_backend_grok_psinfo		elf32_arm_nabi_grok_psinfo
924
925#include "elf32-arm.h"
926
927/* Symbian OS Targets */
928
929#undef TARGET_LITTLE_SYM
930#define TARGET_LITTLE_SYM               bfd_elf32_littlearm_symbian_vec
931#undef TARGET_LITTLE_NAME
932#define TARGET_LITTLE_NAME              "elf32-littlearm-symbian"
933#undef TARGET_BIG_SYM
934#define TARGET_BIG_SYM                  bfd_elf32_bigarm_symbian_vec
935#undef TARGET_BIG_NAME
936#define TARGET_BIG_NAME                 "elf32-bigarm-symbian"
937
938/* Like elf32_arm_link_hash_table_create -- but overrides
939   appropriately for Symbian OS.  */
940static struct bfd_link_hash_table *
941elf32_arm_symbian_link_hash_table_create (bfd *abfd)
942{
943  struct bfd_link_hash_table *ret;
944
945  ret = elf32_arm_link_hash_table_create (abfd);
946  if (ret)
947    {
948      struct elf32_arm_link_hash_table *htab
949	= (struct elf32_arm_link_hash_table *)ret;
950      /* There is no PLT header for Symbian OS.  */
951      htab->plt_header_size = 0;
952      /* The PLT entries are each three instructions.  */
953      htab->plt_entry_size = 4 * NUM_ELEM (elf32_arm_symbian_plt_entry);
954      htab->symbian_p = 1;
955    }
956  return ret;
957}
958
959/* In a BPABI executable, the dynamic linking sections do not go in
960   the loadable read-only segment.  The post-linker may wish to refer
961   to these sections, but they are not part of the final program
962   image.  */
963static struct bfd_elf_special_section const
964  elf32_arm_symbian_special_sections[]=
965{
966  { ".dynamic",        8,  0, SHT_DYNAMIC,  0 },
967  { ".dynstr",         7,  0, SHT_STRTAB,   0 },
968  { ".dynsym",         7,  0, SHT_DYNSYM,   0 },
969  { ".got",            4,  0, SHT_PROGBITS, 0 },
970  { ".hash",           5,  0, SHT_HASH,     0 },
971  { NULL,              0,  0, 0,            0 }
972};
973
974static bfd_boolean
975elf32_arm_symbian_modify_segment_map
976  PARAMS ((bfd *, struct bfd_link_info *));
977
978static bfd_boolean
979elf32_arm_symbian_modify_segment_map (abfd, info)
980     bfd *abfd;
981     struct bfd_link_info *info ATTRIBUTE_UNUSED;
982{
983  struct elf_segment_map *m;
984  asection *dynsec;
985
986  /* The first PT_LOAD segment will have the program headers and file
987     headers in it by default -- but BPABI object files should not
988     include these headers in any loadable segment.  */
989  for (m = elf_tdata (abfd)->segment_map; m != NULL; m = m->next)
990    if (m->p_type == PT_LOAD)
991      {
992	m->includes_filehdr = 0;
993	m->includes_phdrs = 0;
994      }
995
996  /* BPABI shared libraries and executables should have a PT_DYNAMIC
997     segment.  However, because the .dynamic section is not marked
998     with SEC_LOAD, the generic ELF code will not create such a
999     segment.  */
1000  dynsec = bfd_get_section_by_name (abfd, ".dynamic");
1001  if (dynsec)
1002    {
1003      m = _bfd_elf_make_dynamic_segment (abfd, dynsec);
1004      m->next = elf_tdata (abfd)->segment_map;
1005      elf_tdata (abfd)->segment_map = m;
1006    }
1007
1008  return TRUE;
1009}
1010
1011#undef elf32_bed
1012#define elf32_bed elf32_arm_symbian_bed
1013
1014#undef ELF_DYNAMIC_SEC_FLAGS
1015#define ELF_DYNAMIC_SEC_FLAGS \
1016  (SEC_HAS_CONTENTS | SEC_IN_MEMORY | SEC_LINKER_CREATED)
1017
1018#undef bfd_elf32_bfd_link_hash_table_create
1019#define bfd_elf32_bfd_link_hash_table_create \
1020  elf32_arm_symbian_link_hash_table_create
1021
1022#undef elf_backend_special_sections
1023#define elf_backend_special_sections elf32_arm_symbian_special_sections
1024
1025#undef elf_backend_modify_segment_map
1026#define elf_backend_modify_segment_map elf32_arm_symbian_modify_segment_map
1027
1028/* There is no .got section for BPABI objects, and hence no header.  */
1029#undef elf_backend_got_header_size
1030#define elf_backend_got_header_size 0
1031
1032/* Similarly, there is no .got.plt section.  */
1033#undef elf_backend_want_got_plt
1034#define elf_backend_want_got_plt 0
1035
1036#include "elf32-target.h"
1037
1038