1999-06-12 David O'Brien <obrien@freebsd.org>
[binutils.git] / bfd / coff-a29k.c
blobbbf23eed981a4643477fc1f6bc2729b8f32625e8
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.
5 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
21 #define A29K 1
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"
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 *));
40 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
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))
49 /* Provided the symbol, returns the value reffed */
50 static long
51 get_symbol_value (symbol)
52 asymbol *symbol;
54 long relocation = 0;
56 if (bfd_is_com_section (symbol->section))
58 relocation = 0;
60 else
62 relocation = symbol->value +
63 symbol->section->output_section->vma +
64 symbol->section->output_offset;
67 return(relocation);
70 /* this function is in charge of performing all the 29k relocations */
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;
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;
88 unsigned long insn;
89 unsigned long sym_value;
90 unsigned long unsigned_value;
91 unsigned short r_type;
92 long signed_value;
94 unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
95 bfd_byte *hit_data =addr + (bfd_byte *)(data);
97 r_type = reloc_entry->howto->type;
99 if (output_bfd) {
100 /* Partial linking - do nothing */
101 reloc_entry->address += input_section->output_offset;
102 return bfd_reloc_ok;
106 if (symbol_in != NULL
107 && bfd_is_und_section (symbol_in->section))
109 /* Keep the state machine happy in case we're called again */
110 if (r_type == R_IHIHALF)
112 part1_consth_active = true;
113 part1_consth_value = 0;
115 return(bfd_reloc_undefined);
118 if ((part1_consth_active) && (r_type != R_IHCONST))
120 part1_consth_active = false;
121 *error_message = (char *) _("Missing IHCONST");
122 return(bfd_reloc_dangerous);
126 sym_value = get_symbol_value(symbol_in);
128 switch (r_type)
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;
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;
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 */
147 else
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);
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);
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);
218 return(bfd_reloc_ok);
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
234 /*FIXME: I'm not real sure about this table */
235 static reloc_howto_type howto_table[] =
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},
251 #define BADMAG(x) A29KBADMAG(x)
253 #define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
254 reloc_processing(relent, reloc, symbols, abfd, section)
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;
264 static bfd_vma ihihalf_vaddr = (bfd_vma) -1;
266 relent->address = reloc->r_vaddr;
267 relent->howto = howto_table + reloc->r_type;
268 if (reloc->r_type == R_IHCONST)
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;
283 else
285 asymbol *ptr;
286 relent->sym_ptr_ptr = symbols + obj_convert(abfd)[reloc->r_symndx];
288 ptr = *(relent->sym_ptr_ptr);
290 if (ptr
291 && bfd_asymbol_bfd(ptr) == abfd
293 && ((ptr->flags & BSF_OLD_COMMON)== 0))
295 relent->addend = 0;
297 else
299 relent->addend = 0;
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 ();
309 /* The reloc processing routine for the optimized COFF linker. */
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;
323 struct internal_reloc *rel;
324 struct internal_reloc *relend;
325 boolean hihalf;
326 bfd_vma hihalf_val;
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;
334 hihalf = false;
335 hihalf_val = 0;
337 rel = relocs;
338 relend = rel + input_section->reloc_count;
339 for (; rel < relend; rel++)
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;
353 symndx = rel->r_symndx;
354 loc = contents + rel->r_vaddr - input_section->vma;
356 if (symndx == -1 || rel->r_type == R_IHCONST)
357 h = NULL;
358 else
359 h = obj_coff_sym_hashes (input_bfd)[symndx];
361 sym = NULL;
362 sec = NULL;
363 val = 0;
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)
370 if (h == NULL)
372 if (symndx == -1)
373 sec = bfd_abs_section_ptr;
374 else
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);
384 else
386 if (h->root.type == bfd_link_hash_defined
387 || h->root.type == bfd_link_hash_defweak)
389 sec = h->root.u.def.section;
390 val = (h->root.u.def.value
391 + sec->output_section->vma
392 + sec->output_offset);
394 else
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;
403 if (hihalf)
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;
413 overflow = false;
415 switch (rel->r_type)
417 default:
418 bfd_set_error (bfd_error_bad_value);
419 return false;
421 case R_IREL:
422 insn = bfd_get_32 (input_bfd, loc);
424 /* Extract the addend. */
425 signed_value = EXTRACT_HWORD (insn);
426 signed_value = SIGN_EXTEND_HWORD (signed_value);
427 signed_value <<= 2;
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
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.
444 At some point in the future we may want to take out this
445 check. */
447 if (signed_value == - (long) (rel->r_vaddr - input_section->vma))
448 signed_value = 0;
450 /* Determine the destination of the jump. */
451 signed_value += val;
453 if ((signed_value & ~0x3ffff) == 0)
455 /* We can use an absolute jump. */
456 insn |= (1 << 24);
458 else
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)
466 overflow = true;
467 signed_value = 0;
471 /* Put the adjusted value back into the instruction. */
472 signed_value >>= 2;
473 insn = INSERT_HWORD (insn, signed_value);
475 bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
477 break;
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;
487 case R_IHIHALF:
488 /* Save the value for the R_IHCONST reloc. */
489 hihalf = true;
490 hihalf_val = val;
491 break;
493 case R_IHCONST:
494 if (! hihalf)
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;
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);
509 hihalf = false;
511 break;
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;
525 if (overflow)
527 const char *name;
528 char buf[SYMNMLEN + 1];
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
541 strncpy (buf, sym->_n._n_name, SYMNMLEN);
542 buf[SYMNMLEN] = '\0';
543 name = buf;
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;
554 return true;
557 #define coff_relocate_section coff_a29k_relocate_section
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. */
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;
572 if (irel->r_type == R_IHCONST)
573 *adjustedp = true;
574 else
575 *adjustedp = false;
576 return true;
579 #define coff_adjust_symndx coff_a29k_adjust_symndx
581 #include "coffcode.h"
583 const bfd_target a29kcoff_big_vec =
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 */
590 (HAS_RELOC | EXEC_P | /* object flags */
591 HAS_LINENO | HAS_DEBUG |
592 HAS_SYMS | HAS_LOCALS | WP_TEXT),
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,
611 _bfd_dummy_target,
612 coff_object_p,
613 bfd_generic_archive_p,
614 _bfd_dummy_target
617 bfd_false,
618 coff_mkobject,
619 _bfd_generic_mkarchive,
620 bfd_false
623 bfd_false,
624 coff_write_object_contents,
625 _bfd_write_archive_contents,
626 bfd_false
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),
639 COFF_SWAP_TABLE