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

 

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