]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - bfd/coff-a29k.c
* aout-adobe.c: Don't compare against "true" or "false.
[thirdparty/binutils-gdb.git] / bfd / coff-a29k.c
CommitLineData
252b5132 1/* BFD back-end for AMD 29000 COFF binaries.
82e51918 2 Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1999, 2000, 2001, 2002
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 *));
917583ad
NC
40static void reloc_processing
41 PARAMS ((arelent *, struct internal_reloc *, asymbol **, bfd *, asection *));
252b5132
RH
42
43#define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
44
45#define INSERT_HWORD(WORD,HWORD) \
46 (((WORD) & 0xff00ff00) | (((HWORD) & 0xff00) << 8) | ((HWORD)& 0xff))
47#define EXTRACT_HWORD(WORD) \
fc633e5b 48 ((((WORD) & 0x00ff0000) >> 8) | ((WORD) & 0xff))
252b5132 49#define SIGN_EXTEND_HWORD(HWORD) \
fc633e5b 50 (((HWORD) ^ 0x8000) - 0x8000)
252b5132 51
917583ad
NC
52/* Provided the symbol, returns the value reffed. */
53
252b5132 54static long
346ceb11 55get_symbol_value (symbol)
252b5132 56 asymbol *symbol;
346ceb11 57{
252b5132
RH
58 long relocation = 0;
59
60 if (bfd_is_com_section (symbol->section))
917583ad 61 relocation = 0;
346ceb11 62 else
917583ad
NC
63 relocation = symbol->value +
64 symbol->section->output_section->vma +
65 symbol->section->output_offset;
252b5132 66
917583ad 67 return relocation;
252b5132
RH
68}
69
917583ad 70/* This function is in charge of performing all the 29k relocations. */
252b5132
RH
71
72static bfd_reloc_status_type
73a29k_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
74 error_message)
75 bfd *abfd;
76 arelent *reloc_entry;
77 asymbol *symbol_in;
78 PTR data;
79 asection *input_section;
80 bfd *output_bfd;
81 char **error_message;
82{
917583ad
NC
83 /* The consth relocation comes in two parts, we have to remember
84 the state between calls, in these variables. */
252b5132
RH
85 static boolean part1_consth_active = false;
86 static unsigned long part1_consth_value;
252b5132
RH
87 unsigned long insn;
88 unsigned long sym_value;
89 unsigned long unsigned_value;
90 unsigned short r_type;
91 long signed_value;
252b5132 92 unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
6e301b2b 93 bfd_byte *hit_data =addr + (bfd_byte *) (data);
346ceb11 94
252b5132
RH
95 r_type = reloc_entry->howto->type;
96
2a38f751
KH
97 if (output_bfd)
98 {
917583ad 99 /* Partial linking - do nothing. */
2a38f751
KH
100 reloc_entry->address += input_section->output_offset;
101 return bfd_reloc_ok;
2a38f751 102 }
252b5132
RH
103
104 if (symbol_in != NULL
105 && bfd_is_und_section (symbol_in->section))
252b5132 106 {
917583ad 107 /* Keep the state machine happy in case we're called again. */
2a38f751
KH
108 if (r_type == R_IHIHALF)
109 {
110 part1_consth_active = true;
111 part1_consth_value = 0;
112 }
917583ad 113 return bfd_reloc_undefined;
252b5132 114 }
252b5132 115
346ceb11 116 if ((part1_consth_active) && (r_type != R_IHCONST))
2a38f751
KH
117 {
118 part1_consth_active = false;
119 *error_message = (char *) _("Missing IHCONST");
917583ad
NC
120
121 return bfd_reloc_dangerous;
2a38f751 122 }
252b5132 123
252b5132
RH
124 sym_value = get_symbol_value(symbol_in);
125
346ceb11 126 switch (r_type)
252b5132 127 {
2a38f751
KH
128 case R_IREL:
129 insn = bfd_get_32 (abfd, hit_data);
917583ad 130 /* Take the value in the field and sign extend it. */
2a38f751
KH
131 signed_value = EXTRACT_HWORD(insn);
132 signed_value = SIGN_EXTEND_HWORD(signed_value);
133 signed_value <<= 2;
134
135 /* See the note on the R_IREL reloc in coff_a29k_relocate_section. */
136 if (signed_value == - (long) reloc_entry->address)
137 signed_value = 0;
138
139 signed_value += sym_value + reloc_entry->addend;
140 if ((signed_value & ~0x3ffff) == 0)
141 { /* Absolute jmp/call */
917583ad
NC
142 insn |= (1 << 24); /* Make it absolute */
143 /* FIXME: Should we change r_type to R_IABS. */
2a38f751
KH
144 }
145 else
146 {
147 /* Relative jmp/call, so subtract from the value the
917583ad 148 address of the place we're coming from. */
2a38f751
KH
149 signed_value -= (reloc_entry->address
150 + input_section->output_section->vma
151 + input_section->output_offset);
917583ad
NC
152 if (signed_value > 0x1ffff || signed_value < -0x20000)
153 return bfd_reloc_overflow;
2a38f751
KH
154 }
155 signed_value >>= 2;
917583ad 156 insn = INSERT_HWORD (insn, signed_value);
dc810e39 157 bfd_put_32 (abfd, (bfd_vma) insn ,hit_data);
2a38f751
KH
158 break;
159 case R_ILOHALF:
160 insn = bfd_get_32 (abfd, hit_data);
161 unsigned_value = EXTRACT_HWORD(insn);
162 unsigned_value += sym_value + reloc_entry->addend;
163 insn = INSERT_HWORD(insn, unsigned_value);
dc810e39 164 bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
2a38f751
KH
165 break;
166 case R_IHIHALF:
167 insn = bfd_get_32 (abfd, hit_data);
168 /* consth, part 1
917583ad 169 Just get the symbol value that is referenced. */
2a38f751
KH
170 part1_consth_active = true;
171 part1_consth_value = sym_value + reloc_entry->addend;
917583ad 172 /* Don't modify insn until R_IHCONST. */
2a38f751
KH
173 break;
174 case R_IHCONST:
175 insn = bfd_get_32 (abfd, hit_data);
176 /* consth, part 2
917583ad 177 Now relocate the reference. */
82e51918 178 if (! part1_consth_active)
2a38f751
KH
179 {
180 *error_message = (char *) _("Missing IHIHALF");
917583ad 181 return bfd_reloc_dangerous;
2a38f751
KH
182 }
183 /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
184 unsigned_value = 0; /*EXTRACT_HWORD(insn) << 16;*/
185 unsigned_value += reloc_entry->addend; /* r_symndx */
186 unsigned_value += part1_consth_value;
187 unsigned_value = unsigned_value >> 16;
188 insn = INSERT_HWORD(insn, unsigned_value);
189 part1_consth_active = false;
dc810e39 190 bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
2a38f751
KH
191 break;
192 case R_BYTE:
193 insn = bfd_get_8 (abfd, hit_data);
194 unsigned_value = insn + sym_value + reloc_entry->addend;
195 if (unsigned_value & 0xffffff00)
917583ad 196 return bfd_reloc_overflow;
2a38f751
KH
197 bfd_put_8 (abfd, unsigned_value, hit_data);
198 break;
199 case R_HWORD:
200 insn = bfd_get_16 (abfd, hit_data);
201 unsigned_value = insn + sym_value + reloc_entry->addend;
202 if (unsigned_value & 0xffff0000)
917583ad 203 return bfd_reloc_overflow;
dc810e39 204 bfd_put_16 (abfd, (bfd_vma) insn, hit_data);
2a38f751
KH
205 break;
206 case R_WORD:
207 insn = bfd_get_32 (abfd, hit_data);
208 insn += sym_value + reloc_entry->addend;
dc810e39 209 bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
2a38f751
KH
210 break;
211 default:
212 *error_message = _("Unrecognized reloc");
917583ad 213 return bfd_reloc_dangerous;
252b5132 214 }
252b5132 215
346ceb11 216 return(bfd_reloc_ok);
252b5132
RH
217}
218
917583ad 219/*FIXME: I'm not real sure about this table. */
346ceb11 220static reloc_howto_type howto_table[] =
917583ad
NC
221 {
222 {R_ABS, 0, 3, 32, false, 0, complain_overflow_bitfield,a29k_reloc,"ABS", true, 0xffffffff,0xffffffff, false},
223 EMPTY_HOWTO (1),
224 EMPTY_HOWTO (2),
225 EMPTY_HOWTO (3),
226 EMPTY_HOWTO (4),
227 EMPTY_HOWTO (5),
228 EMPTY_HOWTO (6),
229 EMPTY_HOWTO (7),
230 EMPTY_HOWTO (8),
231 EMPTY_HOWTO (9),
232 EMPTY_HOWTO (10),
233 EMPTY_HOWTO (11),
234 EMPTY_HOWTO (12),
235 EMPTY_HOWTO (13),
236 EMPTY_HOWTO (14),
237 EMPTY_HOWTO (15),
238 EMPTY_HOWTO (16),
239 EMPTY_HOWTO (17),
240 EMPTY_HOWTO (18),
241 EMPTY_HOWTO (19),
242 EMPTY_HOWTO (20),
243 EMPTY_HOWTO (21),
244 EMPTY_HOWTO (22),
245 EMPTY_HOWTO (23),
246 {R_IREL, 0, 3, 32, true, 0, complain_overflow_signed,a29k_reloc,"IREL", true, 0xffffffff,0xffffffff, false},
247 {R_IABS, 0, 3, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"IABS", true, 0xffffffff,0xffffffff, false},
248 {R_ILOHALF, 0, 3, 16, true, 0, complain_overflow_signed, a29k_reloc,"ILOHALF", true, 0x0000ffff,0x0000ffff, false},
249 {R_IHIHALF, 0, 3, 16, true, 16, complain_overflow_signed, a29k_reloc,"IHIHALF", true, 0xffff0000,0xffff0000, false},
250 {R_IHCONST, 0, 3, 16, true, 0, complain_overflow_signed, a29k_reloc,"IHCONST", true, 0xffff0000,0xffff0000, false},
251 {R_BYTE, 0, 0, 8, false, 0, complain_overflow_bitfield, a29k_reloc,"BYTE", true, 0x000000ff,0x000000ff, false},
252 {R_HWORD, 0, 1, 16, false, 0, complain_overflow_bitfield, a29k_reloc,"HWORD", true, 0x0000ffff,0x0000ffff, false},
253 {R_WORD, 0, 2, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"WORD", true, 0xffffffff,0xffffffff, false},
254 };
252b5132
RH
255
256#define BADMAG(x) A29KBADMAG(x)
257
258#define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
259 reloc_processing(relent, reloc, symbols, abfd, section)
260
261static void
262reloc_processing (relent,reloc, symbols, abfd, section)
263 arelent *relent;
264 struct internal_reloc *reloc;
265 asymbol **symbols;
266 bfd *abfd;
267 asection *section;
268{
2a38f751 269 static bfd_vma ihihalf_vaddr = (bfd_vma) -1;
252b5132 270
2a38f751
KH
271 relent->address = reloc->r_vaddr;
272 relent->howto = howto_table + reloc->r_type;
273 if (reloc->r_type == R_IHCONST)
346ceb11 274 {
252b5132
RH
275 /* The address of an R_IHCONST should always be the address of
276 the immediately preceding R_IHIHALF. relocs generated by gas
277 are correct, but relocs generated by High C are different (I
278 can't figure out what the address means for High C). We can
279 handle both gas and High C by ignoring the address here, and
280 simply reusing the address saved for R_IHIHALF. */
2a38f751
KH
281 if (ihihalf_vaddr == (bfd_vma) -1)
282 abort ();
283 relent->address = ihihalf_vaddr;
284 ihihalf_vaddr = (bfd_vma) -1;
285 relent->addend = reloc->r_symndx;
286 relent->sym_ptr_ptr= bfd_abs_section_ptr->symbol_ptr_ptr;
252b5132 287 }
2a38f751 288 else
252b5132
RH
289 {
290 asymbol *ptr;
917583ad
NC
291
292 relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
252b5132
RH
293
294 ptr = *(relent->sym_ptr_ptr);
295
346ceb11
KH
296 if (ptr
297 && bfd_asymbol_bfd(ptr) == abfd
917583ad
NC
298 && ((ptr->flags & BSF_OLD_COMMON) == 0))
299 relent->addend = 0;
252b5132 300 else
917583ad
NC
301 relent->addend = 0;
302
252b5132
RH
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)
307 abort ();
2a38f751 308 }
252b5132
RH
309}
310
311/* The reloc processing routine for the optimized COFF linker. */
312
313static boolean
314coff_a29k_relocate_section (output_bfd, info, input_bfd, input_section,
315 contents, relocs, syms, sections)
5f771d47 316 bfd *output_bfd ATTRIBUTE_UNUSED;
252b5132
RH
317 struct bfd_link_info *info;
318 bfd *input_bfd;
319 asection *input_section;
320 bfd_byte *contents;
321 struct internal_reloc *relocs;
322 struct internal_syment *syms;
323 asection **sections;
324{
325 struct internal_reloc *rel;
326 struct internal_reloc *relend;
327 boolean hihalf;
328 bfd_vma hihalf_val;
329
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)
334 return true;
335
336 hihalf = false;
337 hihalf_val = 0;
338
339 rel = relocs;
340 relend = rel + input_section->reloc_count;
341 for (; rel < relend; rel++)
342 {
343 long symndx;
344 bfd_byte *loc;
345 struct coff_link_hash_entry *h;
346 struct internal_syment *sym;
347 asection *sec;
348 bfd_vma val;
349 boolean overflow;
350 unsigned long insn;
351 long signed_value;
352 unsigned long unsigned_value;
353 bfd_reloc_status_type rstat;
354
355 symndx = rel->r_symndx;
356 loc = contents + rel->r_vaddr - input_section->vma;
357
358 if (symndx == -1 || rel->r_type == R_IHCONST)
359 h = NULL;
360 else
361 h = obj_coff_sym_hashes (input_bfd)[symndx];
362
363 sym = NULL;
364 sec = NULL;
365 val = 0;
366
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)
371 {
372 if (h == NULL)
373 {
374 if (symndx == -1)
375 sec = bfd_abs_section_ptr;
376 else
377 {
378 sym = syms + symndx;
379 sec = sections[symndx];
380 val = (sec->output_section->vma
381 + sec->output_offset
382 + sym->n_value
383 - sec->vma);
384 }
385 }
386 else
387 {
917583ad 388 if ( h->root.type == bfd_link_hash_defined
252b5132
RH
389 || h->root.type == bfd_link_hash_defweak)
390 {
391 sec = h->root.u.def.section;
392 val = (h->root.u.def.value
393 + sec->output_section->vma
394 + sec->output_offset);
395 }
396 else
397 {
398 if (! ((*info->callbacks->undefined_symbol)
399 (info, h->root.root.string, input_bfd, input_section,
5cc7c785 400 rel->r_vaddr - input_section->vma, true)))
252b5132
RH
401 return false;
402 }
403 }
404
405 if (hihalf)
406 {
407 if (! ((*info->callbacks->reloc_dangerous)
408 (info, _("missing IHCONST reloc"), input_bfd,
409 input_section, rel->r_vaddr - input_section->vma)))
410 return false;
411 hihalf = false;
412 }
413 }
414
415 overflow = false;
416
417 switch (rel->r_type)
418 {
419 default:
420 bfd_set_error (bfd_error_bad_value);
421 return false;
422
423 case R_IREL:
424 insn = bfd_get_32 (input_bfd, loc);
425
426 /* Extract the addend. */
427 signed_value = EXTRACT_HWORD (insn);
428 signed_value = SIGN_EXTEND_HWORD (signed_value);
429 signed_value <<= 2;
430
431 /* Unfortunately, there are two different versions of COFF
432 a29k. In the original AMD version, the value stored in
433 the field for the R_IREL reloc is a simple addend. In
434 the GNU version, the value is the negative of the address
435 of the reloc within section. We try to cope here by
436 assuming the AMD version, unless the addend is exactly
437 the negative of the address; in the latter case we assume
438 the GNU version. This means that something like
439 .text
440 nop
441 jmp i-4
442 will fail, because the addend of -4 will happen to equal
443 the negative of the address within the section. The
444 compiler will never generate code like this.
445
446 At some point in the future we may want to take out this
447 check. */
448
449 if (signed_value == - (long) (rel->r_vaddr - input_section->vma))
450 signed_value = 0;
451
452 /* Determine the destination of the jump. */
453 signed_value += val;
454
455 if ((signed_value & ~0x3ffff) == 0)
456 {
457 /* We can use an absolute jump. */
458 insn |= (1 << 24);
459 }
460 else
461 {
462 /* Make the destination PC relative. */
463 signed_value -= (input_section->output_section->vma
464 + input_section->output_offset
465 + (rel->r_vaddr - input_section->vma));
466 if (signed_value > 0x1ffff || signed_value < - 0x20000)
467 {
468 overflow = true;
469 signed_value = 0;
470 }
471 }
472
473 /* Put the adjusted value back into the instruction. */
474 signed_value >>= 2;
475 insn = INSERT_HWORD (insn, signed_value);
476
477 bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
252b5132
RH
478 break;
479
480 case R_ILOHALF:
481 insn = bfd_get_32 (input_bfd, loc);
482 unsigned_value = EXTRACT_HWORD (insn);
483 unsigned_value += val;
484 insn = INSERT_HWORD (insn, unsigned_value);
dc810e39 485 bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
252b5132
RH
486 break;
487
488 case R_IHIHALF:
489 /* Save the value for the R_IHCONST reloc. */
490 hihalf = true;
491 hihalf_val = val;
492 break;
493
494 case R_IHCONST:
495 if (! hihalf)
496 {
497 if (! ((*info->callbacks->reloc_dangerous)
498 (info, _("missing IHIHALF reloc"), input_bfd,
499 input_section, rel->r_vaddr - input_section->vma)))
500 return false;
501 hihalf_val = 0;
502 }
503
504 insn = bfd_get_32 (input_bfd, loc);
505 unsigned_value = rel->r_symndx + hihalf_val;
506 unsigned_value >>= 16;
507 insn = INSERT_HWORD (insn, unsigned_value);
508 bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
509
510 hihalf = false;
511
512 break;
513
514 case R_BYTE:
515 case R_HWORD:
516 case R_WORD:
517 rstat = _bfd_relocate_contents (howto_table + rel->r_type,
518 input_bfd, val, loc);
519 if (rstat == bfd_reloc_overflow)
520 overflow = true;
521 else if (rstat != bfd_reloc_ok)
522 abort ();
523 break;
524 }
525
526 if (overflow)
527 {
528 const char *name;
529 char buf[SYMNMLEN + 1];
530
531 if (symndx == -1)
532 name = "*ABS*";
533 else if (h != NULL)
534 name = h->root.root.string;
535 else if (sym == NULL)
536 name = "*unknown*";
537 else if (sym->_n._n_n._n_zeroes == 0
538 && sym->_n._n_n._n_offset != 0)
539 name = obj_coff_strings (input_bfd) + sym->_n._n_n._n_offset;
540 else
541 {
542 strncpy (buf, sym->_n._n_name, SYMNMLEN);
543 buf[SYMNMLEN] = '\0';
544 name = buf;
545 }
546
547 if (! ((*info->callbacks->reloc_overflow)
548 (info, name, howto_table[rel->r_type].name, (bfd_vma) 0,
549 input_bfd, input_section,
550 rel->r_vaddr - input_section->vma)))
551 return false;
552 }
346ceb11 553 }
252b5132
RH
554
555 return true;
556}
557
558#define coff_relocate_section coff_a29k_relocate_section
559
560/* We don't want to change the symndx of a R_IHCONST reloc, since it
561 is actually an addend, not a symbol index at all. */
562
252b5132
RH
563static boolean
564coff_a29k_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
5f771d47
ILT
565 bfd *obfd ATTRIBUTE_UNUSED;
566 struct bfd_link_info *info ATTRIBUTE_UNUSED;
567 bfd *ibfd ATTRIBUTE_UNUSED;
568 asection *sec ATTRIBUTE_UNUSED;
252b5132
RH
569 struct internal_reloc *irel;
570 boolean *adjustedp;
571{
572 if (irel->r_type == R_IHCONST)
573 *adjustedp = true;
574 else
575 *adjustedp = false;
576 return true;
577}
578
579#define coff_adjust_symndx coff_a29k_adjust_symndx
580
581#include "coffcode.h"
582
c3c89269 583CREATE_BIG_COFF_TARGET_VEC (a29kcoff_big_vec, "coff-a29k-big", 0, SEC_READONLY, '_', NULL)