* section.c (bfd_abs_section): Make const.
[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., 675 Mass Ave, Cambridge, MA 02139, 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
35 #define INSERT_HWORD(WORD,HWORD)        \
36     (((WORD) & 0xff00ff00) | (((HWORD) & 0xff00) << 8) | ((HWORD)& 0xff))
37 #define EXTRACT_HWORD(WORD) \
38     (((WORD) & 0x00ff0000) >> 8) | ((WORD)& 0xff)
39 #define SIGN_EXTEND_HWORD(HWORD) \
40     ((HWORD) & 0x8000 ? (HWORD)|0xffff0000 : (HWORD))
41
42 /* Provided the symbol, returns the value reffed */
43 static long
44 get_symbol_value (symbol)       
45      asymbol *symbol;
46 {                                             
47   long relocation = 0;
48
49   if (bfd_is_com_section (symbol->section))
50   {
51     relocation = 0;                           
52   }
53   else 
54   {                                      
55     relocation = symbol->value +
56      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 a29k_reloc (abfd, reloc_entry, symbol_in, data, input_section, output_bfd,
67             error_message)
68      bfd *abfd;
69      arelent *reloc_entry;
70      asymbol *symbol_in;
71      PTR data;
72      asection *input_section;
73      bfd *output_bfd;
74      char **error_message;
75 {
76   /* the consth relocation comes in two parts, we have to remember
77      the state between calls, in these variables */
78   static boolean part1_consth_active = false;
79   static unsigned long part1_consth_value;
80
81   unsigned long insn;
82   unsigned long sym_value;
83   unsigned long unsigned_value;
84   unsigned short r_type;
85   long signed_value;
86
87   unsigned long addr = reloc_entry->address ; /*+ input_section->vma*/
88   bfd_byte  *hit_data =addr + (bfd_byte *)(data);
89         
90   r_type = reloc_entry->howto->type;
91
92   if (output_bfd) {
93     /* Partial linking - do nothing */
94     reloc_entry->address += input_section->output_offset;
95     return bfd_reloc_ok;
96
97   }
98
99   if (symbol_in != NULL
100       && bfd_is_und_section (symbol_in->section))
101   {
102     /* Keep the state machine happy in case we're called again */
103     if (r_type == R_IHIHALF) 
104     {
105       part1_consth_active = true;
106       part1_consth_value  = 0;
107     }
108     return(bfd_reloc_undefined);
109   }
110
111   if ((part1_consth_active) && (r_type != R_IHCONST)) 
112   {
113     part1_consth_active = false;
114     *error_message = (char *) "Missing IHCONST";
115     return(bfd_reloc_dangerous);
116   }
117
118
119   sym_value = get_symbol_value(symbol_in);
120
121   switch (r_type) 
122   {
123    case R_IREL:         
124     insn = bfd_get_32(abfd, hit_data); 
125     /* Take the value in the field and sign extend it */
126     signed_value = EXTRACT_HWORD(insn);
127     signed_value = SIGN_EXTEND_HWORD(signed_value);
128     signed_value <<= 2;
129     signed_value +=  sym_value + reloc_entry->addend;
130     if (((signed_value + reloc_entry->address) & ~0x3ffff) == 0)
131     {                           /* Absolute jmp/call */
132       insn |= (1<<24);          /* Make it absolute */
133       signed_value += reloc_entry->address;
134       /* FIXME: Should we change r_type to R_IABS */
135     } 
136     else 
137     {
138       /* Relative jmp/call, so subtract from the value the
139          address of the place we're coming from */
140       signed_value -= (input_section->output_section->vma
141                        + input_section->output_offset);
142       if (signed_value>0x1ffff || signed_value<-0x20000) 
143        return(bfd_reloc_overflow);
144     }
145     signed_value >>= 2;
146     insn = INSERT_HWORD(insn, signed_value);
147     bfd_put_32(abfd, insn ,hit_data); 
148     break;
149    case R_ILOHALF: 
150     insn = bfd_get_32(abfd, hit_data); 
151     unsigned_value = EXTRACT_HWORD(insn);
152     unsigned_value +=  sym_value + reloc_entry->addend;
153     insn = INSERT_HWORD(insn, unsigned_value);
154     bfd_put_32(abfd, insn, hit_data); 
155     break;
156    case R_IHIHALF:
157     insn = bfd_get_32(abfd, hit_data); 
158     /* consth, part 1 
159        Just get the symbol value that is referenced */
160     part1_consth_active = true;
161     part1_consth_value = sym_value + reloc_entry->addend;
162     /* Don't modify insn until R_IHCONST */
163     break;
164    case R_IHCONST:      
165     insn = bfd_get_32(abfd, hit_data); 
166     /* consth, part 2 
167        Now relocate the reference */
168     if (part1_consth_active == false) {
169       *error_message = (char *) "Missing IHIHALF";
170       return(bfd_reloc_dangerous);
171     }
172     /* sym_ptr_ptr = r_symndx, in coff_slurp_reloc_table() */
173     unsigned_value = 0;         /*EXTRACT_HWORD(insn) << 16;*/
174     unsigned_value += reloc_entry->addend; /* r_symndx */
175     unsigned_value += part1_consth_value;
176     unsigned_value = unsigned_value >> 16;
177     insn = INSERT_HWORD(insn, unsigned_value);
178     part1_consth_active = false;
179     bfd_put_32(abfd, insn, hit_data); 
180     break;
181    case R_BYTE:
182     insn = bfd_get_8(abfd, hit_data); 
183     unsigned_value = insn + sym_value + reloc_entry->addend;    
184     if (unsigned_value & 0xffffff00) {
185       fprintf(stderr,"Relocation problem : ");
186       fprintf(stderr,"byte value too large in module %s\n",
187               abfd->filename); 
188       return(bfd_reloc_overflow);
189     }
190     bfd_put_8(abfd, unsigned_value, hit_data); 
191     break;
192    case R_HWORD:
193     insn = bfd_get_16(abfd, hit_data); 
194     unsigned_value = insn + sym_value + reloc_entry->addend;    
195     if (unsigned_value & 0xffff0000) {
196       fprintf(stderr,"Relocation problem : ");
197       fprintf(stderr,"hword value too large in module %s\n",
198               abfd->filename); 
199       return(bfd_reloc_overflow);
200     }
201
202     bfd_put_16(abfd, insn, hit_data); 
203     break;
204    case R_WORD:
205     insn = bfd_get_32(abfd, hit_data); 
206     insn += sym_value + reloc_entry->addend;  
207     bfd_put_32(abfd, insn, hit_data);
208     break;
209    default:
210     *error_message = "Unrecognized reloc";
211     return (bfd_reloc_dangerous);
212   }
213
214
215   return(bfd_reloc_ok); 
216 }
217
218 /*      type       rightshift
219                        size
220                           bitsize
221                                pc-relative
222                                      bitpos
223                                          absolute
224                                              complain_on_overflow
225                                                   special_function
226                                                     relocation name
227                                                                partial_inplace 
228                                                                       src_mask
229 */
230
231 /*FIXME: I'm not real sure about this table */
232 static reloc_howto_type howto_table[] = 
233 {
234   {R_ABS,     0, 3, 32, false, 0, complain_overflow_bitfield,a29k_reloc,"ABS",     true, 0xffffffff,0xffffffff, false},
235   {1},  {2},  {3},   {4},  {5},  {6},  {7},  {8},  {9}, {10},
236   {11}, {12}, {13}, {14}, {15}, {16}, {17}, {18}, {19}, {20},
237   {21}, {22}, {23},
238   {R_IREL,    0, 3, 32, true,  0, complain_overflow_signed,a29k_reloc,"IREL",    true, 0xffffffff,0xffffffff, false},
239   {R_IABS,    0, 3, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"IABS",    true, 0xffffffff,0xffffffff, false},
240   {R_ILOHALF, 0, 3, 16, true,  0, complain_overflow_signed, a29k_reloc,"ILOHALF", true, 0x0000ffff,0x0000ffff, false},
241   {R_IHIHALF, 0, 3, 16, true,  16, complain_overflow_signed, a29k_reloc,"IHIHALF", true, 0xffff0000,0xffff0000, false},
242   {R_IHCONST, 0, 3, 16, true,  0, complain_overflow_signed, a29k_reloc,"IHCONST", true, 0xffff0000,0xffff0000, false},
243   {R_BYTE,    0, 0, 8, false, 0, complain_overflow_bitfield, a29k_reloc,"BYTE",    true, 0x000000ff,0x000000ff, false},
244   {R_HWORD,   0, 1, 16, false, 0, complain_overflow_bitfield, a29k_reloc,"HWORD",   true, 0x0000ffff,0x0000ffff, false},
245   {R_WORD,    0, 2, 32, false, 0, complain_overflow_bitfield, a29k_reloc,"WORD",    true, 0xffffffff,0xffffffff, false},
246 };
247
248 #define BADMAG(x) A29KBADMAG(x)
249
250 #define RELOC_PROCESSING(relent, reloc, symbols, abfd, section) \
251  reloc_processing(relent, reloc, symbols, abfd, section)
252
253 static void
254 reloc_processing (relent,reloc, symbols, abfd, section)
255      arelent *relent;
256      struct internal_reloc *reloc;
257      asymbol **symbols;
258      bfd *abfd;
259      asection *section;
260 {
261     static bfd_vma ihihalf_vaddr = (bfd_vma) -1;
262
263     relent->address = reloc->r_vaddr;           
264     relent->howto = howto_table + reloc->r_type;
265     if (reloc->r_type == R_IHCONST) 
266     {           
267       /* The address of an R_IHCONST should always be the address of
268          the immediately preceding R_IHIHALF.  relocs generated by gas
269          are correct, but relocs generated by High C are different (I
270          can't figure out what the address means for High C).  We can
271          handle both gas and High C by ignoring the address here, and
272          simply reusing the address saved for R_IHIHALF.  */
273         if (ihihalf_vaddr == (bfd_vma) -1)
274           abort ();
275         relent->address = ihihalf_vaddr;
276         ihihalf_vaddr = (bfd_vma) -1;
277         relent->addend = reloc->r_symndx;               
278         relent->sym_ptr_ptr= bfd_abs_section_ptr->symbol_ptr_ptr;
279     }
280     else 
281     {
282       asymbol *ptr;
283       relent->sym_ptr_ptr = symbols + obj_convert(abfd)[reloc->r_symndx];
284
285       ptr = *(relent->sym_ptr_ptr);
286
287       if (ptr 
288           && bfd_asymbol_bfd(ptr) == abfd               
289
290           && ((ptr->flags & BSF_OLD_COMMON)== 0))       
291       {                                         
292           relent->addend = 0;
293       }                                         
294       else
295       {                                 
296           relent->addend = 0;                   
297       }                 
298       relent->address-= section->vma;
299       if (reloc->r_type == R_IHIHALF)
300         ihihalf_vaddr = relent->address;
301       else if (ihihalf_vaddr != (bfd_vma) -1)
302         abort ();
303   }
304 }
305
306 #include "coffcode.h"
307
308 const bfd_target a29kcoff_big_vec =
309 {
310   "coff-a29k-big",              /* name */
311   bfd_target_coff_flavour,
312   true,                         /* data byte order is big */
313   true,                         /* header byte order is big */
314
315   (HAS_RELOC | EXEC_P |         /* object flags */
316    HAS_LINENO | HAS_DEBUG |
317    HAS_SYMS | HAS_LOCALS | WP_TEXT),
318
319   (SEC_HAS_CONTENTS | SEC_ALLOC /* section flags */
320    | SEC_LOAD | SEC_RELOC  
321    | SEC_READONLY ),
322   '_',                          /* leading underscore */
323   '/',                          /* ar_pad_char */
324   15,                           /* ar_max_namelen */
325   2,                            /* minimum section alignment */
326   /* data */
327   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
328      bfd_getb32, bfd_getb_signed_32,   bfd_putb32,
329      bfd_getb16, bfd_getb_signed_16, bfd_putb16,
330   /* hdrs */
331   bfd_getb64, bfd_getb_signed_64, bfd_putb64,
332      bfd_getb32, bfd_getb_signed_32,   bfd_putb32,
333      bfd_getb16, bfd_getb_signed_16, bfd_putb16,
334
335  {
336             
337    _bfd_dummy_target,
338    coff_object_p,
339    bfd_generic_archive_p,
340    _bfd_dummy_target
341   },
342  {
343    bfd_false,
344    coff_mkobject,
345    _bfd_generic_mkarchive,
346    bfd_false
347   },
348  {
349    bfd_false,
350    coff_write_object_contents,
351    _bfd_write_archive_contents,
352    bfd_false
353   },
354
355      BFD_JUMP_TABLE_GENERIC (coff),
356      BFD_JUMP_TABLE_COPY (coff),
357      BFD_JUMP_TABLE_CORE (_bfd_nocore),
358      BFD_JUMP_TABLE_ARCHIVE (_bfd_archive_coff),
359      BFD_JUMP_TABLE_SYMBOLS (coff),
360      BFD_JUMP_TABLE_RELOCS (coff),
361      BFD_JUMP_TABLE_WRITE (coff),
362      BFD_JUMP_TABLE_LINK (coff),
363      BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
364
365   COFF_SWAP_TABLE
366  };