linux文件操作(ATT汇编)

首先介绍一下linux的shell脚本写法,其实与windows下.bat文件的写法差不多,一行一行的写命令就行了,例如,当我们要用vim打开某个目录(/user/include/printf.h)下的文件,可以这样写:

cd /usr/include

vim printf.h

保存为run.sh

第一次运行shell脚本时,要先给这个脚本权限,假设脚本名称为“run.sh”,命令为“chmod 777 ./run.sh”,之后就能一直使用了。

进入正文,linux下AT&T汇编——文件操作。

事实上汇编文件操作甚至要比某些高级语言更简单,因为不用去记那么一堆打开参数,在汇编中,由于基本是对于底层的操作,所以不会区分以文本方式打开还是以二进制方式打开,诸如此类。

基本步骤:打开文件(获取文件的标识符)-->操作文件(读取文件或者写入文件)-->关闭文件

以32位linux为例(64位下系统调用号是不同的):

打开文件的调用号为5,将5存入eax,ebx存入文件路径字符串的首地址,ecx存入打开方式,只读为“0”,写为“03101”,edx存入权限集合,现在存入“0666”就行了,反正我不懂unix的权限。打开成功后,系统会返回该文件的“文件标识符”,在eax里面。之后全程都要用这个文件标识符指代打开的那个文件。

读取文件的调用号为3,存入eax,文件标识符存入ebx,在此之前,要划一个缓存区,用来储存读取的数据,将该缓存区的首地址存入ecx,长度存入edx。读取成功后,会按照edx中的长度填充缓存区,就是edx的值是多少,就填充多少(当然,由文件的长度而定),返回已经读取的长度。

写入文件的调用号为4,存入eax,其余参数同上。返回写入的字节数或者错误代码(写入失败),存入eax。

关闭文件的调用号为6,存入eax,文件描述符存入ebx。只有这两个参数。

下面有一个例子,可以读取一个文件制定数量的字符串,并将里面的小写字符转换为大写字符,存入另一个文件的。代码在最后。设读取的文件名为“data”,写入的文件为“data1”,data的文件内容如下:

hello,world

abcdefg

hijklmn

opqrst

uvwxyz

编写的shell脚本内容如下:

echo "编译代码:"
make
echo "执行程序:"
./f
echo "返回值:" $?

makefile文件内容如下(makefile文件是用来编译代码的):

f:f_open.o
    ld -m elf_i386 f_open.o -o f
 
f_open.o:f_open.s
    as --32 f_open.s -o f_open.o

注:因为我的系统是centos7_64位,as和ld程序是默认以64位进行处理的,所以“--32”可以告诉as程序以32位进行编译,“-m elf_i386”告诉ld程序链接32位的库。

结果如下:

 

具体的汇编代码如下,120多行:

.section .data
fin_src:
.string "data"
fout_src:
.string "data1"
//定义常量
.equ SYQUIT,1
.equ FILE_OPEN,5
.equ FILE_CLOSE,6
.equ FILE_READ,3
.equ FILE_WRITE,4

.equ ONLY_READ,0
.equ ONLY_WRITE,03101
#储存小写字符值的范围,大于‘a’,小于‘z’。
.equ LETTER_A,'a'
.equ LETTER_Z,'z'

.section .bss
.equ bufSIZE,50 	
.lcomm buf,bufSIZE	#指定一个50byte的缓存区,用来储存从文件获取的字符串
.section .text
.globl _start
_start:
//打开要读取的文件
pushl $fin_src	#文件名地址
pushl $ONLY_READ	#只读
call openFILE	#打开文件
//读取文件
pushl %eax	#文件标识符
pushl $buf 	#缓存区首地址
pushl $bufSIZE	#缓存区长度
call readFILE
//字符转换
call upper_letter	#之所以在这里调用函数,是因为堆栈中仍旧保存着readFILE函数的参数,在这里可以用到。
//关闭文件
subl $8,%esp
call closeFILE

//打开写入文件
pushl $fout_src
pushl $ONLY_WRITE
call openFILE
//写入文件
pushl %eax
pushl $buf
pushl $bufSIZE
call writeFILE
//向屏幕打印缓存区的内容
movl $1,8(%esp)	#修改writeFILE函数第一个参数的值,使其向屏幕打印
call writeFILE
//关闭文件
subl $8,%esp
call closeFILE
//结束程序
sys_exit:
movl $SYQUIT,%eax
int $0x80

#openFILE堆栈参数:打开文件名,模式(返回文件描述符)
openFILE:
pushl %ebp
movl %esp,%ebp
movl $FILE_OPEN,%eax
movl $0666,%edx
movl 8(%ebp),%ecx
movl 12(%ebp),%ebx
int $0x80
movl %ebp,%esp
popl %ebp
ret

#readFILE参数:文件描述符,缓存区首地址,缓冲区长度(返回读取的长度)
readFILE:
pushl %ebp
movl %esp,%ebp
movl $FILE_READ,%eax
movl 8(%ebp),%edx
movl 12(%ebp),%ecx
movl 16(%ebp),%ebx
int $0x80
movl %ebp,%esp
popl %ebp
ret

#writeFILE参数:文件描述符,缓存区首地址,缓冲区长度(返回写入的长度)
writeFILE:
pushl %ebp
movl %esp,%ebp
movl $FILE_WRITE,%eax
movl 8(%ebp),%edx
movl 12(%ebp),%ecx
movl 16(%ebp),%ebx
int $0x80
movl %ebp,%esp
popl %ebp
ret

#closeFile参数:文件描述符(返回是否成功)
closeFILE:
pushl %ebp
movl %esp,%ebp
movl $FILE_CLOSE,%eax
movl 8(%ebp),%ebx
int $0x80
movl %ebp,%esp
popl %ebp
ret

#将小写字符转换为大写字符,参数:缓存区首地址,缓存区长度
upper_letter:
pushl %ebp
movl %esp,%ebp
movl 12(%ebp),%ecx	#ecx储存首地址
movl 8(%ebp),%edx	#edx储存长度
movl $0,%edi
movb (%ecx,%edi,1),%al

letter_loop:
cmp %edx,%edi
jge upexit
movb (%ecx,%edi,1),%al
cmp $LETTER_A,%al	#如果al的值小于'a',说明不是小写字母
jl _up
cmp $LETTER_Z,%al	#如果al的值大于'z',说明不是小写字母
jg _up
//进行到这里,判断出属于小写字母
sub $0x20,%al
movb %al,(%ecx,%edi,1)
_up:
incl %edi
jmp letter_loop

upexit:
movl %ebp,%esp
popl %ebp
ret

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章