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
;
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
);
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
);
217 return(bfd_reloc_ok
);
233 /*FIXME: I'm not real sure about this table */
234 static reloc_howto_type howto_table
[] =
236 {R_ABS
, 0, 3, 32, false, 0, complain_overflow_bitfield
,a29k_reloc
,"ABS", true, 0xffffffff,0xffffffff, false},
260 {R_IREL
, 0, 3, 32, true, 0, complain_overflow_signed
,a29k_reloc
,"IREL", true, 0xffffffff,0xffffffff, false},
261 {R_IABS
, 0, 3, 32, false, 0, complain_overflow_bitfield
, a29k_reloc
,"IABS", true, 0xffffffff,0xffffffff, false},
262 {R_ILOHALF
, 0, 3, 16, true, 0, complain_overflow_signed
, a29k_reloc
,"ILOHALF", true, 0x0000ffff,0x0000ffff, false},
263 {R_IHIHALF
, 0, 3, 16, true, 16, complain_overflow_signed
, a29k_reloc
,"IHIHALF", true, 0xffff0000,0xffff0000, false},
264 {R_IHCONST
, 0, 3, 16, true, 0, complain_overflow_signed
, a29k_reloc
,"IHCONST", true, 0xffff0000,0xffff0000, false},
265 {R_BYTE
, 0, 0, 8, false, 0, complain_overflow_bitfield
, a29k_reloc
,"BYTE", true, 0x000000ff,0x000000ff, false},
266 {R_HWORD
, 0, 1, 16, false, 0, complain_overflow_bitfield
, a29k_reloc
,"HWORD", true, 0x0000ffff,0x0000ffff, false},
267 {R_WORD
, 0, 2, 32, false, 0, complain_overflow_bitfield
, a29k_reloc
,"WORD", true, 0xffffffff,0xffffffff, false},
270 #define BADMAG(x) A29KBADMAG(x)
272 #define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
273 reloc_processing(relent, reloc, symbols, abfd, section)
276 reloc_processing (relent
,reloc
, symbols
, abfd
, section
)
278 struct internal_reloc
*reloc
;
283 static bfd_vma ihihalf_vaddr
= (bfd_vma
) -1;
285 relent
->address
= reloc
->r_vaddr
;
286 relent
->howto
= howto_table
+ reloc
->r_type
;
287 if (reloc
->r_type
== R_IHCONST
)
289 /* The address of an R_IHCONST should always be the address of
290 the immediately preceding R_IHIHALF. relocs generated by gas
291 are correct, but relocs generated by High C are different (I
292 can't figure out what the address means for High C). We can
293 handle both gas and High C by ignoring the address here, and
294 simply reusing the address saved for R_IHIHALF. */
295 if (ihihalf_vaddr
== (bfd_vma
) -1)
297 relent
->address
= ihihalf_vaddr
;
298 ihihalf_vaddr
= (bfd_vma
) -1;
299 relent
->addend
= reloc
->r_symndx
;
300 relent
->sym_ptr_ptr
= bfd_abs_section_ptr
->symbol_ptr_ptr
;
305 relent
->sym_ptr_ptr
= symbols
+ obj_convert(abfd
)[reloc
->r_symndx
];
307 ptr
= *(relent
->sym_ptr_ptr
);
310 && bfd_asymbol_bfd(ptr
) == abfd
312 && ((ptr
->flags
& BSF_OLD_COMMON
)== 0))
320 relent
->address
-= section
->vma
;
321 if (reloc
->r_type
== R_IHIHALF
)
322 ihihalf_vaddr
= relent
->address
;
323 else if (ihihalf_vaddr
!= (bfd_vma
) -1)
328 /* The reloc processing routine for the optimized COFF linker. */
331 coff_a29k_relocate_section (output_bfd
, info
, input_bfd
, input_section
,
332 contents
, relocs
, syms
, sections
)
333 bfd
*output_bfd ATTRIBUTE_UNUSED
;
334 struct bfd_link_info
*info
;
336 asection
*input_section
;
338 struct internal_reloc
*relocs
;
339 struct internal_syment
*syms
;
342 struct internal_reloc
*rel
;
343 struct internal_reloc
*relend
;
347 /* If we are performing a relocateable link, we don't need to do a
348 thing. The caller will take care of adjusting the reloc
349 addresses and symbol indices. */
350 if (info
->relocateable
)
357 relend
= rel
+ input_section
->reloc_count
;
358 for (; rel
< relend
; rel
++)
362 struct coff_link_hash_entry
*h
;
363 struct internal_syment
*sym
;
369 unsigned long unsigned_value
;
370 bfd_reloc_status_type rstat
;
372 symndx
= rel
->r_symndx
;
373 loc
= contents
+ rel
->r_vaddr
- input_section
->vma
;
375 if (symndx
== -1 || rel
->r_type
== R_IHCONST
)
378 h
= obj_coff_sym_hashes (input_bfd
)[symndx
];
384 /* An R_IHCONST reloc does not have a symbol. Instead, the
385 symbol index is an addend. R_IHCONST is always used in
386 conjunction with R_IHHALF. */
387 if (rel
->r_type
!= R_IHCONST
)
392 sec
= bfd_abs_section_ptr
;
396 sec
= sections
[symndx
];
397 val
= (sec
->output_section
->vma
405 if (h
->root
.type
== bfd_link_hash_defined
406 || h
->root
.type
== bfd_link_hash_defweak
)
408 sec
= h
->root
.u
.def
.section
;
409 val
= (h
->root
.u
.def
.value
410 + sec
->output_section
->vma
411 + sec
->output_offset
);
415 if (! ((*info
->callbacks
->undefined_symbol
)
416 (info
, h
->root
.root
.string
, input_bfd
, input_section
,
417 rel
->r_vaddr
- input_section
->vma
, true)))
424 if (! ((*info
->callbacks
->reloc_dangerous
)
425 (info
, _("missing IHCONST reloc"), input_bfd
,
426 input_section
, rel
->r_vaddr
- input_section
->vma
)))
437 bfd_set_error (bfd_error_bad_value
);
441 insn
= bfd_get_32 (input_bfd
, loc
);
443 /* Extract the addend. */
444 signed_value
= EXTRACT_HWORD (insn
);
445 signed_value
= SIGN_EXTEND_HWORD (signed_value
);
448 /* Unfortunately, there are two different versions of COFF
449 a29k. In the original AMD version, the value stored in
450 the field for the R_IREL reloc is a simple addend. In
451 the GNU version, the value is the negative of the address
452 of the reloc within section. We try to cope here by
453 assuming the AMD version, unless the addend is exactly
454 the negative of the address; in the latter case we assume
455 the GNU version. This means that something like
459 will fail, because the addend of -4 will happen to equal
460 the negative of the address within the section. The
461 compiler will never generate code like this.
463 At some point in the future we may want to take out this
466 if (signed_value
== - (long) (rel
->r_vaddr
- input_section
->vma
))
469 /* Determine the destination of the jump. */
472 if ((signed_value
& ~0x3ffff) == 0)
474 /* We can use an absolute jump. */
479 /* Make the destination PC relative. */
480 signed_value
-= (input_section
->output_section
->vma
481 + input_section
->output_offset
482 + (rel
->r_vaddr
- input_section
->vma
));
483 if (signed_value
> 0x1ffff || signed_value
< - 0x20000)
490 /* Put the adjusted value back into the instruction. */
492 insn
= INSERT_HWORD (insn
, signed_value
);
494 bfd_put_32 (input_bfd
, (bfd_vma
) insn
, loc
);
499 insn
= bfd_get_32 (input_bfd
, loc
);
500 unsigned_value
= EXTRACT_HWORD (insn
);
501 unsigned_value
+= val
;
502 insn
= INSERT_HWORD (insn
, unsigned_value
);
503 bfd_put_32 (input_bfd
, insn
, loc
);
507 /* Save the value for the R_IHCONST reloc. */
515 if (! ((*info
->callbacks
->reloc_dangerous
)
516 (info
, _("missing IHIHALF reloc"), input_bfd
,
517 input_section
, rel
->r_vaddr
- input_section
->vma
)))
522 insn
= bfd_get_32 (input_bfd
, loc
);
523 unsigned_value
= rel
->r_symndx
+ hihalf_val
;
524 unsigned_value
>>= 16;
525 insn
= INSERT_HWORD (insn
, unsigned_value
);
526 bfd_put_32 (input_bfd
, (bfd_vma
) insn
, loc
);
535 rstat
= _bfd_relocate_contents (howto_table
+ rel
->r_type
,
536 input_bfd
, val
, loc
);
537 if (rstat
== bfd_reloc_overflow
)
539 else if (rstat
!= bfd_reloc_ok
)
547 char buf
[SYMNMLEN
+ 1];
552 name
= h
->root
.root
.string
;
553 else if (sym
== NULL
)
555 else if (sym
->_n
._n_n
._n_zeroes
== 0
556 && sym
->_n
._n_n
._n_offset
!= 0)
557 name
= obj_coff_strings (input_bfd
) + sym
->_n
._n_n
._n_offset
;
560 strncpy (buf
, sym
->_n
._n_name
, SYMNMLEN
);
561 buf
[SYMNMLEN
] = '\0';
565 if (! ((*info
->callbacks
->reloc_overflow
)
566 (info
, name
, howto_table
[rel
->r_type
].name
, (bfd_vma
) 0,
567 input_bfd
, input_section
,
568 rel
->r_vaddr
- input_section
->vma
)))
576 #define coff_relocate_section coff_a29k_relocate_section
578 /* We don't want to change the symndx of a R_IHCONST reloc, since it
579 is actually an addend, not a symbol index at all. */
582 coff_a29k_adjust_symndx (obfd
, info
, ibfd
, sec
, irel
, adjustedp
)
583 bfd
*obfd ATTRIBUTE_UNUSED
;
584 struct bfd_link_info
*info ATTRIBUTE_UNUSED
;
585 bfd
*ibfd ATTRIBUTE_UNUSED
;
586 asection
*sec ATTRIBUTE_UNUSED
;
587 struct internal_reloc
*irel
;
590 if (irel
->r_type
== R_IHCONST
)
597 #define coff_adjust_symndx coff_a29k_adjust_symndx
599 #include "coffcode.h"
601 CREATE_BIG_COFF_TARGET_VEC (a29kcoff_big_vec
, "coff-a29k-big", 0, SEC_READONLY
, '_', NULL
)