Reputation: 1440
Recently I started using Windbg(x64), To play with it, I have compiled(x64) a sample program using
cl.exe ls.c /Zi /Od /GS-
Interestingly the functions generated for the executable contain FPO optimization. Below is the snippet of the disassembly of a routine.
0:000> uf ls!GetDateString
ls!GetDateString:
00007ff7`459a6d00 mov qword ptr [rsp+8],rcx
00007ff7`459a6d05 sub rsp,88h
00007ff7`459a6d0c mov qword ptr [rsp+58h],0
00007ff7`459a6d15 mov qword ptr [rsp+50h],0
00007ff7`459a6d1e mov eax,dword ptr [ls!dateType (00007ff7`45a14494)]
00007ff7`459a6d24 and eax,1
00007ff7`459a6d27 test eax,eax
00007ff7`459a6d29 je ls!GetDateString+0x3e (00007ff7`459a6d3e)
May I know how can I disable this FPO optimization on x64 VC++ compilers. Looking at the official documentation it seems we cannot disable it via /Oy- switch https://msdn.microsoft.com/en-us/library/2kxx5t2c.aspx
/Oy enables frame-pointer omission and /Oy- disables omission. /Oy is available only in x86 compilers.
I am wondering if this flag is only available for x86, then how come the x64 windows routines like FileTimeToSystemTime has FPO disabled!
0:000> uf .
KERNELBASE!FileTimeToSystemTime:
00007ffc`a03ad120 mov qword ptr [rsp+18h],rbx
00007ffc`a03ad125 push rbp
00007ffc`a03ad126 mov rbp,rsp
00007ffc`a03ad129 sub rsp,40h
00007ffc`a03ad12d mov rax,qword ptr [KERNELBASE!_security_cookie (00007ffc`a0515000)]
00007ffc`a03ad134 xor rax,rsp
00007ffc`a03ad137 mov qword ptr [rbp-8],rax
00007ffc`a03ad13b mov eax,dword ptr [rcx]
00007ffc`a03ad13d mov rbx,rdx
00007ffc`a03ad140 mov dword ptr [rbp-20h],eax
00007ffc`a03ad143 mov eax,dword ptr [rcx+4]
00007ffc`a03ad146 mov dword ptr [rbp-1Ch],eax
Upvotes: 2
Views: 1188
Reputation: 9007
In x64 if you are using the function __alloca()
(allocate memory in stack)
then ebp is used as frame pointer otherwise ebp is a general purpose register ebp is not used as frame pointer
if ebp is used as frame pointer then unwind info may contain
UWOP_PUSH_NONVOL reg: rbp and UWOP_SET_FPREG
sample src compiled with cl /Zi /Od /GS- test.cpp
compiled from a 32 bit machine using windows sdk environment
@call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\setenv.cmd" /x64 /RELEASE
src used
#include <stdio.h>
#include <malloc.h>
__int64 wtfisfpo(__int64 a , __int64 b ) {
char *foo = (char *)_alloca(0x20);
*foo = 'b';
printf("%c\n",foo);
return (b+a);
}
int main(void) {
printf("%I64x\n", wtfisfpo(4,9));
return 1;
}
disassembled with windbg in 32 bit machine loading the exe as dump windbg -z test.exe
0:000> uf test!wtfisfpo
test!wtfisfpo [xxxx\test.cpp @ 4]:
4 00000001`40001020 4889542410 mov qword ptr [rsp+10h],rdx
4 00000001`40001025 48894c2408 mov qword ptr [rsp+8],rcx
4 00000001`4000102a 55 push rbp
4 00000001`4000102b 4883ec30 sub rsp,30h
4 00000001`4000102f 488d6c2420 lea rbp,[rsp+20h]
5 00000001`40001034 8b0424 mov eax,dword ptr [rsp]
5 00000001`40001037 b820000000 mov eax,20h
5 00000001`4000103c 482be0 sub rsp,rax
5 00000001`4000103f 488d442420 lea rax,[rsp+20h]
5 00000001`40001044 8b08 mov ecx,dword ptr [rax]
5 00000001`40001046 48894500 mov qword ptr [rbp],rax
6 00000001`4000104a 488b4500 mov rax,qword ptr [rbp]
6 00000001`4000104e c60062 mov byte ptr [rax],62h
7 00000001`40001051 488b5500 mov rdx,qword ptr [rbp]
7 00000001`40001055 488d0d907c0100 lea rcx,[test!__xt_z+0x12c (00000001`40018cec)]
7 00000001`4000105c e8cf000000 call test!printf (00000001`40001130)
8 00000001`40001061 488b4520 mov rax,qword ptr [rbp+20h]
8 00000001`40001065 488b4d28 mov rcx,qword ptr [rbp+28h]
8 00000001`40001069 4803c8 add rcx,rax
8 00000001`4000106c 488bc1 mov rax,rcx
9 00000001`4000106f 488d6510 lea rsp,[rbp+10h]
9 00000001`40001073 5d pop rbp
9 00000001`40001074 c3 ret
the unwind info details of this function
0:000> .fnent test!wtfisfpo
Debugger function entry 00000000`000d39a0 for:
xxxx\test.cpp(4)
(00000001`40001020) test!wtfisfpo | (00000001`40001080) test!main
Exact matches:
test!wtfisfpo (int64, int64)
BeginAddress = 00000000`00001020
EndAddress = 00000000`00001075
UnwindInfoAddress = 00000000`0001c1b8
Unwind info at 00000001`4001c1b8, a bytes
version 1, flags 0, prolog 14, codes 3
frame reg 5 (rbp), frame offs 20h
00: offs 14, unwind op 3, op info 2 UWOP_SET_FPREG.
01: offs f, unwind op 2, op info 5 UWOP_ALLOC_SMALL.
02: offs b, unwind op 0, op info 5 UWOP_PUSH_NONVOL reg: rbp.
as to the comment why rbp is used maybe the function was compiled as an assembly routine like this
include ksamd64.inc
.CODE
main PROC
call sample
main ENDP
sample PROC FRAME
push_reg rbp
set_frame rbp, 0h
.endprolog
add rsp, 0
pop rbp
ret
sample ENDP
END
assembled with
@call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\setenv.cmd" /x64 /RELEASE
ml64.exe /Zi 64bitasm.asm /link /subsystem:console /defaultlib:kernel32.lib /entry:main /RELEASE
and the relevent disassembly
0:000> x 64bitasm!*
00000001`40002058 64bitasm!$xdatasym = 0x01 ''
00000001`40001000 64bitasm!main (void)
00000001`40001005 64bitasm!sample (void)
0:000> uf 64bitasm!sample
64bitasm!sample [\64bitasm.asm @ 7]:
7 00000001`40001005 55 push rbp
9 00000001`40001006 488bec mov rbp,rsp
11 00000001`40001009 4883c400 add rsp,0
12 00000001`4000100d 5d pop rbp
13 00000001`4000100e c3 ret
0:000> uf 64bitasm!main
64bitasm!main [\64bitasm.asm @ 3]:
3 00000001`40001000 e800000000 call 64bitasm!sample (00000001`40001005)
7 00000001`40001005 55 push rbp
9 00000001`40001006 488bec mov rbp,rsp
11 00000001`40001009 4883c400 add rsp,0
12 00000001`4000100d 5d pop rbp
13 00000001`4000100e c3 ret
Upvotes: 0