为什么我必须使用“rsp”来调用c ++函数?

时间:2016-10-31 14:37:31

标签: assembly x86-64 masm

我刚刚开始我的装配之旅,所以很明显我是一个新手,我一直在写相当简单的基本程序,我只是注意到一些奇怪的东西(对我而言)。

一个程序,以二进制

中的111结尾表中的数字计数

切入点:

#include <iostream>
#include <cstdlib>

extern "C" auto _start(void *, void *)->void;

auto print_msg(char *msg) {
    std::cout << msg;
}

auto print_int(uint64_t val) {
    std::cout << val;
}

auto main()->int {
    _start(print_int, print_msg);
    std::cout << std::endl;
    system("pause");
}

组件:

.const
_tab    dw 65535, 61951, 61949, 61925, 61927, 61734, 61735, 61728
_LENGTH = ($ - _tab) / 2
_msg_1  db 'There are ', 0
_msg_2  db ' numbers ending with 111 in binary!', 0

.code
_start proc
         push     r15
         push     r14
         sub      rsp, 32 + 16
         mov      r14, rcx
         mov      r15, rdx
         xor      rcx, rcx
         xor      r9,  r9
         lea      r8,  _tab
_LOOP:   movzx    rax, word ptr [r8]
         and      rax, 111b
         cmp      rax, 111b
         jz       _INC
         jmp      _END_IF
_INC:    inc      rcx
_END_IF: inc      r9
         add      r8,  2
         cmp      r9,  _LENGTH
         jne      _LOOP
         mov      [rsp + 32], rcx
         lea      rcx, _msg_1
         call     r15
         mov      rcx, [rsp + 32]

         sub      rsp, 8
         call     r14
         add      rsp, 8

         lea      rcx, _msg_2
         call     r15
         add      rsp, 32 + 16
         pop      r14
         pop      r15
         ret
_start endp

end

如果我在“呼叫r14”周围发表评论“sub rsp,8”和“添加rsp,8”,程序将立即崩溃,这对我来说没有意义,我想知道它为什么会发生,并且另外,如果我用“push rcx”和“pop rcx”替换“mov [rsp + 32],rcx”和“mov rcx,[rsp + 32]”,输出将是垃圾,我也很好奇

1 个答案:

答案 0 :(得分:4)

Windows x86-64调用约定要求在CALL指令之前对RSP进行16B对齐。这解释了函数调用周围的sub rsp,8

它还需要为使​​用被调用函数保留32B的阴影空间,这就是sub rsp, 32 + 16正在做的事情。

将这些组合在一起并sub rsp, 32 + 16 + 8进行功能输入是明智之举,然后在结尾之前不要乱用RSP。您可以更改mov [rsp + 32], rcx使用的偏移量,我不确定这是否重要。我没有尝试阅读您的整个代码,因为问题只是堆栈对齐/使用。

使用其阴影空间的被调用函数也解释了为什么如果你只是推/弹CALL,你会得到乱码输出,因为那时你的数据将在阴影空间。

请参阅标记wiki了解ABI /调用约定链接。