博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
4、Linux汇编——文件中结构化数据的操作(下)
阅读量:6871 次
发布时间:2019-06-26

本文共 7274 字,大约阅读时间需要 24 分钟。

hot3.png

5、读取记录

功能:程序读取每条记录,并显示每条记录中的“名”

记录读取功能主要执行以下步骤:

1、打开文件

2、读取一条记录

3、若到文件末尾,则退出;否则计算“名”的字符数

4、将“名”写入STDOUT中

5、输出换行符到STDOUT中

6、返回,并读取另一条记录

(1)字数统计函数

由于每条记录中,“名”的长度不定,因此需要一个函数来统计写入的字符数。该程序存于count-chars.s

#目的:对记录中字符数进行统计,遇到空字符结束#输入:字符串地址#输出:计数值返回到%eax中#变量:   %ecx——字符计数#        %al——当前字符#        %edx——当前字符地址.type count_chars, @function.globl count_chars.equ ST_STRING_START_ADDRESS, 8  #字符串开始地址count_chars:    pushl %ebp                movl %esp, %ebp                                movl $0, %ecx    #计数器从0开始                movl ST_STRING_START_ADDRESS(%ebp), %edx   #数据的起始地址                count_loop_begin:    movb (%edx), %al  #获取当前字符,采用间接寻址方式                     cmpb $0, %al      #判断是否为空字符                     je count_loop_end                                          incl %ecx                     incl %edx                     jmp count_loop_begincount_loop_end:    movl %ecx, %eax   #结束循环,将统计的字数存入%eax中                   popl %ebp                   ret

(2)写一个换行符到STDOUT的函数

该程序存于文件write-newline.s文件中

.include "linux.s".globl write_newline.type write_newline, @function.section .data    newline:             .ascii "\n".section .text    .equ ST_FILEDES, 8    write_newline:    pushl %ebp                  movl %esp, %ebp                                    movl $SYS_WRITE, %eax                  movl ST_FILEDES(%ebp), %ebx                  movl $newline, %ecx                  movl $1, %edx                  int $LINUX_SYSCALL                                    movl %ebp, %esp                  popl %ebp                  ret

(3)主程序

该程序存放在文件read-records.s中。

.include "linux.s".include "record-def.s".section .data    file_name: .ascii "test.dat\0".section .bss    .lcomm record_buffer, RECORD_SIZE    .section .text     .globl _start   #主程序_start:    #定义存储输入输出描述符的栈位置           #也可用一个.data段中的内存地址代替           .equ ST_INPUT_DESCIPTOR, -4           .equ ST_OUTPUT_DESCRIPTOR, -8                      movl %esp, %ebp           subl $8, %esp                      #打开文件           movl $SYS_OPEN, %eax           movl $file_name, %ebx           movl $0, %ecx         #表示只读打开           movl $0666, %edx           int $LINUX_SYSCALL                      movl %eax, ST_INPUT_DESCRIPTOR(%ebp)     #保存输入文件描述符           movl  $STDOUT, ST_OUTPUT_DESCRIPTOR(%ebp) #保存输出文件描述符,此处为“标准输出”            record_loop:    pushl ST_INPUT_DESCRIPTOR(%ebp)   #输入文件描述符                 pushl $record_buffer                 #缓冲区地址指针                 call read_record                 addl $8, %esp                                  #比较读取的字节数和缓冲区大小                 #如果不一致,说明达到文件尾部或出错                 cmpl $RECORD_SIZE, %eax                 jne finished_reading                                  #打印名,需先知道“名”的大小                 pushl $RECORD_FIRSTNAME + record_buffer #该指令将两个常数相加,得到的结果为内存地址                                                         #得到的结果将入栈。RECORD_FIRSTNAME记录从                                                         #起始地址到名字字段之间的字节数                 call count_chars                 addl $4, %esp                                  movl %eax, %edx                 movl ST_OUTPUT_DESCRIPTOR(%ebp), %ebx                 movl $SYS_WRITE, %eax                 movl $RECORD_FIRSTNAME + record_buffer, %ecx                 int $LINUX_SYSCALL                                  jmp recor_loopfinish_reading:    movl $SYS_EXIT, %eax                   movl $0, %ebx                   int $LINUX_SYSCALL

编译、链接、执行上面程序

as read-record.s -o read-record.o

as count-chars.x -o count-chars.o

as write-newline.s -o write-newline.o

as read-records.s -o read-records.o

ld read-record.o count-chars.o write-newline.o read-records.o -o read-records

6、修改记录

修改程序主要有以下步骤:

1、打开输入文件和输出文件

2、从输入文件读取记录

3、递增年龄

4、新纪录写入文件

将下面程序存入文件add-year.s中

.include "linux.s".include "record-def.s".section .data    input_file_name: .ascii "test.dat\0"    output_file_name: .ascii "testout.dat\0".section .bss    .lcomm record_buffer, RECORD_SIZE     #局部变量的栈偏移量.equ ST_INPUT_DESCRIPTOR, -4.equ ST_OUTPUT_DESCRIPTOR, -8.section .text    .globl _start    _start:    movl %esp, %ebp           subl $8, %esp                      #打开输入文件           movl $SYS_OPEN, %eax           movl $input_file_name, %ebx           movl $0, %ecx           movl $0666, %edx           int $LINUX_SYSCALL                      movl %eax, ST_INPUT_DESCRIPTOR(%ebp)   #输入文件的文件描述符                      #打开输出文件           movl %SYS_OPEN, %eax           movl $output_file_name, %ebx           movl $0101, %ecx           movl $0666, %edx           int $LINUX_SYSCALL                      movl %eax,ST_OUTPUT_DESCRIPTOR(%ebp)loop_begin:    pushl ST_INPUT_DESCRIPTOR(%ebp)               pushl $record_buffer               call read_record               addl $8, %esp                              #判断是否到达文件尾部,或出现读错误               cmpl $RECORD_SIZE, %eax               jne loop_end                              #递增年龄               incl record_buffer + RECORD_AGE  #注意此处为直接寻址,和上面的“pushl $a+b”形式区别                              #写记录               pushl ST_OUTPUT_DESCRIPTOR(%ebp)               pushl $record_buffer               call write_record               addl $8, %esp                              jmp loop_begin               loop_end:    movl $SYS_EXIT, %eax             movl $0, %ebx             int $LINUX_SYSCALL

编译、链接、运行上面程序

as add-year.s -o add-years.o

ld add-year.o read-record.o write-record.o -o add-years

./add-years

7、让程序更加健壮

在上面add-years.s程序的基础上,我们添加下面这个程序。该程序打印错误消息并退出,其作为“被调函数”,由add-year.s程序调用。该函数存于文件:error-exit.s。为了使用该函数,需将错误信息的地址和错误代码入栈,然后进行调用。

.include "linux.s".equ ST_ERROR_CODE, 8.equ ST_ERROR-MSG, 12.globl .error_exit.type error_exit, @functionerror_exit:    pushl %ebp               movl %esp, %ebp                              #写错误代码               movl ST_ERROR_CODE(%ebp), %ecx               pushl %ecx               call count_chars    #计算字符数                              popl %ecx               movl %eax, %edx    #字符数量               movl $STDERR, %ebx               movl $SYS_WRITE, %eax               int $LINUX_SYSCALL                              #写错误信息               movl STD_ERROR_MSG(%ebp), %ecx               pushl %ecx               call count_chars                              popl %ecx               movl %eax, %edx               movl $SYS_WRITE, %eax               movl $STDERR, %ebx               int $LINUX_SYSCALL                                pushl $STDERR                call write_newlines                                #退出                movl $SYS_EXIT, %eax                movl $1, %ebx                int $LINUX_SYSCALL

以上为处理出错时的函数。下面将给出add-years.s是如何使用该函数的。

前面的add-year.s在打开文件后并未进行检错——可能出现找不到文件等情况。所以下面程序对打开文件后的返回码进行检测,保证正确打开文件。

#打开供读取的文件movl $SYS_OPEN, %eaxmovl $input_file_name, $ebxmovl $0, %ecxmovl $0666, %edxint $LINUX_SYSCALLmovl %eax, INPUT_DESCRIPTOR(%ebp)    #将返回码存入栈中,供检测#以下将对%eax存储的返回码进行检测,若为负值,则调用错误函数cmpl $0, %eaxjl continue_processing   #0<%eax#发送错误消息.section .data     no_open_file_code:    .ascii "0001:\0"     no_open_file_msg:     .ascii "cant open input file\0".section .text    pushl $no_open_file_msg    pushl $no_open_file_code    call error_exit    continue_processing:    #程序其余部分

编译、链接、运行程序:

as add-year.s -o add-year.o

as error-exit.s -o error-exit.o

ld add-year.o write-newline.o error-exit.o read-record.o write-record.o count-chars.o -o add-year

转载于:https://my.oschina.net/u/438386/blog/546024

你可能感兴趣的文章
对jquery val 获取input 文本框值进行扩展
查看>>
MySQL (select_paren) union_order_or_limit 行为
查看>>
并发不是并行,它更好!
查看>>
nltk 自己训练模型例子
查看>>
间谍卫星的基础?YOLT——利用卷积神经网络对卫星影像进行多尺度目标检测(Part I)...
查看>>
jstl_开发第一个标签
查看>>
程序员哇,你想在下个情人节或者520脱单么?这个秘籍不能错过
查看>>
去不去O,谁说了算?
查看>>
PHP防SQL注入和XSS攻击
查看>>
在SHAREPOINT共享文档库中启用版本控制功能。
查看>>
Http 代理工具 实战 支持网页与QQ代理
查看>>
又见尾递归
查看>>
安装PyGraphics
查看>>
【COCOS2DX-LUA 脚本开发之四】使用TOLUA++编译PKG,从而创建自定义类让LUA脚本使用...
查看>>
开源大数据周刊-第16期
查看>>
遥感图像分类现状及存在的问题
查看>>
Commons Logging存在的ClassLoader问题详解
查看>>
双向链表的操作
查看>>
Flume-ng 高级功能配置
查看>>
我的友情链接
查看>>