Как call использует стек?
Пытаюсь вызвать crt-шный exp. Если перейти по метке func через jmp, для вызова exp нужно отнять из rsp 32 байта (первый вариант кода). А если через call (второй вариант), то 40 байт, иначе windows выдает ошибку. Почему так происходит?
format PE64 console
include 'E:\Fresh\include\win64a.inc'
entry main1
section '.data' data readable writeable
msg db '%lf',10,0
section '.text' code readable executable
main1:
and rsp,-16
sub rsp,32
mov rax,1.0
movq xmm7,rax
jmp func
label1:
mov rcx,msg
movq rdx,xmm7
call [printf]
mov rcx,0
call [ExitProcess]
func:
movsd xmm0,xmm7
sub rsp,32
call [exp_0]
add rsp,32
movsd xmm7,xmm0
jmp label1
section '.idata' import data readable writeable
library kernel32,'KERNEL32.DLL', msvcrt,'MSVCRT.DLL'
import msvcrt, printf,'printf',exp_0,'exp'
import kernel32, ExitProcess, 'ExitProcess'
format PE64 console
include 'E:\Fresh\include\win64a.inc'
entry main1
section '.data' data readable writeable
msg db '%lf',10,0
section '.text' code readable executable
main1:
and rsp,-16
sub rsp,32
mov rax,1.0
movq xmm7,rax
call func
mov rcx,msg
movq rdx,xmm7
call [printf]
mov rcx,0
call [ExitProcess]
func:
movsd xmm0,xmm7
sub rsp,40
call [exp_0]
add rsp,40
movsd xmm7,xmm0
ret
section '.idata' import data readable writeable
library kernel32,'KERNEL32.DLL', msvcrt,'MSVCRT.DLL'
import msvcrt, printf,'printf',exp_0,'exp'
import kernel32, ExitProcess, 'ExitProcess'
Ответы (1 шт):
Разница между jmp и call в том, что call записывает на стек адрес следующей инструкции, а затем переходит на указанный адрес. То есть, разница 8 байт. В соответствии с VC++ calling convention, стек должен быть выровнен по 16 байтам (stack alignment). Любая функция вызывается с с невыровненным стеком, результат call, и первое, что она должна сделать, это выровнять стек. Обычно это push rbp, а вашей программе and rsp,-16.
Вариант 1:
jmp func
func:
; stack alignment 16 bytes
Вариант 2:
call func ; return address is pushed
func:
; stack alignment 8 bytes
Во втором случае sub rsp, 40 компенсирует эти 8 байт.
Вывод: если func это функция и вызывается через call, то она должна вести себя как функция.