bfd/
[deliverable/binutils-gdb.git] / bfd / elf32-or32.c
CommitLineData
3b16e843 1/* OR32-specific support for 32-bit ELF
47b0e7ad 2 Copyright 2002, 2004, 2005 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
3e110533 19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
3b16e843
NC
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
3b16e843
NC
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). */
acf8aed4 30#define USE_REL 1
3b16e843 31
3b16e843
NC
32/* Set the right machine number for an OR32 ELF file. */
33
b34976b6 34static bfd_boolean
47b0e7ad 35or32_elf_object_p (bfd *abfd)
3b16e843
NC
36{
37 (void) bfd_default_set_arch_mach (abfd, bfd_arch_or32, 0);
b34976b6 38 return TRUE;
3b16e843
NC
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
44static void
47b0e7ad
NC
45or32_elf_final_write_processing (bfd *abfd,
46 bfd_boolean linker ATTRIBUTE_UNUSED)
3b16e843 47{
3b16e843 48 elf_elfheader (abfd)->e_flags &=~ EF_OR32_MACH;
3b16e843
NC
49}
50
47b0e7ad
NC
51static bfd_reloc_status_type
52or32_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)
cedb70c5 59{
47b0e7ad 60 if (output_bfd != NULL)
3b16e843
NC
61 {
62 unsigned long insn;
63 bfd_size_type addr = reloc_entry->address;
64
65 reloc_entry->address += input_section->output_offset;
cedb70c5 66
3b16e843
NC
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;
cedb70c5 71 bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
3b16e843
NC
72
73 return bfd_reloc_ok;
74 }
75
76 return bfd_reloc_continue;
77}
78
47b0e7ad
NC
79static bfd_reloc_status_type
80or32_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)
cedb70c5 87{
47b0e7ad 88 if (output_bfd != NULL)
3b16e843
NC
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;
cedb70c5 99 bfd_put_16 (abfd, insn, (bfd_byte *) data + addr);
3b16e843
NC
100
101 return bfd_reloc_ok;
102 }
103
104 return bfd_reloc_continue;
105}
106
47b0e7ad
NC
107static bfd_reloc_status_type
108or32_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)
cedb70c5 115{
47b0e7ad 116 if (output_bfd != NULL)
3b16e843
NC
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;
cedb70c5 127 bfd_put_8 (abfd, insn, (bfd_byte *) data + addr);
3b16e843
NC
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
144struct 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
153static struct or32_consth *or32_consth_list;
154
47b0e7ad
NC
155static bfd_reloc_status_type
156or32_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)
3b16e843
NC
163{
164 bfd_reloc_status_type ret;
165 bfd_vma relocation;
166 struct or32_consth *n;
cedb70c5 167
3b16e843
NC
168 ret = bfd_reloc_ok;
169
170 if (bfd_is_und_section (symbol->section)
47b0e7ad 171 && output_bfd == NULL)
3b16e843
NC
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
07515404 183 if (reloc_entry->address > bfd_get_section_limit (abfd, input_section))
3b16e843
NC
184 return bfd_reloc_outofrange;
185
186 /* Save the information, and let LO16 do the actual relocation. */
47b0e7ad 187 n = bfd_malloc (sizeof *n);
3b16e843
NC
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
47b0e7ad 195 if (output_bfd != NULL)
3b16e843
NC
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
47b0e7ad
NC
205static bfd_reloc_status_type
206or32_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)
3b16e843
NC
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
47b0e7ad 246 if (output_bfd != NULL)
3b16e843
NC
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
47b0e7ad
NC
269static bfd_reloc_status_type
270or32_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)
cedb70c5 277{
47b0e7ad 278 if (output_bfd != NULL)
3b16e843
NC
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);
cedb70c5 289 bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
3b16e843
NC
290
291 return bfd_reloc_ok;
292 }
293
294 return bfd_reloc_continue;
295}
296
47b0e7ad
NC
297static 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
437struct or32_reloc_map
438{
439 bfd_reloc_code_real_type bfd_reloc_val;
440 unsigned char elf_reloc_val;
441};
442
443static 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
456static reloc_howto_type *
457bfd_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/* Set the howto pointer for an OR32 ELF reloc. */
470
471static void
472or32_info_to_howto_rel (bfd *abfd ATTRIBUTE_UNUSED,
473 arelent *cache_ptr,
474 Elf_Internal_Rela *dst)
475{
476 unsigned int r_type;
477
478 r_type = ELF32_R_TYPE (dst->r_info);
479 BFD_ASSERT (r_type < (unsigned int) R_OR32_max);
480 cache_ptr->howto = &elf_or32_howto_table[r_type];
481}
482
3b16e843
NC
483#define TARGET_LITTLE_SYM bfd_elf32_or32_little_vec
484#define TARGET_LITTLE_NAME "elf32-littleor32"
485#define TARGET_BIG_SYM bfd_elf32_or32_big_vec
486#define TARGET_BIG_NAME "elf32-or32"
487#define ELF_ARCH bfd_arch_or32
488#define ELF_MACHINE_CODE EM_OR32
489#define ELF_MAXPAGESIZE 0x1000
490
491#define elf_info_to_howto 0
492#define elf_info_to_howto_rel or32_info_to_howto_rel
493#define elf_backend_object_p or32_elf_object_p
494#define elf_backend_final_write_processing \
495 or32_elf_final_write_processing
496
497#include "elf32-target.h"
This page took 0.259259 seconds and 4 git commands to generate.