问题
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).
a program giving the count of numbers in a table ending with 111 in binary
entry point:
#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");
}
assembly:
.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
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
回答1:
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.
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.
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.
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.
See the x86 tag wiki for ABI / calling convention links.
来源:https://stackoverflow.com/questions/40344385/why-do-i-have-to-play-with-rsp-to-call-a-c-function