Message ID | 20250318091904.52903-2-roger.pau@citrix.com (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | x86/ubsan: fix ubsan on clang + code fixes | expand |
On 18/03/2025 9:19 am, Roger Pau Monne wrote: > When enabling UBSAN with clang, the following error is triggered during the > build: > > common/wait.c:154:9: error: symbol '.L_wq_resume' is already defined > 154 | "push %%rbx; push %%rbp; push %%r12;" > | ^ > <inline asm>:1:121: note: instantiated into assembly here > 1 | push %rbx; push %rbp; push %r12;push %r13; push %r14; push %r15;sub %esp,%ecx;cmp $4096, %ecx;ja .L_skip;mov %rsp,%rsi;.L_wq_resume: rep movsb;mov %rsp,%rsi;.L_skip:pop %r15; pop %r14; pop %r13;pop %r12; pop %rbp; pop %rbx > | ^ > common/wait.c:154:9: error: symbol '.L_skip' is already defined > 154 | "push %%rbx; push %%rbp; push %%r12;" > | ^ > <inline asm>:1:159: note: instantiated into assembly here > 1 | push %rbx; push %rbp; push %r12;push %r13; push %r14; push %r15;sub %esp,%ecx;cmp $4096, %ecx;ja .L_skip;mov %rsp,%rsi;.L_wq_resume: rep movsb;mov %rsp,%rsi;.L_skip:pop %r15; pop %r14; pop %r13;pop %r12; pop %rbp; pop %rbx > | ^ > 2 errors generated. > > The inline assembly block in __prepare_to_wait() is duplicated, thus > leading to multiple definitions of the otherwise unique labels inside the > assembly block. GCC extended-asm documentation notes the possibility of > duplicating asm blocks: > >> Under certain circumstances, GCC may duplicate (or remove duplicates of) >> your assembly code when optimizing. This can lead to unexpected duplicate >> symbol errors during compilation if your asm code defines symbols or >> labels. Using ‘%=’ (see AssemblerTemplate) may help resolve this problem. > Workaround the issue by latching esp to a local variable, this prevents > clang duplicating the inline asm blocks. > > Suggested-by: Jan Beulich <jbeulich@suse.com> > Signed-off-by: Roger Pau Monné <roger.pau@citrix.com> Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
diff --git a/xen/common/wait.c b/xen/common/wait.c index cb6f5ff3c20a..9a11dccb5de5 100644 --- a/xen/common/wait.c +++ b/xen/common/wait.c @@ -124,6 +124,11 @@ static void __prepare_to_wait(struct waitqueue_vcpu *wqv) struct cpu_info *cpu_info = get_cpu_info(); struct vcpu *curr = current; unsigned long dummy; + /* + * Latch esp to a local variable to prevent clang from duplicating the + * inline assembly block when UBSAN is enabled. + */ + void *esp = NULL; ASSERT(wqv->esp == NULL); @@ -166,12 +171,12 @@ static void __prepare_to_wait(struct waitqueue_vcpu *wqv) ".L_skip:" "pop %%r15; pop %%r14; pop %%r13;" "pop %%r12; pop %%rbp; pop %%rbx" - : "=&S" (wqv->esp), "=&c" (dummy), "=&D" (dummy) + : "=&S" (esp), "=&c" (dummy), "=&D" (dummy) : "0" (0), "1" (cpu_info), "2" (wqv->stack), [sz] "i" (PAGE_SIZE) : "memory", "rax", "rdx", "r8", "r9", "r10", "r11" ); - if ( unlikely(wqv->esp == NULL) ) + if ( unlikely(esp == NULL) ) { gdprintk(XENLOG_ERR, "Stack too large in %s\n", __func__); domain_crash(curr->domain); @@ -179,6 +184,7 @@ static void __prepare_to_wait(struct waitqueue_vcpu *wqv) for ( ; ; ) do_softirq(); } + wqv->esp = esp; } static void __finish_wait(struct waitqueue_vcpu *wqv)