1 /* BFD back-end for AMD 29000 COFF binaries.
2 Copyright 1990, 1991, 1992, 1993, 1994 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. */
27 #include "coff/a29k.h"
28 #include "coff/internal.h"
31 static long get_symbol_value PARAMS ((asymbol *));
32 static bfd_reloc_status_type a29k_reloc
33 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
34 static boolean coff_a29k_relocate_section
35 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
36 struct internal_reloc *, struct internal_syment *, asection **));
37 static boolean coff_a29k_adjust_symndx
38 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
39 struct internal_reloc *, boolean *));
41 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
43 #define INSERT_HWORD(WORD,HWORD) \
44 (((WORD) & 0xff00ff00) | (((HWORD) & 0xff00) << 8) | ((HWORD)& 0xff))
45 #define EXTRACT_HWORD(WORD) \
46 ((((WORD) & 0x00ff0000) >> 8) | ((WORD)& 0xff))
47 #define SIGN_EXTEND_HWORD(HWORD) \
48 ((HWORD) & 0x8000 ? (HWORD)|(~0xffffL) : (HWORD))
50 /* Provided the symbol, returns the value reffed */
52 get_symbol_value (symbol)
57 if (bfd_is_com_section (symbol->section))
63 relocation = symbol->value +
64 symbol->section->output_section->vma +
65 symbol->section->output_offset;
71 /* this function is in charge of performing all the 29k relocations */
73 static bfd_reloc_status_type
74 a29k_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
80 asection *input_section;
84 /* the consth relocation comes in two parts, we have to remember
85 the state between calls, in these variables */
86 static boolean part1_consth_active = false;
87 static unsigned long part1_consth_value;
90 unsigned long sym_value;
91 unsigned long unsigned_value;
92 unsigned short r_type;
95 unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
96 bfd_byte *hit_data =addr + (bfd_byte *)(data);
98 r_type = reloc_entry->howto->type;
101 /* Partial linking - do nothing */
102 reloc_entry->address += input_section->output_offset;
107 if (symbol_in != NULL
108 && bfd_is_und_section (symbol_in->section))
110 /* Keep the state machine happy in case we're called again */
111 if (r_type == R_IHIHALF)
113 part1_consth_active = true;
114 part1_consth_value = 0;
116 return(bfd_reloc_undefined);
119 if ((part1_consth_active) && (r_type != R_IHCONST))
121 part1_consth_active = false;
122 *error_message = (char *) "Missing IHCONST";
123 return(bfd_reloc_dangerous);
127 sym_value = get_symbol_value(symbol_in);
132 insn = bfd_get_32(abfd, hit_data);
133 /* Take the value in the field and sign extend it */
134 signed_value = EXTRACT_HWORD(insn);
135 signed_value = SIGN_EXTEND_HWORD(signed_value);
138 /* See the note on the R_IREL reloc in coff_a29k_relocate_section. */
139 if (signed_value == - (long) reloc_entry->address)
142 signed_value += sym_value + reloc_entry->addend;
143 if ((signed_value & ~0x3ffff) == 0)
144 { /* Absolute jmp/call */
145 insn |= (1<<24); /* Make it absolute */
146 /* FIXME: Should we change r_type to R_IABS */
150 /* Relative jmp/call, so subtract from the value the
151 address of the place we're coming from */
152 signed_value -= (reloc_entry->address
153 + input_section->output_section->vma
154 + input_section->output_offset);
155 if (signed_value>0x1ffff || signed_value<-0x20000)
156 return(bfd_reloc_overflow);
159 insn = INSERT_HWORD(insn, signed_value);
160 bfd_put_32(abfd, insn ,hit_data);
163 insn = bfd_get_32(abfd, hit_data);
164 unsigned_value = EXTRACT_HWORD(insn);
165 unsigned_value += sym_value + reloc_entry->addend;
166 insn = INSERT_HWORD(insn, unsigned_value);
167 bfd_put_32(abfd, insn, hit_data);
170 insn = bfd_get_32(abfd, hit_data);
172 Just get the symbol value that is referenced */
173 part1_consth_active = true;
174 part1_consth_value = sym_value + reloc_entry->addend;
175 /* Don't modify insn until R_IHCONST */
178 insn = bfd_get_32(abfd, hit_data);
180 Now relocate the reference */
181 if (part1_consth_active == false) {
182 *error_message = (char *) "Missing IHIHALF";
183 return(bfd_reloc_dangerous);
185 /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
186 unsigned_value = 0; /*EXTRACT_HWORD(insn) << 16;*/
187 unsigned_value += reloc_entry->addend; /* r_symndx */
188 unsigned_value += part1_consth_value;
189 unsigned_value = unsigned_value >> 16;
190 insn = INSERT_HWORD(insn, unsigned_value);
191 part1_consth_active = false;
192 bfd_put_32(abfd, insn, hit_data);
195 insn = bfd_get_8(abfd, hit_data);
196 unsigned_value = insn + sym_value + reloc_entry->addend;
197 if (unsigned_value & 0xffffff00)
198 return(bfd_reloc_overflow);
199 bfd_put_8(abfd, unsigned_value, hit_data);
202 insn = bfd_get_16(abfd, hit_data);
203 unsigned_value = insn + sym_value + reloc_entry->addend;
204 if (unsigned_value & 0xffff0000)
205 return(bfd_reloc_overflow);
206 bfd_put_16(abfd, insn, hit_data);
209 insn = bfd_get_32(abfd, hit_data);
210 insn += sym_value + reloc_entry->addend;
211 bfd_put_32(abfd, insn, hit_data);
214 *error_message = "Unrecognized reloc";
215 return (bfd_reloc_dangerous);
219 return(bfd_reloc_ok);
235 /*FIXME: I'm not real sure about this table */
236 static reloc_howto_type howto_table[] =
238 {R_ABS, 0, 3, 32, false, 0, complain_overflow_bitfield,a29k_reloc,"ABS", true, 0xffffffff,0xffffffff, false},
239 {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10},
240 {11}, {12}, {13}, {14}, {15}, {16}, {17}, {18}, {19}, {20},
242 {R_IREL, 0, 3, 32, true, 0, complain_overflow_signed,a29k_reloc,"IREL", true, 0xffffffff,0xffffffff, false},
243 {R_IABS, 0, 3, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"IABS", true, 0xffffffff,0xffffffff, false},
244 {R_ILOHALF, 0, 3, 16, true, 0, complain_overflow_signed, a29k_reloc,"ILOHALF", true, 0x0000ffff,0x0000ffff, false},
245 {R_IHIHALF, 0, 3, 16, true, 16, complain_overflow_signed, a29k_reloc,"IHIHALF", true, 0xffff0000,0xffff0000, false},
246 {R_IHCONST, 0, 3, 16, true, 0, complain_overflow_signed, a29k_reloc,"IHCONST", true, 0xffff0000,0xffff0000, false},
247 {R_BYTE, 0, 0, 8, false, 0, complain_overflow_bitfield, a29k_reloc,"BYTE", true, 0x000000ff,0x000000ff, false},
248 {R_HWORD, 0, 1, 16, false, 0, complain_overflow_bitfield, a29k_reloc,"HWORD", true, 0x0000ffff,0x0000ffff, false},
249 {R_WORD, 0, 2, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"WORD", true, 0xffffffff,0xffffffff, false},
252 #define BADMAG(x) A29KBADMAG(x)
254 #define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
255 reloc_processing(relent, reloc, symbols, abfd, section)
258 reloc_processing (relent,reloc, symbols, abfd, section)
260 struct internal_reloc *reloc;
265 static bfd_vma ihihalf_vaddr = (bfd_vma) -1;
267 relent->address = reloc->r_vaddr;
268 relent->howto = howto_table + reloc->r_type;
269 if (reloc->r_type == R_IHCONST)
271 /* The address of an R_IHCONST should always be the address of
272 the immediately preceding R_IHIHALF. relocs generated by gas
273 are correct, but relocs generated by High C are different (I
274 can't figure out what the address means for High C). We can
275 handle both gas and High C by ignoring the address here, and
276 simply reusing the address saved for R_IHIHALF. */
277 if (ihihalf_vaddr == (bfd_vma) -1)
279 relent->address = ihihalf_vaddr;
280 ihihalf_vaddr = (bfd_vma) -1;
281 relent->addend = reloc->r_symndx;
282 relent->sym_ptr_ptr= bfd_abs_section_ptr->symbol_ptr_ptr;
287 relent->sym_ptr_ptr = symbols + obj_convert(abfd)[reloc->r_symndx];
289 ptr = *(relent->sym_ptr_ptr);
292 && bfd_asymbol_bfd(ptr) == abfd
294 && ((ptr->flags & BSF_OLD_COMMON)== 0))
302 relent->address-= section->vma;
303 if (reloc->r_type == R_IHIHALF)
304 ihihalf_vaddr = relent->address;
305 else if (ihihalf_vaddr != (bfd_vma) -1)
310 /* The reloc processing routine for the optimized COFF linker. */
313 coff_a29k_relocate_section (output_bfd, info, input_bfd, input_section,
314 contents, relocs, syms, sections)
316 struct bfd_link_info *info;
318 asection *input_section;
320 struct internal_reloc *relocs;
321 struct internal_syment *syms;
324 struct internal_reloc *rel;
325 struct internal_reloc *relend;
329 /* If we are performing a relocateable link, we don't need to do a
330 thing. The caller will take care of adjusting the reloc
331 addresses and symbol indices. */
332 if (info->relocateable)
339 relend = rel + input_section->reloc_count;
340 for (; rel < relend; rel++)
344 struct coff_link_hash_entry *h;
345 struct internal_syment *sym;
351 unsigned long unsigned_value;
352 bfd_reloc_status_type rstat;
354 symndx = rel->r_symndx;
355 loc = contents + rel->r_vaddr - input_section->vma;
360 h = obj_coff_sym_hashes (input_bfd)[symndx];
366 /* An R_IHCONST reloc does not have a symbol. Instead, the
367 symbol index is an addend. R_IHCONST is always used in
368 conjunction with R_IHHALF. */
369 if (rel->r_type != R_IHCONST)
374 sec = bfd_abs_section_ptr;
378 sec = sections[symndx];
379 val = (sec->output_section->vma
387 if (h->root.type == bfd_link_hash_defined
388 || h->root.type == bfd_link_hash_defweak)
390 sec = h->root.u.def.section;
391 val = (h->root.u.def.value
392 + sec->output_section->vma
393 + sec->output_offset);
397 if (! ((*info->callbacks->undefined_symbol)
398 (info, h->root.root.string, input_bfd, input_section,
399 rel->r_vaddr - input_section->vma)))
406 if (! ((*info->callbacks->reloc_dangerous)
407 (info, "missing IHCONST reloc", input_bfd,
408 input_section, rel->r_vaddr - input_section->vma)))
419 bfd_set_error (bfd_error_bad_value);
423 insn = bfd_get_32 (input_bfd, loc);
425 /* Extract the addend. */
426 signed_value = EXTRACT_HWORD (insn);
427 signed_value = SIGN_EXTEND_HWORD (signed_value);
430 /* Unfortunately, there are two different versions of COFF
431 a29k. In the original AMD version, the value stored in
432 the field for the R_IREL reloc is a simple addend. In
433 the GNU version, the value is the negative of the address
434 of the reloc within section. We try to cope here by
435 assuming the AMD version, unless the addend is exactly
436 the negative of the address; in the latter case we assume
437 the GNU version. This means that something like
441 will fail, because the addend of -4 will happen to equal
442 the negative of the address within the section. The
443 compiler will never generate code like this.
445 At some point in the future we may want to take out this
448 if (signed_value == - (long) (rel->r_vaddr - input_section->vma))
451 /* Determine the destination of the jump. */
454 if ((signed_value & ~0x3ffff) == 0)
456 /* We can use an absolute jump. */
461 /* Make the destination PC relative. */
462 signed_value -= (input_section->output_section->vma
463 + input_section->output_offset
464 + (rel->r_vaddr - input_section->vma));
465 if (signed_value > 0x1ffff || signed_value < - 0x20000)
472 /* Put the adjusted value back into the instruction. */
474 insn = INSERT_HWORD (insn, signed_value);
476 bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
481 insn = bfd_get_32 (input_bfd, loc);
482 unsigned_value = EXTRACT_HWORD (insn);
483 unsigned_value += val;
484 insn = INSERT_HWORD (insn, unsigned_value);
485 bfd_put_32 (input_bfd, insn, loc);
489 /* Save the value for the R_IHCONST reloc. */
497 if (! ((*info->callbacks->reloc_dangerous)
498 (info, "missing IHIHALF reloc", input_bfd,
499 input_section, rel->r_vaddr - input_section->vma)))
504 insn = bfd_get_32 (input_bfd, loc);
505 unsigned_value = rel->r_symndx + hihalf_val;
506 unsigned_value >>= 16;
507 insn = INSERT_HWORD (insn, unsigned_value);
508 bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
517 rstat = _bfd_relocate_contents (howto_table + rel->r_type,
518 input_bfd, val, loc);
519 if (rstat == bfd_reloc_overflow)
521 else if (rstat != bfd_reloc_ok)
529 char buf[SYMNMLEN + 1];
534 name = h->root.root.string;
535 else if (sym == NULL)
537 else if (sym->_n._n_n._n_zeroes == 0
538 && sym->_n._n_n._n_offset != 0)
539 name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
542 strncpy (buf, sym->_n._n_name, SYMNMLEN);
543 buf[SYMNMLEN] = '\0';
547 if (! ((*info->callbacks->reloc_overflow)
548 (info, name, howto_table[rel->r_type].name, (bfd_vma) 0,
549 input_bfd, input_section,
550 rel->r_vaddr - input_section->vma)))
558 #define coff_relocate_section coff_a29k_relocate_section
560 /* We don't want to change the symndx of a R_IHCONST reloc, since it
561 is actually an addend, not a symbol index at all. */
565 coff_a29k_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
567 struct bfd_link_info *info;
570 struct internal_reloc *irel;
573 if (irel->r_type == R_IHCONST)
580 #define coff_adjust_symndx coff_a29k_adjust_symndx
582 #include "coffcode.h"
584 const bfd_target a29kcoff_big_vec =
586 "coff-a29k-big", /* name */
587 bfd_target_coff_flavour,
588 BFD_ENDIAN_BIG, /* data byte order is big */
589 BFD_ENDIAN_BIG, /* header byte order is big */
591 (HAS_RELOC | EXEC_P | /* object flags */
592 HAS_LINENO | HAS_DEBUG |
593 HAS_SYMS | HAS_LOCALS | WP_TEXT),
595 (SEC_HAS_CONTENTS | SEC_ALLOC /* section flags */
596 | SEC_LOAD | SEC_RELOC
598 '_', /* leading underscore */
599 '/', /* ar_pad_char */
600 15, /* ar_max_namelen */
602 bfd_getb64, bfd_getb_signed_64, bfd_putb64,
603 bfd_getb32, bfd_getb_signed_32, bfd_putb32,
604 bfd_getb16, bfd_getb_signed_16, bfd_putb16,
606 bfd_getb64, bfd_getb_signed_64, bfd_putb64,
607 bfd_getb32, bfd_getb_signed_32, bfd_putb32,
608 bfd_getb16, bfd_getb_signed_16, bfd_putb16,
614 bfd_generic_archive_p,
620 _bfd_generic_mkarchive,
625 coff_write_object_contents,
626 _bfd_write_archive_contents,
630 BFD_JUMP_TABLE_GENERIC (coff),
631 BFD_JUMP_TABLE_COPY (coff),
632 BFD_JUMP_TABLE_CORE (_bfd_nocore),
633 BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
634 BFD_JUMP_TABLE_SYMBOLS (coff),
635 BFD_JUMP_TABLE_RELOCS (coff),
636 BFD_JUMP_TABLE_WRITE (coff),
637 BFD_JUMP_TABLE_LINK (coff),
638 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),