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