如何将参数传递给Assembly中的函数? 我确实推了Last Param,推动Second Param,推进First Param ..
但我无法访问Meh
函数中的参数..我正在做的事情会使程序崩溃..
format PE console ;Format PE OUT GUI 4.0
entry main
include 'macro/import32.inc'
section '.idata' import data readable ;Import Section.
library msvcrt,'msvcrt.dll'
import msvcrt, printf, 'printf',\
exit,'exit', getchar, 'getchar'
section '.data' data readable writeable ;Constants/Static Section.
InitialValue dd 0
section '.code' code readable executable
main:
push 67
push 66
push 65
call MEH
call [getchar]
mov eax, 0
ret 0
MEH:
push ebx
mov ebp, esp
sub esp, 0
mov eax, [ebp + 8] ; Trying to print first parameter..
push eax
call [printf]
add esp, eax
mov esp, ebp
pop ebx
ret
答案 0 :(得分:5)
小额外说明。 该过程的正确页眉/页脚使用push / pop ebp:
MEH:
push ebp
mov ebp, esp
mov esp, ebp
pop ebp
ret
原因是我们需要在将ebp寄存器用作参数和局部变量的指针之前保存/恢复它。
其次,CCALL调用约定,其中调用者在返回过程后恢复堆栈指针对于C / C ++语言是常见的,但对于汇编编程则不常见。原因很明显 - 编译器可以正确计算堆栈中推送的参数数量。在手写的汇编程序中,使用此约定将使代码不易读。
更好的方法是使用STDCALL调用约定:
MEH:
push ebp
mov ebp, esp
mov esp, ebp
pop ebp
retn 12 ; how many bytes to be automatically
; removed from the stack after return.
更好的做法是使用一些宏来自动创建标准过程元素,并为参数和局部变量提供人类可读标签。例如,FreshLib库中提供的宏具有以下语法:
proc MEH, .arg1, .arg2, .arg3
; define local variables here, if needed.
begin
; place your code here without headers and footers
return ; will clean the stack automatically.
endp
; pushes the arguments in the stack and call MEH
stdcall MEH, 65, 66, 67
FASM软件包提供的标准宏库的语法略有不同,FASM programmers manual详细介绍了这一点。
答案 1 :(得分:3)
让我们看看......
一开始就说你的ESP是0x00180078,然后在三次推送之后
00180078: 67
00180074: 66
00180070: 65
然后你调用MEH,它会立即推送ebx,所以现在你有了堆栈
00180078: 67
00180074: 66
00180070: 65
0018006C: return address
00180068: ebx value
现在加载EBP,ESP = 00180068
sub esp,0 does nothing
mov eax, [ebp+8] ~ 00180068 + 8 = 00180070 = 65
所以不是第一个而是最后一个参数
call [printf]
但问题出现了:
add esp, eax
这应该做什么好事?假设printf保留了传入的这个参数(顺便说一下,这不是必须的),为什么要将参数添加到堆栈指针?这肯定会搞砸你的回报。 你想要做的是将esp恢复为ebp的值并弹出保存的ebx值。
答案 2 :(得分:3)
如果printf()
的调用约定是正确的(它适用于Linux上的32位MinGW和32位gcc),那么你完全忽略了函数所期望的内容,你不会感到惊讶期望的输出。
该函数的原型是:
int printf(const char* format, ...);
format
,第一个参数,是指向ASCIIZ字符串的指针,该字符串包含要打印的文本和/或%d
之类的特殊标记,以替换为可选参数的相应解释format
。
因此,如果您希望printf()
打印'A'
,那么您需要在C中执行此操作:
printf("A");
或
printf("%c", 'A');
以下是你在装配中如何做同样的事情:
myformatstring db "A", 0 ; this line goes into section .data
push myformatstring ; push address of the string
call [printf]
add esp, 4 ; remove all parameters from the stack
或
myformatstring db "%c", 0 ; this line goes into section .data
push 'A'
push myformatstring ; push address of the string
call [printf]
add esp, 2*4 ; remove all parameters from the stack