[PATCH 1/4] LoongArch: Initial support to generate .sframe from CFI directives in assembler

Huang Pei huangpei@loongson.cn
Thu Sep 25 12:48:28 GMT 2025


This introduces initial support to generate .sframe from CFI directives
in assembler on LoongArch 64-bit. There are two remaining issues:

- LoongArch ELF ABI say nothing about stack backtrace based on
frame-pointer(FP), so there is same limitation as s390x that FP is saved
on stack but RA not saved

- LoongArch ELF ABI say nothing about using float point register or
other integer register to save SP/FP/RA(but the ISA support it), but
DRAP need to save the original SP into caller-saved register, when
aligned to the new position. Since DRAP is delayed till SFrame V3, just
leave it some time.

Later patches will solve the Issue one.

include/
	* sframe.h: Add loongarch architecture.
	(SFRAME_ABI_LOONGARCH_ENDIAN_LITTLE): Define SFrame arch/ABI
	identifier for LoongArch.

libsframe/
	* sframe.c: no swapping.

gas/config/
	* tc-loongarch.h: loongarch support to generate .sframe from CFI
	directives in assembler.
	(support_sframe_p): Define.
	(SFRAME_CFA_SP_REG, SFRAME_CFA_FP_REG, SFRAME_CFA_RA_REG):
	Define.
	(sframe_ra_tracking_p): Define.
	(sframe_cfa_rg_offset): Define.
	(sframe_get_abi_arch): Define.
	* tc-loongarch.c: loongarch support to generate .sframe from CFI
	directives in assembler.
	(loongarch_sframe_cfa_sp_reg, loongarch_sframe_fp_reg,
	loongarch_sframe_ra_reg): New. Initialize to DWARF register
	numbers f stack pointer(SP, r3), frame pointer(FP, r22) and
	return address register(RA, r1).
	(loongarch_support_sframe_p): New function. Return true.
	(loongarch_sframe_cfa_ra_offset): New Function. Return
	SFRAME_CFA_FIXED_RA_INVALID).
	(loongarch_sframe_get_abi_arch): New function. Return
	SFRAME_ABI_LOONGARCH_ENDIAN_LITTLE.

gas/testsuite/gas/cfi-sframe/
	* cfi-sframe.exp: Enable common SFrame tests for loongarch. Add
	loongarch-specific SFrame (error) tests.
	* cfi-sframe-loongarch-1.d: New loongarch-specific SFrame test.
	* cfi-sframe-loongarch-1.s: Likewise.
	* cfi-sframe-loongarch-2.d: Likewise.
	* cfi-sframe-loongarch-2.s: Likewise.
	* cfi-sframe-loongarch-3.d: Likewise.
	* cfi-sframe-loongarch-3.d: Likewise.
	* cfi-sframe-loongarch-err-1.d: New Loongarch-specific SFrame
	  error test that FP is saved on stack without RA saved.
	* cfi-sframe-loongarch-err-1.s: Likewise.

gas/testsuite/cfi-sframe/
	* cfi-sframe-loongarch-err-1.s: Rename to ...
	* cfi-sframe-loongarch-err-1.d: Deleted.
	* cfi-sframe-loongarch-4.d: New test for representing FP without
	RA saved in SFrame.

Signed-off-by: Huang Pei <huangpei@loongson.cn>
---
 gas/config/tc-loongarch.c                     | 48 ++++++++++++++
 gas/config/tc-loongarch.h                     | 28 +++++++++
 .../gas/cfi-sframe/cfi-sframe-loongarch-1.d   | 21 +++++++
 .../gas/cfi-sframe/cfi-sframe-loongarch-1.s   | 45 ++++++++++++++
 .../gas/cfi-sframe/cfi-sframe-loongarch-2.d   | 23 +++++++
 .../gas/cfi-sframe/cfi-sframe-loongarch-2.s   | 50 +++++++++++++++
 .../gas/cfi-sframe/cfi-sframe-loongarch-3.d   | 25 ++++++++
 .../gas/cfi-sframe/cfi-sframe-loongarch-3.s   | 62 +++++++++++++++++++
 .../cfi-sframe/cfi-sframe-loongarch-err-1.d   | 15 +++++
 .../cfi-sframe/cfi-sframe-loongarch-err-1.s   | 62 +++++++++++++++++++
 gas/testsuite/gas/cfi-sframe/cfi-sframe.exp   | 10 ++-
 include/sframe.h                              |  1 +
 .../ld-loongarch-elf/ld-loongarch-elf.exp     |  4 ++
 ld/testsuite/ld-loongarch-elf/sframe-bar.s    | 17 +++++
 ld/testsuite/ld-loongarch-elf/sframe-foo.s    |  8 +++
 .../ld-loongarch-elf/sframe-simple-1.d        | 27 ++++++++
 libsframe/sframe.c                            |  1 +
 17 files changed, 446 insertions(+), 1 deletion(-)
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-1.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-2.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-2.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-3.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-3.s
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-err-1.d
 create mode 100644 gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-err-1.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/sframe-bar.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/sframe-foo.s
 create mode 100644 ld/testsuite/ld-loongarch-elf/sframe-simple-1.d

diff --git a/gas/config/tc-loongarch.c b/gas/config/tc-loongarch.c
index 4593f06614a..4ce7bc409f4 100644
--- a/gas/config/tc-loongarch.c
+++ b/gas/config/tc-loongarch.c
@@ -27,6 +27,8 @@
 #include "opcode/loongarch.h"
 #include "obj-elf.h"
 #include "bfd/elfxx-loongarch.h"
+#include "sframe.h"
+#include "gen-sframe.h"
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
@@ -118,6 +120,11 @@ static const char default_arch[] = DEFAULT_ARCH;
 
 static bool call36 = 0;
 
+unsigned int loongarch_sframe_cfa_sp_reg;
+/* The other CFA base register for SFrame stack trace info.  */
+unsigned int loongarch_sframe_cfa_ra_reg;
+unsigned int loongarch_sframe_cfa_fp_reg;
+
 /* The lowest 4-bit is the bytes of instructions.  */
 #define RELAX_BRANCH_16 0xc0000014
 #define RELAX_BRANCH_21 0xc0000024
@@ -512,6 +519,9 @@ md_begin ()
 
   align_hash = htab_create (10, align_sec_sym_hash, align_sec_sym_eq, free);
 
+  loongarch_sframe_cfa_sp_reg = 3;
+  loongarch_sframe_cfa_fp_reg = 22;
+  loongarch_sframe_cfa_ra_reg = 1;
   /* FIXME: expressionS use 'offsetT' as constant,
    * we want this is 64-bit type.  */
   assert (8 <= sizeof (offsetT));
@@ -1900,6 +1910,44 @@ tc_gen_reloc (asection *section ATTRIBUTE_UNUSED, fixS *fixp)
   return reloc;
 }
 
+/* Whether SFrame stack trace info is supported.  */
+
+bool
+loongarch_support_sframe_p (void)
+{
+  /* At this time, SFrame is supported for all LoongArch ABI, since
+   * there is *Only One* calling convention */
+  return true;
+}
+
+/* Whether SFrame return address tracking is needed.  */
+
+bool
+loongarch_sframe_ra_tracking_p (void)
+{
+  /* LoongArch ABI *Does Not* specify the position of RA in call
+   * frame */
+  return true;
+}
+
+/* The fixed offset from CFA for SFrame to recover the return address.
+   (useful only when SFrame RA tracking is not needed).  */
+
+offsetT
+loongarch_sframe_cfa_ra_offset (void)
+{
+  return (offsetT) SFRAME_CFA_FIXED_RA_INVALID;
+}
+
+/* Get the abi/arch identifier for SFrame.  */
+
+unsigned char
+loongarch_sframe_get_abi_arch (void)
+{
+
+  return SFRAME_ABI_LOONGARCH_ENDIAN_LITTLE;
+}
+
 /* Standard calling conventions leave the CFA at SP on entry.  */
 void
 loongarch_cfi_frame_initial_instructions (void)
diff --git a/gas/config/tc-loongarch.h b/gas/config/tc-loongarch.h
index 38ecd036d34..ea13f390b61 100644
--- a/gas/config/tc-loongarch.h
+++ b/gas/config/tc-loongarch.h
@@ -148,4 +148,32 @@ struct reloc_info
 #define md_finish loongarch_md_finish
 extern void loongarch_md_finish (void);
 
+/* Whether SFrame stack trace info is supported.  */
+extern bool loongarch_support_sframe_p (void);
+#define support_sframe_p loongarch_support_sframe_p
+
+/* The stack pointer DWARF register number for SFrame CFA tracking.  */
+extern unsigned int loongarch_sframe_cfa_sp_reg;
+#define SFRAME_CFA_SP_REG loongarch_sframe_cfa_sp_reg
+
+/* The frame pointer DWARF register number for SFrame CFA and FP tracking.  */
+extern unsigned int loongarch_sframe_cfa_fp_reg;
+#define SFRAME_CFA_FP_REG loongarch_sframe_cfa_fp_reg
+
+/* The return address DWARF register number for SFrame RA tracking.  */
+extern unsigned int loongarch_sframe_cfa_ra_reg;
+#define SFRAME_CFA_RA_REG loongarch_sframe_cfa_ra_reg
+
+/* Whether SFrame return address tracking is needed.  */
+extern bool loongarch_sframe_ra_tracking_p (void);
+#define sframe_ra_tracking_p loongarch_sframe_ra_tracking_p
+
+/* The fixed offset from CFA for SFrame to recover the return address.
+   (useful only when SFrame RA tracking is not needed).  */
+extern offsetT loongarch_sframe_cfa_ra_offset (void);
+#define sframe_cfa_ra_offset loongarch_sframe_cfa_ra_offset
+
+/* The abi/arch identifier for SFrame.  */
+unsigned char loongarch_sframe_get_abi_arch (void);
+#define sframe_get_abi_arch loongarch_sframe_get_abi_arch
 #endif
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-1.d
new file mode 100644
index 00000000000..24a2f857c61
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-1.d
@@ -0,0 +1,21 @@
+#name: SFrame generation on loongarch -- Only CFA
+#as: --gsframe
+#objdump: --sframe=.sframe
+#...
+
+Contents of the SFrame section .sframe:
+  Header :
+
+    Version: SFRAME_VERSION_2
+    Flags: SFRAME_F_FDE_FUNC_START_PCREL
+    Num FDEs: 1
+    Num FREs: 3
+
+  Function Index :
+
+    func idx \[0\]: pc = 0x0, size = 88 bytes
+    STARTPC +CFA +FP +RA +
+    0+0000 +sp\+0 +u +u +
+    0+0004 +sp\+96 +u +u +
+    0+0054 +sp\+0 +u +u +
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-1.s
new file mode 100644
index 00000000000..f04f5409fb0
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-1.s
@@ -0,0 +1,45 @@
+        .cfi_sections .sframe
+	.cfi_startproc
+	addi.d	$r3, $r3, -96
+	.cfi_def_cfa_offset 96
+	st.d	$r23, $r3, 88
+	st.d	$r24, $r3, 80
+	st.d	$r25, $r3, 72
+	st.d	$r26, $r3, 64
+	st.d	$r27, $r3, 56
+	st.d	$r28, $r3, 48
+	st.d	$r29, $r3, 40
+	st.d	$r30, $r3, 32
+	st.d	$r31, $r3, 24
+	.cfi_offset 23, -8
+	.cfi_offset 24, -16
+	.cfi_offset 25, -24
+	.cfi_offset 26, -32
+	.cfi_offset 27, -40
+	.cfi_offset 28, -48
+	.cfi_offset 29, -56
+	.cfi_offset 30, -64
+	.cfi_offset 31, -72
+	nop
+	ld.d	$r31, $r3, 24
+	ld.d	$r30, $r3, 32
+	ld.d	$r29, $r3, 40
+	ld.d	$r28, $r3, 48
+	ld.d	$r27, $r3, 56
+	ld.d	$r26, $r3, 64
+	ld.d	$r25, $r3, 72
+	ld.d	$r24, $r3, 80
+	ld.d	$r23, $r3, 88
+	.cfi_restore 31
+	.cfi_restore 30
+	.cfi_restore 29
+	.cfi_restore 28
+	.cfi_restore 27
+	.cfi_restore 26
+	.cfi_restore 25
+	.cfi_restore 24
+	.cfi_restore 23
+	addi.d	$r3, $r3, 96
+	.cfi_def_cfa_offset 0
+	ret
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-2.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-2.d
new file mode 100644
index 00000000000..8d59d67db51
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-2.d
@@ -0,0 +1,23 @@
+#name: SFrame generation on loongarch -- RA without FP
+#as: --gsframe
+#objdump: --sframe=.sframe
+#...
+
+Contents of the SFrame section .sframe:
+  Header :
+
+    Version: SFRAME_VERSION_2
+    Flags: SFRAME_F_FDE_FUNC_START_PCREL
+    Num FDEs: 1
+    Num FREs: 5
+
+  Function Index :
+
+    func idx \[0\]: pc = 0x0, size = 100 bytes
+    STARTPC +CFA +FP +RA +
+    0+0000 +sp\+0 +u +u +
+    0+0004 +sp\+96 +u +u +
+    0+002c +sp\+96 +u +c\-8 +
+    0+005c +sp\+96 +u +u +
+    0+0060 +sp\+0 +u +u +
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-2.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-2.s
new file mode 100644
index 00000000000..b6dcf3d442b
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-2.s
@@ -0,0 +1,50 @@
+        .cfi_sections .sframe
+	.cfi_startproc
+	addi.d	$r3, $r3, -96
+	.cfi_def_cfa_offset 96
+	st.d	$r1, $r3, 88
+	st.d	$r23, $r3, 80
+	st.d	$r24, $r3, 72
+	st.d	$r25, $r3, 64
+	st.d	$r26, $r3, 56
+	st.d	$r27, $r3, 48
+	st.d	$r28, $r3, 40
+	st.d	$r29, $r3, 32
+	st.d	$r30, $r3, 24
+	st.d	$r31, $r3, 16
+	.cfi_offset 1, -8
+	.cfi_offset 23, -16
+	.cfi_offset 24, -24
+	.cfi_offset 25, -32
+	.cfi_offset 26, -40
+	.cfi_offset 27, -48
+	.cfi_offset 28, -56
+	.cfi_offset 29, -64
+	.cfi_offset 30, -72
+	.cfi_offset 31, -80
+	nop
+	ld.d	$r31, $r3, 8
+	ld.d	$r30, $r3, 16
+	ld.d	$r29, $r3, 24
+	ld.d	$r28, $r3, 32
+	ld.d	$r27, $r3, 40
+	ld.d	$r26, $r3, 48
+	ld.d	$r25, $r3, 56
+	ld.d	$r24, $r3, 64
+	ld.d	$r23, $r3, 72
+	ld.d	$r22, $r3, 80
+	ld.d	$r1, $r3, 88
+	.cfi_restore 31
+	.cfi_restore 30
+	.cfi_restore 29
+	.cfi_restore 28
+	.cfi_restore 27
+	.cfi_restore 26
+	.cfi_restore 25
+	.cfi_restore 24
+	.cfi_restore 23
+	.cfi_restore 1
+	addi.d	$r3, $r3, 96
+	.cfi_def_cfa_offset 0
+	ret
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-3.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-3.d
new file mode 100644
index 00000000000..9945b20a9f9
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-3.d
@@ -0,0 +1,25 @@
+#name: SFrame generation on loongarch -- RA and FP with alloca
+#as: --gsframe
+#objdump: --sframe=.sframe
+#...
+
+Contents of the SFrame section .sframe:
+  Header :
+
+    Version: SFRAME_VERSION_2
+    Flags: SFRAME_F_FDE_FUNC_START_PCREL
+    Num FDEs: 1
+    Num FREs: 7
+
+  Function Index :
+
+    func idx \[0\]: pc = 0x0, size = 124 bytes
+    STARTPC +CFA +FP +RA +
+    0+0000 +sp\+0 +u +u +
+    0+0004 +sp\+96 +u +u +
+    0+0030 +sp\+96 +c\-16 +c\-8 +
+    0+0038 +fp\+96 +c\-16 +c\-8 +
+    0+0048 +sp\+96 +c\-16 +c\-8 +
+    0+0074 +sp\+96 +u +u +
+    0+0078 +sp\+0 +u +u +
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-3.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-3.s
new file mode 100644
index 00000000000..f257f26f157
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-3.s
@@ -0,0 +1,62 @@
+        .cfi_sections .sframe
+	.cfi_startproc
+	addi.d	$r3, $r3, -96
+	.cfi_def_cfa_offset 96
+	st.d	$r1, $r3, 88
+	st.d	$r22, $r3, 80
+	st.d	$r23, $r3, 72
+	st.d	$r24, $r3, 64
+	st.d	$r25, $r3, 56
+	st.d	$r26, $r3, 48
+	st.d	$r27, $r3, 40
+	st.d	$r28, $r3, 32
+	st.d	$r29, $r3, 24
+	st.d	$r30, $r3, 16
+	st.d	$r31, $r3, 8
+	.cfi_offset 1, -8
+	.cfi_offset 22, -16
+	.cfi_offset 23, -24
+	.cfi_offset 24, -32
+	.cfi_offset 25, -40
+	.cfi_offset 26, -48
+	.cfi_offset 27, -56
+	.cfi_offset 28, -64
+	.cfi_offset 29, -72
+	.cfi_offset 30, -80
+	.cfi_offset 31, -88
+	nop
+	move	$r22, $r3
+	.cfi_def_cfa_register 22
+
+	addi.d	$r5, $r5, 15
+	bstrins.d $r5, $r0, 3, 0
+	sub.d	$r3, $r3, $r5
+
+	move	$r3, $r22
+	.cfi_def_cfa_register 3
+	ld.d	$r31, $r3, 8
+	ld.d	$r30, $r3, 16
+	ld.d	$r29, $r3, 24
+	ld.d	$r28, $r3, 32
+	ld.d	$r27, $r3, 40
+	ld.d	$r26, $r3, 48
+	ld.d	$r25, $r3, 56
+	ld.d	$r24, $r3, 64
+	ld.d	$r23, $r3, 72
+	ld.d	$r22, $r3, 80
+	ld.d	$r1, $r3, 88
+	.cfi_restore 31
+	.cfi_restore 30
+	.cfi_restore 29
+	.cfi_restore 28
+	.cfi_restore 27
+	.cfi_restore 26
+	.cfi_restore 25
+	.cfi_restore 24
+	.cfi_restore 23
+	.cfi_restore 22
+	.cfi_restore 1
+	addi.d	$r3, $r3, 96
+	.cfi_def_cfa_offset 0
+	ret
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-err-1.d b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-err-1.d
new file mode 100644
index 00000000000..a62e56cc4a1
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-err-1.d
@@ -0,0 +1,15 @@
+#name: SFrame generation on loongarch -- FP without RA saved in register
+#as: --gsframe
+#warning: FP without RA on stack
+#objdump: --sframe=.sframe
+#...
+
+Contents of the SFrame section .sframe:
+  Header :
+
+    Version: SFRAME_VERSION_2
+    Flags: SFRAME_F_FDE_FUNC_START_PCREL
+    Num FDEs: 0
+    Num FREs: 0
+
+#pass
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-err-1.s b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-err-1.s
new file mode 100644
index 00000000000..8d304c29bbd
--- /dev/null
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe-loongarch-err-1.s
@@ -0,0 +1,62 @@
+        .cfi_sections .sframe
+	.cfi_startproc
+	addi.d	$r3, $r3, -96
+	.cfi_def_cfa_offset 96
+	#st.d	$r1, $r3, 88
+	st.d	$r22, $r3, 80
+	st.d	$r23, $r3, 72
+	st.d	$r24, $r3, 64
+	st.d	$r25, $r3, 56
+	st.d	$r26, $r3, 48
+	st.d	$r27, $r3, 40
+	st.d	$r28, $r3, 32
+	st.d	$r29, $r3, 24
+	st.d	$r30, $r3, 16
+	st.d	$r31, $r3, 8
+	#.cfi_offset 1, -8
+	.cfi_offset 22, -16
+	.cfi_offset 23, -24
+	.cfi_offset 24, -32
+	.cfi_offset 25, -40
+	.cfi_offset 26, -48
+	.cfi_offset 27, -56
+	.cfi_offset 28, -64
+	.cfi_offset 29, -72
+	.cfi_offset 30, -80
+	.cfi_offset 31, -88
+	nop
+	move	$r22, $r3
+	.cfi_def_cfa_register 22
+
+	addi.d	$r5, $r5, 15
+	bstrins.d $r5, $r0, 3, 0
+	sub.d	$r3, $r3, $r5
+
+	move	$r3, $r22
+	.cfi_def_cfa_register 3
+	ld.d	$r31, $r3, 8
+	ld.d	$r30, $r3, 16
+	ld.d	$r29, $r3, 24
+	ld.d	$r28, $r3, 32
+	ld.d	$r27, $r3, 40
+	ld.d	$r26, $r3, 48
+	ld.d	$r25, $r3, 56
+	ld.d	$r24, $r3, 64
+	ld.d	$r23, $r3, 72
+	ld.d	$r22, $r3, 80
+	#ld.d	$r1, $r3, 88
+	.cfi_restore 31
+	.cfi_restore 30
+	.cfi_restore 29
+	.cfi_restore 28
+	.cfi_restore 27
+	.cfi_restore 26
+	.cfi_restore 25
+	.cfi_restore 24
+	.cfi_restore 23
+	.cfi_restore 22
+	#.cfi_restore 1
+	addi.d	$r3, $r3, 96
+	.cfi_def_cfa_offset 0
+	ret
+	.cfi_endproc
diff --git a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
index 9380c98fc3d..6509713974f 100644
--- a/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
+++ b/gas/testsuite/gas/cfi-sframe/cfi-sframe.exp
@@ -28,7 +28,7 @@ proc gas_x86_64_check { } {
 
 # common tests
 if  { ([istarget "x86_64-*-*"] || [istarget "aarch64*-*-*"]
-       || [istarget "s390x-*-*"]) \
+       || [istarget "s390x-*-*"] || [istarget "loongarch64-*-*"]) \
       && [gas_sframe_check] } then {
 
     global ASFLAGS
@@ -90,3 +90,11 @@ if { [istarget "s390x*-*-*"] && [gas_sframe_check] } then {
     run_dump_test "cfi-sframe-s390x-fpra-register-1"
     run_dump_test "cfi-sframe-s390x-fpra-register-2"
 }
+
+# loongarch specific tests
+if { [istarget "loongarch64-*-*"] && [gas_sframe_check] } then {
+    run_dump_test "cfi-sframe-loongarch-1"
+    run_dump_test "cfi-sframe-loongarch-2"
+    run_dump_test "cfi-sframe-loongarch-3"
+    run_dump_test "cfi-sframe-loongarch-err-1"
+}
diff --git a/include/sframe.h b/include/sframe.h
index 7523adbef3a..65fc33aafe6 100644
--- a/include/sframe.h
+++ b/include/sframe.h
@@ -105,6 +105,7 @@ extern "C"
 #define SFRAME_ABI_AARCH64_ENDIAN_LITTLE   2 /* AARCH64 little endian.  */
 #define SFRAME_ABI_AMD64_ENDIAN_LITTLE     3 /* AMD64 little endian.  */
 #define SFRAME_ABI_S390X_ENDIAN_BIG        4 /* s390x big endian.  */
+#define SFRAME_ABI_LOONGARCH_ENDIAN_LITTLE 5 /* loongarch little endian.  */
 
 /* SFrame FRE types.  */
 #define SFRAME_FRE_TYPE_ADDR1	0
diff --git a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
index a33727f2efd..984367796f2 100644
--- a/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
+++ b/ld/testsuite/ld-loongarch-elf/ld-loongarch-elf.exp
@@ -240,5 +240,9 @@ if [istarget "loongarch64-*-*"] {
   run_dump_test "provide_abs"
   run_dump_test "provide_noabs"
 
+  if { ![skip_sframe_tests] } {
+    run_dump_test "sframe-simple-1"
+  }
+
 }
 
diff --git a/ld/testsuite/ld-loongarch-elf/sframe-bar.s b/ld/testsuite/ld-loongarch-elf/sframe-bar.s
new file mode 100644
index 00000000000..739d4dd8a92
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/sframe-bar.s
@@ -0,0 +1,17 @@
+	.text
+	.globl	bar
+	.type	bar, @function
+bar:
+	.cfi_startproc
+	addi.d	$r3, $r3, -64
+	.cfi_def_cfa_offset 64
+	st.d	$r1, $r3, 56
+	.cfi_offset 1, -8
+
+	bl	%plt(foo)
+
+	ld.d	$r1, $r3, 56
+	.cfi_restore 1
+	addi.d	$r3, $r3, 64
+	.cfi_def_cfa_offset 0
+	.cfi_endproc
diff --git a/ld/testsuite/ld-loongarch-elf/sframe-foo.s b/ld/testsuite/ld-loongarch-elf/sframe-foo.s
new file mode 100644
index 00000000000..cdc36a5bb61
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/sframe-foo.s
@@ -0,0 +1,8 @@
+	.text
+	.globl	foo
+	.type	foo, @function
+foo:
+	.cfi_startproc
+	move	$a0, $zero
+	ret
+	.cfi_endproc
diff --git a/ld/testsuite/ld-loongarch-elf/sframe-simple-1.d b/ld/testsuite/ld-loongarch-elf/sframe-simple-1.d
new file mode 100644
index 00000000000..1ae73de2828
--- /dev/null
+++ b/ld/testsuite/ld-loongarch-elf/sframe-simple-1.d
@@ -0,0 +1,27 @@
+#as: --gsframe
+#source: sframe-foo.s
+#source: sframe-bar.s
+#objdump: --sframe=.sframe
+#ld: -shared
+#name: SFrame simple link
+
+.*:     file format .*
+
+Contents of the SFrame section .sframe:
+  Header :
+
+    Version: SFRAME_VERSION_2
+    Flags: SFRAME_F_FDE_SORTED,
+           SFRAME_F_FDE_FUNC_START_PCREL
+    Num FDEs: 2
+    Num FREs: 2
+
+  Function Index :
+
+#...
+    STARTPC +CFA +FP +RA +
+    0+[0-9a-f]+ +sp\+0 +u +u +
+
+#...
+    STARTPC +CFA +FP +RA +
+    0+[0-9a-f]+ +sp\+0 +u +u +
diff --git a/libsframe/sframe.c b/libsframe/sframe.c
index 85500791f8a..c064b722d23 100644
--- a/libsframe/sframe.c
+++ b/libsframe/sframe.c
@@ -164,6 +164,7 @@ need_swapping (int endian)
     {
       case SFRAME_ABI_AARCH64_ENDIAN_LITTLE:
       case SFRAME_ABI_AMD64_ENDIAN_LITTLE:
+      case SFRAME_ABI_LOONGARCH_ENDIAN_LITTLE:
 	return !is_little;
       case SFRAME_ABI_AARCH64_ENDIAN_BIG:
       case SFRAME_ABI_S390X_ENDIAN_BIG:
-- 
2.45.2



More information about the Binutils mailing list