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. */
26 #include "coff/a29k.h"
27 #include "coff/internal.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 */
51 get_symbol_value (symbol
)
56 if (bfd_is_com_section (symbol
->section
))
62 relocation
= symbol
->value
+
63 symbol
->section
->output_section
->vma
+
64 symbol
->section
->output_offset
;
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
,
79 asection
*input_section
;
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
;
89 unsigned long sym_value
;
90 unsigned long unsigned_value
;
91 unsigned short r_type
;
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
;
100 /* Partial linking - do nothing */
101 reloc_entry
->address
+= input_section
->output_offset
;
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
);
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
);
137 /* See the note on the R_IREL reloc in coff_a29k_relocate_section. */
138 if (signed_value
== - (long) reloc_entry
->address
)
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 */
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
);
158 insn
= INSERT_HWORD(insn
, signed_value
);
159 bfd_put_32(abfd
, insn
,hit_data
);
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
);
169 insn
= bfd_get_32(abfd
, hit_data
);
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 */
177 insn
= bfd_get_32(abfd
, hit_data
);
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
);
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
);
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
);
208 insn
= bfd_get_32(abfd
, hit_data
);
209 insn
+= sym_value
+ reloc_entry
->addend
;
210 bfd_put_32(abfd
, insn
, hit_data
);
213 *error_message
= _("Unrecognized reloc");
214 return (bfd_reloc_dangerous
);
218 return(bfd_reloc_ok
);
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},
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)
257 reloc_processing (relent
,reloc
, symbols
, abfd
, section
)
259 struct internal_reloc
*reloc
;
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)
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
;
286 relent
->sym_ptr_ptr
= symbols
+ obj_convert(abfd
)[reloc
->r_symndx
];
288 ptr
= *(relent
->sym_ptr_ptr
);
291 && bfd_asymbol_bfd(ptr
) == abfd
293 && ((ptr
->flags
& BSF_OLD_COMMON
)== 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)
309 /* The reloc processing routine for the optimized COFF linker. */
312 coff_a29k_relocate_section (output_bfd
, info
, input_bfd
, input_section
,
313 contents
, relocs
, syms
, sections
)
315 struct bfd_link_info
*info
;
317 asection
*input_section
;
319 struct internal_reloc
*relocs
;
320 struct internal_syment
*syms
;
323 struct internal_reloc
*rel
;
324 struct internal_reloc
*relend
;
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
)
338 relend
= rel
+ input_section
->reloc_count
;
339 for (; rel
< relend
; rel
++)
343 struct coff_link_hash_entry
*h
;
344 struct internal_syment
*sym
;
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
)
359 h
= obj_coff_sym_hashes (input_bfd
)[symndx
];
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
)
373 sec
= bfd_abs_section_ptr
;
377 sec
= sections
[symndx
];
378 val
= (sec
->output_section
->vma
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
);
396 if (! ((*info
->callbacks
->undefined_symbol
)
397 (info
, h
->root
.root
.string
, input_bfd
, input_section
,
398 rel
->r_vaddr
- input_section
->vma
)))
405 if (! ((*info
->callbacks
->reloc_dangerous
)
406 (info
, _("missing IHCONST reloc"), input_bfd
,
407 input_section
, rel
->r_vaddr
- input_section
->vma
)))
418 bfd_set_error (bfd_error_bad_value
);
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
);
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
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
447 if (signed_value
== - (long) (rel
->r_vaddr
- input_section
->vma
))
450 /* Determine the destination of the jump. */
453 if ((signed_value
& ~0x3ffff) == 0)
455 /* We can use an absolute jump. */
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)
471 /* Put the adjusted value back into the instruction. */
473 insn
= INSERT_HWORD (insn
, signed_value
);
475 bfd_put_32 (input_bfd
, (bfd_vma
) insn
, loc
);
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
);
488 /* Save the value for the R_IHCONST reloc. */
496 if (! ((*info
->callbacks
->reloc_dangerous
)
497 (info
, _("missing IHIHALF reloc"), input_bfd
,
498 input_section
, rel
->r_vaddr
- input_section
->vma
)))
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
);
516 rstat
= _bfd_relocate_contents (howto_table
+ rel
->r_type
,
517 input_bfd
, val
, loc
);
518 if (rstat
== bfd_reloc_overflow
)
520 else if (rstat
!= bfd_reloc_ok
)
528 char buf
[SYMNMLEN
+ 1];
533 name
= h
->root
.root
.string
;
534 else if (sym
== NULL
)
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
;
541 strncpy (buf
, sym
->_n
._n_name
, SYMNMLEN
);
542 buf
[SYMNMLEN
] = '\0';
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
)))
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. */
564 coff_a29k_adjust_symndx (obfd
, info
, ibfd
, sec
, irel
, adjustedp
)
566 struct bfd_link_info
*info
;
569 struct internal_reloc
*irel
;
572 if (irel
->r_type
== R_IHCONST
)
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
597 '_', /* leading underscore */
598 '/', /* ar_pad_char */
599 15, /* ar_max_namelen */
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
,
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
,
613 bfd_generic_archive_p
,
619 _bfd_generic_mkarchive
,
624 coff_write_object_contents
,
625 _bfd_write_archive_contents
,
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
),