Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / binutils / bfd / elfarm-oabi.c
1 /* 32-bit ELF support for ARM old abi option.
2    Copyright 1999, 2000, 2001 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
22 #include "elf/arm.h"
23 #include "bfd.h"
24 #include "sysdep.h"
25 #include "libbfd.h"
26 #include "elf-bfd.h"
27
28 #ifndef NUM_ELEM
29 #define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0])
30 #endif
31
32 #define USE_RELA
33
34 #define TARGET_LITTLE_SYM               bfd_elf32_littlearm_oabi_vec
35 #define TARGET_LITTLE_NAME              "elf32-littlearm-oabi"
36 #define TARGET_BIG_SYM                  bfd_elf32_bigarm_oabi_vec
37 #define TARGET_BIG_NAME                 "elf32-bigarm-oabi"
38
39 #define elf_info_to_howto               elf32_arm_info_to_howto
40 #define elf_info_to_howto_rel           0
41
42 #define ARM_ELF_ABI_VERSION             0
43 #define ARM_ELF_OS_ABI_VERSION          0
44
45 static reloc_howto_type * find_howto                  PARAMS ((unsigned int));
46 static void               elf32_arm_info_to_howto     PARAMS ((bfd *, arelent *, Elf32_Internal_Rela *));
47 static reloc_howto_type * elf32_arm_reloc_type_lookup PARAMS ((bfd *, bfd_reloc_code_real_type));
48
49 static 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_ABS8,          /* 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_ABS8",        /* 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            0,                   /* src_mask */
137            0,                   /* 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     HOWTO (R_ARM_THM_PC22,      /* type */
170            1,                   /* rightshift */
171            2,                   /* size (0 = byte, 1 = short, 2 = long) */
172            23,                  /* bitsize */
173            true,                /* pc_relative */
174            0,                   /* bitpos */
175            complain_overflow_signed,    /* complain_on_overflow */
176            bfd_elf_generic_reloc,       /* special_function */
177            "R_ARM_THM_PC22",    /* name */
178            false,               /* partial_inplace */
179            0x07ff07ff,          /* src_mask */
180            0x07ff07ff,          /* dst_mask */
181            true),                       /* pcrel_offset */
182
183     HOWTO (R_ARM_SBREL32,               /* type */
184            0,                   /* rightshift */
185            0,                   /* size (0 = byte, 1 = short, 2 = long) */
186            0,                   /* bitsize */
187            false,               /* pc_relative */
188            0,                   /* bitpos */
189            complain_overflow_dont,/* complain_on_overflow */
190            bfd_elf_generic_reloc,       /* special_function */
191            "R_ARM_SBREL32",     /* name */
192            false,               /* partial_inplace */
193            0,                   /* src_mask */
194            0,                   /* dst_mask */
195            false),              /* pcrel_offset */
196
197     HOWTO (R_ARM_AMP_VCALL9,    /* type */
198            1,                   /* rightshift */
199            1,                   /* size (0 = byte, 1 = short, 2 = long) */
200            8,                   /* bitsize */
201            true,                /* pc_relative */
202            0,                   /* bitpos */
203            complain_overflow_signed,    /* complain_on_overflow */
204            bfd_elf_generic_reloc,       /* special_function */
205            "R_ARM_AMP_VCALL9",  /* name */
206            false,               /* partial_inplace */
207            0x000000ff,          /* src_mask */
208            0x000000ff,          /* dst_mask */
209            true),               /* pcrel_offset */
210
211     /* 12 bit pc relative.  */
212     HOWTO (R_ARM_THM_PC11,      /* type */
213            1,                   /* rightshift */
214            1,                   /* size (0 = byte, 1 = short, 2 = long) */
215            11,                  /* 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_PC11",    /* name */
221            false,               /* partial_inplace */
222            0x000007ff,          /* src_mask */
223            0x000007ff,          /* dst_mask */
224            true),               /* pcrel_offset */
225
226     /* 12 bit pc relative.  */
227     HOWTO (R_ARM_THM_PC9,       /* type */
228            1,                   /* rightshift */
229            1,                   /* size (0 = byte, 1 = short, 2 = long) */
230            8,                   /* bitsize */
231            true,                /* pc_relative */
232            0,                   /* bitpos */
233            complain_overflow_signed,    /* complain_on_overflow */
234            bfd_elf_generic_reloc,       /* special_function */
235            "R_ARM_THM_PC9",     /* name */
236            false,               /* partial_inplace */
237            0x000000ff,          /* src_mask */
238            0x000000ff,          /* dst_mask */
239            true),               /* pcrel_offset */
240
241     /* GNU extension to record C++ vtable hierarchy.  */
242     HOWTO (R_ARM_GNU_VTINHERIT, /* type */
243            0,                     /* rightshift */
244            2,                     /* size (0 = byte, 1 = short, 2 = long) */
245            0,                     /* bitsize */
246            false,                 /* pc_relative */
247            0,                     /* bitpos */
248            complain_overflow_dont, /* complain_on_overflow */
249            NULL,                  /* special_function */
250            "R_ARM_GNU_VTINHERIT", /* name */
251            false,                 /* partial_inplace */
252            0,                     /* src_mask */
253            0,                     /* dst_mask */
254            false),                /* pcrel_offset */
255
256     /* GNU extension to record C++ vtable member usage.  */
257     HOWTO (R_ARM_GNU_VTENTRY,     /* type */
258            0,                     /* rightshift */
259            2,                     /* size (0 = byte, 1 = short, 2 = long) */
260            0,                     /* bitsize */
261            false,                 /* pc_relative */
262            0,                     /* bitpos */
263            complain_overflow_dont, /* complain_on_overflow */
264            _bfd_elf_rel_vtable_reloc_fn,  /* special_function */
265            "R_ARM_GNU_VTENTRY",   /* name */
266            false,                 /* partial_inplace */
267            0,                     /* src_mask */
268            0,                     /* dst_mask */
269            false),                /* pcrel_offset */
270
271     /* XXX - gap in index numbering here.  */
272
273     HOWTO (R_ARM_PLT32,         /* type */
274            2,                   /* rightshift */
275            2,                   /* size (0 = byte, 1 = short, 2 = long) */
276            26,                  /* bitsize */
277            true,                /* pc_relative */
278            0,                   /* bitpos */
279            complain_overflow_bitfield,/* complain_on_overflow */
280            bfd_elf_generic_reloc, /* special_function */
281            "R_ARM_PLT32",       /* name */
282            true,                /* partial_inplace */
283            0x00ffffff,          /* src_mask */
284            0x00ffffff,          /* dst_mask */
285            true),                       /* pcrel_offset */
286
287     /* XXX - gap in index numbering here.  */
288
289     HOWTO (R_ARM_RREL32,        /* type */
290            0,                   /* rightshift */
291            0,                   /* size (0 = byte, 1 = short, 2 = long) */
292            0,                   /* bitsize */
293            false,               /* pc_relative */
294            0,                   /* bitpos */
295            complain_overflow_dont,      /* complain_on_overflow */
296            bfd_elf_generic_reloc,       /* special_function */
297            "R_ARM_RREL32",      /* name */
298            false,               /* partial_inplace */
299            0,                   /* src_mask */
300            0,                   /* dst_mask */
301            false),              /* pcrel_offset */
302
303     HOWTO (R_ARM_RABS32,        /* type */
304            0,                   /* rightshift */
305            0,                   /* size (0 = byte, 1 = short, 2 = long) */
306            0,                   /* bitsize */
307            false,               /* pc_relative */
308            0,                   /* bitpos */
309            complain_overflow_dont,      /* complain_on_overflow */
310            bfd_elf_generic_reloc,       /* special_function */
311            "R_ARM_RABS32",      /* name */
312            false,               /* partial_inplace */
313            0,                   /* src_mask */
314            0,                   /* dst_mask */
315            false),              /* pcrel_offset */
316
317     HOWTO (R_ARM_RPC24,         /* type */
318            0,                   /* rightshift */
319            0,                   /* size (0 = byte, 1 = short, 2 = long) */
320            0,                   /* bitsize */
321            false,               /* pc_relative */
322            0,                   /* bitpos */
323            complain_overflow_dont,      /* complain_on_overflow */
324            bfd_elf_generic_reloc,       /* special_function */
325            "R_ARM_RPC24",       /* name */
326            false,               /* partial_inplace */
327            0,                   /* src_mask */
328            0,                   /* dst_mask */
329            false),              /* pcrel_offset */
330
331     HOWTO (R_ARM_RBASE,         /* type */
332            0,                   /* rightshift */
333            0,                   /* size (0 = byte, 1 = short, 2 = long) */
334            0,                   /* bitsize */
335            false,               /* pc_relative */
336            0,                   /* bitpos */
337            complain_overflow_dont,      /* complain_on_overflow */
338            bfd_elf_generic_reloc,       /* special_function */
339            "R_ARM_RBASE",       /* name */
340            false,               /* partial_inplace */
341            0,                   /* src_mask */
342            0,                   /* dst_mask */
343            false)               /* pcrel_offset */
344   };
345
346 /* Locate a reloc in the howto table.  This function must be used
347    when the entry number is is > R_ARM_GNU_VTINHERIT.  */
348
349 static reloc_howto_type *
350 find_howto (r_type)
351      unsigned int r_type;
352 {
353   int i;
354
355   for (i = NUM_ELEM (elf32_arm_howto_table); i--;)
356     if (elf32_arm_howto_table [i].type == r_type)
357       return elf32_arm_howto_table + i;
358
359   return NULL;
360 }
361
362 static void
363 elf32_arm_info_to_howto (abfd, bfd_reloc, elf_reloc)
364      bfd *abfd ATTRIBUTE_UNUSED;
365      arelent *bfd_reloc;
366      Elf32_Internal_Rela *elf_reloc;
367 {
368   unsigned int r_type;
369
370   r_type = ELF32_R_TYPE (elf_reloc->r_info);
371
372   if (r_type <= R_ARM_GNU_VTINHERIT)
373     bfd_reloc->howto = & elf32_arm_howto_table[r_type];
374   else
375     bfd_reloc->howto = find_howto (r_type);
376 }
377
378 struct elf32_arm_reloc_map
379   {
380     bfd_reloc_code_real_type bfd_reloc_val;
381     unsigned char elf_reloc_val;
382   };
383
384 static const struct elf32_arm_reloc_map elf32_arm_reloc_map[] =
385   {
386     {BFD_RELOC_NONE,                 R_ARM_NONE },
387     {BFD_RELOC_ARM_PCREL_BRANCH,     R_ARM_PC24 },
388     {BFD_RELOC_32,                   R_ARM_ABS32 },
389     {BFD_RELOC_32_PCREL,             R_ARM_REL32 },
390     {BFD_RELOC_8,                    R_ARM_ABS8 },
391     {BFD_RELOC_16,                   R_ARM_ABS16 },
392     {BFD_RELOC_ARM_OFFSET_IMM,       R_ARM_ABS12 },
393     {BFD_RELOC_ARM_THUMB_OFFSET,     R_ARM_THM_ABS5 },
394     {BFD_RELOC_THUMB_PCREL_BRANCH23, R_ARM_THM_PC22 },
395     {BFD_RELOC_NONE,                 R_ARM_SBREL32 },
396     {BFD_RELOC_NONE,                 R_ARM_AMP_VCALL9 },
397     {BFD_RELOC_THUMB_PCREL_BRANCH12, R_ARM_THM_PC11 },
398     {BFD_RELOC_THUMB_PCREL_BRANCH9,  R_ARM_THM_PC9 },
399     {BFD_RELOC_VTABLE_INHERIT,       R_ARM_GNU_VTINHERIT },
400     {BFD_RELOC_VTABLE_ENTRY,         R_ARM_GNU_VTENTRY }
401   };
402
403 static reloc_howto_type *
404 elf32_arm_reloc_type_lookup (abfd, code)
405      bfd * abfd ATTRIBUTE_UNUSED;
406      bfd_reloc_code_real_type code;
407 {
408   unsigned int i;
409
410   for (i = NUM_ELEM (elf32_arm_reloc_map); i--;)
411     if (elf32_arm_reloc_map[i].bfd_reloc_val == code)
412       return & elf32_arm_howto_table [elf32_arm_reloc_map[i].elf_reloc_val];
413
414   if (code == BFD_RELOC_ARM_PLT32)
415     return find_howto (R_ARM_PLT32);
416
417   return NULL;
418 }
419
420 #define bfd_elf32_arm_allocate_interworking_sections \
421         bfd_elf32_arm_oabi_allocate_interworking_sections
422 #define bfd_elf32_arm_get_bfd_for_interworking \
423         bfd_elf32_arm_oabi_get_bfd_for_interworking
424 #define bfd_elf32_arm_process_before_allocation \
425         bfd_elf32_arm_oabi_process_before_allocation
426
427 #include "elf32-arm.h"