Skip to content

Commit f5caf62

Browse files
jpoimboeIngo Molnar
authored andcommitted
x86/asm: Fix inline asm call constraints for Clang
For inline asm statements which have a CALL instruction, we list the stack pointer as a constraint to convince GCC to ensure the frame pointer is set up first: static inline void foo() { register void *__sp asm(_ASM_SP); asm("call bar" : "+r" (__sp)) } Unfortunately, that pattern causes Clang to corrupt the stack pointer. The fix is easy: convert the stack pointer register variable to a global variable. It should be noted that the end result is different based on the GCC version. With GCC 6.4, this patch has exactly the same result as before: defconfig defconfig-nofp distro distro-nofp before 9820389 9491555 8816046 8516940 after 9820389 9491555 8816046 8516940 With GCC 7.2, however, GCC's behavior has changed. It now changes its behavior based on the conversion of the register variable to a global. That somehow convinces it to *always* set up the frame pointer before inserting *any* inline asm. (Therefore, listing the variable as an output constraint is a no-op and is no longer necessary.) It's a bit overkill, but the performance impact should be negligible. And in fact, there's a nice improvement with frame pointers disabled: defconfig defconfig-nofp distro distro-nofp before 9796316 9468236 9076191 8790305 after 9796957 9464267 9076381 8785949 So in summary, while listing the stack pointer as an output constraint is no longer necessary for newer versions of GCC, it's still needed for older versions. Suggested-by: Andrey Ryabinin <[email protected]> Reported-by: Matthias Kaehlcke <[email protected]> Signed-off-by: Josh Poimboeuf <[email protected]> Cc: Alexander Potapenko <[email protected]> Cc: Andy Lutomirski <[email protected]> Cc: Arnd Bergmann <[email protected]> Cc: Dmitriy Vyukov <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Miguel Bernal Marin <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Link: http://lkml.kernel.org/r/3db862e970c432ae823cf515c52b54fec8270e0e.1505942196.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar <[email protected]>
1 parent 0d0970e commit f5caf62

File tree

13 files changed

+42
-45
lines changed

13 files changed

+42
-45
lines changed

arch/x86/include/asm/alternative.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -218,10 +218,9 @@ static inline int alternatives_text_reserved(void *start, void *end)
218218
#define alternative_call_2(oldfunc, newfunc1, feature1, newfunc2, feature2, \
219219
output, input...) \
220220
{ \
221-
register void *__sp asm(_ASM_SP); \
222221
asm volatile (ALTERNATIVE_2("call %P[old]", "call %P[new1]", feature1,\
223222
"call %P[new2]", feature2) \
224-
: output, "+r" (__sp) \
223+
: output, ASM_CALL_CONSTRAINT \
225224
: [old] "i" (oldfunc), [new1] "i" (newfunc1), \
226225
[new2] "i" (newfunc2), ## input); \
227226
}

arch/x86/include/asm/asm.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,4 +132,15 @@
132132
/* For C file, we already have NOKPROBE_SYMBOL macro */
133133
#endif
134134

135+
#ifndef __ASSEMBLY__
136+
/*
137+
* This output constraint should be used for any inline asm which has a "call"
138+
* instruction. Otherwise the asm may be inserted before the frame pointer
139+
* gets set up by the containing function. If you forget to do this, objtool
140+
* may print a "call without frame pointer save/setup" warning.
141+
*/
142+
register unsigned int __asm_call_sp asm("esp");
143+
#define ASM_CALL_CONSTRAINT "+r" (__asm_call_sp)
144+
#endif
145+
135146
#endif /* _ASM_X86_ASM_H */

arch/x86/include/asm/mshyperv.h

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -179,15 +179,14 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output)
179179
u64 input_address = input ? virt_to_phys(input) : 0;
180180
u64 output_address = output ? virt_to_phys(output) : 0;
181181
u64 hv_status;
182-
register void *__sp asm(_ASM_SP);
183182

184183
#ifdef CONFIG_X86_64
185184
if (!hv_hypercall_pg)
186185
return U64_MAX;
187186

188187
__asm__ __volatile__("mov %4, %%r8\n"
189188
"call *%5"
190-
: "=a" (hv_status), "+r" (__sp),
189+
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
191190
"+c" (control), "+d" (input_address)
192191
: "r" (output_address), "m" (hv_hypercall_pg)
193192
: "cc", "memory", "r8", "r9", "r10", "r11");
@@ -202,7 +201,7 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output)
202201

203202
__asm__ __volatile__("call *%7"
204203
: "=A" (hv_status),
205-
"+c" (input_address_lo), "+r" (__sp)
204+
"+c" (input_address_lo), ASM_CALL_CONSTRAINT
206205
: "A" (control),
207206
"b" (input_address_hi),
208207
"D"(output_address_hi), "S"(output_address_lo),
@@ -224,12 +223,11 @@ static inline u64 hv_do_hypercall(u64 control, void *input, void *output)
224223
static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)
225224
{
226225
u64 hv_status, control = (u64)code | HV_HYPERCALL_FAST_BIT;
227-
register void *__sp asm(_ASM_SP);
228226

229227
#ifdef CONFIG_X86_64
230228
{
231229
__asm__ __volatile__("call *%4"
232-
: "=a" (hv_status), "+r" (__sp),
230+
: "=a" (hv_status), ASM_CALL_CONSTRAINT,
233231
"+c" (control), "+d" (input1)
234232
: "m" (hv_hypercall_pg)
235233
: "cc", "r8", "r9", "r10", "r11");
@@ -242,7 +240,7 @@ static inline u64 hv_do_fast_hypercall8(u16 code, u64 input1)
242240
__asm__ __volatile__ ("call *%5"
243241
: "=A"(hv_status),
244242
"+c"(input1_lo),
245-
"+r"(__sp)
243+
ASM_CALL_CONSTRAINT
246244
: "A" (control),
247245
"b" (input1_hi),
248246
"m" (hv_hypercall_pg)

arch/x86/include/asm/paravirt_types.h

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -459,8 +459,8 @@ int paravirt_disable_iospace(void);
459459
*/
460460
#ifdef CONFIG_X86_32
461461
#define PVOP_VCALL_ARGS \
462-
unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx; \
463-
register void *__sp asm("esp")
462+
unsigned long __eax = __eax, __edx = __edx, __ecx = __ecx;
463+
464464
#define PVOP_CALL_ARGS PVOP_VCALL_ARGS
465465

466466
#define PVOP_CALL_ARG1(x) "a" ((unsigned long)(x))
@@ -480,8 +480,8 @@ int paravirt_disable_iospace(void);
480480
/* [re]ax isn't an arg, but the return val */
481481
#define PVOP_VCALL_ARGS \
482482
unsigned long __edi = __edi, __esi = __esi, \
483-
__edx = __edx, __ecx = __ecx, __eax = __eax; \
484-
register void *__sp asm("rsp")
483+
__edx = __edx, __ecx = __ecx, __eax = __eax;
484+
485485
#define PVOP_CALL_ARGS PVOP_VCALL_ARGS
486486

487487
#define PVOP_CALL_ARG1(x) "D" ((unsigned long)(x))
@@ -532,7 +532,7 @@ int paravirt_disable_iospace(void);
532532
asm volatile(pre \
533533
paravirt_alt(PARAVIRT_CALL) \
534534
post \
535-
: call_clbr, "+r" (__sp) \
535+
: call_clbr, ASM_CALL_CONSTRAINT \
536536
: paravirt_type(op), \
537537
paravirt_clobber(clbr), \
538538
##__VA_ARGS__ \
@@ -542,7 +542,7 @@ int paravirt_disable_iospace(void);
542542
asm volatile(pre \
543543
paravirt_alt(PARAVIRT_CALL) \
544544
post \
545-
: call_clbr, "+r" (__sp) \
545+
: call_clbr, ASM_CALL_CONSTRAINT \
546546
: paravirt_type(op), \
547547
paravirt_clobber(clbr), \
548548
##__VA_ARGS__ \
@@ -569,7 +569,7 @@ int paravirt_disable_iospace(void);
569569
asm volatile(pre \
570570
paravirt_alt(PARAVIRT_CALL) \
571571
post \
572-
: call_clbr, "+r" (__sp) \
572+
: call_clbr, ASM_CALL_CONSTRAINT \
573573
: paravirt_type(op), \
574574
paravirt_clobber(clbr), \
575575
##__VA_ARGS__ \

arch/x86/include/asm/preempt.h

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -100,19 +100,14 @@ static __always_inline bool should_resched(int preempt_offset)
100100

101101
#ifdef CONFIG_PREEMPT
102102
extern asmlinkage void ___preempt_schedule(void);
103-
# define __preempt_schedule() \
104-
({ \
105-
register void *__sp asm(_ASM_SP); \
106-
asm volatile ("call ___preempt_schedule" : "+r"(__sp)); \
107-
})
103+
# define __preempt_schedule() \
104+
asm volatile ("call ___preempt_schedule" : ASM_CALL_CONSTRAINT)
108105

109106
extern asmlinkage void preempt_schedule(void);
110107
extern asmlinkage void ___preempt_schedule_notrace(void);
111-
# define __preempt_schedule_notrace() \
112-
({ \
113-
register void *__sp asm(_ASM_SP); \
114-
asm volatile ("call ___preempt_schedule_notrace" : "+r"(__sp)); \
115-
})
108+
# define __preempt_schedule_notrace() \
109+
asm volatile ("call ___preempt_schedule_notrace" : ASM_CALL_CONSTRAINT)
110+
116111
extern asmlinkage void preempt_schedule_notrace(void);
117112
#endif
118113

arch/x86/include/asm/processor.h

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -677,16 +677,14 @@ static inline void sync_core(void)
677677
* Like all of Linux's memory ordering operations, this is a
678678
* compiler barrier as well.
679679
*/
680-
register void *__sp asm(_ASM_SP);
681-
682680
#ifdef CONFIG_X86_32
683681
asm volatile (
684682
"pushfl\n\t"
685683
"pushl %%cs\n\t"
686684
"pushl $1f\n\t"
687685
"iret\n\t"
688686
"1:"
689-
: "+r" (__sp) : : "memory");
687+
: ASM_CALL_CONSTRAINT : : "memory");
690688
#else
691689
unsigned int tmp;
692690

@@ -703,7 +701,7 @@ static inline void sync_core(void)
703701
"iretq\n\t"
704702
UNWIND_HINT_RESTORE
705703
"1:"
706-
: "=&r" (tmp), "+r" (__sp) : : "cc", "memory");
704+
: "=&r" (tmp), ASM_CALL_CONSTRAINT : : "cc", "memory");
707705
#endif
708706
}
709707

arch/x86/include/asm/rwsem.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,6 @@ static inline bool __down_read_trylock(struct rw_semaphore *sem)
103103
({ \
104104
long tmp; \
105105
struct rw_semaphore* ret; \
106-
register void *__sp asm(_ASM_SP); \
107106
\
108107
asm volatile("# beginning down_write\n\t" \
109108
LOCK_PREFIX " xadd %1,(%4)\n\t" \
@@ -114,7 +113,8 @@ static inline bool __down_read_trylock(struct rw_semaphore *sem)
114113
" call " slow_path "\n" \
115114
"1:\n" \
116115
"# ending down_write" \
117-
: "+m" (sem->count), "=d" (tmp), "=a" (ret), "+r" (__sp) \
116+
: "+m" (sem->count), "=d" (tmp), \
117+
"=a" (ret), ASM_CALL_CONSTRAINT \
118118
: "a" (sem), "1" (RWSEM_ACTIVE_WRITE_BIAS) \
119119
: "memory", "cc"); \
120120
ret; \

arch/x86/include/asm/uaccess.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,11 +166,11 @@ __typeof__(__builtin_choose_expr(sizeof(x) > sizeof(0UL), 0ULL, 0UL))
166166
({ \
167167
int __ret_gu; \
168168
register __inttype(*(ptr)) __val_gu asm("%"_ASM_DX); \
169-
register void *__sp asm(_ASM_SP); \
170169
__chk_user_ptr(ptr); \
171170
might_fault(); \
172171
asm volatile("call __get_user_%P4" \
173-
: "=a" (__ret_gu), "=r" (__val_gu), "+r" (__sp) \
172+
: "=a" (__ret_gu), "=r" (__val_gu), \
173+
ASM_CALL_CONSTRAINT \
174174
: "0" (ptr), "i" (sizeof(*(ptr)))); \
175175
(x) = (__force __typeof__(*(ptr))) __val_gu; \
176176
__builtin_expect(__ret_gu, 0); \

arch/x86/include/asm/xen/hypercall.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,9 @@ extern struct { char _entry[32]; } hypercall_page[];
113113
register unsigned long __arg2 asm(__HYPERCALL_ARG2REG) = __arg2; \
114114
register unsigned long __arg3 asm(__HYPERCALL_ARG3REG) = __arg3; \
115115
register unsigned long __arg4 asm(__HYPERCALL_ARG4REG) = __arg4; \
116-
register unsigned long __arg5 asm(__HYPERCALL_ARG5REG) = __arg5; \
117-
register void *__sp asm(_ASM_SP);
116+
register unsigned long __arg5 asm(__HYPERCALL_ARG5REG) = __arg5;
118117

119-
#define __HYPERCALL_0PARAM "=r" (__res), "+r" (__sp)
118+
#define __HYPERCALL_0PARAM "=r" (__res), ASM_CALL_CONSTRAINT
120119
#define __HYPERCALL_1PARAM __HYPERCALL_0PARAM, "+r" (__arg1)
121120
#define __HYPERCALL_2PARAM __HYPERCALL_1PARAM, "+r" (__arg2)
122121
#define __HYPERCALL_3PARAM __HYPERCALL_2PARAM, "+r" (__arg3)

arch/x86/kvm/emulate.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5296,15 +5296,14 @@ static void fetch_possible_mmx_operand(struct x86_emulate_ctxt *ctxt,
52965296

52975297
static int fastop(struct x86_emulate_ctxt *ctxt, void (*fop)(struct fastop *))
52985298
{
5299-
register void *__sp asm(_ASM_SP);
53005299
ulong flags = (ctxt->eflags & EFLAGS_MASK) | X86_EFLAGS_IF;
53015300

53025301
if (!(ctxt->d & ByteOp))
53035302
fop += __ffs(ctxt->dst.bytes) * FASTOP_SIZE;
53045303

53055304
asm("push %[flags]; popf; call *%[fastop]; pushf; pop %[flags]\n"
53065305
: "+a"(ctxt->dst.val), "+d"(ctxt->src.val), [flags]"+D"(flags),
5307-
[fastop]"+S"(fop), "+r"(__sp)
5306+
[fastop]"+S"(fop), ASM_CALL_CONSTRAINT
53085307
: "c"(ctxt->src2.val));
53095308

53105309
ctxt->eflags = (ctxt->eflags & ~EFLAGS_MASK) | (flags & EFLAGS_MASK);

arch/x86/kvm/vmx.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9036,7 +9036,6 @@ static void vmx_complete_atomic_exit(struct vcpu_vmx *vmx)
90369036
static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
90379037
{
90389038
u32 exit_intr_info = vmcs_read32(VM_EXIT_INTR_INFO);
9039-
register void *__sp asm(_ASM_SP);
90409039

90419040
if ((exit_intr_info & (INTR_INFO_VALID_MASK | INTR_INFO_INTR_TYPE_MASK))
90429041
== (INTR_INFO_VALID_MASK | INTR_TYPE_EXT_INTR)) {
@@ -9065,7 +9064,7 @@ static void vmx_handle_external_intr(struct kvm_vcpu *vcpu)
90659064
#ifdef CONFIG_X86_64
90669065
[sp]"=&r"(tmp),
90679066
#endif
9068-
"+r"(__sp)
9067+
ASM_CALL_CONSTRAINT
90699068
:
90709069
[entry]"r"(entry),
90719070
[ss]"i"(__KERNEL_DS),

arch/x86/mm/fault.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -806,7 +806,6 @@ no_context(struct pt_regs *regs, unsigned long error_code,
806806
if (is_vmalloc_addr((void *)address) &&
807807
(((unsigned long)tsk->stack - 1 - address < PAGE_SIZE) ||
808808
address - ((unsigned long)tsk->stack + THREAD_SIZE) < PAGE_SIZE)) {
809-
register void *__sp asm("rsp");
810809
unsigned long stack = this_cpu_read(orig_ist.ist[DOUBLEFAULT_STACK]) - sizeof(void *);
811810
/*
812811
* We're likely to be running with very little stack space
@@ -821,7 +820,7 @@ no_context(struct pt_regs *regs, unsigned long error_code,
821820
asm volatile ("movq %[stack], %%rsp\n\t"
822821
"call handle_stack_overflow\n\t"
823822
"1: jmp 1b"
824-
: "+r" (__sp)
823+
: ASM_CALL_CONSTRAINT
825824
: "D" ("kernel stack overflow (page fault)"),
826825
"S" (regs), "d" (address),
827826
[stack] "rm" (stack));

tools/objtool/Documentation/stack-validation.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,10 +194,10 @@ they mean, and suggestions for how to fix them.
194194
If it's a GCC-compiled .c file, the error may be because the function
195195
uses an inline asm() statement which has a "call" instruction. An
196196
asm() statement with a call instruction must declare the use of the
197-
stack pointer in its output operand. For example, on x86_64:
197+
stack pointer in its output operand. On x86_64, this means adding
198+
the ASM_CALL_CONSTRAINT as an output constraint:
198199

199-
register void *__sp asm("rsp");
200-
asm volatile("call func" : "+r" (__sp));
200+
asm volatile("call func" : ASM_CALL_CONSTRAINT);
201201

202202
Otherwise the stack frame may not get created before the call.
203203

0 commit comments

Comments
 (0)