arm: Add unwind support for mixed register lists
authorVictor Do Nascimento <victor.donascimento@arm.com>
Wed, 18 May 2022 15:25:12 +0000 (16:25 +0100)
committerNick Clifton <nickc@redhat.com>
Wed, 18 May 2022 15:25:12 +0000 (16:25 +0100)
* config/tc-arm.c (parse_reg_list): Add handling of mixed register
types.
(reg_names): Enumerate pseudoregister according to mapped physical
register number.
(s_arm_unwind_save_pseudo): Modify function signature.
(s_arm_unwind_save_core): Likewise.
(s_arm_unwind_save_mixed): New function.
(s_arm_unwind_save): Generate register list mask to pass to nested
functions.
* testsuite/gas/arm/unwind-pacbti-m.s: Expand test for mixed
  register type lists.
  * testsuite/gas/arm/unwind-pacbti-m.d: Likewise.
* testsuite/gas/arm/unwind-pacbti-m-readelf.d: Likewise.

gas/config/tc-arm.c
gas/testsuite/gas/arm/unwind-pacbti-m-readelf.d
gas/testsuite/gas/arm/unwind-pacbti-m.d
gas/testsuite/gas/arm/unwind-pacbti-m.s

index ca4f97b164ae8b0196e1830dc49e4927f8ea2480..8873269d76a482352c69d2d40a248549e7d6ba90 100644 (file)
@@ -1942,6 +1942,22 @@ parse_reg_list (char ** strp, enum reg_list_els etype)
                rt = REG_TYPE_PSEUDO;
 
              reg = arm_reg_parse (&str, rt);
+
+             /* Skip over allowed registers of alternative types in mixed-type
+                register lists.  */
+             if (reg == FAIL && rt == REG_TYPE_PSEUDO
+                 && ((reg = arm_reg_parse (&str, REG_TYPE_RN)) != FAIL))
+               {
+                 cur_reg = reg;
+                 continue;
+               }
+             else if (reg == FAIL && rt == REG_TYPE_RN
+                      && ((reg = arm_reg_parse (&str, REG_TYPE_PSEUDO)) != FAIL))
+               {
+                 cur_reg = reg;
+                 continue;
+               }
+
              if (etype == REGLIST_CLRM)
                {
                  if (reg == REG_SP || reg == REG_PC)
@@ -4281,22 +4297,11 @@ s_arm_unwind_personality (int ignored ATTRIBUTE_UNUSED)
 /* Parse a directive saving pseudo registers.  */
 
 static void
-s_arm_unwind_save_pseudo (void)
+s_arm_unwind_save_pseudo (long range)
 {
   valueT op;
-  long range;
-
-  range = parse_reg_list (&input_line_pointer, REGLIST_PSEUDO);
-  if (range == FAIL)
-    {
-      as_bad (_("expected pseudo register list"));
-      ignore_rest_of_line ();
-      return;
-    }
-
-  demand_empty_rest_of_line ();
 
-  if (range & (1 << 9))
+  if (range & (1 << 12))
     {
       /* Opcode for restoring RA_AUTH_CODE.  */
       op = 0xb4;
@@ -4308,22 +4313,11 @@ s_arm_unwind_save_pseudo (void)
 /* Parse a directive saving core registers.  */
 
 static void
-s_arm_unwind_save_core (void)
+s_arm_unwind_save_core (long range)
 {
   valueT op;
-  long range;
   int n;
 
-  range = parse_reg_list (&input_line_pointer, REGLIST_RN);
-  if (range == FAIL)
-    {
-      as_bad (_("expected register list"));
-      ignore_rest_of_line ();
-      return;
-    }
-
-  demand_empty_rest_of_line ();
-
   /* Turn .unwind_movsp ip followed by .unwind_save {..., ip, ...}
      into .unwind_save {..., sp...}.  We aren't bothered about the value of
      ip because it is clobbered by calls.  */
@@ -4722,6 +4716,40 @@ s_arm_unwind_save_mmxwcg (void)
   ignore_rest_of_line ();
 }
 
+static void
+s_arm_unwind_save_mixed (long range, long mask_range)
+{
+  const long roof = ((sizeof (long) * CHAR_BIT) - 1)
+    - __builtin_clzl (mask_range);
+
+  long subrange = 0;
+  unsigned lim_lo = 0;
+  unsigned lim_hi = 0;
+
+  /* Iterate over pseudoregister to establish subrange bounds.  */
+  for (; lim_hi <= roof; lim_hi++)
+    {
+      if (mask_range & (1 << lim_hi))
+       {
+         /* Once we know where to split our range, construct subrange.  */
+         for (unsigned n = lim_lo; n < lim_hi; n++)
+           {
+             if (range & (1 << n))
+               subrange |= (1 << n);
+           }
+
+         s_arm_unwind_save_core (subrange);
+         s_arm_unwind_save_pseudo (1 << lim_hi);
+
+         subrange = 0;
+         lim_lo = lim_hi + 1;
+       }
+    }
+
+  lim_lo = 0xffff << roof;
+  subrange = range & lim_lo;
+  s_arm_unwind_save_core (subrange);
+}
 
 /* Parse an unwind_save directive.
    If the argument is non-zero, this is a .vsave directive.  */
@@ -4729,7 +4757,8 @@ s_arm_unwind_save_mmxwcg (void)
 static void
 s_arm_unwind_save (int arch_v6)
 {
-  char *peek;
+  char *peek, *mask_peek;
+  long range, mask_range;
   struct reg_entry *reg;
   bool had_brace = false;
 
@@ -4737,7 +4766,7 @@ s_arm_unwind_save (int arch_v6)
     as_bad (MISSING_FNSTART);
 
   /* Figure out what sort of save we have.  */
-  peek = input_line_pointer;
+  peek = mask_peek = input_line_pointer;
 
   if (*peek == '{')
     {
@@ -4767,13 +4796,35 @@ s_arm_unwind_save (int arch_v6)
       s_arm_unwind_save_fpa (reg->number);
       return;
 
+    case REG_TYPE_PSEUDO:
     case REG_TYPE_RN:
-      s_arm_unwind_save_core ();
-      return;
+      mask_range = parse_reg_list (&mask_peek, REGLIST_PSEUDO);
+      range = parse_reg_list (&input_line_pointer, REGLIST_RN);
 
-    case REG_TYPE_PSEUDO:
-      s_arm_unwind_save_pseudo ();
-      return;
+      if (range == FAIL || mask_range == FAIL)
+       {
+         as_bad (_("expected register list"));
+         ignore_rest_of_line ();
+         return;
+       }
+
+      demand_empty_rest_of_line ();
+
+      if (!mask_range)
+       {
+         s_arm_unwind_save_core (range);
+         return;
+       }
+      else if (!range)
+       {
+         s_arm_unwind_save_pseudo (mask_range);
+         return;
+       }
+      else
+       {
+         s_arm_unwind_save_mixed (range, mask_range);
+         return;
+       }
 
     case REG_TYPE_VFD:
       if (arch_v6)
@@ -23976,7 +24027,7 @@ static const struct reg_entry reg_names[] =
      for tc_arm_regname_to_dw2regnum to translate to DWARF reg number using
      134 + reg_number should the range 134 to 142 be used for more pseudo regs
      in the future.  This also helps fit RA_AUTH_CODE into a bitmask.  */
-  REGDEF(ra_auth_code,9,PSEUDO),
+  REGDEF(ra_auth_code,12,PSEUDO),
 };
 #undef REGDEF
 #undef REGNUM
index ba1d76dd18fbe0ca2c391c12ddcb180d1de3b32b..d8d647bb7f0d943ceeec47e2f4fc8d34bb0ea057 100644 (file)
@@ -6,11 +6,15 @@
 # VxWorks needs a special variant of this file.
 #skip: *-*-vxworks*
 
-Unwind section '.ARM.exidx' at offset 0x40 contains 1 entry:
+Unwind section '.ARM.exidx' at offset 0x60 contains 1 entry:
 
-0x0 <foo>: 0x80b4a8b0
-  Compact model index: 0
+0x0 <foo>: @0x0
+  Compact model index: 1
+  0x84 0x00 pop {r14}
+  0xb4      pop {ra_auth_code}
+  0x84 0x00 pop {r14}
+  0xb4      pop {ra_auth_code}
+  0xa3      pop {r4, r5, r6, r7}
   0xb4      pop {ra_auth_code}
   0xa8      pop {r4, r14}
   0xb0      finish
-
index 28021758a7487097689ef4c44cc25546ccac5221..06cb3145e4254b34c2d95616d7ea20506af3a42a 100644 (file)
@@ -8,16 +8,20 @@
 .*:     file format.*
 
 RELOCATION RECORDS FOR \[.ARM.exidx\]:
-OFFSET   TYPE              VALUE 
+OFFSET   TYPE              VALUE.
 00000000 R_ARM_PREL31      .text
-00000000 R_ARM_NONE        __aeabi_unwind_cpp_pr0
+00000000 R_ARM_NONE        __aeabi_unwind_cpp_pr1
+00000004 R_ARM_PREL31      .ARM.extab
 
 
 Contents of section .text:
- 0000 (10b54df8 04cd5df8 04cb10bd|b510f84d cd04f85d cb04bd10)  .*
+ 0000 (10b54df8 04cd5df8 04cb2de9 f050bde8|e8bd50f0 e92dcb04 f85dcd04 f84db510)  .*
+ 0010 (f0502de9 0050bde8 005010bd|bd105000 e8bd5000 e92d50f0)  .*
+Contents of section .ARM.extab:
+ 0000 (00840281 b40084b4 b0a8b4a3|a3b4a8b0 b48400b4 81028400) 00000000  .*
 Contents of section .ARM.exidx:
- 0000 00000000 (b0a8b480|80b4a8b0)  .*
+ 0000 00000000 00000000  .*
 Contents of section .ARM.attributes:
  0000 41(290000 00|000000 29)616561 62690001 (1f000000|0000001f)  .*
  0010 05382e31 2d4d2e4d 41494e00 0615074d  .*
- 0020 09033202 34024a01 4c01               .*
+ 0020 09033202 34024a01 4c01  .*
index 5a6ea2eec2b8e48dd49963f0a4b93fa29c3c3a49..37202293133e95f7e94490aaa1729afb30a0afe7 100644 (file)
@@ -16,5 +16,11 @@ foo:
        push    {r12}
        .save {ra_auth_code}
        pop     {r12}
+       push    {r4-r7, ip, lr}
+       .save {r4-r7, ra_auth_code, lr}
+       pop     {r4-r7, ip, lr}
+       push    {ip, lr}
+       .save {ra_auth_code, lr}
+       pop {ip, lr}
        pop     {r4, pc}
        .fnend