OSDN Git Service

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