x86汇编实现字符串小写转大写:新手技术求助
搞定字符串小写转大写的汇编实现
嘿,这个入门练习选得挺棒的!刚接触汇编遇到细节卡壳太正常了,我来帮你梳理下现有代码的问题,再补全完整的实现逻辑:
先说说你现有代码里的小问题
- 你用
.ascii定义了lowerA和lowerZ(单字节数据),但用movl(4字节加载指令)去读取,这会把后面的内存数据也误读进来,应该用movb来加载单字节值到寄存器的低8位(比如%al、%bl)。 - 变量
i是用来做循环计数器的,但还没把它整合到遍历字符串的逻辑里,我们需要用它(或者直接用寄存器,更高效)来逐个访问字符串的每个字符。 - 核心的循环判断和小写转大写逻辑还没写,最后也缺了输出转换后字符串和退出程序的系统调用代码。
补全后的完整可运行代码
EXIT = 1 WRITE = 4 LINUX_SYSCALL = 0x80 .data lowerA: .ascii "a" ; 小写a的ASCII值(0x61) lowerZ: .ascii "z" ; 小写z的ASCII值(0x7A) msg: .ascii "Hello, world!\n" msglen = (. - msg) i: .int 0 ; 循环计数器,初始为0 .text .global _start _start: movb lowerA, %al ; 把小写a的ASCII值加载到%al寄存器 movb lowerZ, %bl ; 把小写z的ASCII值加载到%bl寄存器 movl $0, %ecx ; 用%ecx作为循环计数器(比内存变量i更高效) loop_start: cmpl $msglen, %ecx ; 判断计数器是否等于字符串长度,相等就退出循环 je loop_end movb msg(%ecx), %dl ; 取出当前位置的字符到%dl寄存器 cmpb %al, %dl ; 把当前字符和小写a比较 jl next_char ; 比a小?不是小写字母,跳过转换 cmpb %bl, %dl ; 把当前字符和小写z比较 jg next_char ; 比z大?不是小写字母,跳过转换 subb $0x20, %dl ; 是小写字母!减去0x20(32)转成大写(ASCII中小写比大写大32) movb %dl, msg(%ecx) ; 把转换后的字符写回原字符串的对应位置 next_char: incl %ecx ; 计数器加1,准备处理下一个字符 jmp loop_start ; 跳回循环开头继续处理 loop_end: ; 调用WRITE系统调用,输出转换后的字符串 movl $WRITE, %eax movl $1, %ebx ; 文件描述符1代表标准输出 movl $msg, %ecx movl $msglen, %edx int $LINUX_SYSCALL ; 调用EXIT系统调用,正常退出程序 movl $EXIT, %eax movl $0, %ebx ; 退出码0表示程序正常结束 int $LINUX_SYSCALL
关键逻辑拆解
- 字符范围判断:通过两次比较,确认当前字符在
a-z的ASCII范围内,只有符合条件的才做转换。 - 大小写转换原理:ASCII表中,每对大小写字母的差值都是32(0x20),所以给小写字母减去这个值就能得到对应的大写字母。
- 循环遍历:用寄存器
%ecx做计数器,逐个遍历字符串的每个字节,直到计数器等于字符串长度,就结束循环。 - Linux系统调用:通过
int $0x80触发系统调用,%eax存储调用号(WRITE是4,EXIT是1),其他寄存器传递调用参数。
你可以用下面的命令编译运行这段代码:
nasm -f elf32 your_program.asm -o your_program.o ld -m elf_i386 your_program.o -o your_program ./your_program
运行后就能看到全大写的HELLO, WORLD!啦~
内容的提问来源于stack exchange,提问作者NGSBNC
相关产品推荐
相关产品推荐

