diff --git a/gas/ChangeLog b/gas/ChangeLog index e48383fc44..9255c57cc4 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,8 @@ +Thu Mar 31 16:51:16 1994 Ian Lance Taylor (ian@tweedledumb.cygnus.com) + + * config/tc-sparc.c (tc_gen_reloc): Add a gruesome hack to get + cross section PC relative relocs right for COFF and ELF. + Mon Mar 28 14:38:23 1994 Ken Raeburn (raeburn@cujo.cygnus.com) * config/obj-coff.h (SEPARATE_STAB_SECTIONS): Always define. diff --git a/gas/config/tc-sparc.c b/gas/config/tc-sparc.c index 24803009b0..4274dedbc9 100644 --- a/gas/config/tc-sparc.c +++ b/gas/config/tc-sparc.c @@ -23,6 +23,7 @@ #include #include "as.h" +#include "subsegs.h" /* careful, this file includes data *declarations* */ #include "opcode/sparc.h" @@ -124,6 +125,19 @@ struct sparc_it struct sparc_it the_insn, set_insn; +static INLINE int +in_signed_range (val, max) + bfd_signed_vma val, max; +{ + if (max <= 0) + abort (); + if (val > max) + return 0; + if (val < ~max) + return 0; + return 1; +} + #if 0 static void print_insn PARAMS ((struct sparc_it *insn)); #endif @@ -1377,8 +1391,7 @@ sparc_ip (str) goto immediate; case 'i': /* 13 bit immediate */ - /* What's the difference between base13 and 13? */ - the_insn.reloc = BFD_RELOC_SPARC_BASE13; + the_insn.reloc = BFD_RELOC_SPARC13; immediate_max = 0x0FFF; /*FALLTHROUGH */ @@ -1464,6 +1477,10 @@ sparc_ip (str) { /* start-sanitize-v9 */ #ifndef NO_V9 + /* Handle %uhi/%ulo by moving the upper word to the lower + one and pretending it's %hi/%lo. We also need to watch + for %hi/%lo: the top word needs to be zeroed otherwise + fixup_segment will complain the value is too big. */ switch (the_insn.reloc) { case BFD_RELOC_SPARC_HH22: @@ -1476,19 +1493,47 @@ sparc_ip (str) break; default: break; + case BFD_RELOC_HI22: + case BFD_RELOC_LO10: + the_insn.exp.X_add_number &= 0xffffffff; + break; } #endif /* end-sanitize-v9 */ + /* For pc-relative call instructions, we reject + constants to get better code. */ + if (the_insn.pcrel + && the_insn.reloc == BFD_RELOC_32_PCREL_S2 + && in_signed_range (the_insn.exp.X_add_number, 0x3fff) + ) + { + error_message = ": PC-relative operand can't be a constant"; + goto error; + } /* Check for invalid constant values. Don't warn if constant was inside %hi or %lo, since these truncate the constant to fit. */ if (immediate_max != 0 && the_insn.reloc != BFD_RELOC_LO10 && the_insn.reloc != BFD_RELOC_HI22 - && (the_insn.exp.X_add_number > immediate_max - || the_insn.exp.X_add_number < ~immediate_max)) - as_bad ("constant value must be between %ld and %ld", - ~immediate_max, immediate_max); + && !in_signed_range (the_insn.exp.X_add_number, + immediate_max) + ) + { + if (the_insn.pcrel) + /* Who knows? After relocation, we may be within + range. Let the linker figure it out. */ + { + the_insn.exp.X_op = O_symbol; + the_insn.exp.X_add_symbol = section_symbol (absolute_section); + } + else + /* Immediate value is non-pcrel, and out of + range. */ + as_bad ("constant value %ld out of range (%ld .. %ld)", + the_insn.exp.X_add_number, + ~immediate_max, immediate_max); + } } /* Reset to prevent extraneous range check. */ @@ -1974,15 +2019,6 @@ md_apply_fix (fixP, value) buf[3] = val & 0xff; break; - case BFD_RELOC_SPARC13: - if (val & ~0x00001fff) - { - as_bad ("relocation overflow"); - } /* on overflow */ - buf[2] |= (val >> 8) & 0x1f; - buf[3] = val & 0xff; - break; - /* start-sanitize-v9 */ #ifndef NO_V9 case BFD_RELOC_SPARC_HM10: @@ -2000,12 +2036,11 @@ md_apply_fix (fixP, value) else buf[3] = 0; break; - case BFD_RELOC_SPARC_BASE13: - if (((val > 0) && (val & ~(offsetT)0x00001fff)) - || ((val < 0) && (~(val - 1) & ~(offsetT)0x00001fff))) - { - as_bad ("relocation overflow"); - } + + case BFD_RELOC_SPARC13: + if (! in_signed_range (val, 0x1fff)) + as_bad ("relocation overflow"); + buf[2] |= (val >> 8) & 0x1f; buf[3] = val; break; @@ -2025,6 +2060,10 @@ md_apply_fix (fixP, value) break; } + /* Are we finished with this relocation now? */ + if (fixP->fx_addsy == 0 && !fixP->fx_pcrel) + fixP->fx_done = 1; + return 1; } @@ -2051,6 +2090,7 @@ tc_gen_reloc (section, fixp) case BFD_RELOC_HI22: case BFD_RELOC_LO10: case BFD_RELOC_32_PCREL_S2: + case BFD_RELOC_SPARC13: case BFD_RELOC_SPARC_BASE13: case BFD_RELOC_SPARC_WDISP22: /* start-sanitize-v9 */ @@ -2076,6 +2116,12 @@ tc_gen_reloc (section, fixp) /* @@ Why fx_addnumber sometimes and fx_offset other times? */ if (reloc->howto->pc_relative == 0) reloc->addend = fixp->fx_addnumber; +#if defined (OBJ_ELF) || defined (OBJ_COFF) + else if ((fixp->fx_addsy->bsym->flags & BSF_SECTION_SYM) != 0) + reloc->addend = (section->vma + + fixp->fx_addnumber + + md_pcrel_from (fixp)); +#endif else reloc->addend = fixp->fx_offset - reloc->address;