]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/elf32-or32.c
7b42c92c61148f86d0f53cbc54811943e8af0821
[thirdparty/binutils-gdb.git] / bfd / elf32-or32.c
1 /* OR32-specific support for 32-bit ELF
2 Copyright 2002, 2004, 2005, 2007 Free Software Foundation, Inc.
3 Contributed by Ivan Guzvinec <ivang@opencores.org>
4
5 This file is part of BFD, the Binary File Descriptor library.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
20
21 #include "bfd.h"
22 #include "sysdep.h"
23 #include "libbfd.h"
24 #include "elf-bfd.h"
25 #include "elf/or32.h"
26 #include "libiberty.h"
27
28 /* Try to minimize the amount of space occupied by relocation tables
29 on the ROM (not that the ROM won't be swamped by other ELF overhead). */
30 #define USE_REL 1
31
32 /* Set the right machine number for an OR32 ELF file. */
33
34 static bfd_boolean
35 or32_elf_object_p (bfd *abfd)
36 {
37 (void) bfd_default_set_arch_mach (abfd, bfd_arch_or32, 0);
38 return TRUE;
39 }
40
41 /* The final processing done just before writing out an OR32 ELF object file.
42 This gets the OR32 architecture right based on the machine number. */
43
44 static void
45 or32_elf_final_write_processing (bfd *abfd,
46 bfd_boolean linker ATTRIBUTE_UNUSED)
47 {
48 elf_elfheader (abfd)->e_flags &=~ EF_OR32_MACH;
49 }
50
51 static bfd_reloc_status_type
52 or32_elf_32_reloc (bfd *abfd,
53 arelent *reloc_entry,
54 asymbol *symbol,
55 void * data,
56 asection *input_section,
57 bfd *output_bfd,
58 char **error_message ATTRIBUTE_UNUSED)
59 {
60 if (output_bfd != NULL)
61 {
62 unsigned long insn;
63 bfd_size_type addr = reloc_entry->address;
64
65 reloc_entry->address += input_section->output_offset;
66
67 insn = bfd_get_32 (abfd, (bfd_byte *) data + addr);
68 insn += symbol->section->output_section->vma;
69 insn += symbol->section->output_offset;
70 insn += symbol->value;
71 bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
72
73 return bfd_reloc_ok;
74 }
75
76 return bfd_reloc_continue;
77 }
78
79 static bfd_reloc_status_type
80 or32_elf_16_reloc (bfd *abfd,
81 arelent *reloc_entry,
82 asymbol *symbol,
83 void * data,
84 asection *input_section,
85 bfd *output_bfd,
86 char **error_message ATTRIBUTE_UNUSED)
87 {
88 if (output_bfd != NULL)
89 {
90 unsigned short insn;
91 bfd_size_type addr = reloc_entry->address;
92
93 reloc_entry->address += input_section->output_offset;
94
95 insn = bfd_get_16 (abfd, (bfd_byte *) data + addr);
96 insn += symbol->section->output_section->vma;
97 insn += symbol->section->output_offset;
98 insn += symbol->value;
99 bfd_put_16 (abfd, insn, (bfd_byte *) data + addr);
100
101 return bfd_reloc_ok;
102 }
103
104 return bfd_reloc_continue;
105 }
106
107 static bfd_reloc_status_type
108 or32_elf_8_reloc (bfd *abfd ATTRIBUTE_UNUSED,
109 arelent *reloc_entry,
110 asymbol *symbol,
111 void * data,
112 asection *input_section,
113 bfd *output_bfd,
114 char **error_message ATTRIBUTE_UNUSED)
115 {
116 if (output_bfd != NULL)
117 {
118 unsigned char insn;
119 bfd_size_type addr = reloc_entry->address;
120
121 reloc_entry->address += input_section->output_offset;
122
123 insn = bfd_get_8 (abfd, (bfd_byte *) data + addr);
124 insn += symbol->section->output_section->vma;
125 insn += symbol->section->output_offset;
126 insn += symbol->value;
127 bfd_put_8 (abfd, insn, (bfd_byte *) data + addr);
128
129 return bfd_reloc_ok;
130 }
131
132 return bfd_reloc_continue;
133 }
134
135 /* Do a R_OR32_CONSTH relocation. This has to be done in combination
136 with a R_OR32_CONST reloc, because there is a carry from the LO16 to
137 the HI16. Here we just save the information we need; we do the
138 actual relocation when we see the LO16. OR32 ELF requires that the
139 LO16 immediately follow the HI16. As a GNU extension, we permit an
140 arbitrary number of HI16 relocs to be associated with a single LO16
141 reloc. This extension permits gcc to output the HI and LO relocs
142 itself. This code is copied from the elf32-mips.c. */
143
144 struct or32_consth
145 {
146 struct or32_consth *next;
147 bfd_byte *addr;
148 bfd_vma addend;
149 };
150
151 /* FIXME: This should not be a static variable. */
152
153 static struct or32_consth *or32_consth_list;
154
155 static bfd_reloc_status_type
156 or32_elf_consth_reloc (bfd *abfd ATTRIBUTE_UNUSED,
157 arelent *reloc_entry,
158 asymbol *symbol,
159 void * data,
160 asection *input_section,
161 bfd *output_bfd,
162 char **error_message ATTRIBUTE_UNUSED)
163 {
164 bfd_reloc_status_type ret;
165 bfd_vma relocation;
166 struct or32_consth *n;
167
168 ret = bfd_reloc_ok;
169
170 if (bfd_is_und_section (symbol->section)
171 && output_bfd == NULL)
172 ret = bfd_reloc_undefined;
173
174 if (bfd_is_com_section (symbol->section))
175 relocation = 0;
176 else
177 relocation = symbol->value;
178
179 relocation += symbol->section->output_section->vma;
180 relocation += symbol->section->output_offset;
181 relocation += reloc_entry->addend;
182
183 if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
184 return bfd_reloc_outofrange;
185
186 /* Save the information, and let LO16 do the actual relocation. */
187 n = bfd_malloc (sizeof *n);
188 if (n == NULL)
189 return bfd_reloc_outofrange;
190 n->addr = (bfd_byte *) data + reloc_entry->address;
191 n->addend = relocation;
192 n->next = or32_consth_list;
193 or32_consth_list = n;
194
195 if (output_bfd != NULL)
196 reloc_entry->address += input_section->output_offset;
197
198 return ret;
199 }
200
201 /* Do a R_OR32_CONST relocation. This is a straightforward 16 bit
202 inplace relocation; this function exists in order to do the
203 R_OR32_CONSTH relocation described above. */
204
205 static bfd_reloc_status_type
206 or32_elf_const_reloc (bfd *abfd,
207 arelent *reloc_entry,
208 asymbol *symbol,
209 void * data,
210 asection *input_section,
211 bfd *output_bfd,
212 char **error_message)
213 {
214 if (or32_consth_list != NULL)
215 {
216 struct or32_consth *l;
217
218 l = or32_consth_list;
219 while (l != NULL)
220 {
221 unsigned long insn;
222 unsigned long val;
223 unsigned long vallo;
224 struct or32_consth *next;
225
226 /* Do the HI16 relocation. Note that we actually don't need
227 to know anything about the LO16 itself, except where to
228 find the low 16 bits of the addend needed by the LO16. */
229 insn = bfd_get_32 (abfd, l->addr);
230 vallo = (bfd_get_32 (abfd, (bfd_byte *) data + reloc_entry->address)
231 & 0xffff);
232 val = ((insn & 0xffff) << 16) + vallo;
233 val += l->addend;
234
235 insn = (insn &~ 0xffff) | ((val >> 16) & 0xffff);
236 bfd_put_32 (abfd, insn, l->addr);
237
238 next = l->next;
239 free (l);
240 l = next;
241 }
242
243 or32_consth_list = NULL;
244 }
245
246 if (output_bfd != NULL)
247 {
248 unsigned long insn, tmp;
249 bfd_size_type addr = reloc_entry->address;
250
251 reloc_entry->address += input_section->output_offset;
252
253 insn = bfd_get_32 (abfd, (bfd_byte *) data + addr);
254 tmp = insn & 0x0000ffff;
255 tmp += symbol->section->output_section->vma;
256 tmp += symbol->section->output_offset;
257 tmp += symbol->value;
258 insn = (insn & 0xffff0000) | (tmp & 0x0000ffff);
259 bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
260
261 return bfd_reloc_ok;
262 }
263
264 /* Now do the LO16 reloc in the usual way. */
265 return bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
266 input_section, output_bfd, error_message);
267 }
268
269 static bfd_reloc_status_type
270 or32_elf_jumptarg_reloc (bfd *abfd,
271 arelent *reloc_entry,
272 asymbol *symbol ATTRIBUTE_UNUSED,
273 void * data,
274 asection *input_section,
275 bfd *output_bfd,
276 char **error_message ATTRIBUTE_UNUSED)
277 {
278 if (output_bfd != NULL)
279 {
280 unsigned long insn, tmp;
281 bfd_size_type addr = reloc_entry->address;
282
283 reloc_entry->address += input_section->output_offset;
284
285 insn = bfd_get_32 (abfd, (bfd_byte *) data + addr);
286 tmp = insn | 0xfc000000;
287 tmp -= (input_section->output_offset >> 2);
288 insn = (insn & 0xfc000000) | (tmp & 0x03ffffff);
289 bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
290
291 return bfd_reloc_ok;
292 }
293
294 return bfd_reloc_continue;
295 }
296
297 static reloc_howto_type elf_or32_howto_table[] =
298 {
299 /* This reloc does nothing. */
300 HOWTO (R_OR32_NONE, /* type */
301 0, /* rightshift */
302 2, /* size (0 = byte, 1 = short, 2 = long) */
303 32, /* bitsize */
304 FALSE, /* pc_relative */
305 0, /* bitpos */
306 complain_overflow_bitfield, /* complain_on_overflow */
307 bfd_elf_generic_reloc, /* special_function */
308 "R_OR32_NONE", /* name */
309 FALSE, /* partial_inplace */
310 0, /* src_mask */
311 0, /* dst_mask */
312 FALSE), /* pcrel_offset */
313
314 /* A standard 32 bit relocation. */
315 HOWTO (R_OR32_32, /* type */
316 0, /* rightshift */
317 2, /* size (0 = byte, 1 = short, 2 = long) */
318 32, /* bitsize */
319 FALSE, /* pc_relative */
320 0, /* bitpos */
321 complain_overflow_bitfield, /* complain_on_overflow */
322 or32_elf_32_reloc, /* special_function */
323 "R_OR32_32", /* name */
324 FALSE, /* partial_inplace */
325 0xffffffff, /* src_mask */
326 0xffffffff, /* dst_mask */
327 FALSE), /* pcrel_offset */
328
329 /* A standard 16 bit relocation. */
330 HOWTO (R_OR32_16, /* type */
331 0, /* rightshift */
332 1, /* size (0 = byte, 1 = short, 2 = long) */
333 16, /* bitsize */
334 FALSE, /* pc_relative */
335 0, /* bitpos */
336 complain_overflow_bitfield, /* complain_on_overflow */
337 or32_elf_16_reloc, /* special_function */
338 "R_OR32_16", /* name */
339 FALSE, /* partial_inplace */
340 0x0000ffff, /* src_mask */
341 0x0000ffff, /* dst_mask */
342 FALSE), /* pcrel_offset */
343
344 /* A standard 8 bit relocation. */
345 HOWTO (R_OR32_8, /* type */
346 0, /* rightshift */
347 0, /* size (0 = byte, 1 = short, 2 = long) */
348 8, /* bitsize */
349 FALSE, /* pc_relative */
350 0, /* bitpos */
351 complain_overflow_bitfield, /* complain_on_overflow */
352 or32_elf_8_reloc, /* special_function */
353 "R_OR32_8", /* name */
354 FALSE, /* partial_inplace */
355 0x000000ff, /* src_mask */
356 0x000000ff, /* dst_mask */
357 FALSE), /* pcrel_offset */
358
359 /* A standard low 16 bit relocation. */
360 HOWTO (R_OR32_CONST, /* type */
361 0, /* rightshift */
362 2, /* size (0 = byte, 1 = short, 2 = long) */
363 16, /* bitsize */
364 FALSE, /* pc_relative */
365 0, /* bitpos */
366 complain_overflow_dont, /* complain_on_overflow */
367 or32_elf_const_reloc, /* special_function */
368 "R_OR32_CONST", /* name */
369 FALSE, /* partial_inplace */
370 0x0000ffff, /* src_mask */
371 0x0000ffff, /* dst_mask */
372 FALSE), /* pcrel_offset */
373
374 /* A standard high 16 bit relocation. */
375 HOWTO (R_OR32_CONSTH, /* type */
376 16, /* rightshift */
377 2, /* size (0 = byte, 1 = short, 2 = long) */
378 16, /* bitsize */
379 TRUE, /* pc_relative */
380 0, /* bitpos */
381 complain_overflow_dont, /* complain_on_overflow */
382 or32_elf_consth_reloc, /* special_function */
383 "R_OR32_CONSTH", /* name */
384 FALSE, /* partial_inplace */
385 0xffff0000, /* src_mask */
386 0x0000ffff, /* dst_mask */
387 FALSE), /* pcrel_offset */
388
389 /* A standard branch relocation. */
390 HOWTO (R_OR32_JUMPTARG, /* type */
391 2, /* rightshift */
392 2, /* size (0 = byte, 1 = short, 2 = long) */
393 28, /* bitsize */
394 TRUE, /* pc_relative */
395 0, /* bitpos */
396 complain_overflow_signed, /* complain_on_overflow */
397 or32_elf_jumptarg_reloc,/* special_function */
398 "R_OR32_JUMPTARG", /* name */
399 FALSE, /* partial_inplace */
400 0, /* src_mask */
401 0x03ffffff, /* dst_mask */
402 TRUE), /* pcrel_offset */
403
404 /* GNU extension to record C++ vtable hierarchy. */
405 HOWTO (R_OR32_GNU_VTINHERIT, /* type */
406 0, /* rightshift */
407 2, /* size (0 = byte, 1 = short, 2 = long) */
408 0, /* bitsize */
409 FALSE, /* pc_relative */
410 0, /* bitpos */
411 complain_overflow_dont, /* complain_on_overflow */
412 NULL, /* special_function */
413 "R_OR32_GNU_VTINHERIT", /* name */
414 FALSE, /* partial_inplace */
415 0, /* src_mask */
416 0, /* dst_mask */
417 FALSE), /* pcrel_offset */
418
419 /* GNU extension to record C++ vtable member usage. */
420 HOWTO (R_OR32_GNU_VTENTRY, /* type */
421 0, /* rightshift */
422 2, /* size (0 = byte, 1 = short, 2 = long) */
423 0, /* bitsize */
424 FALSE, /* pc_relative */
425 0, /* bitpos */
426 complain_overflow_dont, /* complain_on_overflow */
427 _bfd_elf_rel_vtable_reloc_fn, /* special_function */
428 "R_OR32_GNU_VTENTRY", /* name */
429 FALSE, /* partial_inplace */
430 0, /* src_mask */
431 0, /* dst_mask */
432 FALSE), /* pcrel_offset */
433 };
434
435 /* Map BFD reloc types to OR32 ELF reloc types. */
436
437 struct or32_reloc_map
438 {
439 bfd_reloc_code_real_type bfd_reloc_val;
440 unsigned char elf_reloc_val;
441 };
442
443 static const struct or32_reloc_map or32_reloc_map[] =
444 {
445 { BFD_RELOC_NONE, R_OR32_NONE },
446 { BFD_RELOC_32, R_OR32_32 },
447 { BFD_RELOC_16, R_OR32_16 },
448 { BFD_RELOC_8, R_OR32_8 },
449 { BFD_RELOC_LO16, R_OR32_CONST },
450 { BFD_RELOC_HI16, R_OR32_CONSTH },
451 { BFD_RELOC_32_GOT_PCREL, R_OR32_JUMPTARG },
452 { BFD_RELOC_VTABLE_INHERIT, R_OR32_GNU_VTINHERIT },
453 { BFD_RELOC_VTABLE_ENTRY, R_OR32_GNU_VTENTRY },
454 };
455
456 static reloc_howto_type *
457 bfd_elf32_bfd_reloc_type_lookup (bfd *abfd ATTRIBUTE_UNUSED,
458 bfd_reloc_code_real_type code)
459 {
460 unsigned int i;
461
462 for (i = ARRAY_SIZE (or32_reloc_map); i--;)
463 if (or32_reloc_map[i].bfd_reloc_val == code)
464 return &elf_or32_howto_table[or32_reloc_map[i].elf_reloc_val];
465
466 return NULL;
467 }
468
469 static reloc_howto_type *
470 bfd_elf32_bfd_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED,
471 const char *r_name)
472 {
473 unsigned int i;
474
475 for (i = 0;
476 i < sizeof (elf_or32_howto_table) / sizeof (elf_or32_howto_table[0]);
477 i++)
478 if (elf_or32_howto_table[i].name != NULL
479 && strcasecmp (elf_or32_howto_table[i].name, r_name) == 0)
480 return &elf_or32_howto_table[i];
481
482 return NULL;
483 }
484
485 /* Set the howto pointer for an OR32 ELF reloc. */
486
487 static void
488 or32_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
489 arelent *cache_ptr,
490 Elf_Internal_Rela *dst)
491 {
492 unsigned int r_type;
493
494 r_type = ELF32_R_TYPE (dst->r_info);
495 BFD_ASSERT (r_type < (unsigned int) R_OR32_max);
496 cache_ptr->howto = &elf_or32_howto_table[r_type];
497 }
498
499 #define TARGET_LITTLE_SYM bfd_elf32_or32_little_vec
500 #define TARGET_LITTLE_NAME "elf32-littleor32"
501 #define TARGET_BIG_SYM bfd_elf32_or32_big_vec
502 #define TARGET_BIG_NAME "elf32-or32"
503 #define ELF_ARCH bfd_arch_or32
504 #define ELF_MACHINE_CODE EM_OR32
505 #define ELF_MAXPAGESIZE 0x1000
506
507 #define elf_info_to_howto 0
508 #define elf_info_to_howto_rel or32_info_to_howto_rel
509 #define elf_backend_object_p or32_elf_object_p
510 #define elf_backend_final_write_processing \
511 or32_elf_final_write_processing
512
513 #include "elf32-target.h"