1 /* BFD back-end for AMD 29000 COFF binaries.
2 Copyright 1990, 91, 92, 93, 94, 95, 97, 98, 99, 2000
3 Free Software Foundation, Inc.
4 Contributed by David Wood at New York University 7/8/91.
6 This file is part of BFD, the Binary File Descriptor library.
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 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) - 0x8000)
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
;
102 /* Partial linking - do nothing */
103 reloc_entry
->address
+= input_section
->output_offset
;
108 if (symbol_in
!= NULL
109 && bfd_is_und_section (symbol_in
->section
))
111 /* Keep the state machine happy in case we're called again */
112 if (r_type
== R_IHIHALF
)
114 part1_consth_active
= true;
115 part1_consth_value
= 0;
117 return(bfd_reloc_undefined
);
120 if ((part1_consth_active
) && (r_type
!= R_IHCONST
))
122 part1_consth_active
= false;
123 *error_message
= (char *) _("Missing IHCONST");
124 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)
183 *error_message
= (char *) _("Missing IHIHALF");
184 return(bfd_reloc_dangerous
);
186 /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
187 unsigned_value
= 0; /*EXTRACT_HWORD(insn) << 16;*/
188 unsigned_value
+= reloc_entry
->addend
; /* r_symndx */
189 unsigned_value
+= part1_consth_value
;
190 unsigned_value
= unsigned_value
>> 16;
191 insn
= INSERT_HWORD(insn
, unsigned_value
);
192 part1_consth_active
= false;
193 bfd_put_32 (abfd
, insn
, hit_data
);
196 insn
= bfd_get_8 (abfd
, hit_data
);
197 unsigned_value
= insn
+ sym_value
+ reloc_entry
->addend
;
198 if (unsigned_value
& 0xffffff00)
199 return(bfd_reloc_overflow
);
200 bfd_put_8 (abfd
, unsigned_value
, hit_data
);
203 insn
= bfd_get_16 (abfd
, hit_data
);
204 unsigned_value
= insn
+ sym_value
+ reloc_entry
->addend
;
205 if (unsigned_value
& 0xffff0000)
206 return(bfd_reloc_overflow
);
207 bfd_put_16 (abfd
, insn
, hit_data
);
210 insn
= bfd_get_32 (abfd
, hit_data
);
211 insn
+= sym_value
+ reloc_entry
->addend
;
212 bfd_put_32 (abfd
, insn
, hit_data
);
215 *error_message
= _("Unrecognized reloc");
216 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},
262 {R_IREL
, 0, 3, 32, true, 0, complain_overflow_signed
,a29k_reloc
,"IREL", true, 0xffffffff,0xffffffff, false},
263 {R_IABS
, 0, 3, 32, false, 0, complain_overflow_bitfield
, a29k_reloc
,"IABS", true, 0xffffffff,0xffffffff, false},
264 {R_ILOHALF
, 0, 3, 16, true, 0, complain_overflow_signed
, a29k_reloc
,"ILOHALF", true, 0x0000ffff,0x0000ffff, false},
265 {R_IHIHALF
, 0, 3, 16, true, 16, complain_overflow_signed
, a29k_reloc
,"IHIHALF", true, 0xffff0000,0xffff0000, false},
266 {R_IHCONST
, 0, 3, 16, true, 0, complain_overflow_signed
, a29k_reloc
,"IHCONST", true, 0xffff0000,0xffff0000, false},
267 {R_BYTE
, 0, 0, 8, false, 0, complain_overflow_bitfield
, a29k_reloc
,"BYTE", true, 0x000000ff,0x000000ff, false},
268 {R_HWORD
, 0, 1, 16, false, 0, complain_overflow_bitfield
, a29k_reloc
,"HWORD", true, 0x0000ffff,0x0000ffff, false},
269 {R_WORD
, 0, 2, 32, false, 0, complain_overflow_bitfield
, a29k_reloc
,"WORD", true, 0xffffffff,0xffffffff, false},
272 #define BADMAG(x) A29KBADMAG(x)
274 #define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
275 reloc_processing(relent, reloc, symbols, abfd, section)
278 reloc_processing (relent
,reloc
, symbols
, abfd
, section
)
280 struct internal_reloc
*reloc
;
285 static bfd_vma ihihalf_vaddr
= (bfd_vma
) -1;
287 relent
->address
= reloc
->r_vaddr
;
288 relent
->howto
= howto_table
+ reloc
->r_type
;
289 if (reloc
->r_type
== R_IHCONST
)
291 /* The address of an R_IHCONST should always be the address of
292 the immediately preceding R_IHIHALF. relocs generated by gas
293 are correct, but relocs generated by High C are different (I
294 can't figure out what the address means for High C). We can
295 handle both gas and High C by ignoring the address here, and
296 simply reusing the address saved for R_IHIHALF. */
297 if (ihihalf_vaddr
== (bfd_vma
) -1)
299 relent
->address
= ihihalf_vaddr
;
300 ihihalf_vaddr
= (bfd_vma
) -1;
301 relent
->addend
= reloc
->r_symndx
;
302 relent
->sym_ptr_ptr
= bfd_abs_section_ptr
->symbol_ptr_ptr
;
307 relent
->sym_ptr_ptr
= symbols
+ obj_convert(abfd
)[reloc
->r_symndx
];
309 ptr
= *(relent
->sym_ptr_ptr
);
312 && bfd_asymbol_bfd(ptr
) == abfd
314 && ((ptr
->flags
& BSF_OLD_COMMON
)== 0))
322 relent
->address
-= section
->vma
;
323 if (reloc
->r_type
== R_IHIHALF
)
324 ihihalf_vaddr
= relent
->address
;
325 else if (ihihalf_vaddr
!= (bfd_vma
) -1)
330 /* The reloc processing routine for the optimized COFF linker. */
333 coff_a29k_relocate_section (output_bfd
, info
, input_bfd
, input_section
,
334 contents
, relocs
, syms
, sections
)
335 bfd
*output_bfd ATTRIBUTE_UNUSED
;
336 struct bfd_link_info
*info
;
338 asection
*input_section
;
340 struct internal_reloc
*relocs
;
341 struct internal_syment
*syms
;
344 struct internal_reloc
*rel
;
345 struct internal_reloc
*relend
;
349 /* If we are performing a relocateable link, we don't need to do a
350 thing. The caller will take care of adjusting the reloc
351 addresses and symbol indices. */
352 if (info
->relocateable
)
359 relend
= rel
+ input_section
->reloc_count
;
360 for (; rel
< relend
; rel
++)
364 struct coff_link_hash_entry
*h
;
365 struct internal_syment
*sym
;
371 unsigned long unsigned_value
;
372 bfd_reloc_status_type rstat
;
374 symndx
= rel
->r_symndx
;
375 loc
= contents
+ rel
->r_vaddr
- input_section
->vma
;
377 if (symndx
== -1 || rel
->r_type
== R_IHCONST
)
380 h
= obj_coff_sym_hashes (input_bfd
)[symndx
];
386 /* An R_IHCONST reloc does not have a symbol. Instead, the
387 symbol index is an addend. R_IHCONST is always used in
388 conjunction with R_IHHALF. */
389 if (rel
->r_type
!= R_IHCONST
)
394 sec
= bfd_abs_section_ptr
;
398 sec
= sections
[symndx
];
399 val
= (sec
->output_section
->vma
407 if (h
->root
.type
== bfd_link_hash_defined
408 || h
->root
.type
== bfd_link_hash_defweak
)
410 sec
= h
->root
.u
.def
.section
;
411 val
= (h
->root
.u
.def
.value
412 + sec
->output_section
->vma
413 + sec
->output_offset
);
417 if (! ((*info
->callbacks
->undefined_symbol
)
418 (info
, h
->root
.root
.string
, input_bfd
, input_section
,
419 rel
->r_vaddr
- input_section
->vma
, true)))
426 if (! ((*info
->callbacks
->reloc_dangerous
)
427 (info
, _("missing IHCONST reloc"), input_bfd
,
428 input_section
, rel
->r_vaddr
- input_section
->vma
)))
439 bfd_set_error (bfd_error_bad_value
);
443 insn
= bfd_get_32 (input_bfd
, loc
);
445 /* Extract the addend. */
446 signed_value
= EXTRACT_HWORD (insn
);
447 signed_value
= SIGN_EXTEND_HWORD (signed_value
);
450 /* Unfortunately, there are two different versions of COFF
451 a29k. In the original AMD version, the value stored in
452 the field for the R_IREL reloc is a simple addend. In
453 the GNU version, the value is the negative of the address
454 of the reloc within section. We try to cope here by
455 assuming the AMD version, unless the addend is exactly
456 the negative of the address; in the latter case we assume
457 the GNU version. This means that something like
461 will fail, because the addend of -4 will happen to equal
462 the negative of the address within the section. The
463 compiler will never generate code like this.
465 At some point in the future we may want to take out this
468 if (signed_value
== - (long) (rel
->r_vaddr
- input_section
->vma
))
471 /* Determine the destination of the jump. */
474 if ((signed_value
& ~0x3ffff) == 0)
476 /* We can use an absolute jump. */
481 /* Make the destination PC relative. */
482 signed_value
-= (input_section
->output_section
->vma
483 + input_section
->output_offset
484 + (rel
->r_vaddr
- input_section
->vma
));
485 if (signed_value
> 0x1ffff || signed_value
< - 0x20000)
492 /* Put the adjusted value back into the instruction. */
494 insn
= INSERT_HWORD (insn
, signed_value
);
496 bfd_put_32 (input_bfd
, (bfd_vma
) insn
, loc
);
501 insn
= bfd_get_32 (input_bfd
, loc
);
502 unsigned_value
= EXTRACT_HWORD (insn
);
503 unsigned_value
+= val
;
504 insn
= INSERT_HWORD (insn
, unsigned_value
);
505 bfd_put_32 (input_bfd
, insn
, loc
);
509 /* Save the value for the R_IHCONST reloc. */
517 if (! ((*info
->callbacks
->reloc_dangerous
)
518 (info
, _("missing IHIHALF reloc"), input_bfd
,
519 input_section
, rel
->r_vaddr
- input_section
->vma
)))
524 insn
= bfd_get_32 (input_bfd
, loc
);
525 unsigned_value
= rel
->r_symndx
+ hihalf_val
;
526 unsigned_value
>>= 16;
527 insn
= INSERT_HWORD (insn
, unsigned_value
);
528 bfd_put_32 (input_bfd
, (bfd_vma
) insn
, loc
);
537 rstat
= _bfd_relocate_contents (howto_table
+ rel
->r_type
,
538 input_bfd
, val
, loc
);
539 if (rstat
== bfd_reloc_overflow
)
541 else if (rstat
!= bfd_reloc_ok
)
549 char buf
[SYMNMLEN
+ 1];
554 name
= h
->root
.root
.string
;
555 else if (sym
== NULL
)
557 else if (sym
->_n
._n_n
._n_zeroes
== 0
558 && sym
->_n
._n_n
._n_offset
!= 0)
559 name
= obj_coff_strings (input_bfd
) + sym
->_n
._n_n
._n_offset
;
562 strncpy (buf
, sym
->_n
._n_name
, SYMNMLEN
);
563 buf
[SYMNMLEN
] = '\0';
567 if (! ((*info
->callbacks
->reloc_overflow
)
568 (info
, name
, howto_table
[rel
->r_type
].name
, (bfd_vma
) 0,
569 input_bfd
, input_section
,
570 rel
->r_vaddr
- input_section
->vma
)))
578 #define coff_relocate_section coff_a29k_relocate_section
580 /* We don't want to change the symndx of a R_IHCONST reloc, since it
581 is actually an addend, not a symbol index at all. */
584 coff_a29k_adjust_symndx (obfd
, info
, ibfd
, sec
, irel
, adjustedp
)
585 bfd
*obfd ATTRIBUTE_UNUSED
;
586 struct bfd_link_info
*info ATTRIBUTE_UNUSED
;
587 bfd
*ibfd ATTRIBUTE_UNUSED
;
588 asection
*sec ATTRIBUTE_UNUSED
;
589 struct internal_reloc
*irel
;
592 if (irel
->r_type
== R_IHCONST
)
599 #define coff_adjust_symndx coff_a29k_adjust_symndx
601 #include "coffcode.h"
603 CREATE_BIG_COFF_TARGET_VEC (a29kcoff_big_vec
, "coff-a29k-big", 0, SEC_READONLY
, '_', NULL
)