AT&T汇编、调用C库函数、读/写文件
d0321:更新读文件代码(图片)以后会更新代码版。
d0329:汇编文本读取、简单动画。
================================================
本文是利用AT&T风格调用C库,来读取文件内容。(如果安装的是64位的linux,需要安装32位的C库。并在利用gcc编译的时候加入-m32指令。)
64位利用32位库的编译指令如下:(-ggdb是加入gdb调试信息)
gcc -m32 -ggdb readfile.s -o readfile
- 利用C库函数fscanf读文件
-
GDB调试代码
- 查看寄存器中的值
info reg
- 查看内存中的值
x/nfu <addr>
- n表示要显示的内存单元的个数。
- f表示显示方式, 可取如下值:
x 按十六进制格式显示变量。 d 按十进制格式显示变量。
u 按十进制格式显示无符号整型。 o 按八进制格式显示变量。
c 按字符格式显示变量。f 按浮点数格式显示变量。 - u表示一个地址单元的长度,可取下值
b表示单字节,h表示双字节,w表示四字节,g表示八字节。
汇编语言完成简单文本动画
在实现了基本的文件读取功能后,利用汇编语言制作了简单的动画(用空格实现)
该程序的基本流程如下:
.code32
.section .rodata
#参数定义
mode:
.string "r"
sreturn:
.string "Read file success"
freturn:
.string "Read file failed"
space:
.string " "
printstring:
.string "%s"
colorRed:
.string "\033[31m"
colorYellow:
.string "\033[33m"
colorGreen:
.string "\033[36m"
nomalEnd:
.string "\033[0m"
colorType:
.string "%s%s%s"
clear:
.string "clear"
tmp:
.string "@"
#代码部分
.text
#animation
.globl animation
.type animation, @function
animation:
pushl %ebp
movl %esp, %ebp
subl $200, %esp #设置该函数的栈区为ebp-200
xorl %eax, %eax #clear %eax
movl $0,-108(%ebp) #设置刷新10次
file_open:
pushl $mode #将文件读取模式压入栈
pushl 8(%ebp)
call fopen
addl $8, %esp #清除上面压栈的mode和path
check_open:
cmpl $0, %eax #eax中接着的是返回值
je read_fail #如果无法读取就跳转
read_sus:
movl %eax, -104(%ebp) #将文件指针保存在-104
pushl $sreturn #输出成功读取文件提示
call puts
addl $4, %esp #清除上面压栈的sreturn
pushl $clear #将clear指令压栈
call system #调用system系统函数,用来清屏
addl $4,%esp #清除上面压栈的一个参数
read_one_line:
pushl -104(%ebp) #这里是把ebp-104里面存的的值压进去(fp)
pushl $200 #将fgets的第二个参数压栈
leal -100(%ebp), %eax #将从文件中读取的数据保存到ebp-100
pushl %eax #这里是把ebp-100的这个值(地址压进去)
call fgets
addl $12, %esp #清除压栈参数
check_EOF:
pushl -104(%ebp) #这里是把ebp-104里面存的的值压进去(fp)
call feof
addl $4, %esp #清除上面压栈的一个参数
cmpl $0,%eax #判断返回值
jne close_file
movl -108(%ebp),%ebx #将刷新参数读到ebx
print_space:
#pushl $tmp
#call printf
#addl $4,%esp
cmpl $0,%ebx
je print_text #如果已经打印完了就开始输出数据
pushl $space #打印空格
pushl $printstring
call printf
addl $8,%esp #清理压栈
subl $1,%ebx #循环参数减一
jmp print_space
print_text:
leal -100(%ebp), %eax #将刚才读出来的数据压栈,准备输出
pushl $nomalEnd
pushl %eax
pushl $colorYellow
pushl $colorType
call printf
addl $4, %esp #清除上面压栈的一个参数
jmp read_one_line
close_file:
pushl -104(%ebp) #把文件指针压栈
call fclose #关闭文件
addl $4, %esp #清除上面压栈的一个参数
movl $0, -104(%ebp) #清空文件指针
movl -108(%ebp),%ebx #当缓冲空格已经结束
cmp $30,%ebx
je end_main
addl $1,%ebx #刷新剩余次数加一
movl %ebx,-108(%ebp) #保存起来
pushl $80000 #sleep参数
call usleep
pushl $clear #清屏
call system
addl $8,%esp
jmp file_open
read_fail:
pushl $freturn #输出读取失败文件提示
call puts
addl $4, %esp #清除上面压栈的一个参数
end_main:
leave
ret
#main
.section .rodata
welcomemsg:
.string "================================================================\n Welcome!\n Please Input the filename you wantta play!\n================================================================\n"
askagain:
.string "again?(y/n)"
stringType:
.string "%s"
yes:
.string "y"
no:
.string "n"
inttype:
.string "%d"
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
subl $50,%esp #主函数栈区
pushl $welcomemsg
call printf
addl $4,%esp
leal -4(%ebp),%eax #输入文件路径
pushl %eax
pushl $stringType
call scanf
addl $8,%esp
start:
leal -4(%ebp),%eax
pushl %eax
call animation #播放开启动画
addl $4,%esp
ask:
pushl $askagain #again?
call printf
addl $4,%esp
leal -14(%ebp), %eax #y/n
pushl %eax
pushl $stringType
call scanf
addl $8, %esp
subl $16, %esp #is y?
leal -14(%ebp), %eax
pushl %eax
pushl $yes
call strcmp
addl $24, %esp
cmpl $0,%eax
je start
subl $16, %esp #is n?
leal -14(%ebp), %eax
pushl %eax
pushl $no
call strcmp
addl $24, %esp
cmpl $0,%eax
je endmain
jmp ask
endmain:
leave
ret
运行截图:(其中1文件见下)
为动画效果,不好截图,可以将源码拷贝运行一次。
文件1
###########
# #
# #
### # # ###
# # # # # #
# #
# #
# #
#############################
文件2
==== ==== ==== ||||
==== ==== ==== ||||
==== ==== ||||
==== ==== ==== ||||
============ ==== ||||
============ ==== ||||
==== ==== ====
==== ==== ==== ||||
==== ==== ==== ||||