[PATCH 1/3] s390: gas: Fix conversion of FP register names to DWARF register numbers

Jens Remus jremus@linux.ibm.com
Mon Jan 12 15:30:37 GMT 2026


The assembler supports register names in CFI directives.  For floating-
point (FP) registers f0..f15 the register numbers 0..15 are erroneously
converted to DWARF register numbers 16..31 by adding 16.  This is wrong
as the s390 64-bit (s390x) ELF ABI [1] specifies the DWARF register
numbers for the FP registers as follows:

  DWARF               BINARY    BINARY DWARF
  REGISTER  REGISTER  REGISTER  REGISTER
  NUMBER    NAME      NUMBER    NUMBER
  16        f0        0b0000 -> 0b10000
  17        f2        0b0010 -> 0b10001
  18        f4        0b0100 -> 0b10010
  19        f6        0b0110 -> 0b10011
  20        f1        0b0001 -> 0b10100
  21        f3        0b0011 -> 0b10101
  22        f5        0b0101 -> 0b10110
  23        f7        0b0111 -> 0b10111
  24        f8        0b1000 -> 0b11000
  25        f10       0b1010 -> 0b11001
  26        f12       0b1100 -> 0b11010
  27        f14       0b1110 -> 0b11011
  28        f9        0b1001 -> 0b11100
  29        f11       0b1011 -> 0b11101
  30        f13       0b1101 -> 0b11110
  31        f15       0b1111 -> 0b11111

Convert a FP register number (0..15) to its respective DWARF register
number (16..31) as follows:
Right rotate the least significant three bits and add 16.

Add a test case for the use of general register (GR; r0..r15) and
floating-point register (FPR; f0..f15) names in CFI directives.

[1]: s390x ELF ABI, https://github.com/IBM/s390x-abi/releases

gas/
	* config/tc-s390.c (tc_s390_regname_to_dw2regnum): Fix
	conversion of FP register names to DWARF register numbers.

gas/testsuite/
	* gas/s390/s390.exp (cfi-regnames, cfi-regnames-err): Run new
	tests.
	* gas/s390/cfi-regnames.d: New test for GR and FPR names in CFI
	directives.
	* gas/s390/cfi-regnames.s: Likewise.
	* gas/s390/cfi-regnames-err.l: Likewise.
	* gas/s390/cfi-regnames-err.s: Likewise.

Signed-off-by: Jens Remus <jremus@linux.ibm.com>
---
 gas/config/tc-s390.c                      | 12 +++++++-
 gas/testsuite/gas/s390/cfi-regnames-err.l |  8 +++++
 gas/testsuite/gas/s390/cfi-regnames-err.s |  9 ++++++
 gas/testsuite/gas/s390/cfi-regnames.d     | 36 +++++++++++++++++++++++
 gas/testsuite/gas/s390/cfi-regnames.s     | 33 +++++++++++++++++++++
 gas/testsuite/gas/s390/s390.exp           |  2 ++
 6 files changed, 99 insertions(+), 1 deletion(-)
 create mode 100644 gas/testsuite/gas/s390/cfi-regnames-err.l
 create mode 100644 gas/testsuite/gas/s390/cfi-regnames-err.s
 create mode 100644 gas/testsuite/gas/s390/cfi-regnames.d
 create mode 100644 gas/testsuite/gas/s390/cfi-regnames.s

diff --git a/gas/config/tc-s390.c b/gas/config/tc-s390.c
index 8f6bcfc2e84e..55cd43db3a16 100644
--- a/gas/config/tc-s390.c
+++ b/gas/config/tc-s390.c
@@ -2879,7 +2879,17 @@ tc_s390_regname_to_dw2regnum (char *regname)
     {
       regnum = reg_name_search (regname);
       if (regname[0] == 'f' && regnum != -1)
-        regnum += 16;
+	{
+	  /* Convert from floating-point register number (0..15)
+	   * to DWARF floating point register number (15..31):
+	   * Right rotate the least significant three bits and add 16.  */
+	  int dw2_regnum;
+	  dw2_regnum = (regnum & 0b110) >> 1;
+	  dw2_regnum |= (regnum & 0b1) << 2;
+	  dw2_regnum |= (regnum & 0b1000);
+	  dw2_regnum += 16;
+	  regnum = dw2_regnum;
+	}
     }
   else if (strcmp (regname, "ap") == 0)
     regnum = 32;
diff --git a/gas/testsuite/gas/s390/cfi-regnames-err.l b/gas/testsuite/gas/s390/cfi-regnames-err.l
new file mode 100644
index 000000000000..7944f9b78fcb
--- /dev/null
+++ b/gas/testsuite/gas/s390/cfi-regnames-err.l
@@ -0,0 +1,8 @@
+#name: s390/s390x register names in CFI directives errors
+.*: Assembler messages:
+# Invalid general register names
+.*:4: Error: bad register expression
+.*:5: Error: bad register expression
+# Invalid floating-point register names
+.*:7: Error: bad register expression
+.*:8: Error: bad register expression
diff --git a/gas/testsuite/gas/s390/cfi-regnames-err.s b/gas/testsuite/gas/s390/cfi-regnames-err.s
new file mode 100644
index 000000000000..55eae2cf1513
--- /dev/null
+++ b/gas/testsuite/gas/s390/cfi-regnames-err.s
@@ -0,0 +1,9 @@
+	.text
+	.cfi_startproc
+# Invalid general register names
+	.cfi_register r0, r16
+	.cfi_register %r0, %r16
+# Invalid floating-point register names
+	.cfi_register f0, f16
+	.cfi_register %f0, %f16
+	.cfi_endproc
diff --git a/gas/testsuite/gas/s390/cfi-regnames.d b/gas/testsuite/gas/s390/cfi-regnames.d
new file mode 100644
index 000000000000..8e4740587350
--- /dev/null
+++ b/gas/testsuite/gas/s390/cfi-regnames.d
@@ -0,0 +1,36 @@
+#name: s390/s390x register names in CFI directives
+#objdump: -Wf
+
+.*: +file format .*
+
+Contents of the .eh_frame section:
+
+#...
+
+# General register (GR) names r0..r15
+00000018 0000000000000028 0000001c FDE cie=00000000 pc=0000000000000000..0000000000000004
+  DW_CFA_advance_loc: 2 to 0000000000000002
+  DW_CFA_register: r0 in r1
+  DW_CFA_register: r2 in r3
+  DW_CFA_register: r4 in r5
+  DW_CFA_register: r6 in r7
+  DW_CFA_register: r8 in r9
+  DW_CFA_register: r10 in r11
+  DW_CFA_register: r12 in r13
+  DW_CFA_register: r14 in r15
+  DW_CFA_nop
+  DW_CFA_nop
+
+# Floating-point register (FPR) names f0..f15
+00000044 0000000000000028 00000048 FDE cie=00000000 pc=0000000000000004..0000000000000008
+  DW_CFA_advance_loc: 2 to 0000000000000006
+  DW_CFA_register: r16 \(f0\) in r20 \(f1\)
+  DW_CFA_register: r17 \(f2\) in r21 \(f3\)
+  DW_CFA_register: r18 \(f4\) in r22 \(f5\)
+  DW_CFA_register: r19 \(f6\) in r23 \(f7\)
+  DW_CFA_register: r24 \(f8\) in r28 \(f9\)
+  DW_CFA_register: r25 \(f10\) in r29 \(f11\)
+  DW_CFA_register: r26 \(f12\) in r30 \(f13\)
+  DW_CFA_register: r27 \(f14\) in r31 \(f15\)
+  DW_CFA_nop
+  DW_CFA_nop
diff --git a/gas/testsuite/gas/s390/cfi-regnames.s b/gas/testsuite/gas/s390/cfi-regnames.s
new file mode 100644
index 000000000000..cd11d4da450f
--- /dev/null
+++ b/gas/testsuite/gas/s390/cfi-regnames.s
@@ -0,0 +1,33 @@
+	.text
+# General register (GR) names r0..r15
+	.type gr, @function
+gr:
+	.cfi_startproc
+	.word 0
+	.cfi_register r0, r1
+	.cfi_register r2, r3
+	.cfi_register r4, r5
+	.cfi_register r6, r7
+	.cfi_register r8, r9
+	.cfi_register r10, r11
+	.cfi_register r12, r13
+	.cfi_register r14, r15
+	.word 0
+	.cfi_endproc
+	.size gr, .-gr
+# Floating-point register (FPR) names f0..f15
+	.type fpr, @function
+fpr:
+	.cfi_startproc
+	.word 0
+	.cfi_register f0, f1
+	.cfi_register f2, f3
+	.cfi_register f4, f5
+	.cfi_register f6, f7
+	.cfi_register f8, f9
+	.cfi_register f10, f11
+	.cfi_register f12, f13
+	.cfi_register f14, f15
+	.word 0
+	.cfi_endproc
+	.size fpr, .-fpr
diff --git a/gas/testsuite/gas/s390/s390.exp b/gas/testsuite/gas/s390/s390.exp
index 1d5d97f48631..49876aa00e33 100644
--- a/gas/testsuite/gas/s390/s390.exp
+++ b/gas/testsuite/gas/s390/s390.exp
@@ -64,4 +64,6 @@ if [expr [istarget "s390-*-*"] ||  [istarget "s390x-*-*"]]  then {
     run_list_test "zarch-warn-areg-zero" "-m64 -mwarn-areg-zero"
     run_list_test "zarch-warn-regtype-mismatch-strict" "-m64 -mwarn-regtype-mismatch=strict"
     run_list_test "zarch-warn-regtype-mismatch-relaxed" "-m64 -mwarn-regtype-mismatch=relaxed"
+    run_dump_test "cfi-regnames" ""
+    run_list_test "cfi-regnames-err" ""
 }
-- 
2.51.0



More information about the Binutils mailing list