汇编程序--文件操作

2024-02-03 12:58
文章标签 操作 汇编程序

本文主要是介绍汇编程序--文件操作,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在介绍文件操作之前,我先介绍一下缓冲区。缓冲区是连续的字节块,用于批量的数据传输。一般缓冲区仅用于暂时存储数据,然后数据被缓冲区中读出并转换成便于程序处理的形式。注意,缓冲区的大小是固定的,由程序员设定的,例如:如果你想要一次读入500字节的数据,可以将500字节未使用的内存位置的地址发送给read系统调用,并将数字500发送给它,这样read调用的就知道数据的大小。在汇编中通过.bss来创建缓冲区,.bss段类似于数据段,不同的是它不占用可执行程序。.bss段可以保存存储位置,却不能对其进行初始化,e而在数据段中,你既可以保留存储位置,又可以对其进行初始化。例如如下指令:

.section .bss
.lcomm my_buffer, 500
.lcomm 指令将创建一个符号my_buffer ,指代我们用作缓冲区的500字节存储位置,my_buffer表示的数字本身就是缓冲区的起始地址。

下面介绍相关的文件操作,首先是打开文件:

打开文件是通过open系统调用来实现的,其所需要的参数是文件名,表示模式的数字以及权限集合。

1.将系统调用号5存放到%eax寄存器中

2.将文件名的第一个字符的地址应存放到%ebx寄存器中,该字符串必须以空字符串结束。

3.将用于表示打开用于读、写、读写、如果不存在则创建、如果存在则删除等的数字存入%ecx寄存器中

4.将表示打开文件的权限存入%edx寄存器中,当需要创建文件的时候会用到此项

最后在进行open系统调用的时候,新打开的文件描述符存储在%eax寄存器中。

通常代码如下:

#系统调用编号
.equ SYS_OPEN, 5
.equ ST_ARGV_1, 8 #输入文件的名字
.equ ST_ARGV_2, 12#输出文件的名字
<p class="p1"><span class="s1">.equ</span><span class="s2"> ST_FD_IN, </span><span class="s3">-4</span></p><p class="p1"><span class="s1">.equ</span><span class="s2"> ST_FD_OUT, </span><span class="s3">-8</span></p>#文件打开选项
.equ O_RDONLY, 0
.equ O_CREAT_WRONLY_TRUNC, 03101
open_files:
open_fd_in:
###打开输入文件###
#打开系统调用
movl $SYS_OPEN, %eax
#将输入文件名字的指针放入%ebx
movl ST_ARGV_1(%ebp), %ebx
#只读标志
movl $O_RDONLY, %ecx
#这实际上并不影响读操作
movl $0666, %edx
#调用Linux
int $LINUX_SYSCALLopen_fd_out:
###打开输出文件###
#打开文件
movl $SYS_OPEN, %eax
#将输出文件名字的指针放在%ebx
movl ST_ARGV_2(%ebp), %ebx
#写入文件标志
movl $O_CREAT_WRONLY_TRUNC, %ecx
#新文件模式(如果已经创建)
movl $0666, %edx
#调用Linux
int $LINUX_SYSCALL

#这里存储文件描述符
store_fd_in:
movl %eax, ST_FD_IN(%ebp)
store_fd_out:
movl %eax, ST_FD_OUT(%ebp)

下面就是读文件的操作:

读文件通过read体统调用来实现,这个调用的参数是一个用于读取的文件描述符、一个用于写入的缓冲区、以及缓冲区的大小。

1.将系统调用号3存入%eax寄存器中

2.将文件描述符存入%ebx寄存器中

3.将存储数据的缓冲区地址存入%ecx寄存器中

4.将缓冲区的大小存入%edx中

系统调用返回实际读取的字节数或者文件结束符(0),存放到%eax寄存器中。

通常代码如下:

<p class="p1"><span class="s1">.equ</span><span class="s2"> SYS_READ, </span><span class="s3">3</span></p><pre name="code" class="plain"><span style="font-family: Arial, Helvetica, sans-serif;">#####从文件中读取一个数据块#####</span>
movl $SYS_READ, %eax#获取文件描述符movl ST_FD_IN(%ebp), %ebx#放置读取数据的存储位置movl $BUFFER_DATA, %ecx#放置缓冲区的大小movl $BUFFER_SIZE, %edx#读取缓冲区大小返回到%eaxint $LINUX_SYSCALL

 接着是写文件操作: 

写文件是通过write系统调用实现的,需要的参数与read系统调用的参数相同,唯一的区别是缓冲区应该填满了要写的数据。

1.将系统调用号4存入%eax寄存器中

2.将文件描述符存入%ebx寄存器中

3.将存储数据的缓冲区地址存入%ecx寄存器中

4.将缓冲区的大小存入%edx中

系统调用返回实际写入的字节数或者错误代码,存放到%eax寄存器中。

通常代码如下:

####将字符块写入文件####
#缓冲区大小
movl %eax, %edx
movl $SYS_WRITE, %eax
#要使用的文件
movl ST_FD_OUT(%ebp), %ebx
#缓冲区位置
movl $BUFFER_DATA, %ecx
int $LINUX_SYSCALL

最后是关闭文件操作:

关闭文件是通过close系统调用实现,其需要的参数是文件描述符。

1.将系统调用号6存入%eax寄存器中

2.将文件描述符存入%ebx寄存器中

通常代码如下:

##关闭文件##
movl $SYS_CLOSE, %eax
movl ST_FD_OUT(%ebp), %ebx
int $LINUX_SYSCALLmovl $SYS_CLOSE, %eax
movl ST_FD_IN(%ebp), %ebx
int $LINUX_SYSCALL
整个程序的代码如下:

#目的: 本程序将输入文件的所有字母转化成大写字母,然后输#
出到文件#处理过程: (1)打开输入文件
# (2)打开输出文件
# (3)如果未达到输入文件的尾部:
# (a)将部分文件读入到内存缓冲区
# (b)读取内存缓冲区的每一个字节如果该字节#
为小写字母,就将转化为大写字母
# (c)将内存缓冲区写入输出文件.section .data########################
########常数############
#系统调用编号
.equ SYS_OPEN, 5
.equ SYS_CLOSE, 6
.equ SYS_READ, 3
.equ SYS_WRITE, 4
.equ SYS_EXIT, 1#文件打开选项
.equ O_RDONLY, 0
.equ O_CREAT_WRONLY_TRUNC, 03101#标准文件描述符
.equ STDIN, 0
.equ STDOUT, 1
.equ STDERR, 2#系统调用中断
.equ LINUX_SYSCALL, 0x80
.equ END_OF_FILE, 0 #这是读操作的返回值,表明到达文件的结束处
.equ NUMBER_ARGUMENTS, 2.section .bss
#缓冲区--从文件中将数据加载到这里,也要从这里将数据写出到文件
# 由于种种原因,缓冲区大小不应该超过16000字节
.equ BUFFER_SIZE, 500
.lcomm BUFFER_DATA, BUFFER_SIZE.section .text#栈位置
.equ ST_SIZE_RESERVE, 8
.equ ST_FD_IN, -4
.equ ST_FD_OUT, -8
.equ ST_ARGC, 0 #参数数目
.equ ST_ARGV_0, 4 #程序名
.equ ST_ARGV_1, 8 #输入文件的名字
.equ ST_ARGV_2, 12#输出文件的名字.globl _start
_start:
###程序初始化####
#保存栈指针
movl %esp, %ebp#在栈上为文件描述符分配空间
subl $ST_SIZE_RESERVE, %esp #局部变量open_files:
open_fd_in:
###打开输入文件###
#打开系统调用
movl $SYS_OPEN, %eax
#将输入文件名字的指针放入%ebx
movl ST_ARGC(%ebp), %ebx
cmpl $1, %ebx                    #$1放在前面,%ebx放在后面
je input_STDIN
movl ST_ARGV_1(%ebp), %ebx
jmp input_assign_file
input_STDIN:
movl $STDIN, %ebx
input_assign_file:
#只读标志
movl $O_RDONLY, %ecx
#这实际上并不影响读操作
movl $0666, %edx
#调用Linux
int $LINUX_SYSCALLstore_fd_in:
movl %eax, ST_FD_IN(%ebp)open_fd_out:
###打开输出文件###
#打开文件
movl $SYS_OPEN, %eax
#将输出文件名字的指针放在%ebx
movl ST_ARGC(%ebp), %ebx
cmpl $2, %ebx               <span style="font-family: Arial, Helvetica, sans-serif;">#$2放在前面,%ebx放在后面</span>
je output_STDOUT
movl ST_ARGV_2(%ebp), %ebx
jmp output_assign_file
output_STDOUT:
movl $STDOUT, %ebx
output_assign_file:#写入文件标志
movl $O_CREAT_WRONLY_TRUNC, %ecx
#新文件模式(如果已经创建)
movl $0666, %edx
#调用Linux
int $LINUX_SYSCALLstore_fd_out:
#这里存储文件描述符
movl %eax, ST_FD_OUT(%ebp)###主循环开始###
read_loop_begin:#####从文件中读取一个数据块#####
movl $SYS_READ, %eax
#获取文件描述符
movl ST_FD_IN(%ebp), %ebx
#放置读取数据的存储位置
movl $BUFFER_DATA, %ecx
#放置缓冲区的大小
movl $BUFFER_SIZE, %edx
#读取缓冲区大小返回到%eax
int $LINUX_SYSCALL###如果达到文件结束处就退出###
#检查文件结束标志#
cmpl $END_OF_FILE, %eax
#如果发现文件结束符或出现错误,就跳转到程序结束处
jle end_loopcontinue_read_loop:
###将字符块的内容转换成大写形式####
pushl $BUFFER_DATA #缓冲区地址
pushl %eax         #缓冲区大小
call conver_to_upper
popl %eax   #重新获取大小
addl $4, %esp   #恢复%esp####将字符块写入文件####
#缓冲区大小
movl %eax, %edx
movl $SYS_WRITE, %eax
#要使用的文件
movl ST_FD_OUT(%ebp), %ebx
#缓冲区位置
movl $BUFFER_DATA, %ecx
int $LINUX_SYSCALL#循环继续#
jmp read_loop_beginend_loop:
##关闭文件##
movl $SYS_CLOSE, %eax
movl ST_FD_OUT(%ebp), %ebx
int $LINUX_SYSCALLmovl $SYS_CLOSE, %eax
movl ST_FD_IN(%ebp), %ebx
int $LINUX_SYSCALL###退出程序###
movl $SYS_EXIT, %eax
movl $0, %ebx
int $LINUX_SYSCALL#目的; 这个函数实际上是将字符块的内容转化为大写的形式#输入: 第一个参数是要转化的缓冲区的地址
# 第二个参数的是缓冲区的大小#输出: 这个函数以大写字符覆盖当前的缓冲区#变量: 
# %eax--缓冲区起始地址
# %ebx--缓冲区长度
# %edi--当前缓冲区偏移量
# %cl--当前正在检测的字节(%ecxde第一部分)###常数####搜索的下边界
.equ LOWERCASE_A, 'a'
#搜索的上边界
.equ LOWERCASE_Z, 'z'
#大小写转换
.equ UPPER_CONVERSION, 'A'-'a'###栈相关的信息###
.equ ST_BUFFER_LEN, 8 #缓冲区长度
.equ ST_BUFFER, 12    #实际缓冲区conver_to_upper:
pushl %ebp
movl %esp, %ebp#设置变量#
movl ST_BUFFER(%ebp), %eax
movl ST_BUFFER_LEN(%ebp), %ebx
movl $0, %edi#安全检查:如果给定的缓冲区长度为0即离开
cmpl $0, %ebx
je coop_endcoop_start:
#获取当前字节
movb (%eax, %edi, 1), %cl#除非该字节在'a'和'z'之间,否则读取下一个字节
cmpb $LOWERCASE_A, %cl
jl next_bytecmpb $LOWERCASE_Z, %cl
jg next_byte#将字节转化成为大写字母
addb $UPPER_CONVERSION, %cl#并放回原处
movb %cl, (%eax, %edi, 1)#下一字节
next_byte:
incl %edi
cmpl %edi, %ebx #判断是否到缓冲区结束
jne coop_start#缓冲区结束,离开函数
coop_end:
movl %ebp, %esp
popl %ebp
ret


汇编链接程序:

as -32 toupper.s -o toupper.o
ld -m elf_i386 toupper.o -o toupper
./toupper




这篇关于汇编程序--文件操作的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/674221

相关文章

MySQL游标和触发器的操作流程

《MySQL游标和触发器的操作流程》本文介绍了MySQL中的游标和触发器的使用方法,游标可以对查询结果集进行逐行处理,而触发器则可以在数据表发生更改时自动执行预定义的操作,感兴趣的朋友跟随小编一起看看... 目录游标游标的操作流程1. 定义游标2.打开游标3.利用游标检索数据4.关闭游标例题触发器触发器的基

在C#中分离饼图的某个区域的操作指南

《在C#中分离饼图的某个区域的操作指南》在处理Excel饼图时,我们可能需要将饼图的各个部分分离出来,以使它们更加醒目,Spire.XLS提供了Series.DataFormat.Percent属性,... 目录引言如何设置饼图各分片之间分离宽度的代码示例:从整个饼图中分离单个分片的代码示例:引言在处理

Python列表的创建与删除的操作指南

《Python列表的创建与删除的操作指南》列表(list)是Python中最常用、最灵活的内置数据结构之一,它支持动态扩容、混合类型、嵌套结构,几乎无处不在,但你真的会创建和删除列表吗,本文给大家介绍... 目录一、前言二、列表的创建方式1. 字面量语法(最常用)2. 使用list()构造器3. 列表推导式

Go异常处理、泛型和文件操作实例代码

《Go异常处理、泛型和文件操作实例代码》Go语言的异常处理机制与传统的面向对象语言(如Java、C#)所使用的try-catch结构有所不同,它采用了自己独特的设计理念和方法,:本文主要介绍Go异... 目录一:异常处理常见的异常处理向上抛中断程序恢复程序二:泛型泛型函数泛型结构体泛型切片泛型 map三:文

MySQL基本表查询操作汇总之单表查询+多表操作大全

《MySQL基本表查询操作汇总之单表查询+多表操作大全》本文全面介绍了MySQL单表查询与多表操作的关键技术,包括基本语法、高级查询、表别名使用、多表连接及子查询等,并提供了丰富的实例,感兴趣的朋友跟... 目录一、单表查询整合(一)通用模版展示(二)举例说明(三)注意事项(四)Mapper简单举例简单查询

Nginx概念、架构、配置与虚拟主机实战操作指南

《Nginx概念、架构、配置与虚拟主机实战操作指南》Nginx是一个高性能的HTTP服务器、反向代理服务器、负载均衡器和IMAP/POP3/SMTP代理服务器,它支持高并发连接,资源占用低,功能全面且... 目录Nginx 深度解析:概念、架构、配置与虚拟主机实战一、Nginx 的概念二、Nginx 的特点

MySQL 数据库进阶之SQL 数据操作与子查询操作大全

《MySQL数据库进阶之SQL数据操作与子查询操作大全》本文详细介绍了SQL中的子查询、数据添加(INSERT)、数据修改(UPDATE)和数据删除(DELETE、TRUNCATE、DROP)操作... 目录一、子查询:嵌套在查询中的查询1.1 子查询的基本语法1.2 子查询的实战示例二、数据添加:INSE

使用Python在PDF中绘制多种图形的操作示例

《使用Python在PDF中绘制多种图形的操作示例》在进行PDF自动化处理时,人们往往首先想到的是文本生成、图片嵌入或表格绘制等常规需求,然而在许多实际业务场景中,能够在PDF中灵活绘制图形同样至关重... 目录1. 环境准备2. 创建 PDF 文档与页面3. 在 PDF 中绘制不同类型的图形python

Java 操作 MinIO详细步骤

《Java操作MinIO详细步骤》本文详细介绍了如何使用Java操作MinIO,涵盖了从环境准备、核心API详解到实战场景的全过程,文章从基础的桶和对象操作开始,到大文件分片上传、预签名URL生成... 目录Java 操作 MinIO 全指南:从 API 详解到实战场景引言:为什么选择 MinIO?一、环境

在DataGrip中操作MySQL完整流程步骤(从登录到数据查询)

《在DataGrip中操作MySQL完整流程步骤(从登录到数据查询)》DataGrip是JetBrains公司出品的一款现代化数据库管理工具,支持多种数据库系统,包括MySQL,:本文主要介绍在D... 目录前言一、登录 mysql 服务器1.1 打开 DataGrip 并添加数据源1.2 配置 MySQL