aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2025-03-14 10:32:42 +0100
committerJan Beulich <jbeulich@suse.com>2025-03-14 10:32:42 +0100
commitebe00173e32ce714bbc8e0fb877dc6eb5033ad6f (patch)
treee058897ddc6b8dabb600cd88fa89eae04af48ce3
parent9f42fb05256ad5731baf307dcdd321dd5d6b0828 (diff)
downloadbinutils-ebe00173e32ce714bbc8e0fb877dc6eb5033ad6f.zip
binutils-ebe00173e32ce714bbc8e0fb877dc6eb5033ad6f.tar.gz
binutils-ebe00173e32ce714bbc8e0fb877dc6eb5033ad6f.tar.bz2
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.
-rw-r--r--gas/doc/as.texi12
-rw-r--r--gas/dw2gencfi.c31
-rw-r--r--gas/dw2gencfi.h9
-rw-r--r--gas/testsuite/gas/cfi/listing.l4
-rw-r--r--gas/testsuite/gas/cfi/listing.s4
5 files changed, 53 insertions, 7 deletions
diff --git a/gas/doc/as.texi b/gas/doc/as.texi
index edb498a..d68a9bc 100644
--- a/gas/doc/as.texi
+++ b/gas/doc/as.texi
@@ -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,
diff --git a/gas/dw2gencfi.c b/gas/dw2gencfi.c
index 45d2830..a21ae32 100644
--- a/gas/dw2gencfi.c
+++ b/gas/dw2gencfi.c
@@ -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;
}
diff --git a/gas/dw2gencfi.h b/gas/dw2gencfi.h
index c741f8f..fb1342a 100644
--- a/gas/dw2gencfi.h
+++ b/gas/dw2gencfi.h
@@ -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;
diff --git a/gas/testsuite/gas/cfi/listing.l b/gas/testsuite/gas/cfi/listing.l
index b30f114..3290fb6 100644
--- a/gas/testsuite/gas/cfi/listing.l
+++ b/gas/testsuite/gas/cfi/listing.l
@@ -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
diff --git a/gas/testsuite/gas/cfi/listing.s b/gas/testsuite/gas/cfi/listing.s
index 449ac89..6794f8a 100644
--- a/gas/testsuite/gas/cfi/listing.s
+++ b/gas/testsuite/gas/cfi/listing.s
@@ -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