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)
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)
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
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. */
28 #include "coff/maxq.h"
29 #include "coff/internal.h"
31 #include "libiberty.h"
37 #define RTYPE2HOWTO(cache_ptr, dst) \
38 ((cache_ptr)->howto = \
40 ? howto_table + (((dst)->r_type==47) ? 6: ((dst)->r_type)) \
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
59 get_symbol_value (asymbol
*symbol
)
63 if (bfd_is_com_section (symbol
->section
))
66 relocation
= symbol
->value
+
67 symbol
->section
->output_section
->vma
+ symbol
->section
->output_offset
;
72 /* This function performs all the maxq relocations.
73 FIXME: The handling of the addend in the 'BFD_*'
76 static bfd_reloc_status_type
77 coff_maxq20_reloc (bfd
* abfd
,
78 arelent
* reloc_entry
,
81 asection
* input_section ATTRIBUTE_UNUSED
,
82 bfd
* output_bfd ATTRIBUTE_UNUSED
,
83 char ** error_message ATTRIBUTE_UNUSED
)
85 unsigned char *addr
= NULL
;
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. */
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
;
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
;
134 bfd_put_16 (abfd
, (bfd_vma
) x
, addr
);
138 case ABSOLUTE_ADDR_FOR_DATA
:
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
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. */
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
)
172 if (bfd_is_com_section (symbol_in
->section
) ||
173 ((symbol_in
->flags
& BSF_OLD_COMMON
) != 0))
174 addend
= reloc_entry
->addend
;
177 && (call_addr
< (long) (addend
* (-1))))
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
;
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
);
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
)
230 if (bfd_is_com_section (symbol_in
->section
) ||
231 ((symbol_in
->flags
& BSF_OLD_COMMON
) != 0))
232 addend
= reloc_entry
->addend
;
235 && (call_addr
< (long) (addend
* (-1))))
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
);
246 x
= x
| (call_addr
+ addend
);
248 bfd_put_8 (abfd
, (bfd_vma
) x
, addr
);
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
)
266 if (bfd_is_com_section (symbol_in
->section
) ||
267 ((symbol_in
->flags
& BSF_OLD_COMMON
) != 0))
268 addend
= reloc_entry
->addend
;
271 && (call_addr
< (long) (addend
* (-1))))
274 if ((call_addr
+ addend
) > 0xFFFF)
276 bfd_perror (_("Absolute address Exceeds 16 bit Range"));
277 return bfd_reloc_outofrange
;
281 unsigned short val
= (call_addr
+ addend
);
283 x
= bfd_get_16 (abfd
, addr
);
286 x
= (x
& 0x0000); /* Flush garbage value. */
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
);
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
)
309 if (bfd_is_com_section (symbol_in
->section
) ||
310 ((symbol_in
->flags
& BSF_OLD_COMMON
) != 0))
311 addend
= reloc_entry
->addend
;
314 && (call_addr
< (long) (addend
* (-1))))
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
);
333 bfd_perror (_("Unrecognized Reloc Type"));
334 return bfd_reloc_notsupported
;
338 return bfd_reloc_notsupported
;
341 static reloc_howto_type howto_table
[] =
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,
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
375 static reloc_howto_type
*
376 maxq_reloc_type_lookup (bfd
* abfd ATTRIBUTE_UNUSED
,
377 bfd_reloc_code_real_type code
)
382 case BFD_RELOC_16_PCREL_S2
:
383 return howto_table
+ 3;
385 /* INTERSEGMENT JUMP */
387 return howto_table
+ 4;
391 return howto_table
+ 7;
395 return howto_table
+ 5;
399 return howto_table
+ 2;
403 return howto_table
+ 6;
410 static reloc_howto_type
*
411 maxq_reloc_name_lookup (bfd
*abfd ATTRIBUTE_UNUSED
, const char *r_name
)
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
];
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
434 #include "coffcode.h"
436 #ifndef TARGET_UNDERSCORE
437 #define TARGET_UNDERSCORE 1
440 #ifndef EXTRA_S_FLAGS
441 #define EXTRA_S_FLAGS 0
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
);