返回介绍

21.1 参数的传递,加法,减法

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

#!cpp
#include <stdint.h>
uint64_t f1 (uint64_t a, uint64_t b)
{
        return a+b;
};
void f1_test ()
{
#ifdef __GNUC__
        printf ("%lld
", f1(12345678901234, 23456789012345));
#else
        printf ("%I64d
", f1(12345678901234, 23456789012345));
#endif
};
uint64_t f2 (uint64_t a, uint64_t b)
{
        return a-b;
};

代码 21.1: MSVC 2012 /Ox /Ob1

#!bash
_a$ = 8                                             ; size = 8
_b$ = 16                                            ; size = 8
_f1     PROC
        mov     eax, DWORD PTR _a$[esp-4]
        add     eax, DWORD PTR _b$[esp-4]
        mov     edx, DWORD PTR _a$[esp]
        adc     edx, DWORD PTR _b$[esp]
        ret     0
_f1     ENDP

_f1_test    PROC
        push        5461                            ; 00001555H
        push        1972608889                      ; 75939f79H
        push        2874                            ; 00000b3aH
        push        1942892530                      ; 73ce2ff2H
        call        _f1
        push        edx
        push        eax
        push        OFFSET $SG1436 ; ’%I64d’, 0aH, 00H
        call        _printf
        add         esp, 28                         ; 0000001cH
        ret     0
_f1_test    ENDP
_f2     PROC
        mov     eax, DWORD PTR _a$[esp-4]
        sub     eax, DWORD PTR _b$[esp-4]
        mov     edx, DWORD PTR _a$[esp]
        sbb     edx, DWORD PTR _b$[esp]
        ret     0
_f2     ENDP

我们可以看到在函数 f1_test() 中每个 64 位值转化为 2 个 32 位值,高位先转,然后是低位。加法和减法也是如此。

当进行加法操作时,低 32 位部分先做加法。如果相加过程中产生进位,则设置 CF 标志。下一步通过 ADC 指令加上高位部分,如果 CF 置 1 了就增加 1。

减法操作也是如此。第一个 SUB 操作也会导致 CF 标志的改变,并在随后的 SBB 操作中检查:如果 CF 置 1 了,那么最终结果也会减去 1。

在 32 位环境中,64 位的值是从 EDX:EAX 这一对寄存器的函数中返回的。可以很容易看出 f1() 函数是如何转化为 printf() 函数的。

代码 21.2: GCC 4.8.1 -O1 -fno-inline

#!bash
_f1:    
        mov     eax, DWORD PTR [esp+12]
        mov     edx, DWORD PTR [esp+16]
        add     eax, DWORD PTR [esp+4]
        adc     edx, DWORD PTR [esp+8]
        ret

_f1_test:
        sub     esp, 28
        mov     DWORD PTR [esp+8], 1972608889           ; 75939f79H
        mov     DWORD PTR [esp+12], 5461                ; 00001555H
        mov     DWORD PTR [esp], 1942892530             ; 73ce2ff2H
        mov     DWORD PTR [esp+4], 2874                 ; 00000b3aH
        call    _f1
        mov     DWORD PTR [esp+4], eax
        mov     DWORD PTR [esp+8], edx
        mov     DWORD PTR [esp], OFFSET FLAT:LC0        ; "%lld12"
        call    _printf
        add     esp, 28
        ret

_f2:
        mov     eax, DWORD PTR [esp+4]
        mov     edx, DWORD PTR [esp+8]
        sub     eax, DWORD PTR [esp+12]
        sbb     edx, DWORD PTR [esp+16]
        ret

GCC 代码也是如此。

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

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

发布评论

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