【Linux x86汇编踩坑】文件读写(二)读取文件转换大小写

【Linux x86汇编踩坑】文件读写(二)读取文件转换大小写

前言

转换大小写的思路很简单,来尝试用汇编写一个转换大小写的程序吧

转换大小写

由于在汇编中字符也是用ascii码存储的,那么思路就很清晰了,比如a对应的ascii码是97,而A对应的ascii码是65,那么将a转换为A只需要让a +(-32)即可,这个-32是他们之间的差,由于字母之间的ascii码是连续的,那么从a-z的小写字母我们都可以让它们加上-32来转换为大写字母。

知道了实现原理之后我们来实现一下这个函数。

#转换大小写
.type upperConversion, @function
#确定需要转换的字符的上下界限
.equ UP_CRITICAL, 'z'
.equ LOWER_CRITICAL, 'a'
#转换需要相加的数
.equ UPPER_CONVERSION, 'A' - 'a'
upperConversion:
  pushl %ebp
  movl %esp, %ebp
  movl $BUFFER_SIZE, %ebx
  #如果给定的缓冲区的长度为0
  cmpl $0, %ebx
  je conversion_exit

  #索引
  movl $0, %edi
  #读取字节
  read_byte:
    movb BUFFER_DATA(,%edi,1), %cl
    cmpb $UP_CRITICAL, %cl
    jg next_byte
    cmpb $LOWER_CRITICAL, %cl
    jl next_byte

    #转换大小写
    addb $UPPER_CONVERSION, %cl
    movb %cl, BUFFER_DATA(,%edi,1)

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

  conversion_exit:
    popl %ebp
    ret

需要注意的是,BUFFER_DATA和BUFFER_SIZE分别对应我申请的缓冲区大小和缓冲区长度,具体代码在【Linux x86汇编踩坑】文件读写(一)读取文件并输出中,下面我也会附上完整的代码。

整体来看,上述代码用了一个循环read_byte来循环读取缓冲区里的字节,判断是否在a-z的范围内:

cmpb $UP_CRITICAL, %cl
jg next_byte
cmpb $LOWER_CRITICAL, %cl
jl next_byte

如果在范围内则进行转换大小写的操作,也就是给小写字母加上-32,然后将转换后的字符覆盖到原来缓冲区的位置

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

如果在a-z的范围内,也就是不属于小写字母了,那么我们可以跳过,直接读取下一个字符

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

conversion_exit标签用于结束整个函数,把ebp弹出栈,通过ret把把函数返回地址弹出,随后eip寄存器指向函数的返回地址。

conversion_exit:
  popl %ebp
  ret

整个过程还是比较简单的,下面我附上完整的代码,整个程序的功能主要是读取一个文件的所有字符,并将小写字符转换为大写字符后进入标准输出流输出

toupper.s

.section .data
#系统调用号
.equ SYS_EXIT, 1
.equ SYS_READ, 3
.equ SYS_WRITE, 4
.equ SYS_OPEN, 5
.equ SYS_CLOSE, 6

#文件打开选项
.equ FILE_READONLY, 0
.equ FILE_WRITE, 03101

#系统调用中断
.equ SYS_INTERRUP, 0x80

#标准文件描述符
.equ STD_IN, 0
.equ STD_OUT, 1
.equ STD_ERR, 2

#文件结束符
.equ END_OF_FILE, 0

.section .bss
#申请缓冲区20byte
.equ BUFFER_SIZE, 50
.lcomm BUFFER_DATA, BUFFER_SIZE

.section .text
.globl _start
_start:
  #文件名入栈
  movl %esp, %ebp
  pushl 8(%ebp)
  # 打开文件
  call openFile
  addl $4, %esp
  # 文件描述符保存在%eax
  pushl %eax
  # 读取文件
  call readFile
  addl $4, %esp
  #转换大小写
  call upperConversion
  call writeFile
  movl %eax, %ebx
  movl $SYS_EXIT, %eax
  int $SYS_INTERRUP

#系统调用打开文件
.type openFile, @function
openFile:
  pushl %ebp
  movl %esp, %ebp
  #系统调用号
  movl $SYS_OPEN, %eax
  #文件名
  movl 8(%ebp), %ebx
  #读写意图
  movl $FILE_READONLY, %ecx
  #系统权限
  movl $0666, %edx
  #系统中断
  int $SYS_INTERRUP
  popl %ebp
  ret

#读取文件
.type readFile, @function
readFile:
  pushl %ebp
  movl %esp, %ebp
  read_loop:
    #文件描述符
    movl 8(%ebp), %ebx
    #系统调用号
    movl $SYS_READ, %eax
    #缓冲区
    movl $BUFFER_DATA, %ecx
    #缓冲区大小
    movl $BUFFER_SIZE, %edx
    #系统调用
    int $SYS_INTERRUP
    cmpl $END_OF_FILE, %eax
    jle loop_exit
    jmp read_loop

  #读取完毕
  loop_exit:
    #关闭文件
    movl $SYS_CLOSE, %eax
    movl 8(%ebp), %ebx
    int $SYS_INTERRUP
    popl %ebp
    ret

#写入文件
.type writeFile, @function
writeFile:
  pushl %ebp
  movl %esp, %ebp
  #文件描述符
  movl $1, %ebx
  #系统调用号
  movl $SYS_WRITE, %eax
  #缓冲区
  movl $BUFFER_DATA, %ecx
  #缓冲区大小
  movl $BUFFER_SIZE, %edx
  #系统调用
  int $SYS_INTERRUP
  popl %ebp
  ret

#转换大小写
.type upperConversion, @function
#确定需要转换的字符的上下界限
.equ UP_CRITICAL, 'z'
.equ LOWER_CRITICAL, 'a'
#转换需要相加的数
.equ UPPER_CONVERSION, 'A' - 'a'
upperConversion:
  pushl %ebp
  movl %esp, %ebp
  movl $BUFFER_SIZE, %ebx
  #如果给定的缓冲区的长度为0
  cmpl $0, %ebx
  je conversion_exit

  #索引
  movl $0, %edi
  #读取字节
  read_byte:
    movb BUFFER_DATA(,%edi,1), %cl
    cmpb $UP_CRITICAL, %cl
    jg next_byte
    cmpb $LOWER_CRITICAL, %cl
    jl next_byte

    #转换大小写
    addb $UPPER_CONVERSION, %cl
    movb %cl, BUFFER_DATA(,%edi,1)

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

  conversion_exit:
    popl %ebp
    ret

在运行整个程序之前,先来编辑一下需要转换大小写的文件data,在data里写上这么一句,很简单的字符串对吧

hello world, MAN

尝试一下

as toupper.s -o toupper.o
ld toupper.o -o toupper
./toupper data
HELLO WORLD, MAN

successful!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值