2009-07-02 Tristan Gingold <gingold@adacore.com>
[binutils.git] / bfd / coff-maxq.c
blob165d7c86a9bcee44ac7cd25c3360a0fdc439a1e4
1 /* BFD back-end for MAXQ COFF binaries.
2 Copyright 2004, 2007, 2008 Free Software Foundation, Inc.
4 Contributed by Vineet Sharma (vineets@noida.hcltech.com) Inderpreet S.
5 (inderpreetb@noida.hcltech.com)
7 HCL Technologies Ltd.
9 This file is part of BFD, the Binary File Descriptor library.
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.
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.
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. */
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"
33 #ifndef MAXQ20
34 #define MAXQ20 1
35 #endif
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))
43 #define COFF_DEFAULT_SECTION_ALIGNMENT_POWER (2)
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
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
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
58 static long
59 get_symbol_value (asymbol *symbol)
61 long relocation = 0;
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;
69 return relocation;
72 /* This function performs all the maxq relocations.
73 FIXME: The handling of the addend in the 'BFD_*'
74 relocations types. */
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)
85 unsigned char *addr = NULL;
86 unsigned long x = 0;
87 long call_addr = 0;
88 short addend = 0;
89 long diff = 0;
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;
96 if (data && reloc_entry)
98 addr = (unsigned char *) data + reloc_entry->address;
99 call_addr = call_addr - call_addr;
100 call_addr = get_symbol_value (symbol_in);
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. */
107 switch (reloc_entry->howto->type)
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;
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;
122 diff = ((call_addr << 1) - (reloc_entry->address << 1));
124 if (!IS_SJUMP_RANGE (diff))
126 bfd_perror (_("Can't Make it a Short Jump"));
127 return bfd_reloc_outofrange;
130 x = bfd_get_16 (abfd, addr);
132 x = x & LOW_WORD_MASK;
133 x = x | (diff << 8);
134 bfd_put_16 (abfd, (bfd_vma) x, addr);
136 return bfd_reloc_ok;
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);
149 /* Handle any addend. */
150 addend = reloc_entry->addend;
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;
158 if (!bfd_is_com_section (symbol_in->section) &&
159 ((symbol_in->flags & BSF_OLD_COMMON) == 0))
161 if (reloc_entry->addend > symbol_in->value)
162 addend = reloc_entry->addend - symbol_in->value;
164 if ((reloc_entry->addend < symbol_in->value)
165 && (reloc_entry->addend != 0))
166 addend = reloc_entry->addend - symbol_in->value;
168 if (reloc_entry->addend == symbol_in->value)
169 addend = 0;
172 if (bfd_is_com_section (symbol_in->section) ||
173 ((symbol_in->flags & BSF_OLD_COMMON) != 0))
174 addend = reloc_entry->addend;
176 if (addend < 0
177 && (call_addr < (long) (addend * (-1))))
178 addend = 0;
180 call_addr += addend;
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)
186 /* Convert it into words. */
187 call_addr = call_addr >> 1;
189 if (call_addr > 0xFFFF) /* Intersegment Jump. */
191 bfd_perror (_("Exceeds Long Jump Range"));
192 return bfd_reloc_outofrange;
195 else
197 /* case ABSOLUTE_ADDR_FOR_DATA : Resolves any code-data
198 segemnt relocs. These are NOT word aligned. */
200 if (call_addr > 0xFFFF) /* Intersegment Jump. */
202 bfd_perror (_("Absolute address Exceeds 16 bit Range"));
203 return bfd_reloc_outofrange;
207 x = bfd_get_32 (abfd, addr);
209 x = (x & 0xFF00FF00);
210 x = (x | ((call_addr & HIGH_WORD_MASK) >> 8));
211 x = (x | (call_addr & LOW_WORD_MASK) << 16);
213 bfd_put_32 (abfd, (bfd_vma) x, addr);
214 return bfd_reloc_ok;
216 case BFD_RELOC_8:
217 addend = (reloc_entry->addend - reloc_entry->addend);
219 if (!bfd_is_com_section (symbol_in->section) &&
220 ((symbol_in->flags & BSF_OLD_COMMON) == 0))
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;
230 if (bfd_is_com_section (symbol_in->section) ||
231 ((symbol_in->flags & BSF_OLD_COMMON) != 0))
232 addend = reloc_entry->addend;
234 if (addend < 0
235 && (call_addr < (long) (addend * (-1))))
236 addend = 0;
238 if (call_addr + addend > 0xFF)
240 bfd_perror (_("Absolute address Exceeds 8 bit Range"));
241 return bfd_reloc_outofrange;
244 x = bfd_get_8 (abfd, addr);
245 x = x & 0x00;
246 x = x | (call_addr + addend);
248 bfd_put_8 (abfd, (bfd_vma) x, addr);
249 return bfd_reloc_ok;
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))
256 if (reloc_entry->addend > symbol_in->value)
257 addend = reloc_entry->addend - symbol_in->value;
259 if (reloc_entry->addend < symbol_in->value)
260 addend = reloc_entry->addend - symbol_in->value;
262 if (reloc_entry->addend == symbol_in->value)
263 addend = 0;
266 if (bfd_is_com_section (symbol_in->section) ||
267 ((symbol_in->flags & BSF_OLD_COMMON) != 0))
268 addend = reloc_entry->addend;
270 if (addend < 0
271 && (call_addr < (long) (addend * (-1))))
272 addend = 0;
274 if ((call_addr + addend) > 0xFFFF)
276 bfd_perror (_("Absolute address Exceeds 16 bit Range"));
277 return bfd_reloc_outofrange;
279 else
281 unsigned short val = (call_addr + addend);
283 x = bfd_get_16 (abfd, addr);
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. */
292 bfd_put_16 (abfd, (bfd_vma) x, addr);
293 return bfd_reloc_ok;
295 case BFD_RELOC_32:
296 addend = (reloc_entry->addend - reloc_entry->addend);
298 if (!bfd_is_com_section (symbol_in->section) &&
299 ((symbol_in->flags & BSF_OLD_COMMON) == 0))
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;
309 if (bfd_is_com_section (symbol_in->section) ||
310 ((symbol_in->flags & BSF_OLD_COMMON) != 0))
311 addend = reloc_entry->addend;
313 if (addend < 0
314 && (call_addr < (long) (addend * (-1))))
315 addend = 0;
317 if ((call_addr + addend) < 0)
319 bfd_perror ("Absolute address Exceeds 32 bit Range");
320 return bfd_reloc_outofrange;
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. */
329 bfd_put_32 (abfd, (bfd_vma) x, addr);
330 return bfd_reloc_ok;
332 default:
333 bfd_perror (_("Unrecognized Reloc Type"));
334 return bfd_reloc_notsupported;
338 return bfd_reloc_notsupported;
341 static reloc_howto_type howto_table[] =
343 EMPTY_HOWTO (0),
344 EMPTY_HOWTO (1),
346 BFD_RELOC_32, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
347 coff_maxq20_reloc, "32Bit", TRUE, 0x000000ff, 0x000000ff, TRUE
350 SHORT_JUMP, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
351 coff_maxq20_reloc, "SHORT_JMP", TRUE, 0x000000ff, 0x000000ff, TRUE
354 ABSOLUTE_ADDR_FOR_DATA, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
355 coff_maxq20_reloc, "INTERSEGMENT_RELOC", TRUE, 0x00000000, 0x00000000,
356 FALSE
359 BFD_RELOC_16, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
360 coff_maxq20_reloc, "16Bit", TRUE, 0x000000ff, 0x000000ff, TRUE
363 LONG_JUMP, 0, 2, 32, FALSE, 0, complain_overflow_bitfield,
364 coff_maxq20_reloc, "LONG_JUMP", TRUE, 0x00000000, 0x00000000, FALSE
367 BFD_RELOC_8, 0, 1, 8, FALSE, 0, complain_overflow_bitfield,
368 coff_maxq20_reloc, "8bit", TRUE, 0x000000ff, 0x000000ff, TRUE
370 EMPTY_HOWTO (8),
371 EMPTY_HOWTO (9),
372 EMPTY_HOWTO (10),
375 static reloc_howto_type *
376 maxq_reloc_type_lookup (bfd * abfd ATTRIBUTE_UNUSED,
377 bfd_reloc_code_real_type code)
379 switch (code)
381 /* SHORT JUMP */
382 case BFD_RELOC_16_PCREL_S2:
383 return howto_table + 3;
385 /* INTERSEGMENT JUMP */
386 case BFD_RELOC_24:
387 return howto_table + 4;
389 /* BYTE RELOC */
390 case BFD_RELOC_8:
391 return howto_table + 7;
393 /* WORD RELOC */
394 case BFD_RELOC_16:
395 return howto_table + 5;
397 /* LONG RELOC */
398 case BFD_RELOC_32:
399 return howto_table + 2;
401 /* LONG JUMP */
402 case BFD_RELOC_14:
403 return howto_table + 6;
405 default:
406 return NULL;
410 static reloc_howto_type *
411 maxq_reloc_name_lookup (bfd *abfd ATTRIBUTE_UNUSED, const char *r_name)
413 unsigned int i;
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];
420 return NULL;
423 #define coff_bfd_reloc_type_lookup maxq_reloc_type_lookup
424 #define coff_bfd_reloc_name_lookup maxq_reloc_name_lookup
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;
430 #ifndef bfd_pe_print_pdata
431 #define bfd_pe_print_pdata NULL
432 #endif
434 #include "coffcode.h"
436 #ifndef TARGET_UNDERSCORE
437 #define TARGET_UNDERSCORE 1
438 #endif
440 #ifndef EXTRA_S_FLAGS
441 #define EXTRA_S_FLAGS 0
442 #endif
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);