* bfd-in.h: bump version to 1.96
[external/binutils.git] / bfd / coff-a29k.c
1 /* AMD 29000 COFF back-end for BFD.
2    Copyright (C) 1990-1991 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., 675 Mass Ave, Cambridge, MA 02139, USA.  */
20
21 /* $Id$ */
22
23 #define A29K 1
24
25 #include "bfd.h"
26 #include "sysdep.h"
27 #include "libbfd.h"
28 #include "obstack.h"
29 #include "coff/a29k.h"
30 #include "coff/internal.h"
31 #include "libcoff.h"
32
33 #define INSERT_HWORD(WORD,HWORD)        \
34     (((WORD) & 0xff00ff00) | (((HWORD) & 0xff00) << 8) | ((HWORD)& 0xff))
35 #define EXTRACT_HWORD(WORD) \
36     (((WORD) & 0x00ff0000) >> 8) | ((WORD)& 0xff)
37 #define SIGN_EXTEND_HWORD(HWORD) \
38     ((HWORD) & 0x8000 ? (HWORD)|0xffff0000 : (HWORD))
39
40 /* Provided the symbol, returns the value reffed */
41 static  long
42 get_symbol_value(symbol)       
43 asymbol *symbol;
44 {                                             
45   long relocation = 0;
46
47   if (symbol->section == &bfd_com_section) 
48   {
49     relocation = 0;                           
50   }
51   else 
52   {                                      
53     relocation = symbol->value +
54      symbol->section->output_section->vma +
55       symbol->section->output_offset;
56   }                                           
57
58   return(relocation);
59 }
60
61 /* this function is in charge of performing all the 29k relocations */
62
63 static bfd_reloc_status_type
64 DEFUN(a29k_reloc,(abfd, reloc_entry, symbol_in, data, input_section, output_bfd),
65       bfd *abfd AND
66       arelent *reloc_entry AND
67       asymbol *symbol_in AND
68       PTR data AND
69       asection *input_section AND
70       bfd *output_bfd)
71 {
72   /* the consth relocation comes in two parts, we have to remember
73      the state between calls, in these variables */
74   static boolean part1_consth_active = false;
75   static unsigned long part1_consth_value;
76
77   unsigned long insn;
78   unsigned long sym_value;
79   unsigned long unsigned_value;
80   unsigned short r_type;
81   long signed_value;
82
83   unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
84   bfd_byte  *hit_data =addr + (bfd_byte *)(data);
85         
86   r_type = reloc_entry->howto->type;
87
88   if (output_bfd) {
89     /* Partial linking - do nothing */
90     reloc_entry->address += input_section->output_offset;
91     return bfd_reloc_ok;
92
93   }
94
95   if (symbol_in && (symbol_in->section == &bfd_und_section))
96   {
97     /* Keep the state machine happy in case we're called again */
98     if (r_type == R_IHIHALF) 
99     {
100       part1_consth_active = true;
101       part1_consth_value  = 0;
102     }
103     return(bfd_reloc_undefined);
104   }
105
106   if ((part1_consth_active) && (r_type != R_IHCONST)) 
107   {
108     fprintf(stderr,"Relocation problem : ");
109     fprintf(stderr,"Missing IHCONST in module %s\n",abfd->filename);
110     part1_consth_active = false;
111     return(bfd_reloc_dangerous);
112   }
113
114
115   sym_value = get_symbol_value(symbol_in);
116
117   switch (r_type) 
118   {
119    case R_IREL:         
120     insn = bfd_get_32(abfd, hit_data); 
121     /* Take the value in the field and sign extend it */
122     signed_value = EXTRACT_HWORD(insn) << 2;
123     signed_value = SIGN_EXTEND_HWORD(signed_value);
124     signed_value +=  sym_value + reloc_entry->addend;
125     if ((signed_value&~0x3ffff) == 0) 
126     {                           /* Absolute jmp/call */
127       insn |= (1<<24);          /* Make it absolute */
128       /* FIXME: Should we change r_type to R_IABS */
129       signed_value /= 2;
130     } 
131     else 
132     {
133       /* Relative jmp/call, so subtract from the value the
134          address of the place we're coming from */
135       signed_value -= reloc_entry->address + 
136        input_section->output_section->vma + 
137         input_section->output_offset;
138       if (signed_value>0x1ffff || signed_value<-0x20000) 
139        return(bfd_reloc_outofrange);
140
141       signed_value /= 2;
142     }
143     insn = INSERT_HWORD(insn, signed_value);
144     bfd_put_32(abfd, insn ,hit_data); 
145     break;
146    case R_ILOHALF: 
147     insn = bfd_get_32(abfd, hit_data); 
148     unsigned_value = EXTRACT_HWORD(insn);
149     unsigned_value +=  sym_value + reloc_entry->addend;
150     insn = INSERT_HWORD(insn, unsigned_value);
151     bfd_put_32(abfd, insn, hit_data); 
152     break;
153    case R_IHIHALF:
154     insn = bfd_get_32(abfd, hit_data); 
155     /* consth, part 1 
156        Just get the symbol value that is referenced */
157     part1_consth_active = true;
158     part1_consth_value = sym_value + reloc_entry->addend;
159     /* Don't modify insn until R_IHCONST */
160     break;
161    case R_IHCONST:      
162     insn = bfd_get_32(abfd, hit_data); 
163     /* consth, part 2 
164        Now relocate the reference */
165     if (part1_consth_active == false) {
166       fprintf(stderr,"Relocation problem : ");
167       fprintf(stderr,"IHIHALF missing in module %s\n",
168               abfd->filename); 
169       return(bfd_reloc_dangerous);
170     }
171     /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
172     unsigned_value = 0;         /*EXTRACT_HWORD(insn) << 16;*/
173     unsigned_value += reloc_entry->addend; /* r_symndx */
174     unsigned_value += part1_consth_value;
175     unsigned_value = unsigned_value >> 16;
176     insn = INSERT_HWORD(insn, unsigned_value);
177     part1_consth_active = false;
178     bfd_put_32(abfd, insn, hit_data); 
179     break;
180    case R_BYTE:
181     insn = bfd_get_8(abfd, hit_data); 
182     unsigned_value = insn + sym_value + reloc_entry->addend;    
183     if (unsigned_value & 0xffffff00) {
184       fprintf(stderr,"Relocation problem : ");
185       fprintf(stderr,"byte value too large in module %s\n",
186               abfd->filename); 
187       return(bfd_reloc_overflow);
188     }
189     bfd_put_8(abfd, insn, hit_data); 
190     break;
191    case R_HWORD:
192     insn = bfd_get_16(abfd, hit_data); 
193     unsigned_value = insn + sym_value + reloc_entry->addend;    
194     if (unsigned_value & 0xffff0000) {
195       fprintf(stderr,"Relocation problem : ");
196       fprintf(stderr,"hword value too large in module %s\n",
197               abfd->filename); 
198       return(bfd_reloc_overflow);
199     }
200
201     bfd_put_16(abfd, insn, hit_data); 
202     break;
203    case R_WORD:
204     insn = bfd_get_32(abfd, hit_data); 
205     insn += sym_value + reloc_entry->addend;  
206     bfd_put_32(abfd, insn, hit_data);
207     break;
208    default:
209     fprintf(stderr,"Relocation problem : ");
210     fprintf(stderr,"Unrecognized reloc type %d, in module %s\n",
211             r_type,abfd->filename); 
212     return (bfd_reloc_dangerous);
213   }
214
215
216   return(bfd_reloc_ok); 
217 }
218
219 /*      type       rightshift
220                        size
221                           bitsize
222                                pc-relative
223                                      bitpos
224                                          absolute
225                                              complain_on_overflow
226                                                   special_function
227                                                     relocation name
228                                                                partial_inplace 
229                                                                       src_mask
230 */
231
232 /*FIXME: I'm not real sure about this table */
233 #define NA      0       /* Obsolete fields, via the documentation */
234 #define NAB false
235 static reloc_howto_type howto_table[] = 
236 {
237   {R_ABS,     0, 3, NA, false, NA, NAB, true,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, NA, true,  NA, NAB, true,a29k_reloc,"IREL",    true, 0xffffffff,0xffffffff, false},
242   {R_IABS,    0, 3, NA, false, NA, NAB, true,a29k_reloc,"IABS",    true, 0xffffffff,0xffffffff, false},
243   {R_ILOHALF, 0, 3, NA, true,  NA, NAB, true,a29k_reloc,"ILOHALF", true, 0x0000ffff,0x0000ffff, false},
244   {R_IHIHALF, 0, 3, NA, true,  NA, NAB, true,a29k_reloc,"IHIHALF", true, 0xffff0000,0xffff0000, false},
245   {R_IHCONST, 0, 3, NA, true,  NA, NAB, true,a29k_reloc,"IHCONST", true, 0xffff0000,0xffff0000, false},
246   {R_BYTE,    0, 0, NA, false, NA, NAB, true,a29k_reloc,"BYTE",    true, 0x000000ff,0x000000ff, false},
247   {R_HWORD,   0, 1, NA, false, NA, NAB, true,a29k_reloc,"HWORD",   true, 0x0000ffff,0x0000ffff, false},
248   {R_WORD,    0, 2, NA, false, NA, NAB, true,a29k_reloc,"WORD",    true, 0xffffffff,0xffffffff, false},
249 };
250 #undef NA
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 DEFUN(reloc_processing,(relent,reloc, symbols, abfd, section) ,
258            arelent *relent AND
259            struct internal_reloc *reloc AND
260            asymbol **symbols AND
261            bfd *abfd AND
262            asection *section)
263 {
264     relent->address = reloc->r_vaddr;           
265     relent->howto = howto_table + reloc->r_type;
266     if (reloc->r_type == R_IHCONST) 
267     {           
268         relent->addend = reloc->r_symndx;               
269         relent->sym_ptr_ptr= bfd_abs_section.symbol_ptr_ptr;
270     }
271     else 
272     {
273       asymbol *ptr;
274       relent->sym_ptr_ptr = symbols + obj_convert(abfd)[reloc->r_symndx];
275
276       ptr = *(relent->sym_ptr_ptr);
277
278       if (ptr 
279           && ptr->the_bfd == abfd               
280
281           && ((ptr->flags & BSF_OLD_COMMON)== 0))       
282       {                                         
283           relent->addend = 0;
284       }                                         
285       else
286       {                                 
287           relent->addend = 0;                   
288       }                 
289       relent->address-= section->vma;
290   }
291 }
292
293 #include "coffcode.h"
294
295 bfd_target a29kcoff_big_vec =
296 {
297     "coff-a29k-big",            /* name */
298     bfd_target_coff_flavour,
299     true,                       /* data byte order is big */
300     true,                       /* header byte order is big */
301
302     (HAS_RELOC | EXEC_P |       /* object flags */
303      HAS_LINENO | HAS_DEBUG |
304      HAS_SYMS | HAS_LOCALS | DYNAMIC | WP_TEXT),
305
306     (SEC_HAS_CONTENTS | SEC_ALLOC /* section flags */
307      | SEC_LOAD | SEC_RELOC  
308      | SEC_READONLY ),
309     '/',                        /* ar_pad_char */
310     15,                         /* ar_max_namelen */
311     2,                          /* minimum section alignment */
312     /* data */
313     _do_getb64, _do_putb64, _do_getb32,
314     _do_putb32, _do_getb16, _do_putb16,
315     /* hdrs */
316     _do_getb64, _do_putb64, _do_getb32,
317     _do_putb32, _do_getb16, _do_putb16,
318
319   {
320             
321       _bfd_dummy_target,
322       coff_object_p,
323       bfd_generic_archive_p,
324       _bfd_dummy_target
325    },
326   {
327       bfd_false,
328       coff_mkobject,
329       _bfd_generic_mkarchive,
330       bfd_false
331    },
332   {
333       bfd_false,
334       coff_write_object_contents,
335       _bfd_write_archive_contents,
336       bfd_false
337    },
338
339     JUMP_TABLE(coff),
340     COFF_SWAP_TABLE
341  };
342