英文原版地址:NASM Assembly Language Tutorials - asmtutor.com
在NASM中从命令行给你的程序传递参数健翔从栈中弹出它们一样容易。当程序运行时,任何被传递的参数被加载到栈上是倒序的。然后程序的名字被加载到栈上,最后全部的参数数量被加载到栈上。NASM编译的程序中栈上最后两个成员永远是程序名和参数的数量。
所以我们要使用它们首先要做的就是从栈中弹出参数的数量,然后将所有的参数迭代一次接着执行程序的逻辑。在我们的程序中意味着调用打印函数。
functions.asm文件
;------------------------------------------
; int slen(String message)
; 字符串长度计算函数
slen:
push ebx
mov ebx, eax
nextchar:
cmp byte [eax], 0
jz finished
inc eax
jmp nextchar
finished:
sub eax, ebx
pop ebx
ret
;------------------------------------------
; void sprint(String message)
; 字符串打印函数
sprint:
push edx
push ecx
push ebx
push eax
call slen
mov edx, eax
pop eax
mov ecx, eax
mov ebx, 1
mov eax, 4
int 80h
pop ebx
pop ecx
pop edx
ret
;------------------------------------------
; void sprintLF(String message)
; 打印字符串和换行符函数
sprintLF:
call sprint
push eax ; 当我们在这个函数中使用EAX时通过将EAX压入栈来进行保护
mov eax, 0AH ; 将0AH移到EAX中 - 0AH是换行符的ascii码
push eax ; 将换行符放到栈上,以便我们获取地址
mov eax, esp ; 将当前栈指针的地址放到EAX寄存器中给sprint函数
call sprint ; 调用sprint函数
pop eax ; 从栈上移除换行符
pop eax ; 恢复调用函数前EAX原本的值
ret ; 返回程序
;------------------------------------------
; void exit()
; 退出程序并复原资源
quit:
mov ebx, 0
mov eax, 1
int 80h
ret
hello.asm文件
注:使用ECX作为循环计数器,虽然它是通用寄存器,但是初衷是计数器
%include 'functions.asm' ; 包含我们的外部文件
SECTION .text
global _start
_start:
pop ecx ; 栈上的第一个值是参数的数量
nextArg:
cmp ecx, 0h ; 检查是否还有参数
jz noMoreArgs ; 如果放置了0标记,就跳转到noMoreArgs(跳过循环的末尾)
pop eax ; 从栈中弹出下一个参数
call sprintLF ; 调用有换行符的函数
dec ecx ; ECX减一(剩余参数的数量)
jmp nextArg ; 跳转到nextArg
noMoreArgs:
call quit
编译命令
nasm -f elf hello.asm
链接命令
ld -m elf_i386 hello.o -o hello
执行命令
./hello