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.)