OSDN Git Service

daily update
[pf3gnuchains/pf3gnuchains3x.git] / bfd / coff-maxq.c
1 /* BFD back-end for MAXQ COFF binaries.
2    Copyright 2004, 2005, 2006, 2007, 2008  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 3 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., 
23    51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.  */
24
25 #include "sysdep.h"
26 #include "bfd.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   unsigned char *addr = NULL;
86   unsigned long x = 0;
87   long call_addr = 0;
88   short addend = 0;
89   long diff = 0;
90
91   /* If this is an undefined symbol, return error.  */
92   if (symbol_in->section == &bfd_und_section
93       && (symbol_in->flags & BSF_WEAK) == 0)
94     return bfd_reloc_continue;
95
96   if (data && reloc_entry)
97     {
98       addr = (unsigned char *) data + reloc_entry->address;
99       call_addr = call_addr - call_addr;
100       call_addr = get_symbol_value (symbol_in);
101
102       /* Over here the value val stores the 8 bit/16 bit value. We will put a 
103          check if we are moving a 16 bit immediate value into an 8 bit
104          register. In that case we will generate a Upper bytes into PFX[0]
105          and move the lower 8 bits as SRC.  */
106
107       switch (reloc_entry->howto->type)
108         {
109           /* BFD_RELOC_16_PCREL_S2 47 Handles all the relative jumps and
110              calls Note: Every relative jump or call is in words.  */
111         case SHORT_JUMP:
112           /* Handle any addend.  */
113           addend = reloc_entry->addend;
114
115           if (addend > call_addr || addend > 0)
116             call_addr = symbol_in->section->output_section->vma + addend;
117           else if (addend < call_addr && addend > 0)
118             call_addr = call_addr + addend;
119           else if (addend < 0)
120             call_addr = call_addr + addend;
121
122           diff = ((call_addr << 1) - (reloc_entry->address << 1));
123
124           if (!IS_SJUMP_RANGE (diff))
125             {
126               bfd_perror (_("Can't Make it a Short Jump"));
127               return bfd_reloc_outofrange;
128             }
129
130           x = bfd_get_16 (abfd, addr);
131
132           x = x & LOW_WORD_MASK;
133           x = x | (diff << 8);
134           bfd_put_16 (abfd, (bfd_vma) x, addr);
135
136           return bfd_reloc_ok;
137
138         case ABSOLUTE_ADDR_FOR_DATA:
139         case LONG_JUMP:
140           /* BFD_RELOC_14 Handles intersegment or long jumps which might be
141              from code to code or code to data segment jumps. Note: When this 
142              fucntion is called by gas the section flags somehow do not
143              contain the info about the section type(CODE or DATA). Thus the
144              user needs to evoke the linker after assembling the files
145              because the Code-Code relocs are word aligned but code-data are
146              byte aligned.  */
147           addend = (reloc_entry->addend - reloc_entry->addend);
148
149           /* Handle any addend.  */
150           addend = reloc_entry->addend;
151
152           /* For relocation involving multiple file added becomes zero thus
153              this fails - check for zero added. In another case when we try
154              to add a stub to a file the addend shows the offset from the
155              start od this file.  */
156           addend = 0;
157
158           if (!bfd_is_com_section (symbol_in->section) &&
159               ((symbol_in->flags & BSF_OLD_COMMON) == 0))
160             {
161               if (reloc_entry->addend > symbol_in->value)
162                 addend = reloc_entry->addend - symbol_in->value;
163
164               if ((reloc_entry->addend < symbol_in->value)
165                   && (reloc_entry->addend != 0))
166                 addend = reloc_entry->addend - symbol_in->value;
167
168               if (reloc_entry->addend == symbol_in->value)
169                 addend = 0;
170             }
171
172           if (bfd_is_com_section (symbol_in->section) ||
173               ((symbol_in->flags & BSF_OLD_COMMON) != 0))
174             addend = reloc_entry->addend;
175
176           if (addend < 0
177               &&  (call_addr < (long) (addend * (-1))))
178             addend = 0;
179
180           call_addr += addend;
181
182           /* FIXME: This check does not work well with the assembler,
183              linker needs to be run always.  */
184           if ((symbol_in->section->flags & SEC_CODE) == SEC_CODE)
185             {
186               /* Convert it into words.  */
187               call_addr = call_addr >> 1;
188
189               if (call_addr > 0xFFFF)   /* Intersegment Jump.  */
190                 {
191                   bfd_perror (_("Exceeds Long Jump Range"));
192                   return bfd_reloc_outofrange;
193                 }
194             }
195           else
196             {
197               /* case ABSOLUTE_ADDR_FOR_DATA : Resolves any code-data
198                  segemnt relocs. These are NOT word aligned.  */
199
200               if (call_addr > 0xFFFF)   /* Intersegment Jump.  */
201                 {
202                   bfd_perror (_("Absolute address Exceeds 16 bit Range"));
203                   return bfd_reloc_outofrange;
204                 }
205             }
206
207           x = bfd_get_32 (abfd, addr);
208
209           x = (x & 0xFF00FF00);
210           x = (x | ((call_addr & HIGH_WORD_MASK) >> 8));
211           x = (x | (call_addr & LOW_WORD_MASK) << 16);
212
213           bfd_put_32 (abfd, (bfd_vma) x, addr);
214           return bfd_reloc_ok;
215
216         case BFD_RELOC_8:
217           addend = (reloc_entry->addend - reloc_entry->addend);
218
219           if (!bfd_is_com_section (symbol_in->section) &&
220               ((symbol_in->flags & BSF_OLD_COMMON) == 0))
221             {
222               if (reloc_entry->addend > symbol_in->value)
223                 addend = reloc_entry->addend - symbol_in->value;
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 = 0;
228             }
229
230           if (bfd_is_com_section (symbol_in->section) ||
231               ((symbol_in->flags & BSF_OLD_COMMON) != 0))
232             addend = reloc_entry->addend;
233
234           if (addend < 0
235               && (call_addr < (long) (addend * (-1))))
236             addend = 0;
237
238           if (call_addr + addend > 0xFF)
239             {
240               bfd_perror (_("Absolute address Exceeds 8 bit Range"));
241               return bfd_reloc_outofrange;
242             }
243
244           x = bfd_get_8 (abfd, addr);
245           x = x & 0x00;
246           x = x | (call_addr + addend);
247
248           bfd_put_8 (abfd, (bfd_vma) x, addr);
249           return bfd_reloc_ok;
250
251         case BFD_RELOC_16:
252           addend = (reloc_entry->addend - reloc_entry->addend);
253           if (!bfd_is_com_section (symbol_in->section) &&
254               ((symbol_in->flags & BSF_OLD_COMMON) == 0))
255             {
256               if (reloc_entry->addend > symbol_in->value)
257                 addend = reloc_entry->addend - symbol_in->value;
258
259               if (reloc_entry->addend < symbol_in->value)
260                 addend = reloc_entry->addend - symbol_in->value;
261
262               if (reloc_entry->addend == symbol_in->value)
263                 addend = 0;
264             }
265
266           if (bfd_is_com_section (symbol_in->section) ||
267               ((symbol_in->flags & BSF_OLD_COMMON) != 0))
268             addend = reloc_entry->addend;
269
270           if (addend < 0
271               && (call_addr < (long) (addend * (-1))))
272             addend = 0;
273
274           if ((call_addr + addend) > 0xFFFF)
275             {
276               bfd_perror (_("Absolute address Exceeds 16 bit Range"));
277               return bfd_reloc_outofrange;
278             }
279           else
280             {
281               unsigned short val = (call_addr + addend);
282
283               x = bfd_get_16 (abfd, addr);
284
285               /* LE */
286               x = (x & 0x0000); /* Flush garbage value.  */
287               x = val;
288               if ((symbol_in->section->flags & SEC_CODE) == SEC_CODE)
289                 x = x >> 1;     /* Convert it into words.  */
290             }
291
292           bfd_put_16 (abfd, (bfd_vma) x, addr);
293           return bfd_reloc_ok;
294
295         case BFD_RELOC_32:
296           addend = (reloc_entry->addend - reloc_entry->addend);
297
298           if (!bfd_is_com_section (symbol_in->section) &&
299               ((symbol_in->flags & BSF_OLD_COMMON) == 0))
300             {
301               if (reloc_entry->addend > symbol_in->value)
302                 addend = reloc_entry->addend - symbol_in->value;
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 = 0;
307             }
308
309           if (bfd_is_com_section (symbol_in->section) ||
310               ((symbol_in->flags & BSF_OLD_COMMON) != 0))
311             addend = reloc_entry->addend;
312
313           if (addend < 0
314               && (call_addr < (long) (addend * (-1))))
315             addend = 0;
316
317           if ((call_addr + addend) < 0)
318             {
319               bfd_perror ("Absolute address Exceeds 32 bit Range");
320               return bfd_reloc_outofrange;
321             }
322
323           x = bfd_get_32 (abfd, addr);
324           x = (x & 0x0000);     /* Flush garbage value.  */
325           x = call_addr + addend;
326           if ((symbol_in->section->flags & SEC_CODE) == SEC_CODE)
327             x = x >> 1; /* Convert it into words.  */
328
329           bfd_put_32 (abfd, (bfd_vma) x, addr);
330           return bfd_reloc_ok;
331
332         default:
333           bfd_perror (_("Unrecognized Reloc Type"));
334           return bfd_reloc_notsupported;
335         }
336     }
337
338   return bfd_reloc_notsupported;
339 }
340
341 static reloc_howto_type howto_table[] =
342 {
343   EMPTY_HOWTO (0),
344   EMPTY_HOWTO (1),
345   {
346    BFD_RELOC_32, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
347    coff_maxq20_reloc, "32Bit", TRUE, 0x000000ff, 0x000000ff, TRUE
348   },
349   {
350    SHORT_JUMP, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
351    coff_maxq20_reloc, "SHORT_JMP", TRUE, 0x000000ff, 0x000000ff, TRUE
352   },
353   {
354    ABSOLUTE_ADDR_FOR_DATA, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
355    coff_maxq20_reloc, "INTERSEGMENT_RELOC", TRUE, 0x00000000, 0x00000000,
356    FALSE
357   },
358   {
359    BFD_RELOC_16, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
360    coff_maxq20_reloc, "16Bit", TRUE, 0x000000ff, 0x000000ff, TRUE
361   },
362   {
363    LONG_JUMP, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
364    coff_maxq20_reloc, "LONG_JUMP", TRUE, 0x00000000, 0x00000000, FALSE
365   },
366   {
367    BFD_RELOC_8, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
368    coff_maxq20_reloc, "8bit", TRUE, 0x000000ff, 0x000000ff, TRUE
369   },
370   EMPTY_HOWTO (8),
371   EMPTY_HOWTO (9),
372   EMPTY_HOWTO (10),
373 };
374
375 static reloc_howto_type *
376 maxq_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
377                         bfd_reloc_code_real_type code)
378 {
379   switch (code)
380     {
381       /* SHORT JUMP */
382     case BFD_RELOC_16_PCREL_S2:
383       return howto_table + 3;
384       
385       /* INTERSEGMENT JUMP */
386     case BFD_RELOC_24:
387       return howto_table + 4;
388       
389       /* BYTE RELOC */
390     case BFD_RELOC_8:
391       return howto_table + 7;
392       
393       /* WORD RELOC */
394     case BFD_RELOC_16:
395       return howto_table + 5;
396       
397       /* LONG RELOC */
398     case BFD_RELOC_32:
399       return howto_table + 2;
400       
401       /* LONG JUMP */
402     case BFD_RELOC_14:
403       return howto_table + 6;
404       
405     default:
406       return NULL;
407     }
408 }
409
410 static reloc_howto_type *
411 maxq_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
412 {
413   unsigned int i;
414
415   for (i = 0; i < sizeof (howto_table) / sizeof (howto_table[0]); i++)
416     if (howto_table[i].name != NULL
417         && strcasecmp (howto_table[i].name, r_name) == 0)
418       return &howto_table[i];
419
420   return NULL;
421 }
422
423 #define coff_bfd_reloc_type_lookup maxq_reloc_type_lookup
424 #define coff_bfd_reloc_name_lookup maxq_reloc_name_lookup
425
426 /* Perform any necessary magic to the addend in a reloc entry.  */
427 #define CALC_ADDEND(abfd, symbol, ext_reloc, cache_ptr) \
428  cache_ptr->addend =  ext_reloc.r_offset;
429
430 #ifndef bfd_pe_print_pdata
431 #define bfd_pe_print_pdata      NULL
432 #endif
433
434 #include "coffcode.h"
435
436 #ifndef TARGET_UNDERSCORE
437 #define TARGET_UNDERSCORE 1
438 #endif
439
440 #ifndef EXTRA_S_FLAGS
441 #define EXTRA_S_FLAGS 0
442 #endif
443
444 /* Forward declaration for use initialising alternative_target field.  */
445 CREATE_LITTLE_COFF_TARGET_VEC (maxqcoff_vec, "coff-maxq", 0, EXTRA_S_FLAGS,
446                                TARGET_UNDERSCORE, NULL, COFF_SWAP_TABLE);
447