1/* 32-bit ELF support for ARM old 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#define OLD_ARM_ABI
21#define bfd_elf32_arm_allocate_interworking_sections \
22	bfd_elf32_arm_oabi_allocate_interworking_sections
23#define bfd_elf32_arm_get_bfd_for_interworking \
24	bfd_elf32_arm_oabi_get_bfd_for_interworking
25#define bfd_elf32_arm_process_before_allocation \
26	bfd_elf32_arm_oabi_process_before_allocation
27#define bfd_elf32_arm_add_glue_sections_to_bfd \
28	bfd_elf32_arm_oabi_add_glue_sections_to_bfd
29
30#include "elf/arm.h"
31#include "bfd.h"
32#include "sysdep.h"
33#include "libbfd.h"
34#include "elf-bfd.h"
35
36#ifndef NUM_ELEM
37#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0])
38#endif
39
40#define TARGET_LITTLE_SYM               bfd_elf32_littlearm_oabi_vec
41#define TARGET_LITTLE_NAME              "elf32-littlearm-oabi"
42#define TARGET_BIG_SYM                  bfd_elf32_bigarm_oabi_vec
43#define TARGET_BIG_NAME                 "elf32-bigarm-oabi"
44
45#define elf_info_to_howto               elf32_arm_info_to_howto
46#define elf_info_to_howto_rel           0
47
48#define ARM_ELF_ABI_VERSION		0
49#define ARM_ELF_OS_ABI_VERSION		0
50
51static reloc_howto_type * find_howto                  PARAMS ((unsigned int));
52static void               elf32_arm_info_to_howto     PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
53static reloc_howto_type * elf32_arm_reloc_type_lookup PARAMS ((bfd *, bfd_reloc_code_real_type));
54
55static reloc_howto_type elf32_arm_howto_table[] =
56  {
57    /* No relocation.  */
58    HOWTO (R_ARM_NONE,		/* type */
59	   0,			/* rightshift */
60	   0,			/* size (0 = byte, 1 = short, 2 = long) */
61	   0,			/* bitsize */
62	   FALSE,		/* pc_relative */
63	   0,			/* bitpos */
64	   complain_overflow_dont,	/* complain_on_overflow */
65	   bfd_elf_generic_reloc,	/* special_function */
66	   "R_ARM_NONE",	/* name */
67	   FALSE,		/* partial_inplace */
68	   0,			/* src_mask */
69	   0,			/* dst_mask */
70	   FALSE),		/* pcrel_offset */
71
72    HOWTO (R_ARM_PC24,		/* type */
73	   2,			/* rightshift */
74	   2,			/* size (0 = byte, 1 = short, 2 = long) */
75	   24,			/* bitsize */
76	   TRUE,		/* pc_relative */
77	   0,			/* bitpos */
78	   complain_overflow_signed,	/* complain_on_overflow */
79	   bfd_elf_generic_reloc,	/* special_function */
80	   "R_ARM_PC24",	/* name */
81	   FALSE,		/* partial_inplace */
82	   0x00ffffff,		/* src_mask */
83	   0x00ffffff,		/* dst_mask */
84	   TRUE),			/* pcrel_offset */
85
86    /* 32 bit absolute.  */
87    HOWTO (R_ARM_ABS32,		/* type */
88	   0,			/* rightshift */
89	   2,			/* size (0 = byte, 1 = short, 2 = long) */
90	   32,			/* bitsize */
91	   FALSE,		/* pc_relative */
92	   0,			/* bitpos */
93	   complain_overflow_bitfield,	/* complain_on_overflow */
94	   bfd_elf_generic_reloc,	/* special_function */
95	   "R_ARM_ABS32",	/* name */
96	   FALSE,		/* partial_inplace */
97	   0xffffffff,		/* src_mask */
98	   0xffffffff,		/* dst_mask */
99	   FALSE),		/* pcrel_offset */
100
101    /* Standard 32bit pc-relative reloc.  */
102    HOWTO (R_ARM_REL32,		/* type */
103	   0,			/* rightshift */
104	   2,			/* size (0 = byte, 1 = short, 2 = long) */
105	   32,			/* bitsize */
106	   TRUE,		/* pc_relative */
107	   0,			/* bitpos */
108	   complain_overflow_bitfield,	/* complain_on_overflow */
109	   bfd_elf_generic_reloc,	/* special_function */
110	   "R_ARM_REL32",	/* name */
111	   FALSE,		/* partial_inplace */
112	   0xffffffff,		/* src_mask */
113	   0xffffffff,		/* dst_mask */
114	   TRUE),		/* pcrel_offset */
115
116    /* 8 bit absolute.  */
117    HOWTO (R_ARM_ABS8,		/* type */
118	   0,			/* rightshift */
119	   0,			/* size (0 = byte, 1 = short, 2 = long) */
120	   8,			/* bitsize */
121	   FALSE,		/* pc_relative */
122	   0,			/* bitpos */
123	   complain_overflow_bitfield,	/* complain_on_overflow */
124	   bfd_elf_generic_reloc,	/* special_function */
125	   "R_ARM_ABS8",	/* name */
126	   FALSE,		/* partial_inplace */
127	   0x000000ff,		/* src_mask */
128	   0x000000ff,		/* dst_mask */
129	   FALSE),		/* pcrel_offset */
130
131    /* 16 bit absolute.  */
132    HOWTO (R_ARM_ABS16,		/* type */
133	   0,			/* rightshift */
134	   1,			/* size (0 = byte, 1 = short, 2 = long) */
135	   16,			/* bitsize */
136	   FALSE,		/* pc_relative */
137	   0,			/* bitpos */
138	   complain_overflow_bitfield,	/* complain_on_overflow */
139	   bfd_elf_generic_reloc,	/* special_function */
140	   "R_ARM_ABS16",	/* name */
141	   FALSE,		/* partial_inplace */
142	   0,			/* src_mask */
143	   0,			/* dst_mask */
144	   FALSE),		/* pcrel_offset */
145
146    /* 12 bit absolute.  */
147    HOWTO (R_ARM_ABS12,		/* type */
148	   0,			/* rightshift */
149	   2,			/* size (0 = byte, 1 = short, 2 = long) */
150	   12,			/* bitsize */
151	   FALSE,		/* pc_relative */
152	   0,			/* bitpos */
153	   complain_overflow_bitfield,	/* complain_on_overflow */
154	   bfd_elf_generic_reloc,	/* special_function */
155	   "R_ARM_ABS12",	/* name */
156	   FALSE,		/* partial_inplace */
157	   0x000008ff,		/* src_mask */
158	   0x000008ff,		/* dst_mask */
159	   FALSE),		/* pcrel_offset */
160
161    HOWTO (R_ARM_THM_ABS5,	/* type */
162	   6,			/* rightshift */
163	   1,			/* size (0 = byte, 1 = short, 2 = long) */
164	   5,			/* bitsize */
165	   FALSE,		/* pc_relative */
166	   0,			/* bitpos */
167	   complain_overflow_bitfield,	/* complain_on_overflow */
168	   bfd_elf_generic_reloc,	/* special_function */
169	   "R_ARM_THM_ABS5",	/* name */
170	   FALSE,		/* partial_inplace */
171	   0x000007e0,		/* src_mask */
172	   0x000007e0,		/* dst_mask */
173	   FALSE),		/* pcrel_offset */
174
175    HOWTO (R_ARM_THM_PC22,	/* type */
176	   1,			/* rightshift */
177	   2,			/* size (0 = byte, 1 = short, 2 = long) */
178	   23,			/* bitsize */
179	   TRUE,		/* pc_relative */
180	   0,			/* bitpos */
181	   complain_overflow_signed,	/* complain_on_overflow */
182	   bfd_elf_generic_reloc,	/* special_function */
183	   "R_ARM_THM_PC22",	/* name */
184	   FALSE,		/* partial_inplace */
185	   0x07ff07ff,		/* src_mask */
186	   0x07ff07ff,		/* dst_mask */
187	   TRUE),			/* pcrel_offset */
188
189    HOWTO (R_ARM_SBREL32,		/* type */
190	   0,			/* rightshift */
191	   0,			/* size (0 = byte, 1 = short, 2 = long) */
192	   0,			/* bitsize */
193	   FALSE,		/* pc_relative */
194	   0,			/* bitpos */
195	   complain_overflow_dont,/* complain_on_overflow */
196	   bfd_elf_generic_reloc,	/* special_function */
197	   "R_ARM_SBREL32",	/* name */
198	   FALSE,		/* partial_inplace */
199	   0,			/* src_mask */
200	   0,			/* dst_mask */
201	   FALSE),		/* pcrel_offset */
202
203    HOWTO (R_ARM_AMP_VCALL9,	/* type */
204	   1,			/* rightshift */
205	   1,			/* size (0 = byte, 1 = short, 2 = long) */
206	   8,			/* bitsize */
207	   TRUE,		/* pc_relative */
208	   0,			/* bitpos */
209	   complain_overflow_signed,	/* complain_on_overflow */
210	   bfd_elf_generic_reloc,	/* special_function */
211	   "R_ARM_AMP_VCALL9",	/* name */
212	   FALSE,		/* partial_inplace */
213	   0x000000ff,		/* src_mask */
214	   0x000000ff,		/* dst_mask */
215	   TRUE),		/* pcrel_offset */
216
217    /* 12 bit pc relative.  */
218    HOWTO (R_ARM_THM_PC11,	/* type */
219	   1,			/* rightshift */
220	   1,			/* size (0 = byte, 1 = short, 2 = long) */
221	   11,			/* bitsize */
222	   TRUE,		/* pc_relative */
223	   0,			/* bitpos */
224	   complain_overflow_signed,	/* complain_on_overflow */
225	   bfd_elf_generic_reloc,	/* special_function */
226	   "R_ARM_THM_PC11",	/* name */
227	   FALSE,		/* partial_inplace */
228	   0x000007ff,		/* src_mask */
229	   0x000007ff,		/* dst_mask */
230	   TRUE),		/* pcrel_offset */
231
232    /* 12 bit pc relative.  */
233    HOWTO (R_ARM_THM_PC9,	/* type */
234	   1,			/* rightshift */
235	   1,			/* size (0 = byte, 1 = short, 2 = long) */
236	   8,			/* bitsize */
237	   TRUE,		/* pc_relative */
238	   0,			/* bitpos */
239	   complain_overflow_signed,	/* complain_on_overflow */
240	   bfd_elf_generic_reloc,	/* special_function */
241	   "R_ARM_THM_PC9",	/* name */
242	   FALSE,		/* partial_inplace */
243	   0x000000ff,		/* src_mask */
244	   0x000000ff,		/* dst_mask */
245	   TRUE),		/* pcrel_offset */
246
247    /* GNU extension to record C++ vtable hierarchy.  */
248    HOWTO (R_ARM_GNU_VTINHERIT, /* type */
249	   0,                     /* rightshift */
250	   2,                     /* size (0 = byte, 1 = short, 2 = long) */
251	   0,                     /* bitsize */
252	   FALSE,                 /* pc_relative */
253	   0,                     /* bitpos */
254	   complain_overflow_dont, /* complain_on_overflow */
255	   NULL,                  /* special_function */
256	   "R_ARM_GNU_VTINHERIT", /* name */
257	   FALSE,                 /* partial_inplace */
258	   0,                     /* src_mask */
259	   0,                     /* dst_mask */
260	   FALSE),                /* pcrel_offset */
261
262    /* GNU extension to record C++ vtable member usage.  */
263    HOWTO (R_ARM_GNU_VTENTRY,     /* type */
264	   0,                     /* rightshift */
265	   2,                     /* size (0 = byte, 1 = short, 2 = long) */
266	   0,                     /* bitsize */
267	   FALSE,                 /* pc_relative */
268	   0,                     /* bitpos */
269	   complain_overflow_dont, /* complain_on_overflow */
270	   _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
271	   "R_ARM_GNU_VTENTRY",   /* name */
272	   FALSE,                 /* partial_inplace */
273	   0,                     /* src_mask */
274	   0,                     /* dst_mask */
275	   FALSE),                /* pcrel_offset */
276
277    /* XXX - gap in index numbering here.  */
278
279    HOWTO (R_ARM_PLT32,		/* type */
280	   2,                   /* rightshift */
281	   2,                   /* size (0 = byte, 1 = short, 2 = long) */
282	   26,                  /* bitsize */
283	   TRUE,		/* pc_relative */
284	   0,                   /* bitpos */
285	   complain_overflow_bitfield,/* complain_on_overflow */
286	   bfd_elf_generic_reloc, /* special_function */
287	   "R_ARM_PLT32",	/* name */
288	   TRUE,		/* partial_inplace */
289	   0x00ffffff,		/* src_mask */
290	   0x00ffffff,		/* dst_mask */
291	   TRUE),			/* pcrel_offset */
292
293    /* XXX - gap in index numbering here.  */
294
295    HOWTO (R_ARM_RREL32,	/* type */
296	   0,			/* rightshift */
297	   0,			/* size (0 = byte, 1 = short, 2 = long) */
298	   0,			/* bitsize */
299	   FALSE,		/* pc_relative */
300	   0,			/* bitpos */
301	   complain_overflow_dont,	/* complain_on_overflow */
302	   bfd_elf_generic_reloc,	/* special_function */
303	   "R_ARM_RREL32",	/* name */
304	   FALSE,		/* partial_inplace */
305	   0,			/* src_mask */
306	   0,			/* dst_mask */
307	   FALSE),		/* pcrel_offset */
308
309    HOWTO (R_ARM_RABS32,	/* type */
310	   0,			/* rightshift */
311	   0,			/* size (0 = byte, 1 = short, 2 = long) */
312	   0,			/* bitsize */
313	   FALSE,		/* pc_relative */
314	   0,			/* bitpos */
315	   complain_overflow_dont,	/* complain_on_overflow */
316	   bfd_elf_generic_reloc,	/* special_function */
317	   "R_ARM_RABS32",	/* name */
318	   FALSE,		/* partial_inplace */
319	   0,			/* src_mask */
320	   0,			/* dst_mask */
321	   FALSE),		/* pcrel_offset */
322
323    HOWTO (R_ARM_RPC24,		/* type */
324	   0,			/* rightshift */
325	   0,			/* size (0 = byte, 1 = short, 2 = long) */
326	   0,			/* bitsize */
327	   FALSE,		/* pc_relative */
328	   0,			/* bitpos */
329	   complain_overflow_dont,	/* complain_on_overflow */
330	   bfd_elf_generic_reloc,	/* special_function */
331	   "R_ARM_RPC24",	/* name */
332	   FALSE,		/* partial_inplace */
333	   0,			/* src_mask */
334	   0,			/* dst_mask */
335	   FALSE),		/* pcrel_offset */
336
337    HOWTO (R_ARM_RBASE,		/* type */
338	   0,			/* rightshift */
339	   0,			/* size (0 = byte, 1 = short, 2 = long) */
340	   0,			/* bitsize */
341	   FALSE,		/* pc_relative */
342	   0,			/* bitpos */
343	   complain_overflow_dont,	/* complain_on_overflow */
344	   bfd_elf_generic_reloc,	/* special_function */
345	   "R_ARM_RBASE",	/* name */
346	   FALSE,		/* partial_inplace */
347	   0,			/* src_mask */
348	   0,			/* dst_mask */
349	   FALSE)		/* pcrel_offset */
350  };
351
352/* Locate a reloc in the howto table.  This function must be used
353   when the entry number is is > R_ARM_GNU_VTINHERIT.  */
354
355static reloc_howto_type *
356find_howto (r_type)
357     unsigned int r_type;
358{
359  int i;
360
361  for (i = NUM_ELEM (elf32_arm_howto_table); i--;)
362    if (elf32_arm_howto_table [i].type == r_type)
363      return elf32_arm_howto_table + i;
364
365  return NULL;
366}
367
368static void
369elf32_arm_info_to_howto (abfd, bfd_reloc, elf_reloc)
370     bfd *abfd ATTRIBUTE_UNUSED;
371     arelent *bfd_reloc;
372     Elf_Internal_Rela *elf_reloc;
373{
374  unsigned int r_type;
375
376  r_type = ELF32_R_TYPE (elf_reloc->r_info);
377
378  if (r_type <= R_ARM_GNU_VTINHERIT)
379    bfd_reloc->howto = & elf32_arm_howto_table[r_type];
380  else
381    bfd_reloc->howto = find_howto (r_type);
382}
383
384struct elf32_arm_reloc_map
385  {
386    bfd_reloc_code_real_type bfd_reloc_val;
387    unsigned char elf_reloc_val;
388  };
389
390static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
391  {
392    {BFD_RELOC_NONE,                 R_ARM_NONE },
393    {BFD_RELOC_ARM_PCREL_BRANCH,     R_ARM_PC24 },
394    {BFD_RELOC_32,                   R_ARM_ABS32 },
395    {BFD_RELOC_32_PCREL,             R_ARM_REL32 },
396    {BFD_RELOC_8,                    R_ARM_ABS8 },
397    {BFD_RELOC_16,                   R_ARM_ABS16 },
398    {BFD_RELOC_ARM_OFFSET_IMM,       R_ARM_ABS12 },
399    {BFD_RELOC_ARM_THUMB_OFFSET,     R_ARM_THM_ABS5 },
400    {BFD_RELOC_THUMB_PCREL_BRANCH23, R_ARM_THM_PC22 },
401    {BFD_RELOC_NONE,                 R_ARM_SBREL32 },
402    {BFD_RELOC_NONE,                 R_ARM_AMP_VCALL9 },
403    {BFD_RELOC_THUMB_PCREL_BRANCH12, R_ARM_THM_PC11 },
404    {BFD_RELOC_THUMB_PCREL_BRANCH9,  R_ARM_THM_PC9 },
405    {BFD_RELOC_VTABLE_INHERIT,       R_ARM_GNU_VTINHERIT },
406    {BFD_RELOC_VTABLE_ENTRY,         R_ARM_GNU_VTENTRY }
407  };
408
409static reloc_howto_type *
410elf32_arm_reloc_type_lookup (abfd, code)
411     bfd * abfd ATTRIBUTE_UNUSED;
412     bfd_reloc_code_real_type code;
413{
414  unsigned int i;
415
416  for (i = NUM_ELEM (elf32_arm_reloc_map); i--;)
417    if (elf32_arm_reloc_map[i].bfd_reloc_val == code)
418      return & elf32_arm_howto_table [elf32_arm_reloc_map[i].elf_reloc_val];
419
420  if (code == BFD_RELOC_ARM_PLT32)
421    return find_howto (R_ARM_PLT32);
422
423  return NULL;
424}
425
426#include "elf32-arm.h"
427