2000-12-03 Kazu Hirata <kazu@hxi.com>
[deliverable/binutils-gdb.git] / bfd / coff-a29k.c
CommitLineData
252b5132 1/* BFD back-end for AMD 29000 COFF binaries.
fc633e5b 2 Copyright 1990, 91, 92, 93, 94, 95, 97, 98, 99, 2000
5f771d47 3 Free Software Foundation, Inc.
252b5132
RH
4 Contributed by David Wood at New York University 7/8/91.
5
6This file is part of BFD, the Binary File Descriptor library.
7
8This program is free software; you can redistribute it and/or modify
9it under the terms of the GNU General Public License as published by
10the Free Software Foundation; either version 2 of the License, or
11(at your option) any later version.
12
13This program is distributed in the hope that it will be useful,
14but WITHOUT ANY WARRANTY; without even the implied warranty of
15MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16GNU General Public License for more details.
17
18You should have received a copy of the GNU General Public License
19along with this program; if not, write to the Free Software
20Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21
22#define A29K 1
23
24#include "bfd.h"
25#include "sysdep.h"
26#include "libbfd.h"
27#include "coff/a29k.h"
28#include "coff/internal.h"
29#include "libcoff.h"
30
31static long get_symbol_value PARAMS ((asymbol *));
32static bfd_reloc_status_type a29k_reloc
33 PARAMS ((bfd *, arelent *, asymbol *, PTR, asection *, bfd *, char **));
34static boolean coff_a29k_relocate_section
35 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *, bfd_byte *,
36 struct internal_reloc *, struct internal_syment *, asection **));
37static boolean coff_a29k_adjust_symndx
38 PARAMS ((bfd *, struct bfd_link_info *, bfd *, asection *,
39 struct internal_reloc *, boolean *));
40
41#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
42
43#define INSERT_HWORD(WORD,HWORD) \
44 (((WORD) & 0xff00ff00) | (((HWORD) & 0xff00) << 8) | ((HWORD)& 0xff))
45#define EXTRACT_HWORD(WORD) \
fc633e5b 46 ((((WORD) & 0x00ff0000) >> 8) | ((WORD) & 0xff))
252b5132 47#define SIGN_EXTEND_HWORD(HWORD) \
fc633e5b 48 (((HWORD) ^ 0x8000) - 0x8000)
252b5132
RH
49
50/* Provided the symbol, returns the value reffed */
51static long
346ceb11 52get_symbol_value (symbol)
252b5132 53 asymbol *symbol;
346ceb11 54{
252b5132
RH
55 long relocation = 0;
56
57 if (bfd_is_com_section (symbol->section))
58 {
346ceb11 59 relocation = 0;
252b5132 60 }
346ceb11
KH
61 else
62 {
252b5132
RH
63 relocation = symbol->value +
64 symbol->section->output_section->vma +
65 symbol->section->output_offset;
346ceb11 66 }
252b5132
RH
67
68 return(relocation);
69}
70
71/* this function is in charge of performing all the 29k relocations */
72
73static bfd_reloc_status_type
74a29k_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
75 error_message)
76 bfd *abfd;
77 arelent *reloc_entry;
78 asymbol *symbol_in;
79 PTR data;
80 asection *input_section;
81 bfd *output_bfd;
82 char **error_message;
83{
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;
88
89 unsigned long insn;
90 unsigned long sym_value;
91 unsigned long unsigned_value;
92 unsigned short r_type;
93 long signed_value;
94
95 unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
6e301b2b 96 bfd_byte *hit_data =addr + (bfd_byte *) (data);
346ceb11 97
252b5132
RH
98 r_type = reloc_entry->howto->type;
99
100 if (output_bfd) {
101 /* Partial linking - do nothing */
102 reloc_entry->address += input_section->output_offset;
103 return bfd_reloc_ok;
104
105 }
106
107 if (symbol_in != NULL
108 && bfd_is_und_section (symbol_in->section))
109 {
110 /* Keep the state machine happy in case we're called again */
346ceb11 111 if (r_type == R_IHIHALF)
252b5132
RH
112 {
113 part1_consth_active = true;
114 part1_consth_value = 0;
115 }
116 return(bfd_reloc_undefined);
117 }
118
346ceb11 119 if ((part1_consth_active) && (r_type != R_IHCONST))
252b5132
RH
120 {
121 part1_consth_active = false;
122 *error_message = (char *) _("Missing IHCONST");
123 return(bfd_reloc_dangerous);
124 }
125
252b5132
RH
126 sym_value = get_symbol_value(symbol_in);
127
346ceb11 128 switch (r_type)
252b5132 129 {
346ceb11 130 case R_IREL:
6e301b2b 131 insn = bfd_get_32 (abfd, hit_data);
252b5132
RH
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);
135 signed_value <<= 2;
136
137 /* See the note on the R_IREL reloc in coff_a29k_relocate_section. */
138 if (signed_value == - (long) reloc_entry->address)
139 signed_value = 0;
140
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 */
346ceb11
KH
146 }
147 else
252b5132
RH
148 {
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);
346ceb11 154 if (signed_value>0x1ffff || signed_value<-0x20000)
252b5132
RH
155 return(bfd_reloc_overflow);
156 }
157 signed_value >>= 2;
158 insn = INSERT_HWORD(insn, signed_value);
6e301b2b 159 bfd_put_32 (abfd, insn ,hit_data);
252b5132 160 break;
346ceb11 161 case R_ILOHALF:
6e301b2b 162 insn = bfd_get_32 (abfd, hit_data);
252b5132
RH
163 unsigned_value = EXTRACT_HWORD(insn);
164 unsigned_value += sym_value + reloc_entry->addend;
165 insn = INSERT_HWORD(insn, unsigned_value);
6e301b2b 166 bfd_put_32 (abfd, insn, hit_data);
252b5132
RH
167 break;
168 case R_IHIHALF:
6e301b2b 169 insn = bfd_get_32 (abfd, hit_data);
346ceb11 170 /* consth, part 1
252b5132
RH
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 */
175 break;
346ceb11 176 case R_IHCONST:
6e301b2b 177 insn = bfd_get_32 (abfd, hit_data);
346ceb11 178 /* consth, part 2
252b5132
RH
179 Now relocate the reference */
180 if (part1_consth_active == false) {
181 *error_message = (char *) _("Missing IHIHALF");
182 return(bfd_reloc_dangerous);
183 }
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;
6e301b2b 191 bfd_put_32 (abfd, insn, hit_data);
252b5132
RH
192 break;
193 case R_BYTE:
6e301b2b 194 insn = bfd_get_8 (abfd, hit_data);
346ceb11 195 unsigned_value = insn + sym_value + reloc_entry->addend;
252b5132
RH
196 if (unsigned_value & 0xffffff00)
197 return(bfd_reloc_overflow);
6e301b2b 198 bfd_put_8 (abfd, unsigned_value, hit_data);
252b5132
RH
199 break;
200 case R_HWORD:
6e301b2b 201 insn = bfd_get_16 (abfd, hit_data);
346ceb11 202 unsigned_value = insn + sym_value + reloc_entry->addend;
252b5132
RH
203 if (unsigned_value & 0xffff0000)
204 return(bfd_reloc_overflow);
6e301b2b 205 bfd_put_16 (abfd, insn, hit_data);
252b5132
RH
206 break;
207 case R_WORD:
6e301b2b 208 insn = bfd_get_32 (abfd, hit_data);
346ceb11 209 insn += sym_value + reloc_entry->addend;
6e301b2b 210 bfd_put_32 (abfd, insn, hit_data);
252b5132
RH
211 break;
212 default:
213 *error_message = _("Unrecognized reloc");
214 return (bfd_reloc_dangerous);
215 }
216
346ceb11 217 return(bfd_reloc_ok);
252b5132
RH
218}
219
220/* type rightshift
221 size
222 bitsize
223 pc-relative
224 bitpos
225 absolute
226 complain_on_overflow
227 special_function
228 relocation name
346ceb11 229 partial_inplace
252b5132
RH
230 src_mask
231*/
232
233/*FIXME: I'm not real sure about this table */
346ceb11 234static reloc_howto_type howto_table[] =
252b5132
RH
235{
236 {R_ABS, 0, 3, 32, false, 0, complain_overflow_bitfield,a29k_reloc,"ABS", true, 0xffffffff,0xffffffff, false},
5f771d47
ILT
237 EMPTY_HOWTO (1),
238 EMPTY_HOWTO (2),
239 EMPTY_HOWTO (3),
240 EMPTY_HOWTO (4),
241 EMPTY_HOWTO (5),
242 EMPTY_HOWTO (6),
243 EMPTY_HOWTO (7),
244 EMPTY_HOWTO (8),
245 EMPTY_HOWTO (9),
246 EMPTY_HOWTO (10),
247 EMPTY_HOWTO (11),
248 EMPTY_HOWTO (12),
249 EMPTY_HOWTO (13),
250 EMPTY_HOWTO (14),
251 EMPTY_HOWTO (15),
252 EMPTY_HOWTO (16),
253 EMPTY_HOWTO (17),
254 EMPTY_HOWTO (18),
255 EMPTY_HOWTO (19),
256 EMPTY_HOWTO (20),
257 EMPTY_HOWTO (21),
258 EMPTY_HOWTO (22),
259 EMPTY_HOWTO (23),
252b5132
RH
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},
268};
269
270#define BADMAG(x) A29KBADMAG(x)
271
272#define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
273 reloc_processing(relent, reloc, symbols, abfd, section)
274
275static void
276reloc_processing (relent,reloc, symbols, abfd, section)
277 arelent *relent;
278 struct internal_reloc *reloc;
279 asymbol **symbols;
280 bfd *abfd;
281 asection *section;
282{
283 static bfd_vma ihihalf_vaddr = (bfd_vma) -1;
284
346ceb11 285 relent->address = reloc->r_vaddr;
252b5132 286 relent->howto = howto_table + reloc->r_type;
346ceb11
KH
287 if (reloc->r_type == R_IHCONST)
288 {
252b5132
RH
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)
296 abort ();
297 relent->address = ihihalf_vaddr;
298 ihihalf_vaddr = (bfd_vma) -1;
346ceb11 299 relent->addend = reloc->r_symndx;
252b5132
RH
300 relent->sym_ptr_ptr= bfd_abs_section_ptr->symbol_ptr_ptr;
301 }
346ceb11 302 else
252b5132
RH
303 {
304 asymbol *ptr;
305 relent->sym_ptr_ptr = symbols + obj_convert(abfd)[reloc->r_symndx];
306
307 ptr = *(relent->sym_ptr_ptr);
308
346ceb11
KH
309 if (ptr
310 && bfd_asymbol_bfd(ptr) == abfd
252b5132 311
346ceb11
KH
312 && ((ptr->flags & BSF_OLD_COMMON)== 0))
313 {
252b5132 314 relent->addend = 0;
346ceb11 315 }
252b5132 316 else
346ceb11
KH
317 {
318 relent->addend = 0;
319 }
252b5132
RH
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)
324 abort ();
325 }
326}
327
328/* The reloc processing routine for the optimized COFF linker. */
329
330static boolean
331coff_a29k_relocate_section (output_bfd, info, input_bfd, input_section,
332 contents, relocs, syms, sections)
5f771d47 333 bfd *output_bfd ATTRIBUTE_UNUSED;
252b5132
RH
334 struct bfd_link_info *info;
335 bfd *input_bfd;
336 asection *input_section;
337 bfd_byte *contents;
338 struct internal_reloc *relocs;
339 struct internal_syment *syms;
340 asection **sections;
341{
342 struct internal_reloc *rel;
343 struct internal_reloc *relend;
344 boolean hihalf;
345 bfd_vma hihalf_val;
346
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)
351 return true;
352
353 hihalf = false;
354 hihalf_val = 0;
355
356 rel = relocs;
357 relend = rel + input_section->reloc_count;
358 for (; rel < relend; rel++)
359 {
360 long symndx;
361 bfd_byte *loc;
362 struct coff_link_hash_entry *h;
363 struct internal_syment *sym;
364 asection *sec;
365 bfd_vma val;
366 boolean overflow;
367 unsigned long insn;
368 long signed_value;
369 unsigned long unsigned_value;
370 bfd_reloc_status_type rstat;
371
372 symndx = rel->r_symndx;
373 loc = contents + rel->r_vaddr - input_section->vma;
374
375 if (symndx == -1 || rel->r_type == R_IHCONST)
376 h = NULL;
377 else
378 h = obj_coff_sym_hashes (input_bfd)[symndx];
379
380 sym = NULL;
381 sec = NULL;
382 val = 0;
383
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)
388 {
389 if (h == NULL)
390 {
391 if (symndx == -1)
392 sec = bfd_abs_section_ptr;
393 else
394 {
395 sym = syms + symndx;
396 sec = sections[symndx];
397 val = (sec->output_section->vma
398 + sec->output_offset
399 + sym->n_value
400 - sec->vma);
401 }
402 }
403 else
404 {
405 if (h->root.type == bfd_link_hash_defined
406 || h->root.type == bfd_link_hash_defweak)
407 {
408 sec = h->root.u.def.section;
409 val = (h->root.u.def.value
410 + sec->output_section->vma
411 + sec->output_offset);
412 }
413 else
414 {
415 if (! ((*info->callbacks->undefined_symbol)
416 (info, h->root.root.string, input_bfd, input_section,
5cc7c785 417 rel->r_vaddr - input_section->vma, true)))
252b5132
RH
418 return false;
419 }
420 }
421
422 if (hihalf)
423 {
424 if (! ((*info->callbacks->reloc_dangerous)
425 (info, _("missing IHCONST reloc"), input_bfd,
426 input_section, rel->r_vaddr - input_section->vma)))
427 return false;
428 hihalf = false;
429 }
430 }
431
432 overflow = false;
433
434 switch (rel->r_type)
435 {
436 default:
437 bfd_set_error (bfd_error_bad_value);
438 return false;
439
440 case R_IREL:
441 insn = bfd_get_32 (input_bfd, loc);
442
443 /* Extract the addend. */
444 signed_value = EXTRACT_HWORD (insn);
445 signed_value = SIGN_EXTEND_HWORD (signed_value);
446 signed_value <<= 2;
447
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
456 .text
457 nop
458 jmp i-4
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.
462
463 At some point in the future we may want to take out this
464 check. */
465
466 if (signed_value == - (long) (rel->r_vaddr - input_section->vma))
467 signed_value = 0;
468
469 /* Determine the destination of the jump. */
470 signed_value += val;
471
472 if ((signed_value & ~0x3ffff) == 0)
473 {
474 /* We can use an absolute jump. */
475 insn |= (1 << 24);
476 }
477 else
478 {
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)
484 {
485 overflow = true;
486 signed_value = 0;
487 }
488 }
489
490 /* Put the adjusted value back into the instruction. */
491 signed_value >>= 2;
492 insn = INSERT_HWORD (insn, signed_value);
493
494 bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
495
496 break;
497
498 case R_ILOHALF:
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);
504 break;
505
506 case R_IHIHALF:
507 /* Save the value for the R_IHCONST reloc. */
508 hihalf = true;
509 hihalf_val = val;
510 break;
511
512 case R_IHCONST:
513 if (! hihalf)
514 {
515 if (! ((*info->callbacks->reloc_dangerous)
516 (info, _("missing IHIHALF reloc"), input_bfd,
517 input_section, rel->r_vaddr - input_section->vma)))
518 return false;
519 hihalf_val = 0;
520 }
521
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);
527
528 hihalf = false;
529
530 break;
531
532 case R_BYTE:
533 case R_HWORD:
534 case R_WORD:
535 rstat = _bfd_relocate_contents (howto_table + rel->r_type,
536 input_bfd, val, loc);
537 if (rstat == bfd_reloc_overflow)
538 overflow = true;
539 else if (rstat != bfd_reloc_ok)
540 abort ();
541 break;
542 }
543
544 if (overflow)
545 {
546 const char *name;
547 char buf[SYMNMLEN + 1];
548
549 if (symndx == -1)
550 name = "*ABS*";
551 else if (h != NULL)
552 name = h->root.root.string;
553 else if (sym == NULL)
554 name = "*unknown*";
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;
558 else
559 {
560 strncpy (buf, sym->_n._n_name, SYMNMLEN);
561 buf[SYMNMLEN] = '\0';
562 name = buf;
563 }
564
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)))
569 return false;
570 }
346ceb11 571 }
252b5132
RH
572
573 return true;
574}
575
576#define coff_relocate_section coff_a29k_relocate_section
577
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. */
580
252b5132
RH
581static boolean
582coff_a29k_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
5f771d47
ILT
583 bfd *obfd ATTRIBUTE_UNUSED;
584 struct bfd_link_info *info ATTRIBUTE_UNUSED;
585 bfd *ibfd ATTRIBUTE_UNUSED;
586 asection *sec ATTRIBUTE_UNUSED;
252b5132
RH
587 struct internal_reloc *irel;
588 boolean *adjustedp;
589{
590 if (irel->r_type == R_IHCONST)
591 *adjustedp = true;
592 else
593 *adjustedp = false;
594 return true;
595}
596
597#define coff_adjust_symndx coff_a29k_adjust_symndx
598
599#include "coffcode.h"
600
c3c89269 601CREATE_BIG_COFF_TARGET_VEC (a29kcoff_big_vec, "coff-a29k-big", 0, SEC_READONLY, '_', NULL)
This page took 0.084491 seconds and 4 git commands to generate.