https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110533
Bug ID: 110533
Summary: [x86-64] naked with -O0 and register-passed
struct/int128 clobbers parameters/callee-saved regs
Product: gcc
Version: unknown
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: target
Assignee: unassigned at gcc dot gnu.org
Reporter: engelke at in dot tum.de
Target Milestone: ---
Compiling a naked function with a parameter that is split over multiple
registers generates several mov operations with -O0, clobbering other
parameters and callee-saved registers. This does not happen with -O1. This
happens since the introduction of naked in GCC 8, at least up to GCC 13.
Example:
__attribute__((naked))
void fn(__int128 a) {
asm("ret");
}
Compiles to; note that rbx (callee-saved) is clobbered:
fn:
.LFB0:
.cfi_startproc
movq %rdi, %rdx
movq %rsi, %rax
movq %rcx, %rbx
movq %rdx, %rcx
movq %rax, %rbx
#APP
# 3 "<stdin>" 1
ret
# 0 "" 2
#NO_APP
nop
ud2
.cfi_endproc
With two parameters:
__attribute__((naked))
void fn(__int128 a, __int128 b) {
asm("ret");
}
Compiles to; note that rbx and the second parameter are clobbered:
fn:
.LFB0:
.cfi_startproc
movq %rdi, %rdx
movq %rsi, %rax
movq %rcx, %rbx
movq %rdx, %rcx
movq %rax, %rbx
#APP
# 3 "<stdin>" 1
ret
# 0 "" 2
#NO_APP
nop
ud2
.cfi_endproc
With a slight modification everything works as expected:
__attribute__((naked))
void fn(int x, int y, __int128 a) {
asm("ret");
}
Compiles to:
fn:
.LFB0:
.cfi_startproc
#APP
# 3 "<stdin>" 1
ret
# 0 "" 2
#NO_APP
nop
ud2
.cfi_endproc
(Above examples generated with gcc 12.2.1, but many other versions are affected
as well.)