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