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