* config/tc-hppa.c (pa_ip): Handle 'X' operand.
authorJeff Law <law@redhat.com>
Sun, 19 Sep 1999 18:13:50 +0000 (18:13 +0000)
committerJeff Law <law@redhat.com>
Sun, 19 Sep 1999 18:13:50 +0000 (18:13 +0000)
        (md_apply_fix): Handle 22bit pc-rel branches.

gas/ChangeLog
gas/config/tc-hppa.c

index 1071dc75368d08bf496d03cca58f0a00ad70c85a..0d4927f4c63614b46d57b8d9e1275d0be30cf74a 100644 (file)
@@ -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.
index 36722bb2fc940a3dcbc1f76c62276ec51d2273ca..56f8255ed15f7269bad2f83da191647c6adce4db 100644 (file)
@@ -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);