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