【问题标题】:Prologue of "add esp, 0FFFFFFF8h"“add esp, 0FFFFFFF8h”的序言
【发布时间】:2015-10-14 03:29:59
【问题描述】:

我的 MASM 有点生疏了,所以我真的不记得在这里做什么(如果有什么需要做的话)。我有一个如下所示的 MASM (X86) 例程。它有两个局部变量,总共占用 5 个字节:

MSC_ASM_GenerateBlock PROC buffer:DWORD,bsize:DWORD,safety:DWORD
  LOCAL val:DWORD, rc:BYTE  ;; local variables
  MWSIZE EQU 4              ;; machine word size

  .WHILE bsize >= MWSIZE && safety > 0
     ;; RDRAND is not available prior to VS2012. Just emit
     ;;   the byte codes using DB. This is `rdrand eax`.
     DB 0Fh, 0C7h, 0F0h
     setc rc
     ...
  .ENDW
  ...
MSC_ASM_GenerateBlock ENDP

当我检查反汇编时,我看到:

> dumpbin.exe /DISASM rdrand-x86.obj
Dump of file rdrand-x86.obj

_MSC_ASM_GenerateBlock:
  00000000: 55                 push        ebp
  00000001: 8B EC              mov         ebp,esp
  00000003: 83 C4 F8           add         esp,0FFFFFFF8h
  00000006: EB 1D              jmp         00000025
  00000008: 0F C7 F0           rdrand      eax
  0000000B: 0F 92 45 FB        setb        byte ptr [ebp-5]
  0000000F: 80 7D FB 00        cmp         byte ptr [ebp-5],0
  ...

我相信add esp, 0FFFFFFF8hsub esp, 08h 的另一种说法。

正如 Joshua 所指出的,add espsub esp 之间的区别在于操作后的标志。汇编器的混淆或指令选择可能是基于汇编器没有看到RDRAND 上下文的事实。相反,它只看到基于CYjmp,并且汇编程序认为这些标志状态不佳。

为什么 MASM 会生成依赖于无符号整数换行的非直观 add?更重要的是,可以吗?


我使用更广泛的机器字执行了到 MASM64/ML64 的路由端口。它产生相同的代码(模机器字长):

Dump of file rdrand-x64.obj

MSC_ASM_GenerateBlock:
  0000000000000000: 55                 push        rbp
  0000000000000001: 48 8B EC           mov         rbp,rsp
  0000000000000004: 48 83 C4 F0        add         rsp,0FFFFFFFFFFFFFFF0h
  0000000000000008: EB 1D              jmp         0000000000000037
  0000000000000010: 48 0F C7 F0        rdrand      rax
  000000000000001D: 0F 92 45 F7        setb        byte ptr [rbp-9]
  0000000000000024: 80 7D F7 00        cmp         byte ptr [rbp-9],0
  ...

【问题讨论】:

    标签: assembly x86 masm integer-overflow stack-pointer


    【解决方案1】:

    奇怪的编译器。很奇怪。

    add esp, 0FFFFFFF8h
    

    完全一样

    sub esp, 8h
    

    除了它设置不同的标志位。很好,是的,它取决于无符号整数换行。不是问题,因为组装本质上是不可移植的。如果你想知道为什么你必须问微软,他们可能已经不知道了。

    【讨论】:

    • "...除了它设置不同的标志位" - 也许就是这样。尽管RDRAND 设置了标志,但编译器无法判断,因为这是针对cl.exeml.exe 与VS2005、VS2008 和VS2010 一起提供的(它们都不能发出RDRAND)。所有编译器和汇编器看到/理解的是基于CY 的跳转,没有RDRAND 上下文。
    • 但事实并非如此。更改 esp 后不检查标志位。
    • @jww 编译器为什么这样做的一种可能性可能与它需要为本地堆栈空间正好分配 128 个字节的情况有关。在这种情况下,addsub 之间存在差异。 add esp, -128 仍然可以用 3 个字节编码,但 sub esp, 128 需要 6 个字节。在这种情况下只需要 8 个字节,这并不重要(addsub 都编码为 3 个字节)。
    【解决方案2】:

    我不知道为什么 MASM 会认为这是一个好主意,但无符号溢出会起作用(所以这是安全的),更令人困惑的是,即使在 64 位处理器上,这也是一个安全的替换,因为 32 位操作数会将寄存器的高 32 位清零!请参阅this 了解说明。

    此外,由于两条指令都是 3 个字节长,因此没有任何低效率。

    【讨论】:

    • 好吧,除了 64 位模式,RSP 的高 32 位可能不是 0。
    • 他们将在 32 位指令之后!
    • 这意味着它在 64 位模式下不安全。
    • @RossRidge:是的,无论您执行 32 位加法还是 32 位减法,前 32 位都将为 0。因此,可以替换该指令。
    • @RossRidge:您显然不明白这里要问和回答的内容......问题是:“32 位子指令可以用这个 32 位添加指令替换”和答案是的,因为在执行 either 指令后,前 32 位将为 0。 32 位子指令在 64 位模式下可能不安全是完全无关的。
    猜你喜欢
    • 1970-01-01
    • 2022-08-06
    • 1970-01-01
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    • 2011-08-23
    • 2012-10-10
    相关资源
    最近更新 更多