ovmf miscompiles with gcc-12


Jiri Slaby <jirislaby@...>
 

Hi,

we discovered that qemu-ovmf-x86_64 doesn't start when compiled using gcc-12. Originally reported as:
https://bugzilla.suse.com/show_bug.cgi?id=1199597

I run qemu as:
qemu-kvm -drive file=/dev/null,format=raw -drive if=pflash,format=raw,unit=0,readonly=on,file=OVMF.fd -m 3000

The platform repeatedly resets after TemporaryRamMigration as can be seen in the debuglog:
https://bugzilla.suse.com/attachment.cgi?id=858969

The reason is TemporaryRamMigration() overwrites rbp unconditionally --
it adds an offset to rbp even if rbp is NOT used as a frame pointer (-fomit-frame-pointer was always used for compilation here). So commenting out:
//JumpBuffer.Rbp = JumpBuffer.Rbp + DebugAgentContext.StackMigrateOffset;
makes it all work again. Also marking TemporaryRamMigration() as:
__attribute__((optimize("-fno-omit-frame-pointer")))
works around the problem too. (But that doesn't guarantee anything.)

The code is:
if (SetJump (&JumpBuffer) == 0) {
#if defined (MDE_CPU_IA32)
JumpBuffer.Esp = JumpBuffer.Esp + DebugAgentContext.StackMigrateOffset;
JumpBuffer.Ebp = JumpBuffer.Ebp + DebugAgentContext.StackMigrateOffset;
#endif
#if defined (MDE_CPU_X64)
JumpBuffer.Rsp = JumpBuffer.Rsp + DebugAgentContext.StackMigrateOffset;
JumpBuffer.Rbp = JumpBuffer.Rbp + DebugAgentContext.StackMigrateOffset;
#endif
LongJump (&JumpBuffer, (UINTN)-1);
}
It was only coincidence this ever worked -- gcc-11 omits the frame pointer too, but apparently the caller (PeiCheckAndSwitchStack) does not use rbp.

PeiCheckAndSwitchStack() (gcc-12):

79a6: 4c 29 fd sub %r15,%rbp <------ used rbp
79a9: 4d 29 fe sub %r15,%r14
79ac: 48 83 ec 20 sub $0x20,%rsp
79b0: 4d 89 e0 mov %r12,%r8
79b3: 48 8d 4b 08 lea 0x8(%rbx),%rcx
79b7: 48 8b 44 24 50 mov 0x50(%rsp),%rax
79bc: 48 8b 54 24 20 mov 0x20(%rsp),%rdx
79c1: 4d 29 e8 sub %r13,%r8
79c4: 4c 8b 4c 24 30 mov 0x30(%rsp),%r9
79c9: ff 10 call *(%rax) <----------- call to TemporaryRamMigration
79cb: 48 83 c4 20 add $0x20,%rsp
79cf: be 01 00 00 00 mov $0x1,%esi
79d4: 4c 89 f7 mov %r14,%rdi
79d7: e8 f4 a8 ff ff call 22d0 <MigrateMemoryPages>
79dc: 48 83 ec 20 sub $0x20,%rsp
79e0: 4d 89 f0 mov %r14,%r8
79e3: 31 d2 xor %edx,%edx
79e5: 48 89 e9 mov %rbp,%rcx <------ rbp used
gcc-11 seems to copy rbp to r8 first and operates on r8 there instead.

Now, what is the right way to fix this? Do the SetJump/LongJump in assembly and wrap it into push rbp/pop rbp?

thanks,
--
js
suse labs

Join {devel@edk2.groups.io to automatically receive all group messages.