bfd/
[deliverable/binutils-gdb.git] / bfd / coff-a29k.c
1 /* BFD back-end for AMD 29000 COFF binaries.
2 Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1997, 1999, 2000, 2001, 2002
3 Free Software Foundation, Inc.
4 Contributed by David Wood at New York University 7/8/91.
5
6 This file is part of BFD, the Binary File Descriptor library.
7
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.
12
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.
17
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. */
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
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 *));
40 static void reloc_processing
41 PARAMS ((arelent *, struct internal_reloc *, asymbol **, bfd *, asection *));
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) \
48 ((((WORD) & 0x00ff0000) >> 8) | ((WORD) & 0xff))
49 #define SIGN_EXTEND_HWORD(HWORD) \
50 (((HWORD) ^ 0x8000) - 0x8000)
51
52 /* Provided the symbol, returns the value reffed. */
53
54 static long
55 get_symbol_value (symbol)
56 asymbol *symbol;
57 {
58 long relocation = 0;
59
60 if (bfd_is_com_section (symbol->section))
61 relocation = 0;
62 else
63 relocation = symbol->value +
64 symbol->section->output_section->vma +
65 symbol->section->output_offset;
66
67 return relocation;
68 }
69
70 /* This function is in charge of performing all the 29k relocations. */
71
72 static bfd_reloc_status_type
73 a29k_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 {
83 /* The consth relocation comes in two parts, we have to remember
84 the state between calls, in these variables. */
85 static boolean part1_consth_active = false;
86 static unsigned long part1_consth_value;
87 unsigned long insn;
88 unsigned long sym_value;
89 unsigned long unsigned_value;
90 unsigned short r_type;
91 long signed_value;
92 unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
93 bfd_byte *hit_data =addr + (bfd_byte *) (data);
94
95 r_type = reloc_entry->howto->type;
96
97 if (output_bfd)
98 {
99 /* Partial linking - do nothing. */
100 reloc_entry->address += input_section->output_offset;
101 return bfd_reloc_ok;
102 }
103
104 if (symbol_in != NULL
105 && bfd_is_und_section (symbol_in->section))
106 {
107 /* Keep the state machine happy in case we're called again. */
108 if (r_type == R_IHIHALF)
109 {
110 part1_consth_active = true;
111 part1_consth_value = 0;
112 }
113 return bfd_reloc_undefined;
114 }
115
116 if ((part1_consth_active) && (r_type != R_IHCONST))
117 {
118 part1_consth_active = false;
119 *error_message = (char *) _("Missing IHCONST");
120
121 return bfd_reloc_dangerous;
122 }
123
124 sym_value = get_symbol_value(symbol_in);
125
126 switch (r_type)
127 {
128 case R_IREL:
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);
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 */
142 insn |= (1 << 24); /* Make it absolute */
143 /* FIXME: Should we change r_type to R_IABS. */
144 }
145 else
146 {
147 /* Relative jmp/call, so subtract from the value the
148 address of the place we're coming from. */
149 signed_value -= (reloc_entry->address
150 + input_section->output_section->vma
151 + input_section->output_offset);
152 if (signed_value > 0x1ffff || signed_value < -0x20000)
153 return bfd_reloc_overflow;
154 }
155 signed_value >>= 2;
156 insn = INSERT_HWORD (insn, signed_value);
157 bfd_put_32 (abfd, (bfd_vma) insn ,hit_data);
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);
164 bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
165 break;
166 case R_IHIHALF:
167 insn = bfd_get_32 (abfd, hit_data);
168 /* consth, part 1
169 Just get the symbol value that is referenced. */
170 part1_consth_active = true;
171 part1_consth_value = sym_value + reloc_entry->addend;
172 /* Don't modify insn until R_IHCONST. */
173 break;
174 case R_IHCONST:
175 insn = bfd_get_32 (abfd, hit_data);
176 /* consth, part 2
177 Now relocate the reference. */
178 if (! part1_consth_active)
179 {
180 *error_message = (char *) _("Missing IHIHALF");
181 return bfd_reloc_dangerous;
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;
190 bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
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)
196 return bfd_reloc_overflow;
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)
203 return bfd_reloc_overflow;
204 bfd_put_16 (abfd, (bfd_vma) insn, hit_data);
205 break;
206 case R_WORD:
207 insn = bfd_get_32 (abfd, hit_data);
208 insn += sym_value + reloc_entry->addend;
209 bfd_put_32 (abfd, (bfd_vma) insn, hit_data);
210 break;
211 default:
212 *error_message = _("Unrecognized reloc");
213 return bfd_reloc_dangerous;
214 }
215
216 return(bfd_reloc_ok);
217 }
218
219 /*FIXME: I'm not real sure about this table. */
220 static reloc_howto_type howto_table[] =
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 };
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
261 static void
262 reloc_processing (relent,reloc, symbols, abfd, section)
263 arelent *relent;
264 struct internal_reloc *reloc;
265 asymbol **symbols;
266 bfd *abfd;
267 asection *section;
268 {
269 static bfd_vma ihihalf_vaddr = (bfd_vma) -1;
270
271 relent->address = reloc->r_vaddr;
272 relent->howto = howto_table + reloc->r_type;
273 if (reloc->r_type == R_IHCONST)
274 {
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. */
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;
287 }
288 else
289 {
290 asymbol *ptr;
291
292 relent->sym_ptr_ptr = symbols + obj_convert (abfd)[reloc->r_symndx];
293
294 ptr = *(relent->sym_ptr_ptr);
295
296 if (ptr
297 && bfd_asymbol_bfd(ptr) == abfd
298 && ((ptr->flags & BSF_OLD_COMMON) == 0))
299 relent->addend = 0;
300 else
301 relent->addend = 0;
302
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 ();
308 }
309 }
310
311 /* The reloc processing routine for the optimized COFF linker. */
312
313 static boolean
314 coff_a29k_relocate_section (output_bfd, info, input_bfd, input_section,
315 contents, relocs, syms, sections)
316 bfd *output_bfd ATTRIBUTE_UNUSED;
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 {
388 if ( h->root.type == bfd_link_hash_defined
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,
400 rel->r_vaddr - input_section->vma, true)))
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);
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);
485 bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
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 }
553 }
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
563 static boolean
564 coff_a29k_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
565 bfd *obfd ATTRIBUTE_UNUSED;
566 struct bfd_link_info *info ATTRIBUTE_UNUSED;
567 bfd *ibfd ATTRIBUTE_UNUSED;
568 asection *sec ATTRIBUTE_UNUSED;
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
583 CREATE_BIG_COFF_TARGET_VEC (a29kcoff_big_vec, "coff-a29k-big", 0, SEC_READONLY, '_', NULL)
This page took 0.042323 seconds and 4 git commands to generate.