The vdso32 sigreturn.S contains open-coded DWARF bytecode, which
includes a hack for gdb to not try to step back to a previous call
instruction when backtracing from a signal handler.
Neither of those are necessary anymore: the backtracing issue is
handled by ".cfi_entry simple" and ".cfi_signal_frame", both of which
have been supported for a very long time now, which allows the
remaining frame to be built using regular .cfi annotations.
Add a few more register offsets to the signal frame just for good
measure.
Replace the nop on fallthrough of the system call (which should never,
ever happen) with a ud2a trap.
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
---
arch/x86/entry/vdso/vdso32/sigreturn.S | 146 ++++++-------------------
arch/x86/include/asm/dwarf2.h | 1 +
arch/x86/kernel/asm-offsets.c | 6 +
3 files changed, 39 insertions(+), 114 deletions(-)
diff --git a/arch/x86/entry/vdso/vdso32/sigreturn.S b/arch/x86/entry/vdso/vdso32/sigreturn.S
index 965900c6763b..25b0ac4b4bfe 100644
--- a/arch/x86/entry/vdso/vdso32/sigreturn.S
+++ b/arch/x86/entry/vdso/vdso32/sigreturn.S
@@ -1,136 +1,54 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/linkage.h>
#include <asm/unistd_32.h>
+#include <asm/dwarf2.h>
#include <asm/asm-offsets.h>
+.macro STARTPROC_SIGNAL_FRAME sc
+ CFI_STARTPROC simple
+ CFI_SIGNAL_FRAME
+ /* -4 as pretcode has already been popped */
+ CFI_DEF_CFA esp, \sc - 4
+ CFI_OFFSET eip, IA32_SIGCONTEXT_ip
+ CFI_OFFSET eax, IA32_SIGCONTEXT_ax
+ CFI_OFFSET ebx, IA32_SIGCONTEXT_bx
+ CFI_OFFSET ecx, IA32_SIGCONTEXT_cx
+ CFI_OFFSET edx, IA32_SIGCONTEXT_dx
+ CFI_OFFSET esp, IA32_SIGCONTEXT_sp
+ CFI_OFFSET ebp, IA32_SIGCONTEXT_bp
+ CFI_OFFSET esi, IA32_SIGCONTEXT_si
+ CFI_OFFSET edi, IA32_SIGCONTEXT_di
+ CFI_OFFSET es, IA32_SIGCONTEXT_es
+ CFI_OFFSET cs, IA32_SIGCONTEXT_cs
+ CFI_OFFSET ss, IA32_SIGCONTEXT_ss
+ CFI_OFFSET ds, IA32_SIGCONTEXT_ds
+ CFI_OFFSET eflags, IA32_SIGCONTEXT_flags
+.endm
+
.text
.globl __kernel_sigreturn
.type __kernel_sigreturn,@function
- nop /* this guy is needed for .LSTARTFDEDLSI1 below (watch for HACK) */
ALIGN
__kernel_sigreturn:
-.LSTART_sigreturn:
- popl %eax /* XXX does this mean it needs unwind info? */
+ STARTPROC_SIGNAL_FRAME IA32_SIGFRAME_sigcontext
+ popl %eax
+ CFI_ADJUST_CFA_OFFSET -4
movl $__NR_sigreturn, %eax
int $0x80
-.LEND_sigreturn:
SYM_INNER_LABEL(vdso32_sigreturn_landing_pad, SYM_L_GLOBAL)
- nop
- .size __kernel_sigreturn,.-.LSTART_sigreturn
+ ud2a
+ CFI_ENDPROC
+ .size __kernel_sigreturn,.-__kernel_sigreturn
.globl __kernel_rt_sigreturn
.type __kernel_rt_sigreturn,@function
ALIGN
__kernel_rt_sigreturn:
-.LSTART_rt_sigreturn:
+ STARTPROC_SIGNAL_FRAME IA32_RT_SIGFRAME_sigcontext
movl $__NR_rt_sigreturn, %eax
int $0x80
-.LEND_rt_sigreturn:
SYM_INNER_LABEL(vdso32_rt_sigreturn_landing_pad, SYM_L_GLOBAL)
- nop
- .size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn
- .previous
-
- .section .eh_frame,"a",@progbits
-.LSTARTFRAMEDLSI1:
- .long .LENDCIEDLSI1-.LSTARTCIEDLSI1
-.LSTARTCIEDLSI1:
- .long 0 /* CIE ID */
- .byte 1 /* Version number */
- .string "zRS" /* NUL-terminated augmentation string */
- .uleb128 1 /* Code alignment factor */
- .sleb128 -4 /* Data alignment factor */
- .byte 8 /* Return address register column */
- .uleb128 1 /* Augmentation value length */
- .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
- .byte 0 /* DW_CFA_nop */
- .align 4
-.LENDCIEDLSI1:
- .long .LENDFDEDLSI1-.LSTARTFDEDLSI1 /* Length FDE */
-.LSTARTFDEDLSI1:
- .long .LSTARTFDEDLSI1-.LSTARTFRAMEDLSI1 /* CIE pointer */
- /* HACK: The dwarf2 unwind routines will subtract 1 from the
- return address to get an address in the middle of the
- presumed call instruction. Since we didn't get here via
- a call, we need to include the nop before the real start
- to make up for it. */
- .long .LSTART_sigreturn-1-. /* PC-relative start address */
- .long .LEND_sigreturn-.LSTART_sigreturn+1
- .uleb128 0 /* Augmentation */
- /* What follows are the instructions for the table generation.
- We record the locations of each register saved. This is
- complicated by the fact that the "CFA" is always assumed to
- be the value of the stack pointer in the caller. This means
- that we must define the CFA of this body of code to be the
- saved value of the stack pointer in the sigcontext. Which
- also means that there is no fixed relation to the other
- saved registers, which means that we must use DW_CFA_expression
- to compute their addresses. It also means that when we
- adjust the stack with the popl, we have to do it all over again. */
-
-#define do_cfa_expr(offset) \
- .byte 0x0f; /* DW_CFA_def_cfa_expression */ \
- .uleb128 1f-0f; /* length */ \
-0: .byte 0x74; /* DW_OP_breg4 */ \
- .sleb128 offset; /* offset */ \
- .byte 0x06; /* DW_OP_deref */ \
-1:
-
-#define do_expr(regno, offset) \
- .byte 0x10; /* DW_CFA_expression */ \
- .uleb128 regno; /* regno */ \
- .uleb128 1f-0f; /* length */ \
-0: .byte 0x74; /* DW_OP_breg4 */ \
- .sleb128 offset; /* offset */ \
-1:
-
- do_cfa_expr(IA32_SIGCONTEXT_sp+4)
- do_expr(0, IA32_SIGCONTEXT_ax+4)
- do_expr(1, IA32_SIGCONTEXT_cx+4)
- do_expr(2, IA32_SIGCONTEXT_dx+4)
- do_expr(3, IA32_SIGCONTEXT_bx+4)
- do_expr(5, IA32_SIGCONTEXT_bp+4)
- do_expr(6, IA32_SIGCONTEXT_si+4)
- do_expr(7, IA32_SIGCONTEXT_di+4)
- do_expr(8, IA32_SIGCONTEXT_ip+4)
-
- .byte 0x42 /* DW_CFA_advance_loc 2 -- nop; popl eax. */
-
- do_cfa_expr(IA32_SIGCONTEXT_sp)
- do_expr(0, IA32_SIGCONTEXT_ax)
- do_expr(1, IA32_SIGCONTEXT_cx)
- do_expr(2, IA32_SIGCONTEXT_dx)
- do_expr(3, IA32_SIGCONTEXT_bx)
- do_expr(5, IA32_SIGCONTEXT_bp)
- do_expr(6, IA32_SIGCONTEXT_si)
- do_expr(7, IA32_SIGCONTEXT_di)
- do_expr(8, IA32_SIGCONTEXT_ip)
-
- .align 4
-.LENDFDEDLSI1:
-
- .long .LENDFDEDLSI2-.LSTARTFDEDLSI2 /* Length FDE */
-.LSTARTFDEDLSI2:
- .long .LSTARTFDEDLSI2-.LSTARTFRAMEDLSI1 /* CIE pointer */
- /* HACK: See above wrt unwind library assumptions. */
- .long .LSTART_rt_sigreturn-1-. /* PC-relative start address */
- .long .LEND_rt_sigreturn-.LSTART_rt_sigreturn+1
- .uleb128 0 /* Augmentation */
- /* What follows are the instructions for the table generation.
- We record the locations of each register saved. This is
- slightly less complicated than the above, since we don't
- modify the stack pointer in the process. */
-
- do_cfa_expr(IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_sp)
- do_expr(0, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ax)
- do_expr(1, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_cx)
- do_expr(2, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_dx)
- do_expr(3, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_bx)
- do_expr(5, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_bp)
- do_expr(6, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_si)
- do_expr(7, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_di)
- do_expr(8, IA32_RT_SIGFRAME_sigcontext-4 + IA32_SIGCONTEXT_ip)
-
- .align 4
-.LENDFDEDLSI2:
+ ud2a
+ CFI_ENDPROC
+ .size __kernel_rt_sigreturn,.-__kernel_rt_sigreturn
.previous
diff --git a/arch/x86/include/asm/dwarf2.h b/arch/x86/include/asm/dwarf2.h
index 302e11b15da8..09c9684d3ad6 100644
--- a/arch/x86/include/asm/dwarf2.h
+++ b/arch/x86/include/asm/dwarf2.h
@@ -20,6 +20,7 @@
#define CFI_RESTORE_STATE .cfi_restore_state
#define CFI_UNDEFINED .cfi_undefined
#define CFI_ESCAPE .cfi_escape
+#define CFI_SIGNAL_FRAME .cfi_signal_frame
#ifndef BUILD_VDSO
/*
diff --git a/arch/x86/kernel/asm-offsets.c b/arch/x86/kernel/asm-offsets.c
index 25fcde525c68..081816888f7a 100644
--- a/arch/x86/kernel/asm-offsets.c
+++ b/arch/x86/kernel/asm-offsets.c
@@ -63,8 +63,14 @@ static void __used common(void)
OFFSET(IA32_SIGCONTEXT_bp, sigcontext_32, bp);
OFFSET(IA32_SIGCONTEXT_sp, sigcontext_32, sp);
OFFSET(IA32_SIGCONTEXT_ip, sigcontext_32, ip);
+ OFFSET(IA32_SIGCONTEXT_es, sigcontext_32, es);
+ OFFSET(IA32_SIGCONTEXT_cs, sigcontext_32, cs);
+ OFFSET(IA32_SIGCONTEXT_ss, sigcontext_32, ss);
+ OFFSET(IA32_SIGCONTEXT_ds, sigcontext_32, ds);
+ OFFSET(IA32_SIGCONTEXT_flags, sigcontext_32, flags);
BLANK();
+ OFFSET(IA32_SIGFRAME_sigcontext, sigframe_ia32, sc);
OFFSET(IA32_RT_SIGFRAME_sigcontext, rt_sigframe_ia32, uc.uc_mcontext);
#endif
--
2.52.0
Hello Peter!
On 1/6/2026 10:18 PM, H. Peter Anvin wrote:
> The vdso32 sigreturn.S contains open-coded DWARF bytecode, which
> includes a hack for gdb to not try to step back to a previous call
> instruction when backtracing from a signal handler.
>
> Neither of those are necessary anymore: the backtracing issue is
> handled by ".cfi_entry simple" and ".cfi_signal_frame", both of which
> have been supported for a very long time now, which allows the
> remaining frame to be built using regular .cfi annotations.
Hopefully Glibc developers will do something similar for x86-64
__restore_rt() in Glibc sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c.
>
> Add a few more register offsets to the signal frame just for good
> measure.
>
> Replace the nop on fallthrough of the system call (which should never,
> ever happen) with a ud2a trap.
> diff --git a/arch/x86/entry/vdso/vdso32/sigreturn.S b/arch/x86/entry/vdso/vdso32/sigreturn.S
> .text
> .globl __kernel_sigreturn
> .type __kernel_sigreturn,@function
> - nop /* this guy is needed for .LSTARTFDEDLSI1 below (watch for HACK) */
> ALIGN
> __kernel_sigreturn:
> -.LSTART_sigreturn:
> - popl %eax /* XXX does this mean it needs unwind info? */
> + STARTPROC_SIGNAL_FRAME IA32_SIGFRAME_sigcontext
> + popl %eax
> + CFI_ADJUST_CFA_OFFSET -4
> movl $__NR_sigreturn, %eax
> int $0x80
> -.LEND_sigreturn:
...
> .globl __kernel_rt_sigreturn
> .type __kernel_rt_sigreturn,@function
> ALIGN
> __kernel_rt_sigreturn:
> -.LSTART_rt_sigreturn:
> + STARTPROC_SIGNAL_FRAME IA32_RT_SIGFRAME_sigcontext
> movl $__NR_rt_sigreturn, %eax
> int $0x80
> -.LEND_rt_sigreturn:
...
> - .section .eh_frame,"a",@progbits
> -.LSTARTFRAMEDLSI1:
> - .long .LENDCIEDLSI1-.LSTARTCIEDLSI1
> -.LSTARTCIEDLSI1:
> - .long 0 /* CIE ID */
> - .byte 1 /* Version number */
> - .string "zRS" /* NUL-terminated augmentation string */
Note that the "S" in "zRS" is the signal frame indication.
> - .uleb128 1 /* Code alignment factor */
> - .sleb128 -4 /* Data alignment factor */
> - .byte 8 /* Return address register column */
> - .uleb128 1 /* Augmentation value length */
> - .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */
> - .byte 0 /* DW_CFA_nop */
> - .align 4
> -.LENDCIEDLSI1:
> - .long .LENDFDEDLSI1-.LSTARTFDEDLSI1 /* Length FDE */
> -.LSTARTFDEDLSI1:
> - .long .LSTARTFDEDLSI1-.LSTARTFRAMEDLSI1 /* CIE pointer */
> - /* HACK: The dwarf2 unwind routines will subtract 1 from the
> - return address to get an address in the middle of the
> - presumed call instruction. Since we didn't get here via
> - a call, we need to include the nop before the real start
> - to make up for it. */
> - .long .LSTART_sigreturn-1-. /* PC-relative start address */
Your version does no longer have this nop nor does the FDE start one
byte earlier. Isn't that required for unwinders any longer?
See excerpt from dumped DWARF and disassembly for __kernel_sigreturn()
below.
> - .long .LEND_sigreturn-.LSTART_sigreturn+1
> - .uleb128 0 /* Augmentation */
...
> - .align 4
> -.LENDFDEDLSI1:
> -
> - .long .LENDFDEDLSI2-.LSTARTFDEDLSI2 /* Length FDE */
> -.LSTARTFDEDLSI2:
> - .long .LSTARTFDEDLSI2-.LSTARTFRAMEDLSI1 /* CIE pointer */
> - /* HACK: See above wrt unwind library assumptions. */
> - .long .LSTART_rt_sigreturn-1-. /* PC-relative start address */
Ditto.
> - .long .LEND_rt_sigreturn-.LSTART_rt_sigreturn+1
> - .uleb128 0 /* Augmentation */
Excerpt from dump of DWARF and disassembly with your patch:
$ objdump -d -Wf arch/x86/entry/vdso/vdso32/vdso32.so.dbg
...
000001cc 0000003c 00000000 CIE <-- CIE for __kernel_sigreturn
Version: 1
Augmentation: "zRS"
Code alignment factor: 1
Data alignment factor: -4
Return address column: 8
Augmentation data: 1b
DW_CFA_def_cfa: r4 (esp) ofs 4
DW_CFA_offset_extended_sf: r8 (eip) at cfa+56
DW_CFA_offset_extended_sf: r0 (eax) at cfa+44
DW_CFA_offset_extended_sf: r3 (ebx) at cfa+32
DW_CFA_offset_extended_sf: r1 (ecx) at cfa+40
DW_CFA_offset_extended_sf: r2 (edx) at cfa+36
DW_CFA_offset_extended_sf: r4 (esp) at cfa+28
DW_CFA_offset_extended_sf: r5 (ebp) at cfa+24
DW_CFA_offset_extended_sf: r6 (esi) at cfa+20
DW_CFA_offset_extended_sf: r7 (edi) at cfa+16
DW_CFA_offset_extended_sf: r40 (es) at cfa+8
DW_CFA_offset_extended_sf: r41 (cs) at cfa+60
DW_CFA_offset_extended_sf: r42 (ss) at cfa+72
DW_CFA_offset_extended_sf: r43 (ds) at cfa+12
DW_CFA_offset_extended_sf: r9 (eflags) at cfa+64
DW_CFA_nop
0000020c 00000010 00000044 FDE cie=000001cc pc=00001a40..00001a4a <-- FDE for __kernel_sigreturn
DW_CFA_advance_loc: 1 to 00001a41
DW_CFA_def_cfa_offset: 0
[ The FDE covers the range [1a40..1a4a[. Previously it would have
started one byte earlier (at the nop), so that the range would have
been [1a3f..1a4a[. This is/was required for unwinders that always
subtract one from the unwound return address, so that it points into
the instruction that invoked the function (e.g. call) instead of behind
it, in case it was invoked by a non-returning function. Such an
unwinder would now lookup IP=1a3f as belonging to int80_landing_pad (and
use the DWARF rules applicable to its last instruction) instead of
__kernel_sigreturn (and its rules). Likewise for __kernel_rt_sigreturn. ]
...
00001a3c <int80_landing_pad>:
1a3c: 5d pop %ebp
1a3d: 5a pop %edx
1a3e: 59 pop %ecx
1a3f: c3 ret
00001a40 <__kernel_sigreturn>:
1a40: 58 pop %eax
1a41: b8 77 00 00 00 mov $0x77,%eax
1a46: cd 80 int $0x80
00001a48 <vdso32_sigreturn_landing_pad>:
1a48: 0f 0b ud2
1a4a: 8d b6 00 00 00 00 lea 0x0(%esi),%esi
Excerpt without your patch:
$ objdump -d -Wf arch/x86/entry/vdso/vdso32/vdso32.so.dbg
...
000001cc 00000010 00000000 CIE <-- CIE for __kernel_sigreturn and __kernel_rt_sigreturn
Version: 1
Augmentation: "zRS"
Code alignment factor: 1
Data alignment factor: -4
Return address column: 8
Augmentation data: 1b
DW_CFA_nop
DW_CFA_nop
000001e0 00000068 00000018 FDE cie=000001cc pc=00001a6f..00001a78 <-- FDE for __kernel_sigreturn
DW_CFA_def_cfa_expression (DW_OP_breg4 (esp): 32; DW_OP_deref)
DW_CFA_expression: r0 (eax) (DW_OP_breg4 (esp): 48)
DW_CFA_expression: r1 (ecx) (DW_OP_breg4 (esp): 44)
DW_CFA_expression: r2 (edx) (DW_OP_breg4 (esp): 40)
DW_CFA_expression: r3 (ebx) (DW_OP_breg4 (esp): 36)
DW_CFA_expression: r5 (ebp) (DW_OP_breg4 (esp): 28)
DW_CFA_expression: r6 (esi) (DW_OP_breg4 (esp): 24)
DW_CFA_expression: r7 (edi) (DW_OP_breg4 (esp): 20)
DW_CFA_expression: r8 (eip) (DW_OP_breg4 (esp): 60)
DW_CFA_advance_loc: 2 to 00001a71
DW_CFA_def_cfa_expression (DW_OP_breg4 (esp): 28; DW_OP_deref)
DW_CFA_expression: r0 (eax) (DW_OP_breg4 (esp): 44)
DW_CFA_expression: r1 (ecx) (DW_OP_breg4 (esp): 40)
DW_CFA_expression: r2 (edx) (DW_OP_breg4 (esp): 36)
DW_CFA_expression: r3 (ebx) (DW_OP_breg4 (esp): 32)
DW_CFA_expression: r5 (ebp) (DW_OP_breg4 (esp): 24)
DW_CFA_expression: r6 (esi) (DW_OP_breg4 (esp): 20)
DW_CFA_expression: r7 (edi) (DW_OP_breg4 (esp): 16)
DW_CFA_expression: r8 (eip) (DW_OP_breg4 (esp): 56)
[ See how the FDE for __kernel_sigreturn covers the range [1a6f..1a78[.
An unwinder that always subtracts one from the return address would
lookup IP=1a6f as belonging to __kernel_sigreturn (and use the DWARF
rules applicable to the nop preceeding its symbol). Likewise for
__kernel_rt_sigreturn. Or is that no longer true? ]
...
00001a5c <int80_landing_pad>:
1a5c: 5d pop %ebp
1a5d: 5a pop %edx
1a5e: 59 pop %ecx
1a5f: c3 ret
1a60: 90 nop
1a61: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi
1a68: 2e 8d b4 26 00 00 00 lea %cs:0x0(%esi,%eiz,1),%esi
1a6f: 00
00001a70 <__kernel_sigreturn>:
1a70: 58 pop %eax
1a71: b8 77 00 00 00 mov $0x77,%eax
1a76: cd 80 int $0x80
Thanks and regards,
Jens
--
Jens Remus
Linux on Z Development (D3303)
jremus@de.ibm.com / jremus@linux.ibm.com
IBM Deutschland Research & Development GmbH; Vorsitzender des Aufsichtsrats: Wolfgang Wendt; Geschäftsführung: David Faller; Sitz der Gesellschaft: Ehningen; Registergericht: Amtsgericht Stuttgart, HRB 243294
IBM Data Privacy Statement: https://www.ibm.com/privacy/
On February 2, 2026 9:02:48 AM PST, Jens Remus <jremus@linux.ibm.com> wrote: >Hello Peter! > >On 1/6/2026 10:18 PM, H. Peter Anvin wrote: >> The vdso32 sigreturn.S contains open-coded DWARF bytecode, which >> includes a hack for gdb to not try to step back to a previous call >> instruction when backtracing from a signal handler. >> >> Neither of those are necessary anymore: the backtracing issue is >> handled by ".cfi_entry simple" and ".cfi_signal_frame", both of which >> have been supported for a very long time now, which allows the >> remaining frame to be built using regular .cfi annotations. > >Hopefully Glibc developers will do something similar for x86-64 >__restore_rt() in Glibc sysdeps/unix/sysv/linux/x86_64/libc_sigaction.c. > >> >> Add a few more register offsets to the signal frame just for good >> measure. >> >> Replace the nop on fallthrough of the system call (which should never, >> ever happen) with a ud2a trap. >> diff --git a/arch/x86/entry/vdso/vdso32/sigreturn.S b/arch/x86/entry/vdso/vdso32/sigreturn.S > >> .text >> .globl __kernel_sigreturn >> .type __kernel_sigreturn,@function >> - nop /* this guy is needed for .LSTARTFDEDLSI1 below (watch for HACK) */ >> ALIGN >> __kernel_sigreturn: >> -.LSTART_sigreturn: >> - popl %eax /* XXX does this mean it needs unwind info? */ >> + STARTPROC_SIGNAL_FRAME IA32_SIGFRAME_sigcontext >> + popl %eax >> + CFI_ADJUST_CFA_OFFSET -4 >> movl $__NR_sigreturn, %eax >> int $0x80 >> -.LEND_sigreturn: > >... > >> .globl __kernel_rt_sigreturn >> .type __kernel_rt_sigreturn,@function >> ALIGN >> __kernel_rt_sigreturn: >> -.LSTART_rt_sigreturn: >> + STARTPROC_SIGNAL_FRAME IA32_RT_SIGFRAME_sigcontext >> movl $__NR_rt_sigreturn, %eax >> int $0x80 >> -.LEND_rt_sigreturn: > >... > >> - .section .eh_frame,"a",@progbits >> -.LSTARTFRAMEDLSI1: >> - .long .LENDCIEDLSI1-.LSTARTCIEDLSI1 >> -.LSTARTCIEDLSI1: >> - .long 0 /* CIE ID */ >> - .byte 1 /* Version number */ >> - .string "zRS" /* NUL-terminated augmentation string */ > >Note that the "S" in "zRS" is the signal frame indication. > >> - .uleb128 1 /* Code alignment factor */ >> - .sleb128 -4 /* Data alignment factor */ >> - .byte 8 /* Return address register column */ >> - .uleb128 1 /* Augmentation value length */ >> - .byte 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4. */ >> - .byte 0 /* DW_CFA_nop */ >> - .align 4 >> -.LENDCIEDLSI1: >> - .long .LENDFDEDLSI1-.LSTARTFDEDLSI1 /* Length FDE */ >> -.LSTARTFDEDLSI1: >> - .long .LSTARTFDEDLSI1-.LSTARTFRAMEDLSI1 /* CIE pointer */ >> - /* HACK: The dwarf2 unwind routines will subtract 1 from the >> - return address to get an address in the middle of the >> - presumed call instruction. Since we didn't get here via >> - a call, we need to include the nop before the real start >> - to make up for it. */ >> - .long .LSTART_sigreturn-1-. /* PC-relative start address */ > >Your version does no longer have this nop nor does the FDE start one >byte earlier. Isn't that required for unwinders any longer? >See excerpt from dumped DWARF and disassembly for __kernel_sigreturn() >below. > >> - .long .LEND_sigreturn-.LSTART_sigreturn+1 >> - .uleb128 0 /* Augmentation */ >... > >> - .align 4 >> -.LENDFDEDLSI1: >> - >> - .long .LENDFDEDLSI2-.LSTARTFDEDLSI2 /* Length FDE */ >> -.LSTARTFDEDLSI2: >> - .long .LSTARTFDEDLSI2-.LSTARTFRAMEDLSI1 /* CIE pointer */ >> - /* HACK: See above wrt unwind library assumptions. */ >> - .long .LSTART_rt_sigreturn-1-. /* PC-relative start address */ > >Ditto. > >> - .long .LEND_rt_sigreturn-.LSTART_rt_sigreturn+1 >> - .uleb128 0 /* Augmentation */ > >Excerpt from dump of DWARF and disassembly with your patch: > >$ objdump -d -Wf arch/x86/entry/vdso/vdso32/vdso32.so.dbg >... >000001cc 0000003c 00000000 CIE <-- CIE for __kernel_sigreturn > Version: 1 > Augmentation: "zRS" > Code alignment factor: 1 > Data alignment factor: -4 > Return address column: 8 > Augmentation data: 1b > DW_CFA_def_cfa: r4 (esp) ofs 4 > DW_CFA_offset_extended_sf: r8 (eip) at cfa+56 > DW_CFA_offset_extended_sf: r0 (eax) at cfa+44 > DW_CFA_offset_extended_sf: r3 (ebx) at cfa+32 > DW_CFA_offset_extended_sf: r1 (ecx) at cfa+40 > DW_CFA_offset_extended_sf: r2 (edx) at cfa+36 > DW_CFA_offset_extended_sf: r4 (esp) at cfa+28 > DW_CFA_offset_extended_sf: r5 (ebp) at cfa+24 > DW_CFA_offset_extended_sf: r6 (esi) at cfa+20 > DW_CFA_offset_extended_sf: r7 (edi) at cfa+16 > DW_CFA_offset_extended_sf: r40 (es) at cfa+8 > DW_CFA_offset_extended_sf: r41 (cs) at cfa+60 > DW_CFA_offset_extended_sf: r42 (ss) at cfa+72 > DW_CFA_offset_extended_sf: r43 (ds) at cfa+12 > DW_CFA_offset_extended_sf: r9 (eflags) at cfa+64 > DW_CFA_nop > >0000020c 00000010 00000044 FDE cie=000001cc pc=00001a40..00001a4a <-- FDE for __kernel_sigreturn > DW_CFA_advance_loc: 1 to 00001a41 > DW_CFA_def_cfa_offset: 0 > >[ The FDE covers the range [1a40..1a4a[. Previously it would have >started one byte earlier (at the nop), so that the range would have >been [1a3f..1a4a[. This is/was required for unwinders that always >subtract one from the unwound return address, so that it points into >the instruction that invoked the function (e.g. call) instead of behind >it, in case it was invoked by a non-returning function. Such an >unwinder would now lookup IP=1a3f as belonging to int80_landing_pad (and >use the DWARF rules applicable to its last instruction) instead of >__kernel_sigreturn (and its rules). Likewise for __kernel_rt_sigreturn. ] > >... >00001a3c <int80_landing_pad>: > 1a3c: 5d pop %ebp > 1a3d: 5a pop %edx > 1a3e: 59 pop %ecx > 1a3f: c3 ret > >00001a40 <__kernel_sigreturn>: > 1a40: 58 pop %eax > 1a41: b8 77 00 00 00 mov $0x77,%eax > 1a46: cd 80 int $0x80 > >00001a48 <vdso32_sigreturn_landing_pad>: > 1a48: 0f 0b ud2 > 1a4a: 8d b6 00 00 00 00 lea 0x0(%esi),%esi > > >Excerpt without your patch: > >$ objdump -d -Wf arch/x86/entry/vdso/vdso32/vdso32.so.dbg >... >000001cc 00000010 00000000 CIE <-- CIE for __kernel_sigreturn and __kernel_rt_sigreturn > Version: 1 > Augmentation: "zRS" > Code alignment factor: 1 > Data alignment factor: -4 > Return address column: 8 > Augmentation data: 1b > DW_CFA_nop > DW_CFA_nop > >000001e0 00000068 00000018 FDE cie=000001cc pc=00001a6f..00001a78 <-- FDE for __kernel_sigreturn > DW_CFA_def_cfa_expression (DW_OP_breg4 (esp): 32; DW_OP_deref) > DW_CFA_expression: r0 (eax) (DW_OP_breg4 (esp): 48) > DW_CFA_expression: r1 (ecx) (DW_OP_breg4 (esp): 44) > DW_CFA_expression: r2 (edx) (DW_OP_breg4 (esp): 40) > DW_CFA_expression: r3 (ebx) (DW_OP_breg4 (esp): 36) > DW_CFA_expression: r5 (ebp) (DW_OP_breg4 (esp): 28) > DW_CFA_expression: r6 (esi) (DW_OP_breg4 (esp): 24) > DW_CFA_expression: r7 (edi) (DW_OP_breg4 (esp): 20) > DW_CFA_expression: r8 (eip) (DW_OP_breg4 (esp): 60) > DW_CFA_advance_loc: 2 to 00001a71 > DW_CFA_def_cfa_expression (DW_OP_breg4 (esp): 28; DW_OP_deref) > DW_CFA_expression: r0 (eax) (DW_OP_breg4 (esp): 44) > DW_CFA_expression: r1 (ecx) (DW_OP_breg4 (esp): 40) > DW_CFA_expression: r2 (edx) (DW_OP_breg4 (esp): 36) > DW_CFA_expression: r3 (ebx) (DW_OP_breg4 (esp): 32) > DW_CFA_expression: r5 (ebp) (DW_OP_breg4 (esp): 24) > DW_CFA_expression: r6 (esi) (DW_OP_breg4 (esp): 20) > DW_CFA_expression: r7 (edi) (DW_OP_breg4 (esp): 16) > DW_CFA_expression: r8 (eip) (DW_OP_breg4 (esp): 56) > > >[ See how the FDE for __kernel_sigreturn covers the range [1a6f..1a78[. >An unwinder that always subtracts one from the return address would >lookup IP=1a6f as belonging to __kernel_sigreturn (and use the DWARF >rules applicable to the nop preceeding its symbol). Likewise for >__kernel_rt_sigreturn. Or is that no longer true? ] > >... >00001a5c <int80_landing_pad>: > 1a5c: 5d pop %ebp > 1a5d: 5a pop %edx > 1a5e: 59 pop %ecx > 1a5f: c3 ret > 1a60: 90 nop > 1a61: 8d b4 26 00 00 00 00 lea 0x0(%esi,%eiz,1),%esi > 1a68: 2e 8d b4 26 00 00 00 lea %cs:0x0(%esi,%eiz,1),%esi > 1a6f: 00 > >00001a70 <__kernel_sigreturn>: > 1a70: 58 pop %eax > 1a71: b8 77 00 00 00 mov $0x77,%eax > 1a76: cd 80 int $0x80 > >Thanks and regards, >Jens That hack dates back from before the signal frame extension. It is no longer necessary.
© 2016 - 2026 Red Hat, Inc.