xref: /openbsd/gnu/usr.bin/binutils/bfd/elf32-or32.c (revision 09467b48)
1 /* OR32-specific support for 32-bit ELF
2    Copyright 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 
28 static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
29   PARAMS ((bfd *, bfd_reloc_code_real_type));
30 static void or32_info_to_howto_rel
31   PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
32 static bfd_boolean or32_elf_object_p
33   PARAMS ((bfd *));
34 static void or32_elf_final_write_processing
35   PARAMS ((bfd *, bfd_boolean));
36 static bfd_reloc_status_type or32_elf_32_reloc
37   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
38 static bfd_reloc_status_type or32_elf_16_reloc
39   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
40 static bfd_reloc_status_type or32_elf_8_reloc
41   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
42 static bfd_reloc_status_type or32_elf_const_reloc
43   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
44 static bfd_reloc_status_type or32_elf_consth_reloc
45   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
46 static bfd_reloc_status_type or32_elf_jumptarg_reloc
47   PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
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).  */
51 #define USE_REL	1
52 
53 static 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 */
60 	 FALSE,			/* pc_relative */
61 	 0,			/* bitpos */
62 	 complain_overflow_bitfield, /* complain_on_overflow */
63 	 bfd_elf_generic_reloc,	/* special_function */
64 	 "R_OR32_NONE",		/* name */
65 	 FALSE,			/* partial_inplace */
66 	 0,			/* src_mask */
67 	 0,			/* dst_mask */
68 	 FALSE),		/* pcrel_offset */
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 */
75 	 FALSE,	                /* pc_relative */
76 	 0,	                /* bitpos */
77 	 complain_overflow_bitfield, /* complain_on_overflow */
78 	 or32_elf_32_reloc, 	/* special_function */
79 	 "R_OR32_32",		/* name */
80 	 FALSE,	                /* partial_inplace */
81 	 0xffffffff,	        /* src_mask */
82 	 0xffffffff,   		/* dst_mask */
83 	 FALSE),                /* pcrel_offset */
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 */
90 	 FALSE,	                /* pc_relative */
91 	 0,	                /* bitpos */
92 	 complain_overflow_bitfield, /* complain_on_overflow */
93 	 or32_elf_16_reloc, 	/* special_function */
94 	 "R_OR32_16",		/* name */
95 	 FALSE,	                /* partial_inplace */
96 	 0x0000ffff,	        /* src_mask */
97 	 0x0000ffff,   		/* dst_mask */
98 	 FALSE),                /* pcrel_offset */
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 */
105 	 FALSE,	                /* pc_relative */
106 	 0,	                /* bitpos */
107 	 complain_overflow_bitfield, /* complain_on_overflow */
108 	 or32_elf_8_reloc, 	/* special_function */
109 	 "R_OR32_8",		/* name */
110 	 FALSE,	                /* partial_inplace */
111 	 0x000000ff,	        /* src_mask */
112 	 0x000000ff,   		/* dst_mask */
113 	 FALSE),                /* pcrel_offset */
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 */
120 	 FALSE,			/* pc_relative */
121 	 0,			/* bitpos */
122 	 complain_overflow_dont, /* complain_on_overflow */
123 	 or32_elf_const_reloc,	/* special_function */
124 	 "R_OR32_CONST",	/* name */
125 	 FALSE,			/* partial_inplace */
126 	 0x0000ffff,		/* src_mask */
127 	 0x0000ffff,		/* dst_mask */
128 	 FALSE),		/* pcrel_offset */
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 */
135 	 TRUE,			/* pc_relative */
136 	 0,			/* bitpos */
137 	 complain_overflow_dont, /* complain_on_overflow */
138 	 or32_elf_consth_reloc,	/* special_function */
139 	 "R_OR32_CONSTH",	/* name */
140 	 FALSE,			/* partial_inplace */
141 	 0xffff0000,		/* src_mask */
142 	 0x0000ffff,		/* dst_mask */
143 	 FALSE),		/* pcrel_offset */
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 */
150 	 TRUE,			/* pc_relative */
151 	 0,			/* bitpos */
152 	 complain_overflow_signed, /* complain_on_overflow */
153 	 or32_elf_jumptarg_reloc,/* special_function */
154 	 "R_OR32_JUMPTARG",	/* name */
155 	 FALSE,			/* partial_inplace */
156 	 0,			/* src_mask */
157 	 0x03ffffff,		/* dst_mask */
158 	 TRUE), 		/* pcrel_offset */
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 */
165          FALSE,                 /* pc_relative */
166          0,                     /* bitpos */
167          complain_overflow_dont, /* complain_on_overflow */
168          NULL,                  /* special_function */
169          "R_OR32_GNU_VTINHERIT", /* name */
170          FALSE,                 /* partial_inplace */
171          0,                     /* src_mask */
172          0,                     /* dst_mask */
173          FALSE),                /* pcrel_offset */
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 */
180          FALSE,                 /* pc_relative */
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 */
185          FALSE,                 /* partial_inplace */
186          0,                     /* src_mask */
187          0,                     /* dst_mask */
188          FALSE),                /* pcrel_offset */
189 };
190 
191 /* Map BFD reloc types to OR32 ELF reloc types.  */
192 
193 struct or32_reloc_map
194 {
195   bfd_reloc_code_real_type  bfd_reloc_val;
196   unsigned char             elf_reloc_val;
197 };
198 
199 static 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 
212 static reloc_howto_type *
213 bfd_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 
230 static void
231 or32_info_to_howto_rel (abfd, cache_ptr, dst)
232      bfd *abfd ATTRIBUTE_UNUSED;
233      arelent *cache_ptr;
234      Elf_Internal_Rela *dst;
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 
245 static bfd_boolean
246 or32_elf_object_p (abfd)
247      bfd *abfd;
248 {
249   (void) bfd_default_set_arch_mach (abfd, bfd_arch_or32, 0);
250   return TRUE;
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 
256 static void
257 or32_elf_final_write_processing (abfd, linker)
258      bfd *abfd;
259      bfd_boolean linker ATTRIBUTE_UNUSED;
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 
280 bfd_reloc_status_type
281 or32_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;
290 {
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;
297 
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;
302       bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
303 
304       return bfd_reloc_ok;
305     }
306 
307   return bfd_reloc_continue;
308 }
309 
310 bfd_reloc_status_type
311 or32_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;
320 {
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;
332       bfd_put_16 (abfd, insn, (bfd_byte *) data + addr);
333 
334       return bfd_reloc_ok;
335     }
336 
337   return bfd_reloc_continue;
338 }
339 
340 bfd_reloc_status_type
341 or32_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;
350 {
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;
362       bfd_put_8 (abfd, insn, (bfd_byte *) data + addr);
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 
379 struct 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 
388 static struct or32_consth *or32_consth_list;
389 
390 bfd_reloc_status_type
391 or32_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;
404 
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 
442 bfd_reloc_status_type
443 or32_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 
508 bfd_reloc_status_type
509 or32_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;
518 {
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);
530       bfd_put_32 (abfd, insn, (bfd_byte *) data + addr);
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"
553