返回介绍

14.1 x86

发布于 2025-02-22 14:00:44 字数 1533 浏览 0 评论 0 收藏 0

以一种十分容易预测的方式编译的

#!bash
_a$ = 8             ; size = 4
_f   PROC
    push    ebp
    mov     ebp, esp
    mov     eax, DWORD PTR _a$[ebp]
    cdq             ; sign extend EAX to EDX:EAX
    mov     ecx, 9
    idiv    ecx
    pop     ebp
    ret     0
_f  ENDP

IDIV 有符号数除法指令 64 位的被除数分存在两个寄存器 EDX:EAX,除数放在单个寄存器 ECX 中。运算结束后,商放在 EAX,余数放在 EDX。f()函数的返回值将包含在 eax 寄存器中,也就是说,在进行除法运算之后,值不会再放到其他位置,它已经在合适的地方了。正因为 IDIV 指令要求被除数分存在 EDX:EAX 里,所以需要在做除法前用 CDQ 指令将 EAX 中的值扩展成 64 位有符号数,就像 MOVSX 指令(13.1.1) 所做的一样。如果我们切换到优化模式(/0x),我们会得到

清单 14.2:MSVC 优化模式

#!bash
_a$ = 8                         ; size = 4
_f   PROC

    mov     ecx, DWORD PTR _a$[esp-4]
    mov     eax, 954437177      ; 38e38e39H
    imul    ecx
    sar     edx, 1
    mov     eax, edx
    shr     eax, 31             ; 0000001fH
    add     eax, edx
    ret     0
_f   ENDP

这里将除法优化为乘法。乘法运算要快得多。使用这种技巧可以得到更高效的代码。

在编译器优化中,这也称为“strength reduction”

GCC4.4.1 甚至在没有打开优化模式的情况下生成了和在 MSVC 下打开优化模式的生成的几乎一样的代码。

清单 14.3 GCC 4.4.1 非优化模式

#!bash
        public f
f       procnear
arg_0   = dword ptr 8

        push    ebp
        mov     ebp, esp
        mov     ecx, [ebp+arg_0]
        mov     edx, 954437177 ; 38E38E39h
        mov     eax, ecx
        imul    edx
        sar     edx, 1
        mov     eax, ecx
        sar     eax, 1Fh
        mov     ecx, edx
        sub     ecx, eax
        mov     eax, ecx
        pop     ebp
        retn
f       endp

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文