Use fprintf_vma to print vma values.
[external/binutils.git] / bfd / coff-maxq.c
1 /* BFD back-end for MAXQ COFF binaries.
2    Copyright 2004    Free Software Foundation, Inc.
3
4    Contributed by Vineet Sharma (vineets@noida.hcltech.com) Inderpreet S.
5    (inderpreetb@noida.hcltech.com)
6
7    HCL Technologies Ltd.
8
9    This file is part of BFD, the Binary File Descriptor library.
10
11    This program is free software; you can redistribute it and/or modify it
12    under the terms of the GNU General Public License as published by the Free 
13    Software Foundation; either version 2 of the License, or (at your option)
14    any later version.
15
16    This program is distributed in the hope that it will be useful, but
17    WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
18    or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19    for more details.
20
21    You should have received a copy of the GNU General Public License along
22    with this program; if not, write to the Free Software Foundation, Inc., 59 
23    Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
24
25 #include "bfd.h"
26 #include "sysdep.h"
27 #include "libbfd.h"
28 #include "coff/maxq.h"
29 #include "coff/internal.h"
30 #include "libcoff.h"
31 #include "libiberty.h"
32
33 #ifndef MAXQ20
34 #define MAXQ20 1
35 #endif
36
37 #define RTYPE2HOWTO(cache_ptr, dst)                                     \
38   ((cache_ptr)->howto =                                                 \
39    ((dst)->r_type < 48                                                  \
40     ? howto_table + (((dst)->r_type==47) ? 6: ((dst)->r_type))          \
41     : NULL))
42
43 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
44
45 /* Code to swap in the reloc offset.  */
46 #define SWAP_IN_RELOC_OFFSET    H_GET_16
47 #define SWAP_OUT_RELOC_OFFSET   H_PUT_16
48
49 #define SHORT_JUMP              BFD_RELOC_16_PCREL_S2
50 #define LONG_JUMP               BFD_RELOC_14
51 #define ABSOLUTE_ADDR_FOR_DATA  BFD_RELOC_24
52
53 /* checks the range of short jump -127 to 128 */
54 #define IS_SJUMP_RANGE(x) ((x > -128) && (x < 129))
55 #define HIGH_WORD_MASK    0xff00
56 #define LOW_WORD_MASK     0x00ff
57
58 static long
59 get_symbol_value (asymbol *symbol)
60 {
61   long relocation = 0;
62
63   if (bfd_is_com_section (symbol->section))
64     relocation = 0;
65   else
66     relocation = symbol->value +
67       symbol->section->output_section->vma + symbol->section->output_offset;
68
69   return relocation;
70 }
71
72 /* This function performs all the maxq relocations.
73    FIXME:  The handling of the addend in the 'BFD_*'
74    relocations types.  */
75
76 static bfd_reloc_status_type
77 coff_maxq20_reloc (bfd *      abfd,
78                    arelent *  reloc_entry,
79                    asymbol *  symbol_in,
80                    void *     data,
81                    asection * input_section ATTRIBUTE_UNUSED,
82                    bfd *      output_bfd    ATTRIBUTE_UNUSED,
83                    char **    error_message ATTRIBUTE_UNUSED)
84 {
85   reloc_howto_type *howto = NULL;
86   unsigned char *addr = NULL;
87   unsigned long x = 0;
88   long call_addr = 0;
89   short addend = 0;
90   long diff = 0;
91
92   /* If this is an undefined symbol, return error.  */
93   if (symbol_in->section == &bfd_und_section
94       && (symbol_in->flags & BSF_WEAK) == 0)
95     return bfd_reloc_continue;
96
97   if (data && reloc_entry)
98     {
99       howto = reloc_entry->howto;
100       addr = (unsigned char *) data + reloc_entry->address;
101       call_addr = call_addr - call_addr;
102       call_addr = get_symbol_value (symbol_in);
103
104       /* Over here the value val stores the 8 bit/16 bit value. We will put a 
105          check if we are moving a 16 bit immediate value into an 8 bit
106          register. In that case we will generate a Upper bytes into PFX[0]
107          and move the lower 8 bits as SRC.  */
108
109       switch (reloc_entry->howto->type)
110         {
111           /* BFD_RELOC_16_PCREL_S2 47 Handles all the relative jumps and
112              calls Note: Every relative jump or call is in words.  */
113         case SHORT_JUMP:
114           /* Handle any addend.  */
115           addend = reloc_entry->addend;
116
117           if (addend > call_addr || addend > 0)
118             call_addr = symbol_in->section->output_section->vma + addend;
119           else if (addend < call_addr && addend > 0)
120             call_addr = call_addr + addend;
121           else if (addend < 0)
122             call_addr = call_addr + addend;
123
124           diff = ((call_addr << 1) - (reloc_entry->address << 1));
125
126           if (!IS_SJUMP_RANGE (diff))
127             {
128               bfd_perror (_("Can't Make it a Short Jump"));
129               return bfd_reloc_outofrange;
130             }
131
132           x = bfd_get_16 (abfd, addr);
133
134           x = x & LOW_WORD_MASK;
135           x = x | (diff << 8);
136           bfd_put_16 (abfd, (bfd_vma) x, addr);
137
138           return bfd_reloc_ok;
139
140         case ABSOLUTE_ADDR_FOR_DATA:
141         case LONG_JUMP:
142           /* BFD_RELOC_14 Handles intersegment or long jumps which might be
143              from code to code or code to data segment jumps. Note: When this 
144              fucntion is called by gas the section flags somehow do not
145              contain the info about the section type(CODE or DATA). Thus the
146              user needs to evoke the linker after assembling the files
147              because the Code-Code relocs are word aligned but code-data are
148              byte aligned.  */
149           addend = (reloc_entry->addend - reloc_entry->addend);
150
151           /* Handle any addend.  */
152           addend = reloc_entry->addend;
153
154           /* For relocation involving multiple file added becomes zero thus
155              this fails - check for zero added. In another case when we try
156              to add a stub to a file the addend shows the offset from the
157              start od this file.  */
158           addend = 0;
159
160           if (!bfd_is_com_section (symbol_in->section) &&
161               ((symbol_in->flags & BSF_OLD_COMMON) == 0))
162             {
163               if (reloc_entry->addend > symbol_in->value)
164                 addend = reloc_entry->addend - symbol_in->value;
165
166               if ((reloc_entry->addend < symbol_in->value)
167                   && (reloc_entry->addend != 0))
168                 addend = reloc_entry->addend - symbol_in->value;
169
170               if (reloc_entry->addend == symbol_in->value)
171                 addend = 0;
172             }
173
174           if (bfd_is_com_section (symbol_in->section) ||
175               ((symbol_in->flags & BSF_OLD_COMMON) != 0))
176             addend = reloc_entry->addend;
177
178           if (addend < 0
179               &&  (call_addr < (long) (addend * (-1))))
180             addend = 0;
181
182           call_addr += addend;
183
184           /* FIXME: This check does not work well with the assembler,
185              linker needs to be run always.  */
186           if ((symbol_in->section->flags & SEC_CODE) == SEC_CODE)
187             {
188               /* Convert it into words.  */
189               call_addr = call_addr >> 1;
190
191               if (call_addr > 0xFFFF)   /* Intersegment Jump.  */
192                 {
193                   bfd_perror (_("Exceeds Long Jump Range"));
194                   return bfd_reloc_outofrange;
195                 }
196             }
197           else
198             {
199               /* case ABSOLUTE_ADDR_FOR_DATA : Resolves any code-data
200                  segemnt relocs. These are NOT word aligned.  */
201
202               if (call_addr > 0xFFFF)   /* Intersegment Jump.  */
203                 {
204                   bfd_perror (_("Absolute address Exceeds 16 bit Range"));
205                   return bfd_reloc_outofrange;
206                 }
207             }
208
209           x = bfd_get_32 (abfd, addr);
210
211           x = (x & 0xFF00FF00);
212           x = (x | ((call_addr & HIGH_WORD_MASK) >> 8));
213           x = (x | (call_addr & LOW_WORD_MASK) << 16);
214
215           bfd_put_32 (abfd, (bfd_vma) x, addr);
216           return bfd_reloc_ok;
217
218         case BFD_RELOC_8:
219           addend = (reloc_entry->addend - reloc_entry->addend);
220
221           if (!bfd_is_com_section (symbol_in->section) &&
222               ((symbol_in->flags & BSF_OLD_COMMON) == 0))
223             {
224               if (reloc_entry->addend > symbol_in->value)
225                 addend = reloc_entry->addend - symbol_in->value;
226               if (reloc_entry->addend < symbol_in->value)
227                 addend = reloc_entry->addend - symbol_in->value;
228               if (reloc_entry->addend == symbol_in->value)
229                 addend = 0;
230             }
231
232           if (bfd_is_com_section (symbol_in->section) ||
233               ((symbol_in->flags & BSF_OLD_COMMON) != 0))
234             addend = reloc_entry->addend;
235
236           if (addend < 0
237               && (call_addr < (long) (addend * (-1))))
238             addend = 0;
239
240           if (call_addr + addend > 0xFF)
241             {
242               bfd_perror (_("Absolute address Exceeds 8 bit Range"));
243               return bfd_reloc_outofrange;
244             }
245
246           x = bfd_get_8 (abfd, addr);
247           x = x & 0x00;
248           x = x | (call_addr + addend);
249
250           bfd_put_8 (abfd, (bfd_vma) x, addr);
251           return bfd_reloc_ok;
252
253         case BFD_RELOC_16:
254           addend = (reloc_entry->addend - reloc_entry->addend);
255           if (!bfd_is_com_section (symbol_in->section) &&
256               ((symbol_in->flags & BSF_OLD_COMMON) == 0))
257             {
258               if (reloc_entry->addend > symbol_in->value)
259                 addend = reloc_entry->addend - symbol_in->value;
260
261               if (reloc_entry->addend < symbol_in->value)
262                 addend = reloc_entry->addend - symbol_in->value;
263
264               if (reloc_entry->addend == symbol_in->value)
265                 addend = 0;
266             }
267
268           if (bfd_is_com_section (symbol_in->section) ||
269               ((symbol_in->flags & BSF_OLD_COMMON) != 0))
270             addend = reloc_entry->addend;
271
272           if (addend < 0
273               && (call_addr < (long) (addend * (-1))))
274             addend = 0;
275
276           if ((call_addr + addend) > 0xFFFF)
277             {
278               bfd_perror (_("Absolute address Exceeds 16 bit Range"));
279               return bfd_reloc_outofrange;
280             }
281           else
282             {
283               unsigned short val = (call_addr + addend);
284
285               x = bfd_get_16 (abfd, addr);
286
287               /* LE */
288               x = (x & 0x0000); /* Flush garbage value.  */
289               x = val;
290               if ((symbol_in->section->flags & SEC_CODE) == SEC_CODE)
291                 x = x >> 1;     /* Convert it into words.  */
292             }
293
294           bfd_put_16 (abfd, (bfd_vma) x, addr);
295           return bfd_reloc_ok;
296
297         case BFD_RELOC_32:
298           addend = (reloc_entry->addend - reloc_entry->addend);
299
300           if (!bfd_is_com_section (symbol_in->section) &&
301               ((symbol_in->flags & BSF_OLD_COMMON) == 0))
302             {
303               if (reloc_entry->addend > symbol_in->value)
304                 addend = reloc_entry->addend - symbol_in->value;
305               if (reloc_entry->addend < symbol_in->value)
306                 addend = reloc_entry->addend - symbol_in->value;
307               if (reloc_entry->addend == symbol_in->value)
308                 addend = 0;
309             }
310
311           if (bfd_is_com_section (symbol_in->section) ||
312               ((symbol_in->flags & BSF_OLD_COMMON) != 0))
313             addend = reloc_entry->addend;
314
315           if (addend < 0
316               && (call_addr < (long) (addend * (-1))))
317             addend = 0;
318
319           if ((call_addr + addend) < 0)
320             {
321               bfd_perror ("Absolute address Exceeds 32 bit Range");
322               return bfd_reloc_outofrange;
323             }
324
325           x = bfd_get_32 (abfd, addr);
326           x = (x & 0x0000);     /* Flush garbage value.  */
327           x = call_addr + addend;
328           if ((symbol_in->section->flags & SEC_CODE) == SEC_CODE)
329             x = x >> 1; /* Convert it into words.  */
330
331           bfd_put_32 (abfd, (bfd_vma) x, addr);
332           return bfd_reloc_ok;
333
334         default:
335           bfd_perror (_("Unrecognized Reloc Type"));
336           return bfd_reloc_notsupported;
337         }
338     }
339
340   return bfd_reloc_notsupported;
341 }
342
343 static reloc_howto_type howto_table[] =
344 {
345   EMPTY_HOWTO (0),
346   EMPTY_HOWTO (1),
347   {
348    BFD_RELOC_32, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
349    coff_maxq20_reloc, "32Bit", TRUE, 0x000000ff, 0x000000ff, TRUE
350   },
351   {
352    SHORT_JUMP, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
353    coff_maxq20_reloc, "SHORT_JMP", TRUE, 0x000000ff, 0x000000ff, TRUE
354   },
355   {
356    ABSOLUTE_ADDR_FOR_DATA, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
357    coff_maxq20_reloc, "INTERSEGMENT_RELOC", TRUE, 0x00000000, 0x00000000,
358    FALSE
359   },
360   {
361    BFD_RELOC_16, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
362    coff_maxq20_reloc, "16Bit", TRUE, 0x000000ff, 0x000000ff, TRUE
363   },
364   {
365    LONG_JUMP, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
366    coff_maxq20_reloc, "LONG_JUMP", TRUE, 0x00000000, 0x00000000, FALSE
367   },
368   {
369    BFD_RELOC_8, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
370    coff_maxq20_reloc, "8bit", TRUE, 0x000000ff, 0x000000ff, TRUE
371   },
372   EMPTY_HOWTO (8),
373   EMPTY_HOWTO (9),
374   EMPTY_HOWTO (10),
375 };
376
377 /* Map BFD reloc types to MAXQ COFF reloc types.  */
378
379 typedef struct maxq_reloc_map
380 {
381   bfd_reloc_code_real_type  bfd_reloc_val;
382   unsigned int              maxq_reloc_val;
383   reloc_howto_type *        table;
384 }
385 reloc_map;
386
387 static const reloc_map maxq_reloc_map[] =
388 {
389   {BFD_RELOC_16_PCREL_S2, SHORT_JUMP, howto_table},
390   {BFD_RELOC_16,          LONG_JUMP,  howto_table},
391 };
392
393 static reloc_howto_type *
394 maxq_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
395                         bfd_reloc_code_real_type code)
396 {
397   unsigned int i;
398
399   for (i = 0; i < ARRAY_SIZE (maxq_reloc_map); i++)
400     {
401       const reloc_map *entry;
402
403       entry = maxq_reloc_map + i;
404
405       switch (code)
406         {
407           /* SHORT JUMP */
408         case BFD_RELOC_16_PCREL_S2:
409           return howto_table + 3;
410
411           /* INTERSEGMENT JUMP */
412         case BFD_RELOC_24:
413           return howto_table + 4;
414
415           /* BYTE RELOC */
416         case BFD_RELOC_8:
417           return howto_table + 7;
418
419           /* WORD RELOC */
420         case BFD_RELOC_16:
421           return howto_table + 5;
422
423           /* LONG RELOC */
424         case BFD_RELOC_32:
425           return howto_table + 2;
426
427           /* LONG JUMP */
428         case BFD_RELOC_14:
429           return howto_table + 6;
430
431         default:
432           return NULL;
433         }
434     }
435
436   return NULL;
437 }
438
439 #define coff_bfd_reloc_type_lookup maxq_reloc_type_lookup
440
441 /* Perform any necessary magic to the addend in a reloc entry.  */
442 #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
443  cache_ptr->addend =  ext_reloc.r_offset;
444
445 #include "coffcode.h"
446
447 #ifndef TARGET_UNDERSCORE
448 #define TARGET_UNDERSCORE 1
449 #endif
450
451 #ifndef EXTRA_S_FLAGS
452 #define EXTRA_S_FLAGS 0
453 #endif
454
455 /* Forward declaration for use initialising alternative_target field.  */
456 CREATE_LITTLE_COFF_TARGET_VEC (maxqcoff_vec, "coff-maxq", 0, EXTRA_S_FLAGS,
457                                TARGET_UNDERSCORE, NULL, COFF_SWAP_TABLE);
458