source: trunk/src/binutils/bfd/elf32-d30v.c@ 2002

Last change on this file since 2002 was 610, checked in by bird, 22 years ago

This commit was generated by cvs2svn to compensate for changes in r609,
which included commits to RCS files with non-trunk default branches.

  • Property cvs2svn:cvs-rev set to 1.1.1.2
  • Property svn:eol-style set to native
  • Property svn:executable set to *
File size: 16.6 KB
Line 
1/* D30V-specific support for 32-bit ELF
2 Copyright 1997, 1998, 1999, 2000, 2001, 2002
3 Free Software Foundation, Inc.
4 Contributed by Martin Hunt (hunt@cygnus.com).
5
6This file is part of BFD, the Binary File Descriptor library.
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2 of the License, or
11(at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21
22#include "bfd.h"
23#include "sysdep.h"
24#include "libbfd.h"
25#include "elf-bfd.h"
26#include "elf/d30v.h"
27
28static reloc_howto_type *bfd_elf32_bfd_reloc_type_lookup
29 PARAMS ((bfd *abfd, bfd_reloc_code_real_type code));
30static void d30v_info_to_howto_rel
31 PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
32static void d30v_info_to_howto_rela
33 PARAMS ((bfd *, arelent *, Elf_Internal_Rela *));
34static bfd_reloc_status_type bfd_elf_d30v_reloc PARAMS ((
35 bfd *abfd,
36 arelent *reloc_entry,
37 asymbol *symbol,
38 PTR data,
39 asection *input_section,
40 bfd *output_bfd,
41 char **error_message));
42static bfd_reloc_status_type bfd_elf_d30v_reloc_21 PARAMS ((
43 bfd *abfd,
44 arelent *reloc_entry,
45 asymbol *symbol,
46 PTR data,
47 asection *input_section,
48 bfd *output_bfd,
49 char **error_message));
50
51static reloc_howto_type elf_d30v_howto_table[] =
52{
53 /* This reloc does nothing. */
54 HOWTO (R_D30V_NONE, /* type */
55 0, /* rightshift */
56 2, /* size (0 = byte, 1 = short, 2 = long) */
57 32, /* bitsize */
58 FALSE, /* pc_relative */
59 0, /* bitpos */
60 complain_overflow_bitfield, /* complain_on_overflow */
61 bfd_elf_generic_reloc, /* special_function */
62 "R_D30V_NONE", /* name */
63 FALSE, /* partial_inplace */
64 0, /* src_mask */
65 0, /* dst_mask */
66 FALSE), /* pcrel_offset */
67
68 /* A 6 bit absolute relocation */
69 HOWTO (R_D30V_6, /* type */
70 0, /* rightshift */
71 2, /* size (0 = byte, 1 = short, 2 = long) */
72 6, /* bitsize */
73 FALSE, /* pc_relative */
74 0, /* bitpos */
75 complain_overflow_bitfield, /* complain_on_overflow */
76 bfd_elf_generic_reloc, /* special_function */
77 "R_D30V_6", /* name */
78 FALSE, /* partial_inplace */
79 0x3f, /* src_mask */
80 0x3f, /* dst_mask */
81 FALSE), /* pcrel_offset */
82
83 /* A relative 9 bit relocation, right shifted by 3 */
84 HOWTO (R_D30V_9_PCREL, /* type */
85 3, /* rightshift */
86 2, /* size (0 = byte, 1 = short, 2 = long) */
87 6, /* bitsize */
88 TRUE, /* pc_relative */
89 0, /* bitpos */
90 complain_overflow_signed, /* complain_on_overflow */
91 bfd_elf_d30v_reloc_21, /* special_function */
92 "R_D30V_9_PCREL", /* name */
93 FALSE, /* partial_inplace */
94 0x3f, /* src_mask */
95 0x3f, /* dst_mask */
96 TRUE), /* pcrel_offset */
97
98 /* A relative 9 bit relocation, right shifted by 3 */
99 HOWTO (R_D30V_9_PCREL_R, /* type */
100 3, /* rightshift */
101 2, /* size (0 = byte, 1 = short, 2 = long) */
102 6, /* bitsize */
103 TRUE, /* pc_relative */
104 0, /* bitpos */
105 complain_overflow_signed, /* complain_on_overflow */
106 bfd_elf_d30v_reloc_21, /* special_function */
107 "R_D30V_9_PCREL_R", /* name */
108 FALSE, /* partial_inplace */
109 0x3f, /* src_mask */
110 0x3f, /* dst_mask */
111 TRUE), /* pcrel_offset */
112
113 /* An absolute 15 bit relocation, right shifted by 3 */
114 HOWTO (R_D30V_15, /* type */
115 3, /* rightshift */
116 2, /* size (0 = byte, 1 = short, 2 = long) */
117 12, /* bitsize */
118 FALSE, /* pc_relative */
119 0, /* bitpos */
120 complain_overflow_signed, /* complain_on_overflow */
121 bfd_elf_generic_reloc, /* special_function */
122 "R_D30V_15", /* name */
123 FALSE, /* partial_inplace */
124 0xfff, /* src_mask */
125 0xfff, /* dst_mask */
126 FALSE), /* pcrel_offset */
127
128 /* A relative 15 bit relocation, right shifted by 3 */
129 HOWTO (R_D30V_15_PCREL, /* type */
130 3, /* rightshift */
131 2, /* size (0 = byte, 1 = short, 2 = long) */
132 12, /* bitsize */
133 TRUE, /* pc_relative */
134 0, /* bitpos */
135 complain_overflow_signed, /* complain_on_overflow */
136 bfd_elf_d30v_reloc_21, /* special_function */
137 "R_D30V_15_PCREL", /* name */
138 FALSE, /* partial_inplace */
139 0xfff, /* src_mask */
140 0xfff, /* dst_mask */
141 TRUE), /* pcrel_offset */
142
143 /* A relative 15 bit relocation, right shifted by 3 */
144 HOWTO (R_D30V_15_PCREL_R, /* type */
145 3, /* rightshift */
146 2, /* size (0 = byte, 1 = short, 2 = long) */
147 12, /* bitsize */
148 TRUE, /* pc_relative */
149 0, /* bitpos */
150 complain_overflow_signed, /* complain_on_overflow */
151 bfd_elf_d30v_reloc_21, /* special_function */
152 "R_D30V_15_PCREL_R", /* name */
153 FALSE, /* partial_inplace */
154 0xfff, /* src_mask */
155 0xfff, /* dst_mask */
156 TRUE), /* pcrel_offset */
157
158 /* An absolute 21 bit relocation, right shifted by 3 */
159 HOWTO (R_D30V_21, /* type */
160 3, /* rightshift */
161 2, /* size (0 = byte, 1 = short, 2 = long) */
162 18, /* bitsize */
163 FALSE, /* pc_relative */
164 0, /* bitpos */
165 complain_overflow_signed, /* complain_on_overflow */
166 bfd_elf_generic_reloc, /* special_function */
167 "R_D30V_21", /* name */
168 FALSE, /* partial_inplace */
169 0x3ffff, /* src_mask */
170 0x3ffff, /* dst_mask */
171 FALSE), /* pcrel_offset */
172
173 /* A relative 21 bit relocation, right shifted by 3 */
174 HOWTO (R_D30V_21_PCREL, /* type */
175 3, /* rightshift */
176 2, /* size (0 = byte, 1 = short, 2 = long) */
177 18, /* bitsize */
178 TRUE, /* pc_relative */
179 0, /* bitpos */
180 complain_overflow_signed, /* complain_on_overflow */
181 bfd_elf_d30v_reloc_21, /* special_function */
182 "R_D30V_21_PCREL", /* name */
183 FALSE, /* partial_inplace */
184 0x3ffff, /* src_mask */
185 0x3ffff, /* dst_mask */
186 TRUE), /* pcrel_offset */
187
188 /* A relative 21 bit relocation, right shifted by 3, in the Right container */
189 HOWTO (R_D30V_21_PCREL_R, /* type */
190 3, /* rightshift */
191 2, /* size (0 = byte, 1 = short, 2 = long) */
192 18, /* bitsize */
193 TRUE, /* pc_relative */
194 0, /* bitpos */
195 complain_overflow_signed, /* complain_on_overflow */
196 bfd_elf_d30v_reloc_21, /* special_function */
197 "R_D30V_21_PCREL_R", /* name */
198 FALSE, /* partial_inplace */
199 0x3ffff, /* src_mask */
200 0x3ffff, /* dst_mask */
201 TRUE), /* pcrel_offset */
202
203 /* A D30V 32 bit absolute relocation */
204 HOWTO (R_D30V_32, /* type */
205 0, /* rightshift */
206 4, /* size (0 = byte, 1 = short, 2 = long) */
207 32, /* bitsize */
208 FALSE, /* pc_relative */
209 0, /* bitpos */
210 complain_overflow_bitfield, /* complain_on_overflow */
211 bfd_elf_d30v_reloc, /* special_function */
212 "R_D30V_32", /* name */
213 FALSE, /* partial_inplace */
214 0xffffffff, /* src_mask */
215 0xffffffff, /* dst_mask */
216 FALSE), /* pcrel_offset */
217
218 /* A relative 32 bit relocation */
219 HOWTO (R_D30V_32_PCREL, /* type */
220 0, /* rightshift */
221 4, /* size (0 = byte, 1 = short, 2 = long) */
222 32, /* bitsize */
223 TRUE, /* pc_relative */
224 0, /* bitpos */
225 complain_overflow_signed, /* complain_on_overflow */
226 bfd_elf_d30v_reloc, /* special_function */
227 "R_D30V_32_PCREL", /* name */
228 FALSE, /* partial_inplace */
229 0xffffffff, /* src_mask */
230 0xffffffff, /* dst_mask */
231 TRUE), /* pcrel_offset */
232
233 /* A regular 32 bit absolute relocation */
234 HOWTO (R_D30V_32_NORMAL, /* type */
235 0, /* rightshift */
236 2, /* size (0 = byte, 1 = short, 2 = long) */
237 32, /* bitsize */
238 FALSE, /* pc_relative */
239 0, /* bitpos */
240 complain_overflow_bitfield, /* complain_on_overflow */
241 bfd_elf_generic_reloc, /* special_function */
242 "R_D30V_32_NORMAL", /* name */
243 FALSE, /* partial_inplace */
244 0xffffffff, /* src_mask */
245 0xffffffff, /* dst_mask */
246 FALSE), /* pcrel_offset */
247
248};
249
250#define MAX32 ((bfd_signed_vma) 0x7fffffff)
251#define MIN32 (- MAX32 - 1)
252
253static bfd_reloc_status_type
254bfd_elf_d30v_reloc (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message)
255 bfd *abfd;
256 arelent *reloc_entry;
257 asymbol *symbol;
258 PTR data;
259 asection *input_section;
260 bfd *output_bfd;
261 char **error_message;
262{
263 bfd_signed_vma relocation;
264 bfd_vma in1, in2, num;
265 bfd_vma tmp_addr = 0;
266 bfd_reloc_status_type r;
267 asection *reloc_target_output_section;
268 bfd_size_type addr = reloc_entry->address;
269 bfd_reloc_status_type flag = bfd_reloc_ok;
270 bfd_vma output_base = 0;
271 reloc_howto_type *howto = reloc_entry->howto;
272 int make_absolute = 0;
273
274 if (output_bfd != (bfd *) NULL)
275 {
276 /* Partial linking -- do nothing. */
277 reloc_entry->address += input_section->output_offset;
278 return bfd_reloc_ok;
279 }
280
281 r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
282 input_section, output_bfd, error_message);
283 if (r != bfd_reloc_continue)
284 return r;
285
286 /* a hacked-up version of bfd_perform_reloc() follows */
287 if (bfd_is_und_section (symbol->section)
288 && (symbol->flags & BSF_WEAK) == 0
289 && output_bfd == (bfd *) NULL)
290 flag = bfd_reloc_undefined;
291
292 /* Is the address of the relocation really within the section? */
293 if (reloc_entry->address > input_section->_cooked_size)
294 return bfd_reloc_outofrange;
295
296 /* Work out which section the relocation is targetted at and the
297 initial relocation command value. */
298
299 /* Get symbol value. (Common symbols are special.) */
300 if (bfd_is_com_section (symbol->section))
301 relocation = 0;
302 else
303 relocation = symbol->value;
304
305 reloc_target_output_section = symbol->section->output_section;
306
307 /* Convert input-section-relative symbol value to absolute. */
308 output_base = reloc_target_output_section->vma;
309 relocation += output_base + symbol->section->output_offset;
310
311 /* Add in supplied addend. */
312 relocation += reloc_entry->addend;
313
314 /* Here the variable relocation holds the final address of the
315 symbol we are relocating against, plus any addend. */
316
317 if (howto->pc_relative)
318 {
319 tmp_addr = input_section->output_section->vma + input_section->output_offset
320 + reloc_entry->address;
321 relocation -= tmp_addr;
322 }
323
324 in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr);
325 in2 = bfd_get_32 (abfd, (bfd_byte *) data + addr + 4);
326
327 /* extract the addend */
328 num = ((in2 & 0x3FFFF)
329 | ((in2 & 0xFF00000) >> 2)
330 | ((in1 & 0x3F) << 26));
331 in1 &= 0xFFFFFFC0;
332 in2 = 0x80000000;
333
334 relocation += num;
335
336 if (howto->pc_relative && howto->bitsize == 32)
337 {
338 /* The D30V has a PC that doesn't wrap and PC-relative jumps are
339 signed, so a PC-relative jump can't be more than +/- 2^31 bytes.
340 If one exceeds this, change it to an absolute jump. */
341 if (relocation > MAX32 || relocation < MIN32)
342 {
343 relocation = (relocation + tmp_addr) & 0xffffffff;
344 make_absolute = 1;
345 }
346 }
347
348 in1 |= (relocation >> 26) & 0x3F; /* top 6 bits */
349 in2 |= ((relocation & 0x03FC0000) << 2); /* next 8 bits */
350 in2 |= relocation & 0x0003FFFF; /* bottom 18 bits */
351
352 /* change a PC-relative instruction to its absolute equivalent */
353 /* with this simple hack */
354 if (make_absolute)
355 in1 |= 0x00100000;
356
357 bfd_put_32 (abfd, in1, (bfd_byte *) data + addr);
358 bfd_put_32 (abfd, in2, (bfd_byte *) data + addr + 4);
359
360 return flag;
361}
362
363static bfd_reloc_status_type
364bfd_elf_d30v_reloc_21 (abfd, reloc_entry, symbol, data, input_section, output_bfd, error_message)
365 bfd *abfd;
366 arelent *reloc_entry;
367 asymbol *symbol;
368 PTR data;
369 asection *input_section;
370 bfd *output_bfd;
371 char **error_message;
372{
373 bfd_vma relocation;
374 bfd_vma in1, num;
375 bfd_reloc_status_type r;
376 asection *reloc_target_output_section;
377 bfd_size_type addr = reloc_entry->address;
378 bfd_reloc_status_type flag = bfd_reloc_ok;
379 bfd_vma output_base = 0;
380 reloc_howto_type *howto = reloc_entry->howto;
381 int mask, max;
382
383 if (output_bfd != (bfd *) NULL)
384 {
385 /* Partial linking -- do nothing. */
386 reloc_entry->address += input_section->output_offset;
387 return bfd_reloc_ok;
388 }
389
390 r = bfd_elf_generic_reloc (abfd, reloc_entry, symbol, data,
391 input_section, output_bfd, error_message);
392 if (r != bfd_reloc_continue)
393 return r;
394
395 /* a hacked-up version of bfd_perform_reloc() follows */
396 if (bfd_is_und_section (symbol->section)
397 && (symbol->flags & BSF_WEAK) == 0
398 && output_bfd == (bfd *) NULL)
399 flag = bfd_reloc_undefined;
400
401 /* Is the address of the relocation really within the section? */
402 if (reloc_entry->address > input_section->_cooked_size)
403 return bfd_reloc_outofrange;
404
405 /* Work out which section the relocation is targetted at and the
406 initial relocation command value. */
407
408 /* Get symbol value. (Common symbols are special.) */
409 if (bfd_is_com_section (symbol->section))
410 relocation = 0;
411 else
412 relocation = symbol->value;
413
414 reloc_target_output_section = symbol->section->output_section;
415
416 /* Convert input-section-relative symbol value to absolute. */
417 output_base = reloc_target_output_section->vma;
418 relocation += output_base + symbol->section->output_offset;
419
420 /* Add in supplied addend. */
421 relocation += reloc_entry->addend;
422
423 /* Here the variable relocation holds the final address of the
424 symbol we are relocating against, plus any addend. */
425
426 if (howto->pc_relative)
427 {
428 relocation -= (input_section->output_section->vma
429 + input_section->output_offset);
430 if (howto->pcrel_offset)
431 relocation -= reloc_entry->address;
432 }
433
434 in1 = bfd_get_32 (abfd, (bfd_byte *) data + addr);
435
436 mask = (1 << howto->bitsize) - 1;
437 if (howto->bitsize == 6)
438 mask <<= 12;
439 max = (1 << (howto->bitsize + 2)) - 1;
440
441 /* extract the addend */
442 num = in1 & mask; /* 18 bits */
443 if (howto->bitsize == 6)
444 num >>= 12;
445 num <<= 3; /* shift left 3 */
446 in1 &= ~mask; /* mask out addend */
447
448 relocation += num;
449 if (howto->type == R_D30V_21_PCREL_R || howto->type == R_D30V_15_PCREL_R ||
450 howto->type == R_D30V_9_PCREL_R )
451 {
452 relocation += 4;
453 }
454
455 if ((int)relocation < 0 )
456 {
457 if (~(int)relocation > max)
458 flag = bfd_reloc_overflow;
459 }
460 else
461 {
462 if ((int)relocation > max)
463 flag = bfd_reloc_overflow;
464 }
465 relocation >>= 3;
466 if (howto->bitsize == 6)
467 in1 |= ((relocation & (mask >> 12)) << 12);
468 else
469 in1 |= relocation & mask;
470
471 bfd_put_32 (abfd, in1, (bfd_byte *) data + addr);
472
473 return flag;
474}
475
476/* Map BFD reloc types to D30V ELF reloc types. */
477
478struct d30v_reloc_map
479{
480 bfd_reloc_code_real_type bfd_reloc_val;
481 unsigned char elf_reloc_val;
482};
483
484static const struct d30v_reloc_map d30v_reloc_map[] =
485{
486 { BFD_RELOC_NONE, R_D30V_NONE, },
487 { BFD_RELOC_D30V_6, R_D30V_6 },
488 { BFD_RELOC_D30V_9_PCREL, R_D30V_9_PCREL },
489 { BFD_RELOC_D30V_9_PCREL_R, R_D30V_9_PCREL_R },
490 { BFD_RELOC_D30V_15, R_D30V_15 },
491 { BFD_RELOC_D30V_15_PCREL, R_D30V_15_PCREL },
492 { BFD_RELOC_D30V_15_PCREL_R, R_D30V_15_PCREL_R },
493 { BFD_RELOC_D30V_21, R_D30V_21 },
494 { BFD_RELOC_D30V_21_PCREL, R_D30V_21_PCREL },
495 { BFD_RELOC_D30V_21_PCREL_R, R_D30V_21_PCREL_R },
496 { BFD_RELOC_D30V_32, R_D30V_32 },
497 { BFD_RELOC_D30V_32_PCREL, R_D30V_32_PCREL },
498 { BFD_RELOC_32, R_D30V_32_NORMAL },
499};
500
501static reloc_howto_type *
502bfd_elf32_bfd_reloc_type_lookup (abfd, code)
503 bfd *abfd ATTRIBUTE_UNUSED;
504 bfd_reloc_code_real_type code;
505{
506 unsigned int i;
507
508 for (i = 0;
509 i < sizeof (d30v_reloc_map) / sizeof (struct d30v_reloc_map);
510 i++)
511 {
512 if (d30v_reloc_map[i].bfd_reloc_val == code)
513 return &elf_d30v_howto_table[d30v_reloc_map[i].elf_reloc_val];
514 }
515
516 return NULL;
517}
518
519/* Set the howto pointer for an D30V ELF reloc (type REL). */
520
521static void
522d30v_info_to_howto_rel (abfd, cache_ptr, dst)
523 bfd *abfd ATTRIBUTE_UNUSED;
524 arelent *cache_ptr;
525 Elf_Internal_Rela *dst;
526{
527 unsigned int r_type;
528
529 r_type = ELF32_R_TYPE (dst->r_info);
530 BFD_ASSERT (r_type < (unsigned int) R_D30V_max);
531 cache_ptr->howto = &elf_d30v_howto_table[r_type];
532}
533
534/* Set the howto pointer for an D30V ELF reloc (type RELA). */
535
536static void
537d30v_info_to_howto_rela (abfd, cache_ptr, dst)
538 bfd *abfd ATTRIBUTE_UNUSED;
539 arelent *cache_ptr;
540 Elf_Internal_Rela *dst;
541{
542 unsigned int r_type;
543
544 r_type = ELF32_R_TYPE (dst->r_info);
545 BFD_ASSERT (r_type < (unsigned int) R_D30V_max);
546 cache_ptr->howto = &elf_d30v_howto_table[r_type];
547}
548
549#define ELF_ARCH bfd_arch_d30v
550#define ELF_MACHINE_CODE EM_D30V
551#define ELF_MACHINE_ALT1 EM_CYGNUS_D30V
552#define ELF_MAXPAGESIZE 0x1000
553
554#define TARGET_BIG_SYM bfd_elf32_d30v_vec
555#define TARGET_BIG_NAME "elf32-d30v"
556
557#define elf_info_to_howto d30v_info_to_howto_rela
558#define elf_info_to_howto_rel d30v_info_to_howto_rel
559#define elf_backend_object_p 0
560#define elf_backend_final_write_processing 0
561
562#include "elf32-target.h"
Note: See TracBrowser for help on using the repository browser.