本文介绍了为什么我必须和"rsp"一起玩?调用C ++函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近才刚刚开始我的汇编之旅,所以显然我是一个新手,我一直在编写相当简单和基本的程序,我只是发现一些奇怪的东西(对我而言).

I just started my assembly journey like recently, so obviously I'm a newbie, I've been writing fairly simple and basic programs and I just noticed something weird (to me).

给出二进制表中以111结尾的表中的数字计数的程序

a program giving the count of numbers in a table ending with 111 in binary

进入点:

#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

如果我在"call r14"周围注释"sub rsp,8"和"add rsp,8",该程序将立即崩溃,这对我来说没有意义,我想知道它为什么会发生,并且另外,如果我用"push rcx"和"pop rcx"替换"mov [rsp + 32],rcx"和"mov rcx,[rsp + 32]",输出将是垃圾,我也对此感到好奇

if I comment "sub rsp, 8" and "add rsp, 8" around "call r14" out, the program will crash immediately, that doesn't make sense to me, I want to know why it happens, and also, if I replace "mov [rsp + 32], rcx" and "mov rcx, [rsp + 32]" with "push rcx" and "pop rcx", the output will be garbage, I'm also curious about that

推荐答案

Windows x86-64调用约定要求CALL指令之前RSP的16B对齐.这说明了函数调用周围的sub rsp,8.

The Windows x86-64 calling convention requires 16B alignment of RSP before a CALL instruction. This explains the sub rsp,8 around the function call.

它还需要保留32B的阴影空间以供调用的函数使用,而这正是sub rsp, 32 + 16所做的.

It also requires 32B of shadow space reserved for the use of the called function, and that's what the sub rsp, 32 + 16 is doing.

将它们组合在一起,然后在函数入口上输入sub rsp, 32 + 16 + 8,然后在结语之前不要与RSP混为一谈是很明智的.您可能会更改用于mov [rsp + 32], rcx的偏移量,但不确定是否很重要.我没有尝试阅读您的全部代码,因为问题仅在于堆栈对齐/使用.

It would be smart to just combine those together, and sub rsp, 32 + 16 + 8 on function entry, and then don't mess with RSP until the epilogue. You might change the offset you're using for mov [rsp + 32], rcx, I'm not sure if that matters. I didn't try to read your whole code since the question was just about stack alignment/usage.

利用其影子空间进行调用的函数还解释了为什么仅在CALL上推入/弹出会导致输出乱码,因为那样您的数据将位于影子空间中.

The called function making use of its shadow space also explains why you get garbled output if you just push/pop around the CALL, because then your data will be in the shadow space.

请参见 x86 标签Wiki的ABI/调用约定链接.

See the x86 tag wiki for ABI / calling convention links.

这篇关于为什么我必须和"rsp"一起玩?调用C ++函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-17 16:11