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