UNIX文件处理

UNIX文件处理


专栏目录(文章在更新中)

> 汇编及C/C++汇编调用约定(汇总帖)
> 汇编编译和gdb调试命令列表
> gdb TUI使用方法
> 汇编C语言调用约定(标准函数)
> 汇编C语言调用约定(递归函数)
> C++内存模型以及寄存器指针rsp和rbp



1. 一些系统调用号

open — 5
write — 4
read — 3
close — 6
exit — 1

2. 设置.bss缓冲区

.lcomm指令将创建一个符号my_buffer,指代我们用作缓冲区的500字节的存储位置

  .section .bss
  .lcomm my_buffer, 500

打开一个文件进行读取,文件描述符放置在%ebx中

3. gdb 设置参数

  1. 汇编命令行参数在内存中的位置参考这篇帖子:linux平台学x86汇编(十五):使用命令行参数
  2. 设置参数:
    • run args1 args2 ...
    • gdb --args ./testprg arg1 arg2
    • set args — Set argument list to give program being debugged when it is started.
  3. 在gdb中查看参数:
    在这里插入图片描述

4. 文件操作

  1. 打开文件
    • open,系统调用5,当通过一个文件名打开一个文件时,系统会提供一个编号,即文件描述符,用它来指代该文件,直到使用close。关闭文件后文件描述符及失效。
    • 打开文件时文件名第一个字符的地址应存放在%ebx,以数字表示的读/写意图应存放在%ecx,权限集合应作为数字存储在%edx中。
    • Linux将返回文件描述符到%eax,即将在整个程序中用这个数字来指代这一文件。
    • 打开输入文件:
          .equ SYS_OPEN, 5
          .equ ST_ARGV_1, 8
          .equ O_RDONLY, 0
          .equ LINUX_SYSCALL, 0X80
          .equ ST_FD_IN, -4
          
          movl $SYS_OPEN, %eax
          movl $ST_ARGV_1(%ebp), %ebx
          movl $O_RDONLY, %ecx
          movl $0666, %edx
          int $LINUX_SYSCALL
          
          # 保存返回的文件描述符
          movl %eax, ST_FD_IN(%ebp)
      
    • 打开输出文件:
          .equ SYS_OPEN, 5
          .equ ST_ARGV_2, 12
          .equ O_CREAT_WRONLY_TRUNC, 03101
          .equ LINUX_SYSCALL, 0X80
          .equ ST_FD_IN, -8
          
          movl $SYS_OPEN, %eax
          movl $ST_ARGV_2(%ebp), %ebx
          movl $O_CREAT_WRONLY_TRUNC, %ecx
          movl $0666, %edx
          int $LINUX_SYSCALL
          
          # 保存返回的文件描述符
          movl %eax, ST_FD_OUT(%ebp)
      
  2. 关闭文件
    • close,系统调用6,close的唯一参数就是文件描述符,应存储在%ebx中。
          .equ SYS_CLOSE, 6
          .equ ST_FD_OUT, -8
          .equ LINUX_SYSCALL, 0X80
      
          movl $SYS_CLOSE, %eax
          movl ST_FD_OUT(%ebp), %ebx
          int $LINUX_SYSCALL
      
  3. 设置.bss缓冲区
.section .bss
  .equ BUFFER_SIZE, 500
  .lcomm BUFFER_DATA, BUFFER_SIZE
  1. 从文件中读/写数据到缓冲区
    • 读过程 :将文件描述符存入%ebx,将存储数据的缓冲区地址存入%ecx,将缓冲区大小放入%edx,read将返回从文件中读取的字符数或错误代码(负数)
          .section .bss
          .equ BUFFER_SIZE, 500
          .lcomm BUFFER_DATA, BUFFER_SIZE
          
          .section .text
          .equ SYS_READ, 3
          .equ ST_FD_IN, -4
      
      
          movl $SYS_READ, %eax
          movl $ST_FD_IN(%ebp), %ebx
          movl $BUFFER_DATA, %ecx
          movl $BUFFER_SIZE, %edx
          int $LINUX_SYSCALL
      
          cmpl $END_OF_FILE, %eax
          jle end_loop
      
    • 写过程:写的参数与读相同,唯一的区别是缓冲区应该已经填满了要写入的数据,将把写入的字节数或错误代码存入%eax
          .section .bss
          .equ BUFFER_SIZE, 500
          .lcomm BUFFER_DATA, BUFFER_SIZE
          
          .section .text
          .equ SYS_WRITE, 4
          .equ ST_FD_OUT, -8
      
          # eax 保存的是文件写入缓冲区后缓冲区的大小
          movl %eax, %edx
          movl $SYS_READ, %eax
          movl $ST_FD_IN(%ebp), %ebx
          movl $BUFFER_DATA, %ecx
          int $LINUX_SYSCALL
      

5. 关于函数初始化时的栈指针偏移

     .equ ST_SIZE_RESERVE, 8
     .equ ST_FD_IN, -4
     .equ ST_FD_OUT, -8
     .globl _start
   _start:
     movl %esp, %ebp
     subl $ST_SIZE_RESERVE, %esp

   # 通过此将数据存入预留的栈空间中
   store_fd_in:
     movl %eax, ST_FD_IN(%ebp)
   store_fd_out:
     movl %eax, ST_FD_OUT(%ebp)

在这里插入图片描述

6. 完整示例

  .section .data

  # 系统调用号
  .equ SYS_OPEN, 5
  .equ SYS_WRITE, 4
  .equ SYS_READ, 3
  .equ SYS_CLOSE, 6
  .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
  .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
  movl ST_ARGV_1(%ebp), %ebx
  movl $O_RDONLY, %ecx
  movl $0666, %edx
  int $LINUX_SYSCALL


store_fd_in:
  movl %eax, ST_FD_IN(%ebp)

open_fd_out:
  movl $SYS_OPEN, %eax
  movl ST_ARGV_2(%ebp), %ebx
  movl $O_CREAT_WRONLY_TRUNC, %ecx
  movl $0666, %edx
  int $LINUX_SYSCALL

store_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
  int $LINUX_SYSCALL

  # 返回缓冲区中读取到的大小存入%eax
  cmpl $END_OF_FILE, %eax 
  jle end_loop

continue_read_loop:
  # 将缓冲区和缓冲区大小入栈
  pushl $BUFFER_DATA
  pushl %eax
  call convert_to_upper

  # 释放压栈的缓冲区和缓冲区大小
  popl %eax
  addl $4, %esp

  movl %eax, %edx
  movl $SYS_WRITE, %eax
  movl ST_FD_OUT(%ebp), %ebx
  movl $BUFFER_DATA, %ecx
  int $LINUX_SYSCALL
  jmp read_loop_begin

end_loop:
  movl $SYS_CLOSE, %eax
  movl ST_FD_OUT(%ebp), %ebx
  int $LINUX_SYSCALL

  movl $SYS_CLOSE, %eax
  movl ST_FD_IN(%ebp), %ebx
  int $LINUX_SYSCALL

  movl $SYS_EXIT, %eax
  movl $0, %ebx
  int $LINUX_SYSCALL


  .equ LOWERCASE_A, 'a'
  .equ LOWERCASE_Z, 'z'
  .equ UPPER_CONVERSION, 'A' - 'a'

  # 栈上缓冲区基址寻址
  .equ ST_BUFFER_LEN, 8
  .equ ST_BUFFER, 12

convert_to_upper:
  pushl %ebp
  movl %esp, %ebp

  movl ST_BUFFER(%ebp), %eax
  movl ST_BUFFER_LEN(%ebp), %ebx
  movl $0, %edi

  cmpl $0, %ebx
  je end_convert_loop

convert_loop:
  movb (%eax, %edi, 1), %cl
  cmpb $LOWERCASE_A, %cl
  jl next_byte
  cmpb $LOWERCASE_Z, %cl
  jg next_byte

  addb $UPPER_CONVERSION, %cl
  movb %cl, (%eax, %edi, 1)

next_byte:
  incl %edi
  cmpl %edi, %ebx
  jne convert_loop

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


在这里插入图片描述


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值