OSDN Git Service

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