]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/coff-maxq.c
config:
[thirdparty/binutils-gdb.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