* targets.c (enum bfd_endian): Define.
[external/binutils.git] / bfd / coff-a29k.c
1 /* BFD back-end for AMD 29000 COFF binaries.
2    Copyright 1990, 1991, 1992, 1993, 1994 Free Software Foundation, Inc.
3    Contributed by David Wood at New York University 7/8/91.
4
5 This file is part of BFD, the Binary File Descriptor library.
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
20
21 #define A29K 1
22
23 #include "bfd.h"
24 #include "sysdep.h"
25 #include "libbfd.h"
26 #include "obstack.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   {1},  {2},  {3},   {4},  {5},  {6},  {7},  {8},  {9}, {10},
240   {11}, {12}, {13}, {14}, {15}, {16}, {17}, {18}, {19}, {20},
241   {21}, {22}, {23},
242   {R_IREL,    0, 3, 32, true,  0, complain_overflow_signed,a29k_reloc,"IREL",    true, 0xffffffff,0xffffffff, false},
243   {R_IABS,    0, 3, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"IABS",    true, 0xffffffff,0xffffffff, false},
244   {R_ILOHALF, 0, 3, 16, true,  0, complain_overflow_signed, a29k_reloc,"ILOHALF", true, 0x0000ffff,0x0000ffff, false},
245   {R_IHIHALF, 0, 3, 16, true,  16, complain_overflow_signed, a29k_reloc,"IHIHALF", true, 0xffff0000,0xffff0000, false},
246   {R_IHCONST, 0, 3, 16, true,  0, complain_overflow_signed, a29k_reloc,"IHCONST", true, 0xffff0000,0xffff0000, false},
247   {R_BYTE,    0, 0, 8, false, 0, complain_overflow_bitfield, a29k_reloc,"BYTE",    true, 0x000000ff,0x000000ff, false},
248   {R_HWORD,   0, 1, 16, false, 0, complain_overflow_bitfield, a29k_reloc,"HWORD",   true, 0x0000ffff,0x0000ffff, false},
249   {R_WORD,    0, 2, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"WORD",    true, 0xffffffff,0xffffffff, false},
250 };
251
252 #define BADMAG(x) A29KBADMAG(x)
253
254 #define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
255  reloc_processing(relent, reloc, symbols, abfd, section)
256
257 static void
258 reloc_processing (relent,reloc, symbols, abfd, section)
259      arelent *relent;
260      struct internal_reloc *reloc;
261      asymbol **symbols;
262      bfd *abfd;
263      asection *section;
264 {
265     static bfd_vma ihihalf_vaddr = (bfd_vma) -1;
266
267     relent->address = reloc->r_vaddr;           
268     relent->howto = howto_table + reloc->r_type;
269     if (reloc->r_type == R_IHCONST) 
270     {           
271       /* The address of an R_IHCONST should always be the address of
272          the immediately preceding R_IHIHALF.  relocs generated by gas
273          are correct, but relocs generated by High C are different (I
274          can't figure out what the address means for High C).  We can
275          handle both gas and High C by ignoring the address here, and
276          simply reusing the address saved for R_IHIHALF.  */
277         if (ihihalf_vaddr == (bfd_vma) -1)
278           abort ();
279         relent->address = ihihalf_vaddr;
280         ihihalf_vaddr = (bfd_vma) -1;
281         relent->addend = reloc->r_symndx;               
282         relent->sym_ptr_ptr= bfd_abs_section_ptr->symbol_ptr_ptr;
283     }
284     else 
285     {
286       asymbol *ptr;
287       relent->sym_ptr_ptr = symbols + obj_convert(abfd)[reloc->r_symndx];
288
289       ptr = *(relent->sym_ptr_ptr);
290
291       if (ptr 
292           && bfd_asymbol_bfd(ptr) == abfd               
293
294           && ((ptr->flags & BSF_OLD_COMMON)== 0))       
295       {                                         
296           relent->addend = 0;
297       }                                         
298       else
299       {                                 
300           relent->addend = 0;                   
301       }                 
302       relent->address-= section->vma;
303       if (reloc->r_type == R_IHIHALF)
304         ihihalf_vaddr = relent->address;
305       else if (ihihalf_vaddr != (bfd_vma) -1)
306         abort ();
307   }
308 }
309
310 /* The reloc processing routine for the optimized COFF linker.  */
311
312 static boolean
313 coff_a29k_relocate_section (output_bfd, info, input_bfd, input_section,
314                             contents, relocs, syms, sections)
315      bfd *output_bfd;
316      struct bfd_link_info *info;
317      bfd *input_bfd;
318      asection *input_section;
319      bfd_byte *contents;
320      struct internal_reloc *relocs;
321      struct internal_syment *syms;
322      asection **sections;
323 {
324   struct internal_reloc *rel;
325   struct internal_reloc *relend;
326   boolean hihalf;
327   bfd_vma hihalf_val;
328
329   /* If we are performing a relocateable link, we don't need to do a
330      thing.  The caller will take care of adjusting the reloc
331      addresses and symbol indices.  */
332   if (info->relocateable)
333     return true;
334
335   hihalf = false;
336   hihalf_val = 0;
337
338   rel = relocs;
339   relend = rel + input_section->reloc_count;
340   for (; rel < relend; rel++)
341     {
342       long symndx;
343       bfd_byte *loc;
344       struct coff_link_hash_entry *h;
345       struct internal_syment *sym;
346       asection *sec;
347       bfd_vma val;
348       boolean overflow;
349       unsigned long insn;
350       long signed_value;
351       unsigned long unsigned_value;
352       bfd_reloc_status_type rstat;
353
354       symndx = rel->r_symndx;
355       loc = contents + rel->r_vaddr - input_section->vma;
356
357       if (symndx == -1)
358         h = NULL;
359       else
360         h = obj_coff_sym_hashes (input_bfd)[symndx];
361
362       sym = NULL;
363       sec = NULL;
364       val = 0;
365
366       /* An R_IHCONST reloc does not have a symbol.  Instead, the
367          symbol index is an addend.  R_IHCONST is always used in
368          conjunction with R_IHHALF.  */
369       if (rel->r_type != R_IHCONST)
370         {
371           if (h == NULL)
372             {
373               if (symndx == -1)
374                 sec = bfd_abs_section_ptr;
375               else
376                 {
377                   sym = syms + symndx;
378                   sec = sections[symndx];
379                   val = (sec->output_section->vma
380                          + sec->output_offset
381                          + sym->n_value
382                          - sec->vma);
383                 }
384             }
385           else
386             {
387               if (h->root.type == bfd_link_hash_defined
388                   || h->root.type == bfd_link_hash_defweak)
389                 {
390                   sec = h->root.u.def.section;
391                   val = (h->root.u.def.value
392                          + sec->output_section->vma
393                          + sec->output_offset);
394                 }
395               else
396                 {
397                   if (! ((*info->callbacks->undefined_symbol)
398                          (info, h->root.root.string, input_bfd, input_section,
399                           rel->r_vaddr - input_section->vma)))
400                     return false;
401                 }
402             }
403
404           if (hihalf)
405             {
406               if (! ((*info->callbacks->reloc_dangerous)
407                      (info, "missing IHCONST reloc", input_bfd,
408                       input_section, rel->r_vaddr - input_section->vma)))
409                 return false;
410               hihalf = false;
411             }
412         }
413
414       overflow = false;
415
416       switch (rel->r_type)
417         {
418         default:
419           bfd_set_error (bfd_error_bad_value);
420           return false;
421
422         case R_IREL:
423           insn = bfd_get_32 (input_bfd, loc);
424
425           /* Extract the addend.  */
426           signed_value = EXTRACT_HWORD (insn);
427           signed_value = SIGN_EXTEND_HWORD (signed_value);
428           signed_value <<= 2;
429
430           /* Unfortunately, there are two different versions of COFF
431              a29k.  In the original AMD version, the value stored in
432              the field for the R_IREL reloc is a simple addend.  In
433              the GNU version, the value is the negative of the address
434              of the reloc within section.  We try to cope here by
435              assuming the AMD version, unless the addend is exactly
436              the negative of the address; in the latter case we assume
437              the GNU version.  This means that something like
438                  .text
439                  nop
440                  jmp i-4
441              will fail, because the addend of -4 will happen to equal
442              the negative of the address within the section.  The
443              compiler will never generate code like this.
444
445              At some point in the future we may want to take out this
446              check.  */
447
448           if (signed_value == - (long) (rel->r_vaddr - input_section->vma))
449             signed_value = 0;
450
451           /* Determine the destination of the jump.  */
452           signed_value += val;
453
454           if ((signed_value & ~0x3ffff) == 0)
455             {
456               /* We can use an absolute jump.  */
457               insn |= (1 << 24);
458             }
459           else
460             {
461               /* Make the destination PC relative.  */
462               signed_value -= (input_section->output_section->vma
463                                + input_section->output_offset
464                                + (rel->r_vaddr - input_section->vma));
465               if (signed_value > 0x1ffff || signed_value < - 0x20000)
466                 {
467                   overflow = true;
468                   signed_value = 0;
469                 }
470             }
471
472           /* Put the adjusted value back into the instruction.  */
473           signed_value >>= 2;
474           insn = INSERT_HWORD (insn, signed_value);
475
476           bfd_put_32 (input_bfd, (bfd_vma) insn, loc);
477
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, 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 /*ARGSUSED*/
564 static boolean
565 coff_a29k_adjust_symndx (obfd, info, ibfd, sec, irel, adjustedp)
566      bfd *obfd;
567      struct bfd_link_info *info;
568      bfd *ibfd;
569      asection *sec;
570      struct internal_reloc *irel;
571      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 const bfd_target a29kcoff_big_vec =
585 {
586   "coff-a29k-big",              /* name */
587   bfd_target_coff_flavour,
588   BFD_ENDIAN_BIG,               /* data byte order is big */
589   BFD_ENDIAN_BIG,               /* header byte order is big */
590
591   (HAS_RELOC | EXEC_P |         /* object flags */
592    HAS_LINENO | HAS_DEBUG |
593    HAS_SYMS | HAS_LOCALS | WP_TEXT),
594
595   (SEC_HAS_CONTENTS | SEC_ALLOC /* section flags */
596    | SEC_LOAD | SEC_RELOC  
597    | SEC_READONLY ),
598   '_',                          /* leading underscore */
599   '/',                          /* ar_pad_char */
600   15,                           /* ar_max_namelen */
601   /* data */
602   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
603      bfd_getb32, bfd_getb_signed_32,   bfd_putb32,
604      bfd_getb16, bfd_getb_signed_16, bfd_putb16,
605   /* hdrs */
606   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
607      bfd_getb32, bfd_getb_signed_32,   bfd_putb32,
608      bfd_getb16, bfd_getb_signed_16, bfd_putb16,
609
610  {
611             
612    _bfd_dummy_target,
613    coff_object_p,
614    bfd_generic_archive_p,
615    _bfd_dummy_target
616   },
617  {
618    bfd_false,
619    coff_mkobject,
620    _bfd_generic_mkarchive,
621    bfd_false
622   },
623  {
624    bfd_false,
625    coff_write_object_contents,
626    _bfd_write_archive_contents,
627    bfd_false
628   },
629
630      BFD_JUMP_TABLE_GENERIC (coff),
631      BFD_JUMP_TABLE_COPY (coff),
632      BFD_JUMP_TABLE_CORE (_bfd_nocore),
633      BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
634      BFD_JUMP_TABLE_SYMBOLS (coff),
635      BFD_JUMP_TABLE_RELOCS (coff),
636      BFD_JUMP_TABLE_WRITE (coff),
637      BFD_JUMP_TABLE_LINK (coff),
638      BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
639
640   COFF_SWAP_TABLE
641  };