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., 675 Mass Ave, Cambridge, MA 02139, 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
**));
38 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
40 #define INSERT_HWORD(WORD,HWORD) \
41 (((WORD) & 0xff00ff00) | (((HWORD) & 0xff00) << 8) | ((HWORD)& 0xff))
42 #define EXTRACT_HWORD(WORD) \
43 (((WORD) & 0x00ff0000) >> 8) | ((WORD)& 0xff)
44 #define SIGN_EXTEND_HWORD(HWORD) \
45 ((HWORD) & 0x8000 ? (HWORD)|0xffff0000 : (HWORD))
47 /* Provided the symbol, returns the value reffed */
49 get_symbol_value (symbol
)
54 if (bfd_is_com_section (symbol
->section
))
60 relocation
= symbol
->value
+
61 symbol
->section
->output_section
->vma
+
62 symbol
->section
->output_offset
;
68 /* this function is in charge of performing all the 29k relocations */
70 static bfd_reloc_status_type
71 a29k_reloc (abfd
, reloc_entry
, symbol_in
, data
, input_section
, output_bfd
,
77 asection
*input_section
;
81 /* the consth relocation comes in two parts, we have to remember
82 the state between calls, in these variables */
83 static boolean part1_consth_active
= false;
84 static unsigned long part1_consth_value
;
87 unsigned long sym_value
;
88 unsigned long unsigned_value
;
89 unsigned short r_type
;
92 unsigned long addr
= reloc_entry
->address
; /*+ input_section->vma*/
93 bfd_byte
*hit_data
=addr
+ (bfd_byte
*)(data
);
95 r_type
= reloc_entry
->howto
->type
;
98 /* Partial linking - do nothing */
99 reloc_entry
->address
+= input_section
->output_offset
;
104 if (symbol_in
!= NULL
105 && bfd_is_und_section (symbol_in
->section
))
107 /* Keep the state machine happy in case we're called again */
108 if (r_type
== R_IHIHALF
)
110 part1_consth_active
= true;
111 part1_consth_value
= 0;
113 return(bfd_reloc_undefined
);
116 if ((part1_consth_active
) && (r_type
!= R_IHCONST
))
118 part1_consth_active
= false;
119 *error_message
= (char *) "Missing IHCONST";
120 return(bfd_reloc_dangerous
);
124 sym_value
= get_symbol_value(symbol_in
);
129 insn
= bfd_get_32(abfd
, hit_data
);
130 /* Take the value in the field and sign extend it */
131 signed_value
= EXTRACT_HWORD(insn
);
132 signed_value
= SIGN_EXTEND_HWORD(signed_value
);
134 signed_value
+= sym_value
+ reloc_entry
->addend
;
135 if (((signed_value
+ reloc_entry
->address
) & ~0x3ffff) == 0)
136 { /* Absolute jmp/call */
137 insn
|= (1<<24); /* Make it absolute */
138 signed_value
+= reloc_entry
->address
;
139 /* FIXME: Should we change r_type to R_IABS */
143 /* Relative jmp/call, so subtract from the value the
144 address of the place we're coming from */
145 signed_value
-= (input_section
->output_section
->vma
146 + input_section
->output_offset
);
147 if (signed_value
>0x1ffff || signed_value
<-0x20000)
148 return(bfd_reloc_overflow
);
151 insn
= INSERT_HWORD(insn
, signed_value
);
152 bfd_put_32(abfd
, insn
,hit_data
);
155 insn
= bfd_get_32(abfd
, hit_data
);
156 unsigned_value
= EXTRACT_HWORD(insn
);
157 unsigned_value
+= sym_value
+ reloc_entry
->addend
;
158 insn
= INSERT_HWORD(insn
, unsigned_value
);
159 bfd_put_32(abfd
, insn
, hit_data
);
162 insn
= bfd_get_32(abfd
, hit_data
);
164 Just get the symbol value that is referenced */
165 part1_consth_active
= true;
166 part1_consth_value
= sym_value
+ reloc_entry
->addend
;
167 /* Don't modify insn until R_IHCONST */
170 insn
= bfd_get_32(abfd
, hit_data
);
172 Now relocate the reference */
173 if (part1_consth_active
== false) {
174 *error_message
= (char *) "Missing IHIHALF";
175 return(bfd_reloc_dangerous
);
177 /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
178 unsigned_value
= 0; /*EXTRACT_HWORD(insn) << 16;*/
179 unsigned_value
+= reloc_entry
->addend
; /* r_symndx */
180 unsigned_value
+= part1_consth_value
;
181 unsigned_value
= unsigned_value
>> 16;
182 insn
= INSERT_HWORD(insn
, unsigned_value
);
183 part1_consth_active
= false;
184 bfd_put_32(abfd
, insn
, hit_data
);
187 insn
= bfd_get_8(abfd
, hit_data
);
188 unsigned_value
= insn
+ sym_value
+ reloc_entry
->addend
;
189 if (unsigned_value
& 0xffffff00) {
190 fprintf(stderr
,"Relocation problem : ");
191 fprintf(stderr
,"byte value too large in module %s\n",
193 return(bfd_reloc_overflow
);
195 bfd_put_8(abfd
, unsigned_value
, hit_data
);
198 insn
= bfd_get_16(abfd
, hit_data
);
199 unsigned_value
= insn
+ sym_value
+ reloc_entry
->addend
;
200 if (unsigned_value
& 0xffff0000) {
201 fprintf(stderr
,"Relocation problem : ");
202 fprintf(stderr
,"hword value too large in module %s\n",
204 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
);
220 return(bfd_reloc_ok
);
236 /*FIXME: I'm not real sure about this table */
237 static reloc_howto_type howto_table
[] =
239 {R_ABS
, 0, 3, 32, false, 0, complain_overflow_bitfield
,a29k_reloc
,"ABS", true, 0xffffffff,0xffffffff, false},
240 {1}, {2}, {3}, {4}, {5}, {6}, {7}, {8}, {9}, {10},
241 {11}, {12}, {13}, {14}, {15}, {16}, {17}, {18}, {19}, {20},
243 {R_IREL
, 0, 3, 32, true, 0, complain_overflow_signed
,a29k_reloc
,"IREL", true, 0xffffffff,0xffffffff, false},
244 {R_IABS
, 0, 3, 32, false, 0, complain_overflow_bitfield
, a29k_reloc
,"IABS", true, 0xffffffff,0xffffffff, false},
245 {R_ILOHALF
, 0, 3, 16, true, 0, complain_overflow_signed
, a29k_reloc
,"ILOHALF", true, 0x0000ffff,0x0000ffff, false},
246 {R_IHIHALF
, 0, 3, 16, true, 16, complain_overflow_signed
, a29k_reloc
,"IHIHALF", true, 0xffff0000,0xffff0000, false},
247 {R_IHCONST
, 0, 3, 16, true, 0, complain_overflow_signed
, a29k_reloc
,"IHCONST", true, 0xffff0000,0xffff0000, false},
248 {R_BYTE
, 0, 0, 8, false, 0, complain_overflow_bitfield
, a29k_reloc
,"BYTE", true, 0x000000ff,0x000000ff, false},
249 {R_HWORD
, 0, 1, 16, false, 0, complain_overflow_bitfield
, a29k_reloc
,"HWORD", true, 0x0000ffff,0x0000ffff, false},
250 {R_WORD
, 0, 2, 32, false, 0, complain_overflow_bitfield
, a29k_reloc
,"WORD", true, 0xffffffff,0xffffffff, false},
253 #define BADMAG(x) A29KBADMAG(x)
255 #define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
256 reloc_processing(relent, reloc, symbols, abfd, section)
259 reloc_processing (relent
,reloc
, symbols
, abfd
, section
)
261 struct internal_reloc
*reloc
;
266 static bfd_vma ihihalf_vaddr
= (bfd_vma
) -1;
268 relent
->address
= reloc
->r_vaddr
;
269 relent
->howto
= howto_table
+ reloc
->r_type
;
270 if (reloc
->r_type
== R_IHCONST
)
272 /* The address of an R_IHCONST should always be the address of
273 the immediately preceding R_IHIHALF. relocs generated by gas
274 are correct, but relocs generated by High C are different (I
275 can't figure out what the address means for High C). We can
276 handle both gas and High C by ignoring the address here, and
277 simply reusing the address saved for R_IHIHALF. */
278 if (ihihalf_vaddr
== (bfd_vma
) -1)
280 relent
->address
= ihihalf_vaddr
;
281 ihihalf_vaddr
= (bfd_vma
) -1;
282 relent
->addend
= reloc
->r_symndx
;
283 relent
->sym_ptr_ptr
= bfd_abs_section_ptr
->symbol_ptr_ptr
;
288 relent
->sym_ptr_ptr
= symbols
+ obj_convert(abfd
)[reloc
->r_symndx
];
290 ptr
= *(relent
->sym_ptr_ptr
);
293 && bfd_asymbol_bfd(ptr
) == abfd
295 && ((ptr
->flags
& BSF_OLD_COMMON
)== 0))
303 relent
->address
-= section
->vma
;
304 if (reloc
->r_type
== R_IHIHALF
)
305 ihihalf_vaddr
= relent
->address
;
306 else if (ihihalf_vaddr
!= (bfd_vma
) -1)
311 /* The reloc processing routine for the optimized COFF linker. */
314 coff_a29k_relocate_section (output_bfd
, info
, input_bfd
, input_section
,
315 contents
, relocs
, syms
, sections
)
317 struct bfd_link_info
*info
;
319 asection
*input_section
;
321 struct internal_reloc
*relocs
;
322 struct internal_syment
*syms
;
325 struct internal_reloc
*rel
;
326 struct internal_reloc
*relend
;
330 /* If we are performing a relocateable link, we don't need to do a
331 thing. The caller will take care of adjusting the reloc
332 addresses and symbol indices. */
333 if (info
->relocateable
)
340 relend
= rel
+ input_section
->reloc_count
;
341 for (; rel
< relend
; rel
++)
345 struct coff_link_hash_entry
*h
;
346 struct internal_syment
*sym
;
352 unsigned long unsigned_value
;
353 bfd_reloc_status_type rstat
;
355 symndx
= rel
->r_symndx
;
356 loc
= contents
+ rel
->r_vaddr
- input_section
->vma
;
361 h
= obj_coff_sym_hashes (input_bfd
)[symndx
];
367 /* An R_IHCONST reloc does not have a symbol. Instead, the
368 symbol index is an addend. R_IHCONST is always used in
369 conjunction with R_IHHALF. */
370 if (rel
->r_type
!= R_IHCONST
)
375 sec
= bfd_abs_section_ptr
;
379 sec
= sections
[symndx
];
380 val
= (sec
->output_section
->vma
388 if (h
->root
.type
== bfd_link_hash_defined
389 || h
->root
.type
== bfd_link_hash_defweak
)
391 sec
= h
->root
.u
.def
.section
;
392 val
= (h
->root
.u
.def
.value
393 + sec
->output_section
->vma
394 + sec
->output_offset
);
398 if (! ((*info
->callbacks
->undefined_symbol
)
399 (info
, h
->root
.root
.string
, input_bfd
, input_section
,
400 rel
->r_vaddr
- input_section
->vma
)))
407 if (! ((*info
->callbacks
->reloc_dangerous
)
408 (info
, "missing IHCONST reloc", input_bfd
,
409 input_section
, rel
->r_vaddr
- input_section
->vma
)))
420 bfd_set_error (bfd_error_bad_value
);
424 insn
= bfd_get_32 (input_bfd
, loc
);
426 /* Extract the addend. */
427 signed_value
= EXTRACT_HWORD (insn
);
428 signed_value
= SIGN_EXTEND_HWORD (signed_value
);
431 /* Determine the destination of the jump. */
432 signed_value
+= val
+ rel
->r_vaddr
- input_section
->vma
;
434 if ((signed_value
& ~0x3ffff) == 0)
436 /* We can use an absolute jump. */
441 /* Make the destination PC relative. */
442 signed_value
-= (input_section
->output_section
->vma
443 + input_section
->output_offset
444 + (rel
->r_vaddr
- input_section
->vma
));
445 if (signed_value
> 0x1ffff || signed_value
< - 0x20000)
452 /* Put the adjusted value back into the instruction. */
454 insn
= INSERT_HWORD (insn
, signed_value
);
456 bfd_put_32 (input_bfd
, (bfd_vma
) insn
, loc
);
461 insn
= bfd_get_32 (input_bfd
, loc
);
462 unsigned_value
= EXTRACT_HWORD (insn
);
463 unsigned_value
+= val
;
464 insn
= INSERT_HWORD (insn
, unsigned_value
);
465 bfd_put_32 (input_bfd
, insn
, loc
);
469 /* Save the value for the R_IHCONST reloc. */
477 if (! ((*info
->callbacks
->reloc_dangerous
)
478 (info
, "missing IHIHALF reloc", input_bfd
,
479 input_section
, rel
->r_vaddr
- input_section
->vma
)))
484 insn
= bfd_get_32 (input_bfd
, loc
);
485 unsigned_value
= rel
->r_symndx
+ hihalf_val
;
486 unsigned_value
>>= 16;
487 insn
= INSERT_HWORD (insn
, unsigned_value
);
488 bfd_put_32 (input_bfd
, (bfd_vma
) insn
, loc
);
497 rstat
= _bfd_relocate_contents (howto_table
+ rel
->r_type
,
498 input_bfd
, val
, loc
);
499 if (rstat
== bfd_reloc_overflow
)
501 else if (rstat
!= bfd_reloc_ok
)
509 char buf
[SYMNMLEN
+ 1];
514 name
= h
->root
.root
.string
;
515 else if (sym
== NULL
)
517 else if (sym
->_n
._n_n
._n_zeroes
== 0
518 && sym
->_n
._n_n
._n_offset
!= 0)
519 name
= obj_coff_strings (input_bfd
) + sym
->_n
._n_n
._n_offset
;
522 strncpy (buf
, sym
->_n
._n_name
, SYMNMLEN
);
523 buf
[SYMNMLEN
] = '\0';
527 if (! ((*info
->callbacks
->reloc_overflow
)
528 (info
, name
, howto_table
[rel
->r_type
].name
, (bfd_vma
) 0,
529 input_bfd
, input_section
,
530 rel
->r_vaddr
- input_section
->vma
)))
538 #define coff_relocate_section coff_a29k_relocate_section
540 #include "coffcode.h"
542 const bfd_target a29kcoff_big_vec
=
544 "coff-a29k-big", /* name */
545 bfd_target_coff_flavour
,
546 true, /* data byte order is big */
547 true, /* header byte order is big */
549 (HAS_RELOC
| EXEC_P
| /* object flags */
550 HAS_LINENO
| HAS_DEBUG
|
551 HAS_SYMS
| HAS_LOCALS
| WP_TEXT
),
553 (SEC_HAS_CONTENTS
| SEC_ALLOC
/* section flags */
554 | SEC_LOAD
| SEC_RELOC
556 '_', /* leading underscore */
557 '/', /* ar_pad_char */
558 15, /* ar_max_namelen */
559 2, /* minimum section alignment */
561 bfd_getb64
, bfd_getb_signed_64
, bfd_putb64
,
562 bfd_getb32
, bfd_getb_signed_32
, bfd_putb32
,
563 bfd_getb16
, bfd_getb_signed_16
, bfd_putb16
,
565 bfd_getb64
, bfd_getb_signed_64
, bfd_putb64
,
566 bfd_getb32
, bfd_getb_signed_32
, bfd_putb32
,
567 bfd_getb16
, bfd_getb_signed_16
, bfd_putb16
,
573 bfd_generic_archive_p
,
579 _bfd_generic_mkarchive
,
584 coff_write_object_contents
,
585 _bfd_write_archive_contents
,
589 BFD_JUMP_TABLE_GENERIC (coff
),
590 BFD_JUMP_TABLE_COPY (coff
),
591 BFD_JUMP_TABLE_CORE (_bfd_nocore
),
592 BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff
),
593 BFD_JUMP_TABLE_SYMBOLS (coff
),
594 BFD_JUMP_TABLE_RELOCS (coff
),
595 BFD_JUMP_TABLE_WRITE (coff
),
596 BFD_JUMP_TABLE_LINK (coff
),
597 BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic
),