【问题标题】:How to disable FPO optimisation on x64 VC++ compiler如何在 x64 VC++ 编译器上禁用 FPO 优化
【发布时间】:2015-11-17 04:20:50
【问题描述】:

最近我开始使用 Windbg(x64),为了玩它,我用它编译了一个示例程序(x64)

cl.exe ls.c /Zi /Od /GS-

有趣的是,为可执行文件生成的函数包含 FPO 优化。下面是一个例程的反汇编的sn-p。

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)

我可以知道如何在 x64 VC++ 编译器上禁用此 FPO 优化。查看官方文档似乎我们无法通过 /Oy- 开关禁用它 https://msdn.microsoft.com/en-us/library/2kxx5t2c.aspx

/Oy 启用帧指针省略和 /Oy- 禁用省略。 /Oy 是 仅在 x86 编译器中可用。

我想知道这个标志是否仅适用于 x86,那么像 FileTimeToSystemTime 这样的 x64 Windows 例程怎么会禁用 FPO!

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

【问题讨论】:

  • “为什么像 FileTimeToSystemTime 这样的 x64 Windows 例程禁用了 FPO!” - 操作系统没有使用作为 Visual Studio 一部分提供的相同编译器进行编译。
  • 为什么要禁用帧指针省略?
  • @RossRidge 我真的不想禁用帧指针省略。但只是想知道 Windows 二进制文件的 x64 版本是如何禁用 FPO 的。我正在寻找某种可能导致这种情况的编译器标志。我对 FPO 优化很好。
  • Microsoft x64 ABI 不要求函数具有帧指针,除非函数在堆栈上动态分配空间。

标签: windows winapi visual-c++ windbg disassembly


【解决方案1】:

在 x64 中,如果您使用函数 __alloca() (allocate memory in stack) 然后 ebp 用作帧指针,否则 ebp 是通用寄存器 ebp 不用作帧指针
如果 ebp 用作帧指针,则展开信息可能包含

UWOP_PUSH_NONVOL reg: rbp and UWOP_SET_FPREG 

使用cl /Zi /Od /GS- test.cpp编译的示例src
使用windows sdk环境从32位机器编译

@call "C:\Program Files\Microsoft SDKs\Windows\v7.1\Bin\setenv.cmd" /x64 /RELEASE

使用的源代码

#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;
}

在 32 位机器上用 windbg 反汇编,将 exe 作为转储加载 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

此函数的展开信息详情

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.

关于为什么使用 rbp 的注释可能该函数被编译为这样的汇编例程

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

组装在一起

@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

以及相关的反汇编

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

【讨论】:

  • 云请解释一下x64版本的KERNELBASE!FileTimeToSystemTime怎么会有rbp?
  • 可以编译成程序集吗?使用 set_frame ebp ,0 查看您也可以进行的编辑
猜你喜欢
  • 2011-08-11
  • 2010-11-15
  • 2013-08-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-19
  • 2022-11-25
相关资源
最近更新 更多