NASM学习(二)——从命令行获取参数

NASM学习(二)——从命令行获取参数

学习汇编的目的是增强自己对硬件体系的熟悉与编译、链接等等阶段的熟悉

上文我们已经学会了怎么使用NASM来打印HELLO,WORLD了,总结一下,主要是使用系统调用来进行输出
甚至,程序的退出也是使用系统调用exit()——因为我们的程序是一个单独的进程,当进程要结束的时候应当主动调用进程销毁调用,否则就会引发错误

但是,还有一些不好的地方:

  1. 注意到,每次使用系统调用的时候都需要手写一大段调用准备,不利于程序的调试和维护,如果可以把它们封装起来,效果更好
  2. 注意到,msg db 'hello, world', 0x0a中,手动输入了换行符。但是在具体的场景中,我们可能希望根据具体条件进行换行与否——总之,写死就是不对的

在上文的基础上,我们分别对这两个问题进行解决:

include引用

使用%include进行文件的引用
首先,对一些函数进行封装

; int slen(string msg)

slen:
	push	ebx	; 保存接下来将使用的寄存器
	mov	ebx, eax; 将msg的地址复制到ebx中
nextchar:
	cmp	byte [eax], 0	; 将*eax和'\0'进行比较
	jz	finished	; 若等于'\0',则跳转到结束
	inc	eax		; eax ++
	jmp	nextchar
finished:
	sub	eax, ebx	; 将结果保存在eax寄存器中
	pop	ebx		; 恢复ebx寄存器
	ret			; 返回

quit:
	mov	ebx, 0	; 出错数:0
	mov	eax, 1	; 使用1号调用
	int	0x80
	ret

接下来,封装打印函数:

; 打印函数
; void sprint(string msg)

%include 'slen.s'

sprint:
	push	edx
	push	ecx
	push	ebx
	push	eax	; 保存寄存器现场
	call	slen	; 调用slen函数,结果保存在eax中

	mov	edx, eax; 将字符长度复制到edx寄存器中,作为参数
	pop	eax	; 恢复eax寄存器

	mov	ecx, eax; 将字符串地址当作参数输入
	mov	ebx, 1	; 输出到stdout
	mov	eax, 4	; 使用4号调用
	int	0x80	; 调用系统调用

	pop	ebx
	pop	ecx
	pop	edx
	ret		; 恢复寄存器现场

使用%include就可以引用其他文件的内容

换行问题

为了程序的可维护性,我们可以写个函数,在字符串后输出'\n'
主要思路是,输出字符串后,再输出一个回车
主要问题是sys_write系统调用需要获取字符的地址和长度
我们可以使用栈来完成

ESP指针的特点是,每当使用PUSH操作后,它都会指向栈中最新的数据的地址
因此,我们可以把'\n'压入栈,然后通过ESP获取其地址

; void sprintLF(string msg)

%include	'sprint.s'

sprintLF:
	call	sprint	; 将数据保存在缓存中,因为没有碰到回车,所以不会立即输出

	push	eax		; 保存现场
	mov	eax, 0x0a	; 将'\n'压入栈
	push	eax
	mov	eax, esp	; 获取'\n'地址
	call	sprint		; 输出
	pop	eax		; '\n'
	pop	eax		; 恢复现场
	ret

注意,PUSH操作压入4个字节,而'\n'仅仅只有一个字节,因此被压入的内容是0x0a 0x00 0x00 0x00(地址从低到高),因此slen返回1

为什么在sprintLF中调用了两次sprint,但是只输出了一次?
理由:Linux中,输出函数使用行缓存,未碰到回车的时候并不会输出
详见这篇文章

参数

如何使用汇编程序读取参数呢?
在C语言中,main函数的参数可以表示为int argc, char *argv[]
实际上,在程序开始运行的时候,会将参数逆序压入栈,然后再压入程序的名字(或者说运行程序的方式),最后压入所有参数的个数(程序的名字也算参数)
例如:

参数N
参数N-1
……
参数1
程序名
参数个数:N+1

因此,使用POP方式就可以轻易获取参数

以下是一个打印所有参数的例程

%include	'sprintLF.s'
%include	'quit.s'

SECTION .text	; 代码段开始
global _start	; 程序入口

_start:
	pop	ecx	; 栈中的第一个值是参数的数量

nextArg:
	cmp	ecx, 0x00	; 检查是否还有参数
	jz	noMoreArgs	; 没有参数了,退出
	pop	eax		; 将参数加载到eax中
	call	sprintLF	; 进行打印
	dec	ecx		; ecx --
	jmp	nextArg
noMoreArgs:
	call	quit
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值