mirror of
https://github.com/espressif/binutils-gdb.git
synced 2025-06-25 04:49:54 +08:00
arm: Add unwind support for mixed register lists
* 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.
This commit is contained in:

committed by
Nick Clifton

parent
301fe55e9c
commit
3363d8560f
@ -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_RN:
|
||||
s_arm_unwind_save_core ();
|
||||
return;
|
||||
|
||||
case REG_TYPE_PSEUDO:
|
||||
s_arm_unwind_save_pseudo ();
|
||||
return;
|
||||
case REG_TYPE_RN:
|
||||
mask_range = parse_reg_list (&mask_peek, REGLIST_PSEUDO);
|
||||
range = parse_reg_list (&input_line_pointer, REGLIST_RN);
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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 .*
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user