RadASM:
;右键 -> 生成依赖项 -> 生成自定义 -> masm
.586
.model flat,stdcall
option casemap:none
include msvcrt.inc
include Kernel32.inc
include User32.inc
includelib msvcrt.lib
includelib Kernel32.lib
includelib User32.lib
scanf proto c :ptr,:vararg
printf proto c :ptr,:vararg
.data
szBuffer db "Hello Word!",0
format db "%s",0
readBuffer db 20 dup(0)
.code
start:
invoke scanf,addr format,addr readBuffer
invoke printf,addr szBuffer
invoke MessageBoxA,0,addr readBuffer,addr readBuffer,0
invoke ExitProcess,0
end start
Visual Studio:
;右键 -> 生成依赖项 -> 生成自定义 -> masm
.586
.model flat,stdcall
option casemap:none
includelib ucrt.lib
includelib legacy_stdio_definitions.lib
includelib Kernel32.lib
includelib User32.lib
extern scanf:proc ;C函数也可以Extern声明
printf proto c :ptr,:vararg ;函数必须全部声明
MessageBoxA proto :dword,:ptr,:ptr,:dword
ExitProcess proto :dword
.data
szBuffer db "Hello Word!",0
format db "%s",0
readBuffer db 20 dup(0)
.code
start:
push offset readBuffer
push offset format
call scanf
add esp,8
invoke printf,addr szBuffer
invoke MessageBoxA,0,addr readBuffer,addr readBuffer,0
invoke ExitProcess,0
end start
对于所有要用到的库函数(或Windows API函数),在程序的开始部分必须预先声明(如果不是RadASM,是Visual Studio写汇编,那messagebox和exitprocess也的声明)。包括函数的名称、参数的类型等,如:
在汇编语言程序中,函数声明为:
函数名称 PROTO [调用规则] :[第一个参数类型] [,:后续参数类型]
其中,PROTO后的调用规则是可选项。如果不写,则使用model语句中指定的调用规则。
如果函数使用C调用规则,则PROTO后跟一个C(大小写都可以)。接下来是参数的说明。如果参数个数、类型不定,则用VARARG说明(varible argument)。
先看在C语言头文件stdio.h中printf的函数声明:
_CRTIMP int __cdecl printf(const char *, ...);
可知printf函数的调用规则为C调用规则(__cdecl, 即c declare),第一个参数是字符串指针,后面的参数数量及类型不定。
这里,用ptr sbyte代表const char *。
printf PROTO C :ptr sbyte,:vararg
下面这篇博客更详细