* Many files: Changes to avoid gcc warnings: Add ATTRIBUTE_UNUSED
[external/binutils.git] / bfd / coff-a29k.c
1 /* BFD back-end for AMD 29000 COFF binaries.
2    Copyright 1990, 91, 92, 93, 94, 95, 97, 98, 1999
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 ? (HWORD)|(~0xffffL) : (HWORD))
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     /* 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 */
111     if (r_type == R_IHIHALF) 
112     {
113       part1_consth_active = true;
114       part1_consth_value  = 0;
115     }
116     return(bfd_reloc_undefined);
117   }
118
119   if ((part1_consth_active) && (r_type != R_IHCONST)) 
120   {
121     part1_consth_active = false;
122     *error_message = (char *) _("Missing IHCONST");
123     return(bfd_reloc_dangerous);
124   }
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       *error_message = (char *) _("Missing IHIHALF");
183       return(bfd_reloc_dangerous);
184     }
185     /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
186     unsigned_value = 0;         /*EXTRACT_HWORD(insn) << 16;*/
187     unsigned_value += reloc_entry->addend; /* r_symndx */
188     unsigned_value += part1_consth_value;
189     unsigned_value = unsigned_value >> 16;
190     insn = INSERT_HWORD(insn, unsigned_value);
191     part1_consth_active = false;
192     bfd_put_32(abfd, insn, hit_data); 
193     break;
194    case R_BYTE:
195     insn = bfd_get_8(abfd, hit_data); 
196     unsigned_value = insn + sym_value + reloc_entry->addend;    
197     if (unsigned_value & 0xffffff00)
198       return(bfd_reloc_overflow);
199     bfd_put_8(abfd, unsigned_value, hit_data); 
200     break;
201    case R_HWORD:
202     insn = bfd_get_16(abfd, hit_data); 
203     unsigned_value = insn + sym_value + reloc_entry->addend;    
204     if (unsigned_value & 0xffff0000)
205       return(bfd_reloc_overflow);
206     bfd_put_16(abfd, insn, hit_data); 
207     break;
208    case R_WORD:
209     insn = bfd_get_32(abfd, hit_data); 
210     insn += sym_value + reloc_entry->addend;  
211     bfd_put_32(abfd, insn, hit_data);
212     break;
213    default:
214     *error_message = _("Unrecognized reloc");
215     return (bfd_reloc_dangerous);
216   }
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)))
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 /*ARGSUSED*/
584 static boolean
585 coff_a29k_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
586      bfd *obfd ATTRIBUTE_UNUSED;
587      struct bfd_link_info *info ATTRIBUTE_UNUSED;
588      bfd *ibfd ATTRIBUTE_UNUSED;
589      asection *sec ATTRIBUTE_UNUSED;
590      struct internal_reloc *irel;
591      boolean *adjustedp;
592 {
593   if (irel->r_type == R_IHCONST)
594     *adjustedp = true;
595   else
596     *adjustedp = false;
597   return true;
598 }
599
600 #define coff_adjust_symndx coff_a29k_adjust_symndx
601
602 #include "coffcode.h"
603
604 const bfd_target a29kcoff_big_vec =
605 {
606   "coff-a29k-big",              /* name */
607   bfd_target_coff_flavour,
608   BFD_ENDIAN_BIG,               /* data byte order is big */
609   BFD_ENDIAN_BIG,               /* header byte order is big */
610
611   (HAS_RELOC | EXEC_P |         /* object flags */
612    HAS_LINENO | HAS_DEBUG |
613    HAS_SYMS | HAS_LOCALS | WP_TEXT),
614
615   (SEC_HAS_CONTENTS | SEC_ALLOC /* section flags */
616    | SEC_LOAD | SEC_RELOC  
617    | SEC_READONLY ),
618   '_',                          /* leading underscore */
619   '/',                          /* ar_pad_char */
620   15,                           /* ar_max_namelen */
621   /* data */
622   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
623      bfd_getb32, bfd_getb_signed_32,   bfd_putb32,
624      bfd_getb16, bfd_getb_signed_16, bfd_putb16,
625   /* hdrs */
626   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
627      bfd_getb32, bfd_getb_signed_32,   bfd_putb32,
628      bfd_getb16, bfd_getb_signed_16, bfd_putb16,
629
630  {
631             
632    _bfd_dummy_target,
633    coff_object_p,
634    bfd_generic_archive_p,
635    _bfd_dummy_target
636   },
637  {
638    bfd_false,
639    coff_mkobject,
640    _bfd_generic_mkarchive,
641    bfd_false
642   },
643  {
644    bfd_false,
645    coff_write_object_contents,
646    _bfd_write_archive_contents,
647    bfd_false
648   },
649
650      BFD_JUMP_TABLE_GENERIC (coff),
651      BFD_JUMP_TABLE_COPY (coff),
652      BFD_JUMP_TABLE_CORE (_bfd_nocore),
653      BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
654      BFD_JUMP_TABLE_SYMBOLS (coff),
655      BFD_JUMP_TABLE_RELOCS (coff),
656      BFD_JUMP_TABLE_WRITE (coff),
657      BFD_JUMP_TABLE_LINK (coff),
658      BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
659
660   COFF_SWAP_TABLE
661  };