Abstract out the calling of true system calls from the vdso into
macros.
It has been a very long time since gcc did not allow %ebx or %ebp in
inline asm in 32-bit PIC mode; remove the corresponding hacks.
Remove the use of memory output constraints in gettimeofday.h in favor
of "memory" clobbers. The resulting code is identical for the current
use cases, as the system call is usually a terminal fallback anyway,
and it merely complicates the macroization.
This patch adds only a handful of more lines of code than it removes,
and in fact could be made substantially smaller by removing the macros
for the argument counts that aren't currently used, however, it seems
better to be general from the start.
Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
---
arch/x86/include/asm/vdso/gettimeofday.h | 108 ++------------------
arch/x86/include/asm/vdso/sys_call.h | 119 +++++++++++++++++++++++
2 files changed, 127 insertions(+), 100 deletions(-)
create mode 100644 arch/x86/include/asm/vdso/sys_call.h
diff --git a/arch/x86/include/asm/vdso/gettimeofday.h b/arch/x86/include/asm/vdso/gettimeofday.h
index 73b2e7ee8f0f..3cf214cc4a75 100644
--- a/arch/x86/include/asm/vdso/gettimeofday.h
+++ b/arch/x86/include/asm/vdso/gettimeofday.h
@@ -18,6 +18,7 @@
#include <asm/msr.h>
#include <asm/pvclock.h>
#include <clocksource/hyperv_timer.h>
+#include <asm/vdso/sys_call.h>
#define VDSO_HAS_TIME 1
@@ -53,130 +54,37 @@ extern struct ms_hyperv_tsc_page hvclock_page
__attribute__((visibility("hidden")));
#endif
-#ifndef BUILD_VDSO32
-
static __always_inline
long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
{
- long ret;
-
- asm ("syscall" : "=a" (ret), "=m" (*_ts) :
- "0" (__NR_clock_gettime), "D" (_clkid), "S" (_ts) :
- "rcx", "r11");
-
- return ret;
+ return VDSO_SYSCALL2(clock_gettime,64,_clkid,_ts);
}
static __always_inline
long gettimeofday_fallback(struct __kernel_old_timeval *_tv,
struct timezone *_tz)
{
- long ret;
-
- asm("syscall" : "=a" (ret) :
- "0" (__NR_gettimeofday), "D" (_tv), "S" (_tz) : "memory");
-
- return ret;
+ return VDSO_SYSCALL2(gettimeofday,,_tv,_tz);
}
static __always_inline
long clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
{
- long ret;
-
- asm ("syscall" : "=a" (ret), "=m" (*_ts) :
- "0" (__NR_clock_getres), "D" (_clkid), "S" (_ts) :
- "rcx", "r11");
-
- return ret;
+ return VDSO_SYSCALL2(clock_getres,_time64,_clkid,_ts);
}
-#else
-
-static __always_inline
-long clock_gettime_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
-{
- long ret;
-
- asm (
- "mov %%ebx, %%edx \n"
- "mov %[clock], %%ebx \n"
- "call __kernel_vsyscall \n"
- "mov %%edx, %%ebx \n"
- : "=a" (ret), "=m" (*_ts)
- : "0" (__NR_clock_gettime64), [clock] "g" (_clkid), "c" (_ts)
- : "edx");
-
- return ret;
-}
+#ifndef CONFIG_X86_64
static __always_inline
long clock_gettime32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
{
- long ret;
-
- asm (
- "mov %%ebx, %%edx \n"
- "mov %[clock], %%ebx \n"
- "call __kernel_vsyscall \n"
- "mov %%edx, %%ebx \n"
- : "=a" (ret), "=m" (*_ts)
- : "0" (__NR_clock_gettime), [clock] "g" (_clkid), "c" (_ts)
- : "edx");
-
- return ret;
-}
-
-static __always_inline
-long gettimeofday_fallback(struct __kernel_old_timeval *_tv,
- struct timezone *_tz)
-{
- long ret;
-
- asm(
- "mov %%ebx, %%edx \n"
- "mov %2, %%ebx \n"
- "call __kernel_vsyscall \n"
- "mov %%edx, %%ebx \n"
- : "=a" (ret)
- : "0" (__NR_gettimeofday), "g" (_tv), "c" (_tz)
- : "memory", "edx");
-
- return ret;
+ return VDSO_SYSCALL2(clock_gettime,,_clkid,_ts);
}
static __always_inline long
-clock_getres_fallback(clockid_t _clkid, struct __kernel_timespec *_ts)
-{
- long ret;
-
- asm (
- "mov %%ebx, %%edx \n"
- "mov %[clock], %%ebx \n"
- "call __kernel_vsyscall \n"
- "mov %%edx, %%ebx \n"
- : "=a" (ret), "=m" (*_ts)
- : "0" (__NR_clock_getres_time64), [clock] "g" (_clkid), "c" (_ts)
- : "edx");
-
- return ret;
-}
-
-static __always_inline
-long clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
+clock_getres32_fallback(clockid_t _clkid, struct old_timespec32 *_ts)
{
- long ret;
-
- asm (
- "mov %%ebx, %%edx \n"
- "mov %[clock], %%ebx \n"
- "call __kernel_vsyscall \n"
- "mov %%edx, %%ebx \n"
- : "=a" (ret), "=m" (*_ts)
- : "0" (__NR_clock_getres), [clock] "g" (_clkid), "c" (_ts)
- : "edx");
-
- return ret;
+ return VDSO_SYSCALL2(clock_getres,,_clkid,_ts);
}
#endif
diff --git a/arch/x86/include/asm/vdso/sys_call.h b/arch/x86/include/asm/vdso/sys_call.h
new file mode 100644
index 000000000000..6b1fbcdcbd5c
--- /dev/null
+++ b/arch/x86/include/asm/vdso/sys_call.h
@@ -0,0 +1,119 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Macros for issuing an inline system call from the vDSO.
+ */
+
+#ifndef X86_ASM_VDSO_SYS_CALL_H
+#define X86_ASM_VDSO_SYS_CALL_H
+
+#include <linux/compiler.h>
+#include <asm/cpufeatures.h>
+#include <asm/alternative.h>
+
+/*
+ * Note: only three arguments are currently supported,
+ * because there are no constraint letters for r10, r8, r9.
+ */
+#ifdef CONFIG_X86_64
+/* Using dummy output registers instead of clobbers avoids messing up
+ user-specified clobbers. */
+#define __sys_instr "syscall"
+#define __sys_clobber "rcx", "r11", "memory"
+#define __sys_nr(x,y) __NR_ ## x
+#define __sys_reg1 "rdi"
+#define __sys_reg2 "rsi"
+#define __sys_reg3 "rdx"
+#define __sys_reg4 "r10"
+#define __sys_reg5 "r8"
+#define __sys_reg6 "r9"
+#else
+#define __sys_instr "call __kernel_vsyscall"
+#define __sys_clobber "memory"
+#define __sys_nr(x,y) __NR_ ## x ## y
+#define __sys_reg1 "ebx"
+#define __sys_reg2 "ecx"
+#define __sys_reg3 "edx"
+#define __sys_reg4 "esi"
+#define __sys_reg5 "edi"
+#define __sys_reg6 "ebp"
+#endif
+
+/*
+ * Example usage:
+ *
+ * result = VDSO_SYSCALL3(foo,64,x,y,z);
+ *
+ * ... calls foo(x,y,z) on 64 bits, and foo64(x,y,z) on 32 bits.
+ */
+#define _VDSO_SYSCALL(name,suf32,...) \
+ ({ \
+ long _sys_num_ret = __sys_nr(name,suf32); \
+ asm_inline volatile( \
+ __sys_instr \
+ : "+a" (_sys_num_ret) \
+ : __VA_ARGS__ \
+ : __sys_clobber); \
+ _sys_num_ret; \
+ })
+
+#define VDSO_SYSCALL0(name,suf32) \
+ _VDSO_SYSCALL(name,suf32)
+#define VDSO_SYSCALL1(name,suf32,a1) \
+ ({ \
+ register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \
+ _VDSO_SYSCALL(name,suf32, \
+ "r" (_sys_arg1)); \
+ })
+#define VDSO_SYSCALL2(name,suf32,a1,a2) \
+ ({ \
+ register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \
+ register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \
+ _VDSO_SYSCALL(name,suf32, \
+ "r" (_sys_arg1), "r" (_sys_arg2)); \
+ })
+#define VDSO_SYSCALL3(name,suf32,a1,a2,a3) \
+ ({ \
+ register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \
+ register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \
+ register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \
+ _VDSO_SYSCALL(name,suf32, \
+ "r" (_sys_arg1), "r" (_sys_arg2), \
+ "r" (_sys_arg3)); \
+ })
+#define VDSO_SYSCALL4(name,suf32,a1,a2,a3,a4) \
+ ({ \
+ register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \
+ register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \
+ register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \
+ register long _sys_arg4 asm(__sys_reg4) = (long)(a4); \
+ _VDSO_SYSCALL(name,suf32, \
+ "r" (_sys_arg1), "r" (_sys_arg2), \
+ "r" (_sys_arg3), "r" (_sys_arg4)); \
+ })
+#define VDSO_SYSCALL5(name,suf32,a1,a2,a3,a4,a5) \
+ ({ \
+ register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \
+ register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \
+ register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \
+ register long _sys_arg4 asm(__sys_reg4) = (long)(a4); \
+ register long _sys_arg5 asm(__sys_reg5) = (long)(a5); \
+ _VDSO_SYSCALL(name,suf32, \
+ "r" (_sys_arg1), "r" (_sys_arg2), \
+ "r" (_sys_arg3), "r" (_sys_arg4), \
+ "r" (_sys_arg5)); \
+ })
+#define VDSO_SYSCALL6(name,suf32,a1,a2,a3,a4,a5,a6) \
+ ({ \
+ register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \
+ register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \
+ register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \
+ register long _sys_arg4 asm(__sys_reg4) = (long)(a4); \
+ register long _sys_arg5 asm(__sys_reg5) = (long)(a5); \
+ register long _sys_arg6 asm(__sys_reg6) = (long)(a6); \
+ _VDSO_SYSCALL(name,suf32, \
+ "r" (_sys_arg1), "r" (_sys_arg2), \
+ "r" (_sys_arg3), "r" (_sys_arg4), \
+ "r" (_sys_arg5), "r" (_sys_arg6)); \
+ })
+
+#endif /* X86_VDSO_SYS_CALL_H */
--
2.51.1
On Wed, Nov 12, 2025 at 5:38 AM H. Peter Anvin <hpa@zytor.com> wrote:
>
> Abstract out the calling of true system calls from the vdso into
> macros.
>
> It has been a very long time since gcc did not allow %ebx or %ebp in
> inline asm in 32-bit PIC mode; remove the corresponding hacks.
>
> Remove the use of memory output constraints in gettimeofday.h in favor
> of "memory" clobbers. The resulting code is identical for the current
> use cases, as the system call is usually a terminal fallback anyway,
> and it merely complicates the macroization.
>
> This patch adds only a handful of more lines of code than it removes,
> and in fact could be made substantially smaller by removing the macros
> for the argument counts that aren't currently used, however, it seems
> better to be general from the start.
>
> Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
[...]
> diff --git a/arch/x86/include/asm/vdso/sys_call.h b/arch/x86/include/asm/vdso/sys_call.h
> new file mode 100644
> index 000000000000..6b1fbcdcbd5c
> --- /dev/null
> +++ b/arch/x86/include/asm/vdso/sys_call.h
> @@ -0,0 +1,119 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +/*
> + * Macros for issuing an inline system call from the vDSO.
> + */
> +
> +#ifndef X86_ASM_VDSO_SYS_CALL_H
> +#define X86_ASM_VDSO_SYS_CALL_H
> +
> +#include <linux/compiler.h>
> +#include <asm/cpufeatures.h>
> +#include <asm/alternative.h>
> +
> +/*
> + * Note: only three arguments are currently supported,
> + * because there are no constraint letters for r10, r8, r9.
The above comment does not apply when using local variables associated
with a register.
> + */
> +#ifdef CONFIG_X86_64
> +/* Using dummy output registers instead of clobbers avoids messing up
> + user-specified clobbers. */
> +#define __sys_instr "syscall"
> +#define __sys_clobber "rcx", "r11", "memory"
> +#define __sys_nr(x,y) __NR_ ## x
> +#define __sys_reg1 "rdi"
> +#define __sys_reg2 "rsi"
> +#define __sys_reg3 "rdx"
> +#define __sys_reg4 "r10"
> +#define __sys_reg5 "r8"
> +#define __sys_reg6 "r9"
> +#else
> +#define __sys_instr "call __kernel_vsyscall"
> +#define __sys_clobber "memory"
> +#define __sys_nr(x,y) __NR_ ## x ## y
> +#define __sys_reg1 "ebx"
> +#define __sys_reg2 "ecx"
> +#define __sys_reg3 "edx"
> +#define __sys_reg4 "esi"
> +#define __sys_reg5 "edi"
> +#define __sys_reg6 "ebp"
> +#endif
[...]
> +#define VDSO_SYSCALL6(name,suf32,a1,a2,a3,a4,a5,a6) \
> + ({ \
> + register long _sys_arg1 asm(__sys_reg1) = (long)(a1); \
> + register long _sys_arg2 asm(__sys_reg2) = (long)(a2); \
> + register long _sys_arg3 asm(__sys_reg3) = (long)(a3); \
> + register long _sys_arg4 asm(__sys_reg4) = (long)(a4); \
> + register long _sys_arg5 asm(__sys_reg5) = (long)(a5); \
> + register long _sys_arg6 asm(__sys_reg6) = (long)(a6); \
> + _VDSO_SYSCALL(name,suf32, \
> + "r" (_sys_arg1), "r" (_sys_arg2), \
> + "r" (_sys_arg3), "r" (_sys_arg4), \
> + "r" (_sys_arg5), "r" (_sys_arg6)); \
> + })
Unfortunately, %ebp is still special with -fno-omit-frame-pointer, so
using "ebp" as _sys_arg6 on 32-bit targets will result in:
error: bp cannot be used in ‘asm’ here
Please see how %ebp register is handled in
arch/x86/include/asm/vmware.h, vmware_hypercall_hb_out() and
vmware_hypercall_hb_in().
Uros.
On 2025-11-12 02:31, Uros Bizjak wrote:
>
> Unfortunately, %ebp is still special with -fno-omit-frame-pointer, so
> using "ebp" as _sys_arg6 on 32-bit targets will result in:
>
> error: bp cannot be used in ‘asm’ here
>
> Please see how %ebp register is handled in
> arch/x86/include/asm/vmware.h, vmware_hypercall_hb_out() and
> vmware_hypercall_hb_in().
>
#ifdef CONFIG_X86_64
#define VMW_BP_CONSTRAINT "r"
#else
#define VMW_BP_CONSTRAINT "m"
#endif
asm_inline volatile (
UNWIND_HINT_SAVE
"push %%" _ASM_BP "\n\t"
UNWIND_HINT_UNDEFINED
"mov %[in6], %%" _ASM_BP "\n\t"
"rep outsb\n\t"
"pop %%" _ASM_BP "\n\t"
UNWIND_HINT_RESTORE
: "=a" (out0), "=b" (*out1)
: "a" (VMWARE_HYPERVISOR_MAGIC),
"b" (cmd),
"c" (in2),
"d" (in3 | VMWARE_HYPERVISOR_PORT_HB),
"S" (in4),
"D" (in5),
[in6] VMW_BP_CONSTRAINT (in6)
: "cc", "memory");
return out0;
That code is actually incorrect, in at least two ways:
1. It should be conditioned on frame pointers enabled, not x86-64 vs i386.
2. The compiler is perfectly within its right to emit an %esp-relative
reference for the "m"-constrained [in6]. This is particularly likely
when *not* compiled with frame pointers, see #1.
A better sequence might be:
pushl %[in6]
push %ebp
mov 4(%esp),%ebp
<stuff>
pop %ebp
pop %[junk]
Then %[in6] can even safely be a "g" constraint (hence pushl).
-hpa
On Wed, Nov 12, 2025 at 10:25 PM H. Peter Anvin <hpa@zytor.com> wrote: > > On 2025-11-12 02:31, Uros Bizjak wrote: > > > > Unfortunately, %ebp is still special with -fno-omit-frame-pointer, so > > using "ebp" as _sys_arg6 on 32-bit targets will result in: > > > > error: bp cannot be used in ‘asm’ here > > > > Please see how %ebp register is handled in > > arch/x86/include/asm/vmware.h, vmware_hypercall_hb_out() and > > vmware_hypercall_hb_in(). > > > > #ifdef CONFIG_X86_64 > #define VMW_BP_CONSTRAINT "r" > #else > #define VMW_BP_CONSTRAINT "m" > #endif > > asm_inline volatile ( > UNWIND_HINT_SAVE > "push %%" _ASM_BP "\n\t" > UNWIND_HINT_UNDEFINED > "mov %[in6], %%" _ASM_BP "\n\t" > "rep outsb\n\t" > "pop %%" _ASM_BP "\n\t" > UNWIND_HINT_RESTORE > : "=a" (out0), "=b" (*out1) > : "a" (VMWARE_HYPERVISOR_MAGIC), > "b" (cmd), > "c" (in2), > "d" (in3 | VMWARE_HYPERVISOR_PORT_HB), > "S" (in4), > "D" (in5), > [in6] VMW_BP_CONSTRAINT (in6) > : "cc", "memory"); > return out0; > > That code is actually incorrect, in at least two ways: > > > 1. It should be conditioned on frame pointers enabled, not x86-64 vs i386. > 2. The compiler is perfectly within its right to emit an %esp-relative > reference for the "m"-constrained [in6]. This is particularly likely > when *not* compiled with frame pointers, see #1. > > A better sequence might be: > > pushl %[in6] > push %ebp > mov 4(%esp),%ebp > <stuff> > pop %ebp > pop %[junk] > > Then %[in6] can even safely be a "g" constraint (hence pushl). If we want to also handle x86_64, the above code (including push) needs to be 64-bit, with "rme" constraint for the pushed value. I have CC'd the author of the above code, he might be interested in the above discussion. Uros.
On November 12, 2025 11:15:08 PM PST, Uros Bizjak <ubizjak@gmail.com> wrote: >On Wed, Nov 12, 2025 at 10:25 PM H. Peter Anvin <hpa@zytor.com> wrote: >> >> On 2025-11-12 02:31, Uros Bizjak wrote: >> > >> > Unfortunately, %ebp is still special with -fno-omit-frame-pointer, so >> > using "ebp" as _sys_arg6 on 32-bit targets will result in: >> > >> > error: bp cannot be used in ‘asm’ here >> > >> > Please see how %ebp register is handled in >> > arch/x86/include/asm/vmware.h, vmware_hypercall_hb_out() and >> > vmware_hypercall_hb_in(). >> > >> >> #ifdef CONFIG_X86_64 >> #define VMW_BP_CONSTRAINT "r" >> #else >> #define VMW_BP_CONSTRAINT "m" >> #endif >> >> asm_inline volatile ( >> UNWIND_HINT_SAVE >> "push %%" _ASM_BP "\n\t" >> UNWIND_HINT_UNDEFINED >> "mov %[in6], %%" _ASM_BP "\n\t" >> "rep outsb\n\t" >> "pop %%" _ASM_BP "\n\t" >> UNWIND_HINT_RESTORE >> : "=a" (out0), "=b" (*out1) >> : "a" (VMWARE_HYPERVISOR_MAGIC), >> "b" (cmd), >> "c" (in2), >> "d" (in3 | VMWARE_HYPERVISOR_PORT_HB), >> "S" (in4), >> "D" (in5), >> [in6] VMW_BP_CONSTRAINT (in6) >> : "cc", "memory"); >> return out0; >> >> That code is actually incorrect, in at least two ways: >> >> >> 1. It should be conditioned on frame pointers enabled, not x86-64 vs i386. >> 2. The compiler is perfectly within its right to emit an %esp-relative >> reference for the "m"-constrained [in6]. This is particularly likely >> when *not* compiled with frame pointers, see #1. >> >> A better sequence might be: >> >> pushl %[in6] >> push %ebp >> mov 4(%esp),%ebp >> <stuff> >> pop %ebp >> pop %[junk] >> >> Then %[in6] can even safely be a "g" constraint (hence pushl). > >If we want to also handle x86_64, the above code (including push) >needs to be 64-bit, with "rme" constraint for the pushed value. > >I have CC'd the author of the above code, he might be interested in >the above discussion. > >Uros. > Note: for the specific case of VDSO_SYSCALL6 the %eax value is always a constant, so: push %%ebp mov %%eax,%%ebp mov %[sysnr],%%eax /* "i" constraint */ <syscall sequence> pop %%ebp ... would be easiest.
On November 12, 2025 11:15:08 PM PST, Uros Bizjak <ubizjak@gmail.com> wrote: >On Wed, Nov 12, 2025 at 10:25 PM H. Peter Anvin <hpa@zytor.com> wrote: >> >> On 2025-11-12 02:31, Uros Bizjak wrote: >> > >> > Unfortunately, %ebp is still special with -fno-omit-frame-pointer, so >> > using "ebp" as _sys_arg6 on 32-bit targets will result in: >> > >> > error: bp cannot be used in ‘asm’ here >> > >> > Please see how %ebp register is handled in >> > arch/x86/include/asm/vmware.h, vmware_hypercall_hb_out() and >> > vmware_hypercall_hb_in(). >> > >> >> #ifdef CONFIG_X86_64 >> #define VMW_BP_CONSTRAINT "r" >> #else >> #define VMW_BP_CONSTRAINT "m" >> #endif >> >> asm_inline volatile ( >> UNWIND_HINT_SAVE >> "push %%" _ASM_BP "\n\t" >> UNWIND_HINT_UNDEFINED >> "mov %[in6], %%" _ASM_BP "\n\t" >> "rep outsb\n\t" >> "pop %%" _ASM_BP "\n\t" >> UNWIND_HINT_RESTORE >> : "=a" (out0), "=b" (*out1) >> : "a" (VMWARE_HYPERVISOR_MAGIC), >> "b" (cmd), >> "c" (in2), >> "d" (in3 | VMWARE_HYPERVISOR_PORT_HB), >> "S" (in4), >> "D" (in5), >> [in6] VMW_BP_CONSTRAINT (in6) >> : "cc", "memory"); >> return out0; >> >> That code is actually incorrect, in at least two ways: >> >> >> 1. It should be conditioned on frame pointers enabled, not x86-64 vs i386. >> 2. The compiler is perfectly within its right to emit an %esp-relative >> reference for the "m"-constrained [in6]. This is particularly likely >> when *not* compiled with frame pointers, see #1. >> >> A better sequence might be: >> >> pushl %[in6] >> push %ebp >> mov 4(%esp),%ebp >> <stuff> >> pop %ebp >> pop %[junk] >> >> Then %[in6] can even safely be a "g" constraint (hence pushl). > >If we want to also handle x86_64, the above code (including push) >needs to be 64-bit, with "rme" constraint for the pushed value. > >I have CC'd the author of the above code, he might be interested in >the above discussion. > >Uros. > For 64 bits, if you need frame pointer support *and* frob %rsp, using: xchg %[arg],%%rbp <stuff> xchg %[arg],%%rbp ... is probably easiest, with %[arg] in a register.
On 2025-11-13 20:40, H. Peter Anvin wrote: > > For 64 bits, if you need frame pointer support *and* frob %rsp, using: > > xchg %[arg],%%rbp > <stuff> > xchg %[arg],%%rbp > > ... is probably easiest, with %[arg] in a register. > Incidentally, ORC is one thing, but if you need DWARF information to be correct for user space, it is definitely "fun". With the xchg hack for 64 bits it is just a matter of using .cfi_def_cfa_register to change the frame pointer around, but in the 32-bit case the best I could come up with was: .cfi_remember_state push %ebp .cfi_escape 0x0f,3,0x74,0,0x06 // CFA address in *%esp mov %eax, %ebp mov $syscall_no, %eax int $0x80 pop %ebp .cfi_restore_state Note that in both cases you need to *NOT* put in any of these CFI directives when compiling without frame pointers (in which case you need to let gcc take care of it if you want any hope of getting the CFI correct.) -hpa
© 2016 - 2026 Red Hat, Inc.