]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/coff-a29k.c
19990502 sourceware import
[thirdparty/binutils-gdb.git] / bfd / coff-a29k.c
1 /* BFD back-end for AMD 29000 COFF binaries.
2 Copyright 1990, 91, 92, 93, 94, 95, 1997 Free Software Foundation, Inc.
3 Contributed by David Wood at New York University 7/8/91.
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 #define A29K 1
22
23 #include "bfd.h"
24 #include "sysdep.h"
25 #include "libbfd.h"
26 #include "coff/a29k.h"
27 #include "coff/internal.h"
28 #include "libcoff.h"
29
30 static long get_symbol_value PARAMS ((asymbol *));
31 static bfd_reloc_status_type a29k_reloc
32 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
33 static boolean coff_a29k_relocate_section
34 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
35 struct internal_reloc *, struct internal_syment *, asection **));
36 static boolean coff_a29k_adjust_symndx
37 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
38 struct internal_reloc *, boolean *));
39
40 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
41
42 #define INSERT_HWORD(WORD,HWORD) \
43 (((WORD) & 0xff00ff00) | (((HWORD) & 0xff00) << 8) | ((HWORD)& 0xff))
44 #define EXTRACT_HWORD(WORD) \
45 ((((WORD) & 0x00ff0000) >> 8) | ((WORD)& 0xff))
46 #define SIGN_EXTEND_HWORD(HWORD) \
47 ((HWORD) & 0x8000 ? (HWORD)|(~0xffffL) : (HWORD))
48
49 /* Provided the symbol, returns the value reffed */
50 static long
51 get_symbol_value (symbol)
52 asymbol *symbol;
53 {
54 long relocation = 0;
55
56 if (bfd_is_com_section (symbol->section))
57 {
58 relocation = 0;
59 }
60 else
61 {
62 relocation = symbol->value +
63 symbol->section->output_section->vma +
64 symbol->section->output_offset;
65 }
66
67 return(relocation);
68 }
69
70 /* this function is in charge of performing all the 29k relocations */
71
72 static bfd_reloc_status_type
73 a29k_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
74 error_message)
75 bfd *abfd;
76 arelent *reloc_entry;
77 asymbol *symbol_in;
78 PTR data;
79 asection *input_section;
80 bfd *output_bfd;
81 char **error_message;
82 {
83 /* the consth relocation comes in two parts, we have to remember
84 the state between calls, in these variables */
85 static boolean part1_consth_active = false;
86 static unsigned long part1_consth_value;
87
88 unsigned long insn;
89 unsigned long sym_value;
90 unsigned long unsigned_value;
91 unsigned short r_type;
92 long signed_value;
93
94 unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
95 bfd_byte *hit_data =addr + (bfd_byte *)(data);
96
97 r_type = reloc_entry->howto->type;
98
99 if (output_bfd) {
100 /* Partial linking - do nothing */
101 reloc_entry->address += input_section->output_offset;
102 return bfd_reloc_ok;
103
104 }
105
106 if (symbol_in != NULL
107 && bfd_is_und_section (symbol_in->section))
108 {
109 /* Keep the state machine happy in case we're called again */
110 if (r_type == R_IHIHALF)
111 {
112 part1_consth_active = true;
113 part1_consth_value = 0;
114 }
115 return(bfd_reloc_undefined);
116 }
117
118 if ((part1_consth_active) && (r_type != R_IHCONST))
119 {
120 part1_consth_active = false;
121 *error_message = (char *) _("Missing IHCONST");
122 return(bfd_reloc_dangerous);
123 }
124
125
126 sym_value = get_symbol_value(symbol_in);
127
128 switch (r_type)
129 {
130 case R_IREL:
131 insn = bfd_get_32(abfd, hit_data);
132 /* Take the value in the field and sign extend it */
133 signed_value = EXTRACT_HWORD(insn);
134 signed_value = SIGN_EXTEND_HWORD(signed_value);
135 signed_value <<= 2;
136
137 /* See the note on the R_IREL reloc in coff_a29k_relocate_section. */
138 if (signed_value == - (long) reloc_entry->address)
139 signed_value = 0;
140
141 signed_value += sym_value + reloc_entry->addend;
142 if ((signed_value & ~0x3ffff) == 0)
143 { /* Absolute jmp/call */
144 insn |= (1<<24); /* Make it absolute */
145 /* FIXME: Should we change r_type to R_IABS */
146 }
147 else
148 {
149 /* Relative jmp/call, so subtract from the value the
150 address of the place we're coming from */
151 signed_value -= (reloc_entry->address
152 + input_section->output_section->vma
153 + input_section->output_offset);
154 if (signed_value>0x1ffff || signed_value<-0x20000)
155 return(bfd_reloc_overflow);
156 }
157 signed_value >>= 2;
158 insn = INSERT_HWORD(insn, signed_value);
159 bfd_put_32(abfd, insn ,hit_data);
160 break;
161 case R_ILOHALF:
162 insn = bfd_get_32(abfd, hit_data);
163 unsigned_value = EXTRACT_HWORD(insn);
164 unsigned_value += sym_value + reloc_entry->addend;
165 insn = INSERT_HWORD(insn, unsigned_value);
166 bfd_put_32(abfd, insn, hit_data);
167 break;
168 case R_IHIHALF:
169 insn = bfd_get_32(abfd, hit_data);
170 /* consth, part 1
171 Just get the symbol value that is referenced */
172 part1_consth_active = true;
173 part1_consth_value = sym_value + reloc_entry->addend;
174 /* Don't modify insn until R_IHCONST */
175 break;
176 case R_IHCONST:
177 insn = bfd_get_32(abfd, hit_data);
178 /* consth, part 2
179 Now relocate the reference */
180 if (part1_consth_active == false) {
181 *error_message = (char *) _("Missing IHIHALF");
182 return(bfd_reloc_dangerous);
183 }
184 /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
185 unsigned_value = 0; /*EXTRACT_HWORD(insn) << 16;*/
186 unsigned_value += reloc_entry->addend; /* r_symndx */
187 unsigned_value += part1_consth_value;
188 unsigned_value = unsigned_value >> 16;
189 insn = INSERT_HWORD(insn, unsigned_value);
190 part1_consth_active = false;
191 bfd_put_32(abfd, insn, hit_data);
192 break;
193 case R_BYTE:
194 insn = bfd_get_8(abfd, hit_data);
195 unsigned_value = insn + sym_value + reloc_entry->addend;
196 if (unsigned_value & 0xffffff00)
197 return(bfd_reloc_overflow);
198 bfd_put_8(abfd, unsigned_value, hit_data);
199 break;
200 case R_HWORD:
201 insn = bfd_get_16(abfd, hit_data);
202 unsigned_value = insn + sym_value + reloc_entry->addend;
203 if (unsigned_value & 0xffff0000)
204 return(bfd_reloc_overflow);
205 bfd_put_16(abfd, insn, hit_data);
206 break;
207 case R_WORD:
208 insn = bfd_get_32(abfd, hit_data);
209 insn += sym_value + reloc_entry->addend;
210 bfd_put_32(abfd, insn, hit_data);
211 break;
212 default:
213 *error_message = _("Unrecognized reloc");
214 return (bfd_reloc_dangerous);
215 }
216
217
218 return(bfd_reloc_ok);
219 }
220
221 /* type rightshift
222 size
223 bitsize
224 pc-relative
225 bitpos
226 absolute
227 complain_on_overflow
228 special_function
229 relocation name
230 partial_inplace
231 src_mask
232 */
233
234 /*FIXME: I'm not real sure about this table */
235 static reloc_howto_type howto_table[] =
236 {
237 {R_ABS, 0, 3, 32, false, 0, complain_overflow_bitfield,a29k_reloc,"ABS", true, 0xffffffff,0xffffffff, false},
238 {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10},
239 {11}, {12}, {13}, {14}, {15}, {16}, {17}, {18}, {19}, {20},
240 {21}, {22}, {23},
241 {R_IREL, 0, 3, 32, true, 0, complain_overflow_signed,a29k_reloc,"IREL", true, 0xffffffff,0xffffffff, false},
242 {R_IABS, 0, 3, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"IABS", true, 0xffffffff,0xffffffff, false},
243 {R_ILOHALF, 0, 3, 16, true, 0, complain_overflow_signed, a29k_reloc,"ILOHALF", true, 0x0000ffff,0x0000ffff, false},
244 {R_IHIHALF, 0, 3, 16, true, 16, complain_overflow_signed, a29k_reloc,"IHIHALF", true, 0xffff0000,0xffff0000, false},
245 {R_IHCONST, 0, 3, 16, true, 0, complain_overflow_signed, a29k_reloc,"IHCONST", true, 0xffff0000,0xffff0000, false},
246 {R_BYTE, 0, 0, 8, false, 0, complain_overflow_bitfield, a29k_reloc,"BYTE", true, 0x000000ff,0x000000ff, false},
247 {R_HWORD, 0, 1, 16, false, 0, complain_overflow_bitfield, a29k_reloc,"HWORD", true, 0x0000ffff,0x0000ffff, false},
248 {R_WORD, 0, 2, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"WORD", true, 0xffffffff,0xffffffff, false},
249 };
250
251 #define BADMAG(x) A29KBADMAG(x)
252
253 #define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
254 reloc_processing(relent, reloc, symbols, abfd, section)
255
256 static void
257 reloc_processing (relent,reloc, symbols, abfd, section)
258 arelent *relent;
259 struct internal_reloc *reloc;
260 asymbol **symbols;
261 bfd *abfd;
262 asection *section;
263 {
264 static bfd_vma ihihalf_vaddr = (bfd_vma) -1;
265
266 relent->address = reloc->r_vaddr;
267 relent->howto = howto_table + reloc->r_type;
268 if (reloc->r_type == R_IHCONST)
269 {
270 /* The address of an R_IHCONST should always be the address of
271 the immediately preceding R_IHIHALF. relocs generated by gas
272 are correct, but relocs generated by High C are different (I
273 can't figure out what the address means for High C). We can
274 handle both gas and High C by ignoring the address here, and
275 simply reusing the address saved for R_IHIHALF. */
276 if (ihihalf_vaddr == (bfd_vma) -1)
277 abort ();
278 relent->address = ihihalf_vaddr;
279 ihihalf_vaddr = (bfd_vma) -1;
280 relent->addend = reloc->r_symndx;
281 relent->sym_ptr_ptr= bfd_abs_section_ptr->symbol_ptr_ptr;
282 }
283 else
284 {
285 asymbol *ptr;
286 relent->sym_ptr_ptr = symbols + obj_convert(abfd)[reloc->r_symndx];
287
288 ptr = *(relent->sym_ptr_ptr);
289
290 if (ptr
291 && bfd_asymbol_bfd(ptr) == abfd
292
293 && ((ptr->flags & BSF_OLD_COMMON)== 0))
294 {
295 relent->addend = 0;
296 }
297 else
298 {
299 relent->addend = 0;
300 }
301 relent->address-= section->vma;
302 if (reloc->r_type == R_IHIHALF)
303 ihihalf_vaddr = relent->address;
304 else if (ihihalf_vaddr != (bfd_vma) -1)
305 abort ();
306 }
307 }
308
309 /* The reloc processing routine for the optimized COFF linker. */
310
311 static boolean
312 coff_a29k_relocate_section (output_bfd, info, input_bfd, input_section,
313 contents, relocs, syms, sections)
314 bfd *output_bfd;
315 struct bfd_link_info *info;
316 bfd *input_bfd;
317 asection *input_section;
318 bfd_byte *contents;
319 struct internal_reloc *relocs;
320 struct internal_syment *syms;
321 asection **sections;
322 {
323 struct internal_reloc *rel;
324 struct internal_reloc *relend;
325 boolean hihalf;
326 bfd_vma hihalf_val;
327
328 /* If we are performing a relocateable link, we don't need to do a
329 thing. The caller will take care of adjusting the reloc
330 addresses and symbol indices. */
331 if (info->relocateable)
332 return true;
333
334 hihalf = false;
335 hihalf_val = 0;
336
337 rel = relocs;
338 relend = rel + input_section->reloc_count;
339 for (; rel < relend; rel++)
340 {
341 long symndx;
342 bfd_byte *loc;
343 struct coff_link_hash_entry *h;
344 struct internal_syment *sym;
345 asection *sec;
346 bfd_vma val;
347 boolean overflow;
348 unsigned long insn;
349 long signed_value;
350 unsigned long unsigned_value;
351 bfd_reloc_status_type rstat;
352
353 symndx = rel->r_symndx;
354 loc = contents + rel->r_vaddr - input_section->vma;
355
356 if (symndx == -1 || rel->r_type == R_IHCONST)
357 h = NULL;
358 else
359 h = obj_coff_sym_hashes (input_bfd)[symndx];
360
361 sym = NULL;
362 sec = NULL;
363 val = 0;
364
365 /* An R_IHCONST reloc does not have a symbol. Instead, the
366 symbol index is an addend. R_IHCONST is always used in
367 conjunction with R_IHHALF. */
368 if (rel->r_type != R_IHCONST)
369 {
370 if (h == NULL)
371 {
372 if (symndx == -1)
373 sec = bfd_abs_section_ptr;
374 else
375 {
376 sym = syms + symndx;
377 sec = sections[symndx];
378 val = (sec->output_section->vma
379 + sec->output_offset
380 + sym->n_value
381 - sec->vma);
382 }
383 }
384 else
385 {
386 if (h->root.type == bfd_link_hash_defined
387 || h->root.type == bfd_link_hash_defweak)
388 {
389 sec = h->root.u.def.section;
390 val = (h->root.u.def.value
391 + sec->output_section->vma
392 + sec->output_offset);
393 }
394 else
395 {
396 if (! ((*info->callbacks->undefined_symbol)
397 (info, h->root.root.string, input_bfd, input_section,
398 rel->r_vaddr - input_section->vma)))
399 return false;
400 }
401 }
402
403 if (hihalf)
404 {
405 if (! ((*info->callbacks->reloc_dangerous)
406 (info, _("missing IHCONST reloc"), input_bfd,
407 input_section, rel->r_vaddr - input_section->vma)))
408 return false;
409 hihalf = false;
410 }
411 }
412
413 overflow = false;
414
415 switch (rel->r_type)
416 {
417 default:
418 bfd_set_error (bfd_error_bad_value);
419 return false;
420
421 case R_IREL:
422 insn = bfd_get_32 (input_bfd, loc);
423
424 /* Extract the addend. */
425 signed_value = EXTRACT_HWORD (insn);
426 signed_value = SIGN_EXTEND_HWORD (signed_value);
427 signed_value <<= 2;
428
429 /* Unfortunately, there are two different versions of COFF
430 a29k. In the original AMD version, the value stored in
431 the field for the R_IREL reloc is a simple addend. In
432 the GNU version, the value is the negative of the address
433 of the reloc within section. We try to cope here by
434 assuming the AMD version, unless the addend is exactly
435 the negative of the address; in the latter case we assume
436 the GNU version. This means that something like
437 .text
438 nop
439 jmp i-4
440 will fail, because the addend of -4 will happen to equal
441 the negative of the address within the section. The
442 compiler will never generate code like this.
443
444 At some point in the future we may want to take out this
445 check. */
446
447 if (signed_value == - (long) (rel->r_vaddr - input_section->vma))
448 signed_value = 0;
449
450 /* Determine the destination of the jump. */
451 signed_value += val;
452
453 if ((signed_value & ~0x3ffff) == 0)
454 {
455 /* We can use an absolute jump. */
456 insn |= (1 << 24);
457 }
458 else
459 {
460 /* Make the destination PC relative. */
461 signed_value -= (input_section->output_section->vma
462 + input_section->output_offset
463 + (rel->r_vaddr - input_section->vma));
464 if (signed_value > 0x1ffff || signed_value < - 0x20000)
465 {
466 overflow = true;
467 signed_value = 0;
468 }
469 }
470
471 /* Put the adjusted value back into the instruction. */
472 signed_value >>= 2;
473 insn = INSERT_HWORD (insn, signed_value);
474
475 bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
476
477 break;
478
479 case R_ILOHALF:
480 insn = bfd_get_32 (input_bfd, loc);
481 unsigned_value = EXTRACT_HWORD (insn);
482 unsigned_value += val;
483 insn = INSERT_HWORD (insn, unsigned_value);
484 bfd_put_32 (input_bfd, insn, loc);
485 break;
486
487 case R_IHIHALF:
488 /* Save the value for the R_IHCONST reloc. */
489 hihalf = true;
490 hihalf_val = val;
491 break;
492
493 case R_IHCONST:
494 if (! hihalf)
495 {
496 if (! ((*info->callbacks->reloc_dangerous)
497 (info, _("missing IHIHALF reloc"), input_bfd,
498 input_section, rel->r_vaddr - input_section->vma)))
499 return false;
500 hihalf_val = 0;
501 }
502
503 insn = bfd_get_32 (input_bfd, loc);
504 unsigned_value = rel->r_symndx + hihalf_val;
505 unsigned_value >>= 16;
506 insn = INSERT_HWORD (insn, unsigned_value);
507 bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
508
509 hihalf = false;
510
511 break;
512
513 case R_BYTE:
514 case R_HWORD:
515 case R_WORD:
516 rstat = _bfd_relocate_contents (howto_table + rel->r_type,
517 input_bfd, val, loc);
518 if (rstat == bfd_reloc_overflow)
519 overflow = true;
520 else if (rstat != bfd_reloc_ok)
521 abort ();
522 break;
523 }
524
525 if (overflow)
526 {
527 const char *name;
528 char buf[SYMNMLEN + 1];
529
530 if (symndx == -1)
531 name = "*ABS*";
532 else if (h != NULL)
533 name = h->root.root.string;
534 else if (sym == NULL)
535 name = "*unknown*";
536 else if (sym->_n._n_n._n_zeroes == 0
537 && sym->_n._n_n._n_offset != 0)
538 name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
539 else
540 {
541 strncpy (buf, sym->_n._n_name, SYMNMLEN);
542 buf[SYMNMLEN] = '\0';
543 name = buf;
544 }
545
546 if (! ((*info->callbacks->reloc_overflow)
547 (info, name, howto_table[rel->r_type].name, (bfd_vma) 0,
548 input_bfd, input_section,
549 rel->r_vaddr - input_section->vma)))
550 return false;
551 }
552 }
553
554 return true;
555 }
556
557 #define coff_relocate_section coff_a29k_relocate_section
558
559 /* We don't want to change the symndx of a R_IHCONST reloc, since it
560 is actually an addend, not a symbol index at all. */
561
562 /*ARGSUSED*/
563 static boolean
564 coff_a29k_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
565 bfd *obfd;
566 struct bfd_link_info *info;
567 bfd *ibfd;
568 asection *sec;
569 struct internal_reloc *irel;
570 boolean *adjustedp;
571 {
572 if (irel->r_type == R_IHCONST)
573 *adjustedp = true;
574 else
575 *adjustedp = false;
576 return true;
577 }
578
579 #define coff_adjust_symndx coff_a29k_adjust_symndx
580
581 #include "coffcode.h"
582
583 const bfd_target a29kcoff_big_vec =
584 {
585 "coff-a29k-big", /* name */
586 bfd_target_coff_flavour,
587 BFD_ENDIAN_BIG, /* data byte order is big */
588 BFD_ENDIAN_BIG, /* header byte order is big */
589
590 (HAS_RELOC | EXEC_P | /* object flags */
591 HAS_LINENO | HAS_DEBUG |
592 HAS_SYMS | HAS_LOCALS | WP_TEXT),
593
594 (SEC_HAS_CONTENTS | SEC_ALLOC /* section flags */
595 | SEC_LOAD | SEC_RELOC
596 | SEC_READONLY ),
597 '_', /* leading underscore */
598 '/', /* ar_pad_char */
599 15, /* ar_max_namelen */
600 /* data */
601 bfd_getb64, bfd_getb_signed_64, bfd_putb64,
602 bfd_getb32, bfd_getb_signed_32, bfd_putb32,
603 bfd_getb16, bfd_getb_signed_16, bfd_putb16,
604 /* hdrs */
605 bfd_getb64, bfd_getb_signed_64, bfd_putb64,
606 bfd_getb32, bfd_getb_signed_32, bfd_putb32,
607 bfd_getb16, bfd_getb_signed_16, bfd_putb16,
608
609 {
610
611 _bfd_dummy_target,
612 coff_object_p,
613 bfd_generic_archive_p,
614 _bfd_dummy_target
615 },
616 {
617 bfd_false,
618 coff_mkobject,
619 _bfd_generic_mkarchive,
620 bfd_false
621 },
622 {
623 bfd_false,
624 coff_write_object_contents,
625 _bfd_write_archive_contents,
626 bfd_false
627 },
628
629 BFD_JUMP_TABLE_GENERIC (coff),
630 BFD_JUMP_TABLE_COPY (coff),
631 BFD_JUMP_TABLE_CORE (_bfd_nocore),
632 BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
633 BFD_JUMP_TABLE_SYMBOLS (coff),
634 BFD_JUMP_TABLE_RELOCS (coff),
635 BFD_JUMP_TABLE_WRITE (coff),
636 BFD_JUMP_TABLE_LINK (coff),
637 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
638
639 COFF_SWAP_TABLE
640 };