diff options
Diffstat (limited to 'gas')
-rw-r--r-- | gas/write.c | 518 |
1 files changed, 269 insertions, 249 deletions
diff --git a/gas/write.c b/gas/write.c index 9e0ba8e..0f86417 100644 --- a/gas/write.c +++ b/gas/write.c @@ -30,6 +30,10 @@ #define NOP_OPCODE 0x00 #endif +#ifndef TC_ADJUST_RELOC_COUNT +#define TC_ADJUST_RELOC_COUNT(FIXP,COUNT) +#endif + #ifndef TC_FORCE_RELOCATION #define TC_FORCE_RELOCATION(FIXP) 0 #endif @@ -651,8 +655,9 @@ write_relocs (abfd, sec, xxx) reloc->addend += reloc->address; } /* Pass bogus address so that when bfd_perform_relocation adds - `address' back in, it'll come up with `data', which is where - we want it to operate. */ + `reloc->address' back in, it'll come up with `data', which is where + we want it to operate. We can't just do it by fudging reloc->address, + since that might be used in the calculations(?). */ s = bfd_perform_relocation (stdoutput, reloc, data - reloc->address, sec, stdoutput); switch (s) @@ -1812,292 +1817,307 @@ fixup_segment (fixP, this_segment_type) register fixS *fixP; segT this_segment_type; /* N_TYPE bits for segment. */ { - register long seg_reloc_count; - register symbolS *add_symbolP; - register symbolS *sub_symbolP; + long seg_reloc_count = 0; + symbolS *add_symbolP; + symbolS *sub_symbolP; valueT add_number; - register int size; - register char *place; - register long where; - register char pcrel; - register fragS *fragP; - register segT add_symbol_segment = absolute_section; - - seg_reloc_count = 0; - /* If the linker is doing the relaxing, we must not do any fixups. */ - /* Well, strictly speaking that's not true -- we could do any that - are PC-relative and don't cross regions that could change size. - And for the i960 (the only machine for which we've got a relaxing - linker right now), we might be able to turn callx/callj into bal - in cases where we know the maximum displacement. */ + int size; + char *place; + long where; + char pcrel; + fragS *fragP; + segT add_symbol_segment = absolute_section; + + /* If the linker is doing the relaxing, we must not do any fixups. + + Well, strictly speaking that's not true -- we could do any that are + PC-relative and don't cross regions that could change size. And for the + i960 (the only machine for which we've got a relaxing linker right now), + we might be able to turn callx/callj into bal anyways in cases where we + know the maximum displacement. */ if (linkrelax) - for (; fixP; fixP = fixP->fx_next) - seg_reloc_count++; - else - for (; fixP; fixP = fixP->fx_next) - { - fragP = fixP->fx_frag; - know (fragP); - where = fixP->fx_where; - place = fragP->fr_literal + where; - size = fixP->fx_size; - add_symbolP = fixP->fx_addsy; -#ifdef TC_I960 - if (fixP->fx_tcbit && TC_S_IS_CALLNAME (add_symbolP)) - { - /* Relocation should be done via the associated 'bal' - entry point symbol. */ + { + for (; fixP; fixP = fixP->fx_next) + seg_reloc_count++; + TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count); + return seg_reloc_count; + } - if (!TC_S_IS_BALNAME (tc_get_bal_of_call (add_symbolP))) - { - as_bad ("No 'bal' entry point for leafproc %s", - S_GET_NAME (add_symbolP)); - continue; - } - fixP->fx_addsy = add_symbolP = tc_get_bal_of_call (add_symbolP); - } + for (; fixP; fixP = fixP->fx_next) + { + fragP = fixP->fx_frag; + know (fragP); + where = fixP->fx_where; + place = fragP->fr_literal + where; + size = fixP->fx_size; + add_symbolP = fixP->fx_addsy; +#ifdef TC_VALIDATE_FIX + TC_VALIDATE_FIX (fixP, this_segment_type, skip); #endif - sub_symbolP = fixP->fx_subsy; - add_number = fixP->fx_offset; - pcrel = fixP->fx_pcrel; - - if (add_symbolP) - add_symbol_segment = S_GET_SEGMENT (add_symbolP); - - if (sub_symbolP) - { - if (!add_symbolP) - { - /* Its just -sym */ - /* @@ Should try converting to pcrel ref to fixed addr. */ - if (S_GET_SEGMENT (sub_symbolP) != absolute_section) - as_bad ("Negative of non-absolute symbol %s", - S_GET_NAME (sub_symbolP)); - + sub_symbolP = fixP->fx_subsy; + add_number = fixP->fx_offset; + pcrel = fixP->fx_pcrel; + + if (add_symbolP) + add_symbol_segment = S_GET_SEGMENT (add_symbolP); + + if (sub_symbolP) + { + if (!add_symbolP) + { + /* Its just -sym */ + if (S_GET_SEGMENT (sub_symbolP) == absolute_section) add_number -= S_GET_VALUE (sub_symbolP); - } - else if ((S_GET_SEGMENT (sub_symbolP) == add_symbol_segment) - && (SEG_NORMAL (add_symbol_segment) - || (add_symbol_segment == absolute_section))) - { - /* Difference of 2 symbols from same segment. - Can't make difference of 2 undefineds: 'value' means - something different for N_UNDF. */ + else if (pcrel + && S_GET_SEGMENT (sub_symbolP) == this_segment_type) + { + /* Should try converting to a constant. */ + goto bad_sub_reloc; + } + else + bad_sub_reloc: + as_bad ("Negative of non-absolute symbol %s", + S_GET_NAME (sub_symbolP)); + } + else if ((S_GET_SEGMENT (sub_symbolP) == add_symbol_segment) + && (SEG_NORMAL (add_symbol_segment) + || (add_symbol_segment == absolute_section))) + { + /* Difference of 2 symbols from same segment. + Can't make difference of 2 undefineds: 'value' means + something different for N_UNDF. */ #ifdef TC_I960 - /* Makes no sense to use the difference of 2 arbitrary symbols - as the target of a call instruction. */ - if (fixP->fx_tcbit) - { - as_bad ("callj to difference of 2 symbols"); - } + /* Makes no sense to use the difference of 2 arbitrary symbols + as the target of a call instruction. */ + if (fixP->fx_tcbit) + as_bad ("callj to difference of 2 symbols"); #endif /* TC_I960 */ - add_number += S_GET_VALUE (add_symbolP) - - S_GET_VALUE (sub_symbolP); + add_number += S_GET_VALUE (add_symbolP) - + S_GET_VALUE (sub_symbolP); - add_symbolP = NULL; + add_symbolP = NULL; - /* Let the target machine make the final determination - as to whether or not a relocation will be needed to - handle this fixup. */ - if (!TC_FORCE_RELOCATION (fixP)) - fixP->fx_addsy = NULL; - } - else - { - /* Different segments in subtraction. */ - know (!(S_IS_EXTERNAL (sub_symbolP) - && (S_GET_SEGMENT (sub_symbolP) == absolute_section))); + /* Let the target machine make the final determination + as to whether or not a relocation will be needed to + handle this fixup. */ + if (!TC_FORCE_RELOCATION (fixP)) + fixP->fx_addsy = NULL; + } + else + { + /* Different segments in subtraction. */ + know (!(S_IS_EXTERNAL (sub_symbolP) + && (S_GET_SEGMENT (sub_symbolP) == absolute_section))); + + if ((S_GET_SEGMENT (sub_symbolP) == absolute_section)) + add_number -= S_GET_VALUE (sub_symbolP); - if ((S_GET_SEGMENT (sub_symbolP) == absolute_section)) - { - add_number -= S_GET_VALUE (sub_symbolP); - } #ifdef DIFF_EXPR_OK - else if (S_GET_SEGMENT (sub_symbolP) == this_segment_type -#if 0 - /* Do this even if it's already described as - pc-relative. For example, on the m68k, an - operand of "pc@(foo-.-2)" should address "foo" - in a pc-relative mode. */ - && pcrel + else if (S_GET_SEGMENT (sub_symbolP) == this_segment_type +#if 0 /* Do this even if it's already described as pc-relative. For example, + on the m68k, an operand of "pc@(foo-.-2)" should address "foo" in a + pc-relative mode. */ + && pcrel #endif - ) - { - /* Make it pc-relative. */ - add_number += (md_pcrel_from (fixP) - - S_GET_VALUE (sub_symbolP)); - pcrel = 1; - fixP->fx_pcrel = 1; - sub_symbolP = 0; - fixP->fx_subsy = 0; - } + ) + { + /* Make it pc-relative. */ + add_number += (md_pcrel_from (fixP) + - S_GET_VALUE (sub_symbolP)); + pcrel = 1; + fixP->fx_pcrel = 1; + sub_symbolP = 0; + fixP->fx_subsy = 0; + } #endif - else - { - char buf[50]; - sprint_value (buf, fragP->fr_address + where); - as_bad ("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %s.", - segment_name (S_GET_SEGMENT (sub_symbolP)), - S_GET_NAME (sub_symbolP), buf); - } - } - } + else + { + char buf[50]; + sprint_value (buf, fragP->fr_address + where); + as_bad ("Can't emit reloc {- %s-seg symbol \"%s\"} @ file address %s.", + segment_name (S_GET_SEGMENT (sub_symbolP)), + S_GET_NAME (sub_symbolP), buf); + } + } + } - if (add_symbolP) - { - if (add_symbol_segment == this_segment_type && pcrel) - { - /* - * This fixup was made when the symbol's segment was - * SEG_UNKNOWN, but it is now in the local segment. - * So we know how to do the address without relocation. - */ + if (add_symbolP) + { + if (add_symbol_segment == this_segment_type && pcrel) + { + /* + * This fixup was made when the symbol's segment was + * SEG_UNKNOWN, but it is now in the local segment. + * So we know how to do the address without relocation. + */ #ifdef TC_I960 - /* reloc_callj() may replace a 'call' with a 'calls' or a - 'bal', in which cases it modifies *fixP as appropriate. - In the case of a 'calls', no further work is required, - and *fixP has been set up to make the rest of the code - below a no-op. */ - reloc_callj (fixP); + /* reloc_callj() may replace a 'call' with a 'calls' or a + 'bal', in which cases it modifies *fixP as appropriate. + In the case of a 'calls', no further work is required, + and *fixP has been set up to make the rest of the code + below a no-op. */ + reloc_callj (fixP); #endif /* TC_I960 */ - add_number += S_GET_VALUE (add_symbolP); - add_number -= md_pcrel_from (fixP); - pcrel = 0; /* Lie. Don't want further pcrel processing. */ - - /* Let the target machine make the final determination - as to whether or not a relocation will be needed to - handle this fixup. */ - if (!TC_FORCE_RELOCATION (fixP)) - fixP->fx_addsy = NULL; - } - else - { - if (add_symbol_segment == absolute_section) - { + add_number += S_GET_VALUE (add_symbolP); + add_number -= md_pcrel_from (fixP); + pcrel = 0; /* Lie. Don't want further pcrel processing. */ + + /* Let the target machine make the final determination + as to whether or not a relocation will be needed to + handle this fixup. */ + if (!TC_FORCE_RELOCATION (fixP)) + fixP->fx_addsy = NULL; + } + else + { + if (add_symbol_segment == absolute_section) + { #ifdef TC_I960 - /* See comment about reloc_callj() above. */ - reloc_callj (fixP); + /* See comment about reloc_callj() above. */ + reloc_callj (fixP); #endif /* TC_I960 */ - add_number += S_GET_VALUE (add_symbolP); - - /* Let the target machine make the final determination - as to whether or not a relocation will be needed to - handle this fixup. */ - if (!TC_FORCE_RELOCATION (fixP)) - fixP->fx_addsy = NULL; - add_symbolP = NULL; - } - else if (add_symbol_segment == undefined_section + add_number += S_GET_VALUE (add_symbolP); + + /* Let the target machine make the final determination + as to whether or not a relocation will be needed to + handle this fixup. */ + if (!TC_FORCE_RELOCATION (fixP)) + fixP->fx_addsy = NULL; + add_symbolP = NULL; + } + else if (add_symbol_segment == undefined_section #ifdef BFD_ASSEMBLER - || bfd_is_com_section (add_symbol_segment) + || bfd_is_com_section (add_symbol_segment) #endif - ) - { + ) + { #ifdef TC_I960 - if ((int) fixP->fx_bit_fixP == 13) - { - /* This is a COBR instruction. They have only a - * 13-bit displacement and are only to be used - * for local branches: flag as error, don't generate - * relocation. - */ - as_bad ("can't use COBR format with external label"); - - /* Let the target machine make the final determination - as to whether or not a relocation will be needed to - handle this fixup. */ - if (!TC_FORCE_RELOCATION (fixP)) - fixP->fx_addsy = NULL; - continue; - } /* COBR */ + if ((int) fixP->fx_bit_fixP == 13) + { + /* This is a COBR instruction. They have only a + * 13-bit displacement and are only to be used + * for local branches: flag as error, don't generate + * relocation. + */ + as_bad ("can't use COBR format with external label"); + + /* Let the target machine make the final determination + as to whether or not a relocation will be needed to + handle this fixup. */ + if (!TC_FORCE_RELOCATION (fixP)) + fixP->fx_addsy = NULL; + continue; + } /* COBR */ #endif /* TC_I960 */ - + #ifdef OBJ_COFF #ifdef TE_I386AIX - if (S_IS_COMMON (add_symbolP)) - add_number += S_GET_VALUE (add_symbolP); + if (S_IS_COMMON (add_symbolP)) + add_number += S_GET_VALUE (add_symbolP); #endif /* TE_I386AIX */ #endif /* OBJ_COFF */ - ++seg_reloc_count; - } - else - { - seg_reloc_count++; - add_number += S_GET_VALUE (add_symbolP); - } - } - } + ++seg_reloc_count; + } + else + { + seg_reloc_count++; + add_number += S_GET_VALUE (add_symbolP); + } + } + } - if (pcrel) - { - add_number -= md_pcrel_from (fixP); - if (add_symbolP == 0) - { - fixP->fx_addsy = &abs_symbol; - ++seg_reloc_count; - } /* if there's an add_symbol */ - } /* if pcrel */ + if (pcrel) + { + add_number -= md_pcrel_from (fixP); + if (add_symbolP == 0) + { + fixP->fx_addsy = &abs_symbol; + ++seg_reloc_count; + } /* if there's an add_symbol */ + } /* if pcrel */ - if (!fixP->fx_bit_fixP && size > 0) - { - valueT mask = 0; - /* set all bits to one */ - mask--; - /* Technically speaking, combining these produces an - undefined result if size is sizeof (valueT), though I - think these two half-way operations should both be - defined. */ - mask <<= size * 4; - mask <<= size * 4; - if ((add_number & mask) != 0 - && (add_number & mask) != mask) - { - char buf[50], buf2[50]; - sprint_value (buf, fragP->fr_address + where); - if (add_number > 1000) - sprint_value (buf2, add_number); - else - sprintf (buf2, "%ld", (long) add_number); - as_bad_where (fixP->fx_file, fixP->fx_line, - "Value of %s too large for field of %d bytes at %s", - buf2, size, buf); - } /* generic error checking */ -#ifdef WARN_SIGNED_OVERFLOW_WORD - /* Warn if a .word value is too large when treated as a signed - number. We already know it is not too negative. This is to - catch over-large switches generated by gcc on the 68k. */ - if (!flagseen['J'] - && size == 2 - && add_number > 0x7fff) + if (!fixP->fx_bit_fixP && size > 0) + { + valueT mask = 0; + /* set all bits to one */ + mask--; + /* Technically speaking, combining these produces an + undefined result if size is sizeof (valueT), though I + think these two half-way operations should both be + defined. */ + mask <<= size * 4; + mask <<= size * 4; + if ((add_number & mask) != 0 + && (add_number & mask) != mask) + { + char buf[50], buf2[50]; + sprint_value (buf, fragP->fr_address + where); + if (add_number > 1000) + sprint_value (buf2, add_number); + else + sprintf (buf2, "%ld", (long) add_number); as_bad_where (fixP->fx_file, fixP->fx_line, - "Signed .word overflow; switch may be too large; %ld at 0x%lx", - (long) add_number, - (unsigned long) (fragP->fr_address + where)); + "Value of %s too large for field of %d bytes at %s", + buf2, size, buf); + } /* generic error checking */ +#ifdef WARN_SIGNED_OVERFLOW_WORD + /* Warn if a .word value is too large when treated as a signed + number. We already know it is not too negative. This is to + catch over-large switches generated by gcc on the 68k. */ + if (!flagseen['J'] + && size == 2 + && add_number > 0x7fff) + as_bad_where (fixP->fx_file, fixP->fx_line, + "Signed .word overflow; switch may be too large; %ld at 0x%lx", + (long) add_number, + (unsigned long) (fragP->fr_address + where)); #endif - } /* not a bit fix */ + } /* not a bit fix */ #ifdef BFD_ASSEMBLER - md_apply_fix (fixP, &add_number); + md_apply_fix (fixP, &add_number); #else - md_apply_fix (fixP, add_number); + md_apply_fix (fixP, add_number); #endif - } /* For each fixS in this segment. */ + skip: + ; + } /* For each fixS in this segment. */ -#if defined (OBJ_COFF) && defined (TC_I960) - { - fixS *topP = fixP; + TC_ADJUST_RELOC_COUNT (fixP, seg_reloc_count); + return seg_reloc_count; +} - /* two relocs per callj under coff. */ - for (fixP = topP; fixP; fixP = fixP->fx_next) - if (fixP->fx_tcbit && fixP->fx_addsy != 0) - ++seg_reloc_count; - } -#endif /* OBJ_COFF && TC_I960 */ +#endif /* defined (BFD_ASSEMBLER) || !defined (BFD) */ - return (seg_reloc_count); +void +number_to_chars_bigendian (buf, val, n) + char *buf; + valueT val; + int n; +{ + if (n > sizeof (val)|| n <= 0) + abort (); + while (n--) + { + buf[n] = val & 0xff; + val >>= 8; + } } -#endif /* defined (BFD_ASSEMBLER) || !defined (BFD) */ +void +number_to_chars_littleendian (buf, val, n) + char *buf; + valueT val; + int n; +{ + if (n > sizeof (val) || n <= 0) + abort (); + while (n--) + { + *buf++ = val & 0xff; + val >>= 8; + } +} /* end of write.c */ |