nasm的Hello, World!程序应该这么写(Win32控制台)

;hello.asm 仅仅适用于win32控制台程序
;nasm -f win32 -o hello.o hello.asm
;gcc -o hello.exe hello.o

bits 32 ;这似乎不是必须的,但nasm还可以编译16位程序及16、32位
		;混合编程的程序,所以在32位程序中习惯上加上这个

;这里定义了一个宏,以模拟enter指令,nasm似乎没有这个指令
%ifndef ENTER
%define ENTER
%macro enter 0
	push ebp
	mov ebp, esp
%endmacro
%endif

global _main ;因为要用到gcc链接,这里应该把此处的main标记为全局标号
extern _printf ;从c标准库中引用的过程,因此标记为外部标号

section .text ;正文段,这似乎是必须的,否则无法链接

_main:
	enter
	
	sub esp, 0x20 * 4 ;在栈中预留出32个空间
	
	mov eax, [esp + 0x20 * 4 + 2 * 4];获取int main(int argc, char* argv[])
									 ;函数的第一个参数, 即argc, 这个参数
									 ;为命令行被空格分隔字符串的个数
	mov [c], eax
	
	mov dword [esp + 0 * 4], str ;第一个参数入栈,虽然没有参考过printf函数的原型
						 ;但基本知道大概是void printf(const char* s, ...),
						 ;返回值类型没有深究过,第一行参数为常字符串(为
						 ;可变参数提供格式化字符串),后面为若干个参数
	mov eax, [i] 
	mov dword [esp + 1 * 4], eax ;第二个参数入栈
	mov eax, [c]
	mov dword [esp + 2 * 4], eax ;第三个参数入栈
	
	;下面是上述两条指令的”等价形式“
	;push dword [i]
	;push str
	
	call _printf
	
	;一般的为了不破坏栈,若采用”等价形式“需要在call指令后加入如下类似的指令
	;add esp, 2 * 4
	
	add esp, 0x20 * 4 ;释放在栈中预留的空间
	
	leave ;恢复栈值,相当于用下面的两条指令,详见nasm手册
		  ;mov esp, ebp
		  ;pop ebp
	ret

align 32	
section .data ;数据段
str: db 'Hello, World!   %d   %d', 0xa, 0 ;格式化参数字符串,可以看出printf
										  ;在实际中第一个参数后又有两个参数
i dd 0x378

align 32
section .bss ;未初始化段
c resd 1


发布了159 篇原创文章 · 获赞 14 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_39410618/article/details/103543511