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.,
23 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, 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
get_symbol_value(asymbol * symbol)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
coff_maxq20_reloc(bfd * abfd,arelent * reloc_entry,asymbol * symbol_in,void * data,asection * input_section ATTRIBUTE_UNUSED,bfd * output_bfd ATTRIBUTE_UNUSED,char ** error_message ATTRIBUTE_UNUSED)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 *
maxq_reloc_type_lookup(bfd * abfd ATTRIBUTE_UNUSED,bfd_reloc_code_real_type code)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
459