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