gas: permit wider-than-byte operands for .cfi_escape

Some DW_CFA_* and DW_OP_* take wider than byte, but non-LEB128 operands.
Having to hand-encode such when needing to resort to .cfi_escape isn't
very helpful.
This commit is contained in:
Jan Beulich 2025-03-14 10:32:42 +01:00
parent 9f42fb0525
commit ebe00173e3
5 changed files with 53 additions and 7 deletions

View File

@ -5181,6 +5181,18 @@ also use extended kind-of-expression forms:
@itemize @bullet
@item @code{data2(@var{expression})}
to emit a 2-byte item,
@item @code{data4(@var{expression})}
to emit a 4-byte item (provided address size is at least 32 bits),
@item @code{data8(@var{expression})}
to emit an 8-byte item (provided address size is at least 64 bits),
@item @code{addr(@var{expression})}
to emit an address-sized item,
@item @code{sleb128(@var{expression})}
to emit a SLEB128 item,

View File

@ -938,6 +938,21 @@ dot_cfi (int arg)
demand_empty_rest_of_line ();
}
#ifndef TC_ADDRESS_BYTES
#define TC_ADDRESS_BYTES address_bytes
static inline unsigned int
address_bytes (void)
{
/* Choose smallest of 1, 2, 4, 8 bytes that is large enough to
contain an address. */
unsigned int n = (stdoutput->arch_info->bits_per_address - 1) / 8;
n |= n >> 1;
n |= n >> 2;
return n + 1;
}
#endif
static void
dot_cfi_escape (int ignored ATTRIBUTE_UNUSED)
{
@ -968,6 +983,14 @@ dot_cfi_escape (int ignored ATTRIBUTE_UNUSED)
e->type = CFI_ESC_sleb128;
else if (strcmp (id, "uleb128") == 0)
e->type = CFI_ESC_uleb128;
else if (strcmp (id, "data2") == 0)
e->type = 2;
else if (TC_ADDRESS_BYTES () >= 4 && strcmp (id, "data4") == 0)
e->type = 4;
else if (TC_ADDRESS_BYTES () >= 8 && strcmp (id, "data8") == 0)
e->type = 8;
else if (strcmp (id, "addr") == 0)
e->type = TC_ADDRESS_BYTES ();
else
e->type = CFI_ESC_byte;
@ -991,7 +1014,11 @@ dot_cfi_escape (int ignored ATTRIBUTE_UNUSED)
expression (&e->exp);
}
else
e->reloc = do_parse_cons_expression (&e->exp, 1);
{
/* We may still be at the opening parenthesis. Leave it to expression()
to parse it and find the matching closing one. */
e->reloc = do_parse_cons_expression (&e->exp, e->type);
}
*tail = e;
tail = &e->next;
@ -1813,7 +1840,7 @@ output_cfi_insn (struct cfi_insn_data *insn)
if (e->type == CFI_ESC_sleb128 || e->type == CFI_ESC_uleb128)
emit_leb128_expr (&e->exp, e->type == CFI_ESC_sleb128);
else
emit_expr_with_reloc (&e->exp, 1, e->reloc);
emit_expr_with_reloc (&e->exp, e->type, e->reloc);
}
break;
}

View File

@ -98,7 +98,14 @@ struct cfi_escape_data
struct cfi_escape_data *next;
expressionS exp;
enum {
CFI_ESC_byte,
/* "Plain" data is indicated just by their size, such that values can be
easily passed to other functions. The CFI_ESC_data<N> enumerators exist
here only as placeholders. */
CFI_ESC_byte = 1,
CFI_ESC_data2 = 2,
CFI_ESC_data4 = 4,
CFI_ESC_data8 = 8,
/* LEB128 data needs dedicated enumerators. */
CFI_ESC_sleb128,
CFI_ESC_uleb128,
} type;

View File

@ -9,8 +9,8 @@
[ ]*[0-9]*[ ]+[0-9a-f]{4} 4.02 ?0002[ ]+\.cfi_escape 0x02, 0x00, 0x02, 0x00
[ ]*[0-9]*[ ]+00
[ ]*[0-9]*[ ]+[0-9a-f]{4} .*[ ]\.nop
[ ]*[0-9]*[ ]+[0-9a-f]{4} 4.03 ?0000[ ]+\.cfi_escape 0x03; .cfi_escape 0x00, 0x00
[ ]*[0-9]*[ ]+[0-9a-f]{4} 0400 ?0000[ ]+\.cfi_escape 0x04; .cfi_escape 0x00, 0x00, 0x00, 0x00
[ ]*[0-9]*[ ]+[0-9a-f]{4} 4.03 ?0000[ ]+\.cfi_escape 0x03; .cfi_escape data2\(0\)
[ ]*[0-9]*[ ]+[0-9a-f]{4} 0400 ?0000[ ]+\.cfi_escape 0x04; .cfi_escape data4\(0\)
[ ]*[0-9]*[ ]+00
[ ]*[0-9]*[ ]+[0-9a-f]{4} .*[ ]\.nop
[ ]*[0-9]*[ ]+[0-9a-f]{4} 4.0B[ ]+\.cfi_escape 0x0b

View File

@ -7,8 +7,8 @@ func:
.nop
.cfi_escape 0x02, 0x00, 0x02, 0x00
.nop
.cfi_escape 0x03; .cfi_escape 0x00, 0x00
.cfi_escape 0x04; .cfi_escape 0x00, 0x00, 0x00, 0x00
.cfi_escape 0x03; .cfi_escape data2(0)
.cfi_escape 0x04; .cfi_escape data4(0)
.nop
.cfi_escape 0x0b
.nop