diff options
-rw-r--r-- | gas/ChangeLog | 3 | ||||
-rw-r--r-- | gas/config/tc-hppa.c | 62 |
2 files changed, 65 insertions, 0 deletions
diff --git a/gas/ChangeLog b/gas/ChangeLog index 1071dc7..0d4927f 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,5 +1,8 @@ Sun Sep 19 10:43:31 1999 Jeffrey A Law (law@cygnus.com) + * config/tc-hppa.c (pa_ip): Handle 'X' operand. + (md_apply_fix): Handle 22bit pc-rel branches. + * config/tc-hppa.c (pa_ip): Handle 'B' operand. * config/tc-hppa.c (pa_ip): Handle 'L' and 'M' operands. diff --git a/gas/config/tc-hppa.c b/gas/config/tc-hppa.c index 36722bb..56f8255 100644 --- a/gas/config/tc-hppa.c +++ b/gas/config/tc-hppa.c @@ -2865,6 +2865,45 @@ pa_ip (str) continue; } + /* Handle a 22 bit branch displacement. */ + case 'X': + the_insn.field_selector = pa_chk_field_selector (&s); + get_expression (s); + s = expr_end; + the_insn.pcrel = 1; + if (!the_insn.exp.X_add_symbol + || !strcmp (S_GET_NAME (the_insn.exp.X_add_symbol), + "L$0\001")) + { + unsigned int w3, w2, w1, w, result; + + num = evaluate_absolute (&the_insn); + if (num % 4) + { + as_bad (_("Branch to unaligned address")); + break; + } + CHECK_FIELD (num, 8388607, -8388608, 0); + + if (the_insn.exp.X_add_symbol) + num -= 8; + + sign_unext (num >> 2, 22, &result); + dis_assemble_22 (result, &w3, &w1, &w2, &w); + INSERT_FIELD_AND_CONTINUE (opcode, + ((w3 << 21) | (w2 << 2) + | (w1 << 16) | w), + 0); + } + else + { + the_insn.reloc = R_HPPA_PCREL_CALL; + the_insn.format = 22; + the_insn.arg_reloc = last_call_desc.arg_reloc; + memset (&last_call_desc, 0, sizeof (struct call_desc)); + continue; + } + /* Handle an absolute 17 bit branch target. */ case 'z': the_insn.field_selector = pa_chk_field_selector (&s); @@ -3961,6 +4000,29 @@ md_apply_fix (fixP, valp) break; } + case 22: + { + int distance = *valp, w3; + + CHECK_FIELD (new_val, 8388607, -8388608, 0); + + /* If this is an absolute branch (ie no link) with an out of + range target, then we want to complain. */ + if (fixP->fx_r_type == R_HPPA_PCREL_CALL + && (distance > 8388607 || distance < -8388608) + && (bfd_get_32 (stdoutput, buf) & 0xffe00000) == 0xe8000000) + CHECK_FIELD (distance, 8388607, -8388608, 0); + + /* Mask off 22 bits to be changed. */ + bfd_put_32 (stdoutput, + bfd_get_32 (stdoutput, buf) & 0xfc00e002, + buf); + sign_unext ((new_val - 8) >> 2, 22, &resulti); + dis_assemble_22 (resulti, &w3, &w1, &w2, &w); + result = ((w3 << 21) | (w2 << 2) | (w1 << 16) | w); + break; + } + case 32: result = 0; bfd_put_32 (stdoutput, new_val, buf); |