[7/8] gas: permit LEB128 operands for .cfi_escape
Checks
Commit Message
Many DW_CFA_* and DW_OP_* take LEB128 operands. Having to hand-encode
such when needing to resort to .cfi_escape isn't very helpful.
Comments
On 2/26/25 7:18 AM, Jan Beulich wrote:
> Many DW_CFA_* and DW_OP_* take LEB128 operands. Having to hand-encode
> such when needing to resort to .cfi_escape isn't very helpful.
>
> --- a/gas/doc/as.texi
> +++ b/gas/doc/as.texi
> @@ -5176,7 +5176,18 @@ SPARC register window has been saved.
> @subsection @code{.cfi_escape} @var{expression}[, @dots{}]
> Allows the user to add arbitrary bytes to the unwind info. One
> might use this to add OS-specific CFI opcodes, or generic CFI
> -opcodes that GAS does not yet support.
> +opcodes that GAS does not yet support. To emit multi-byte data one may
> +also use extended kind-of-expression forms:
> +
> +@itemize @bullet
> +
> +@item @code{sleb128(@var{expression})}
> +to emit a SLEB128 item,
> +
> +@item @code{uleb128(@var{expression})}
> +to emit a SLEB128 item.
> +
Typo: ULEB128 item.
> +@end itemize
>
> @subsection @code{.cfi_val_encoded_addr @var{register}, @var{encoding}, @var{label}}
> The current value of @var{register} is @var{label}. The value of @var{label}
> --- a/gas/dw2gencfi.c
> +++ b/gas/dw2gencfi.c
> @@ -372,6 +372,11 @@ struct cfi_escape_data
> {
> struct cfi_escape_data *next;
> expressionS exp;
> + enum {
> + ESC_byte,
> + ESC_sleb128,
> + ESC_uleb128,
> + } type;
> TC_PARSE_CONS_RETURN_TYPE reloc;
> };
>
> @@ -948,7 +953,7 @@ dot_cfi (int arg)
> static void
> dot_cfi_escape (int ignored ATTRIBUTE_UNUSED)
> {
> - struct cfi_escape_data *head, **tail, *e;
> + struct cfi_escape_data *head, **tail;
> struct cfi_insn_data *insn;
>
> if (frchain_now->frch_cfi_data == NULL)
> @@ -967,8 +972,39 @@ dot_cfi_escape (int ignored ATTRIBUTE_UN
> tail = &head;
> do
> {
> - e = notes_alloc (sizeof (*e));
> - e->reloc = do_parse_cons_expression (&e->exp, 1);
> + struct cfi_escape_data *e = notes_alloc (sizeof (*e));
> + char *id, *ilp_save = input_line_pointer;
> + char c = get_symbol_name (&id);
> +
> + if (strcmp (id, "sleb128") == 0)
> + e->type = ESC_sleb128;
> + else if (strcmp (id, "uleb128") == 0)
> + e->type = ESC_uleb128;
> + else
> + e->type = ESC_byte;
> +
> + c = restore_line_pointer (c);
> +
> + if (e->type != ESC_byte)
> + {
> + if (is_whitespace (c))
> + c = *++input_line_pointer;
> + if (c != '(')
> + {
> + input_line_pointer = ilp_save;
> + e->type = ESC_byte;
> + }
> + }
> +
> + if (e->type == ESC_sleb128 || e->type == ESC_uleb128)
> + {
> + /* We're still at the opening parenthesis. Leave it to expression()
> + to parse it and find the matching closing one. */
> + expression (&e->exp);
> + }
> + else
> + e->reloc = do_parse_cons_expression (&e->exp, 1);
> +
> *tail = e;
> tail = &e->next;
> }
> @@ -1785,7 +1821,12 @@ output_cfi_insn (struct cfi_insn_data *i
> {
> struct cfi_escape_data *e;
> for (e = insn->u.esc; e ; e = e->next)
> - emit_expr_with_reloc (&e->exp, 1, e->reloc);
> + {
> + if (e->type == ESC_sleb128 || e->type == ESC_uleb128)
> + emit_leb128_expr (&e->exp, e->type == ESC_sleb128);
> + else
> + emit_expr_with_reloc (&e->exp, 1, e->reloc);
> + }
> break;
> }
>
> --- a/gas/testsuite/gas/cfi/listing.l
> +++ b/gas/testsuite/gas/cfi/listing.l
> @@ -20,8 +20,20 @@
> [ ]*[0-9]*[ ]+([0-9a-f]{4} [0 ]+)?\.cfi_endproc
> [ ]*[0-9]*[ ]*
> [ ]*[0-9]*[ ]+func2:
> -[ ]*[0-9]*[ ]+[0-9a-f]{4} (1[048]00 ?0000|0000 ?001[048])[ ]+\.cfi_startproc
> +[ ]*[0-9]*[ ]+[0-9a-f]{4} ((1C|2[048])00 ?0000|0000 ?00(1C|2[048]))[ ]+\.cfi_startproc
> [ ]*[0-9]*[ ]+(4[048]00 ?0000|0000 ?004[048]) *
> [ ]*[0-9]*[ ]+[0-9a-f]{4} .*[ ]\.nop
> +[ ]*[0-9]*[ ]+/\* DW_CFA_register reg127, reg129. \*/
> +[ ]*[0-9]*[ ]+[0-9a-f]{4} 4.09 ?7F81[ ]+\.cfi_escape 0x09, uleb128\(127\), uleb128\(129\)
> +[ ]*[0-9]*[ ]+01
> +[ ]*[0-9]*[ ]+/\* DW_CFA_val_expression reg250, ... \*/
> +[ ]*[0-9]*[ ]+[0-9a-f]{4} 16FA ?01[ ]+\.cfi_escape 0x16, uleb128\(250\)
> +[ ]*[0-9]*[ ]+/\* ... <len>. \*/
> +[ ]*[0-9]*[ ]+[0-9a-f]{4} 03[ ]+\.cfi_escape uleb128\(.LE0e - .LE0s\)
> +[ ]*[0-9]*[ ]+\.cfi_label .LE0s
> +[ ]*[0-9]*[ ]+/\* DW_OP_breg3. \*/
> +[ ]*[0-9]*[ ]+[0-9a-f]{4} 7380 ?78[ ]+\.cfi_escape 0x73, sleb128\(-1024\)
> +[ ]*[0-9]*[ ]+\.cfi_label .LE0e
> +[ ]*[0-9]*[ ]+[0-9a-f]{4} .*[ ]\.nop
> [ ]*[0-9]*[ ]+([0-9a-f]{4} [0 ]+)?\.cfi_endproc
> #pass
> --- a/gas/testsuite/gas/cfi/listing.s
> +++ b/gas/testsuite/gas/cfi/listing.s
> @@ -19,4 +19,15 @@ func:
> func2:
> .cfi_startproc
> .nop
> + /* DW_CFA_register reg127, reg129. */
> + .cfi_escape 0x09, uleb128(127), uleb128(129)
> + /* DW_CFA_val_expression reg250, ... */
> + .cfi_escape 0x16, uleb128(250)
> + /* ... <len>. */
> + .cfi_escape uleb128(.LE0e - .LE0s)
> + .cfi_label .LE0s
> + /* DW_OP_breg3. */
> + .cfi_escape 0x73, sleb128(-1024)
> + .cfi_label .LE0e
> + .nop
> .cfi_endproc
>
@@ -5176,7 +5176,18 @@ SPARC register window has been saved.
@subsection @code{.cfi_escape} @var{expression}[, @dots{}]
Allows the user to add arbitrary bytes to the unwind info. One
might use this to add OS-specific CFI opcodes, or generic CFI
-opcodes that GAS does not yet support.
+opcodes that GAS does not yet support. To emit multi-byte data one may
+also use extended kind-of-expression forms:
+
+@itemize @bullet
+
+@item @code{sleb128(@var{expression})}
+to emit a SLEB128 item,
+
+@item @code{uleb128(@var{expression})}
+to emit a SLEB128 item.
+
+@end itemize
@subsection @code{.cfi_val_encoded_addr @var{register}, @var{encoding}, @var{label}}
The current value of @var{register} is @var{label}. The value of @var{label}
@@ -372,6 +372,11 @@ struct cfi_escape_data
{
struct cfi_escape_data *next;
expressionS exp;
+ enum {
+ ESC_byte,
+ ESC_sleb128,
+ ESC_uleb128,
+ } type;
TC_PARSE_CONS_RETURN_TYPE reloc;
};
@@ -948,7 +953,7 @@ dot_cfi (int arg)
static void
dot_cfi_escape (int ignored ATTRIBUTE_UNUSED)
{
- struct cfi_escape_data *head, **tail, *e;
+ struct cfi_escape_data *head, **tail;
struct cfi_insn_data *insn;
if (frchain_now->frch_cfi_data == NULL)
@@ -967,8 +972,39 @@ dot_cfi_escape (int ignored ATTRIBUTE_UN
tail = &head;
do
{
- e = notes_alloc (sizeof (*e));
- e->reloc = do_parse_cons_expression (&e->exp, 1);
+ struct cfi_escape_data *e = notes_alloc (sizeof (*e));
+ char *id, *ilp_save = input_line_pointer;
+ char c = get_symbol_name (&id);
+
+ if (strcmp (id, "sleb128") == 0)
+ e->type = ESC_sleb128;
+ else if (strcmp (id, "uleb128") == 0)
+ e->type = ESC_uleb128;
+ else
+ e->type = ESC_byte;
+
+ c = restore_line_pointer (c);
+
+ if (e->type != ESC_byte)
+ {
+ if (is_whitespace (c))
+ c = *++input_line_pointer;
+ if (c != '(')
+ {
+ input_line_pointer = ilp_save;
+ e->type = ESC_byte;
+ }
+ }
+
+ if (e->type == ESC_sleb128 || e->type == ESC_uleb128)
+ {
+ /* We're still at the opening parenthesis. Leave it to expression()
+ to parse it and find the matching closing one. */
+ expression (&e->exp);
+ }
+ else
+ e->reloc = do_parse_cons_expression (&e->exp, 1);
+
*tail = e;
tail = &e->next;
}
@@ -1785,7 +1821,12 @@ output_cfi_insn (struct cfi_insn_data *i
{
struct cfi_escape_data *e;
for (e = insn->u.esc; e ; e = e->next)
- emit_expr_with_reloc (&e->exp, 1, e->reloc);
+ {
+ if (e->type == ESC_sleb128 || e->type == ESC_uleb128)
+ emit_leb128_expr (&e->exp, e->type == ESC_sleb128);
+ else
+ emit_expr_with_reloc (&e->exp, 1, e->reloc);
+ }
break;
}
@@ -20,8 +20,20 @@
[ ]*[0-9]*[ ]+([0-9a-f]{4} [0 ]+)?\.cfi_endproc
[ ]*[0-9]*[ ]*
[ ]*[0-9]*[ ]+func2:
-[ ]*[0-9]*[ ]+[0-9a-f]{4} (1[048]00 ?0000|0000 ?001[048])[ ]+\.cfi_startproc
+[ ]*[0-9]*[ ]+[0-9a-f]{4} ((1C|2[048])00 ?0000|0000 ?00(1C|2[048]))[ ]+\.cfi_startproc
[ ]*[0-9]*[ ]+(4[048]00 ?0000|0000 ?004[048]) *
[ ]*[0-9]*[ ]+[0-9a-f]{4} .*[ ]\.nop
+[ ]*[0-9]*[ ]+/\* DW_CFA_register reg127, reg129. \*/
+[ ]*[0-9]*[ ]+[0-9a-f]{4} 4.09 ?7F81[ ]+\.cfi_escape 0x09, uleb128\(127\), uleb128\(129\)
+[ ]*[0-9]*[ ]+01
+[ ]*[0-9]*[ ]+/\* DW_CFA_val_expression reg250, ... \*/
+[ ]*[0-9]*[ ]+[0-9a-f]{4} 16FA ?01[ ]+\.cfi_escape 0x16, uleb128\(250\)
+[ ]*[0-9]*[ ]+/\* ... <len>. \*/
+[ ]*[0-9]*[ ]+[0-9a-f]{4} 03[ ]+\.cfi_escape uleb128\(.LE0e - .LE0s\)
+[ ]*[0-9]*[ ]+\.cfi_label .LE0s
+[ ]*[0-9]*[ ]+/\* DW_OP_breg3. \*/
+[ ]*[0-9]*[ ]+[0-9a-f]{4} 7380 ?78[ ]+\.cfi_escape 0x73, sleb128\(-1024\)
+[ ]*[0-9]*[ ]+\.cfi_label .LE0e
+[ ]*[0-9]*[ ]+[0-9a-f]{4} .*[ ]\.nop
[ ]*[0-9]*[ ]+([0-9a-f]{4} [0 ]+)?\.cfi_endproc
#pass
@@ -19,4 +19,15 @@ func:
func2:
.cfi_startproc
.nop
+ /* DW_CFA_register reg127, reg129. */
+ .cfi_escape 0x09, uleb128(127), uleb128(129)
+ /* DW_CFA_val_expression reg250, ... */
+ .cfi_escape 0x16, uleb128(250)
+ /* ... <len>. */
+ .cfi_escape uleb128(.LE0e - .LE0s)
+ .cfi_label .LE0s
+ /* DW_OP_breg3. */
+ .cfi_escape 0x73, sleb128(-1024)
+ .cfi_label .LE0e
+ .nop
.cfi_endproc