汇编语言学习_3_计算字符串长度

第三节

计算字符串长度

翻译自:https://asmtutor.com/

背景知识

为什么我们需要计算字符串的长度?

好吧,sys_write 要求我们向它传递一个指向我们要在内存中输出的字符串的指针,以及我们要打印出的字节长度。如果我们要修改我们的消息字符串,我们也必须更新我们传递给 sys_write 的字节长度,否则它不会正确打印。

您可以使用第二节中的程序了解我的意思。将消息字符串修改为“Hello, brave new world!”然后编译、链接并运行新程序。输出将是“Hello, brave”(前 13 个字符),因为我们仍然只将 13 个字节作为其长度传递给 sys_write。当我们想要打印出用户输入时,这将是特别必要的。由于我们在编译程序时不知道数据的长度,因此我们需要一种在运行时计算长度的方法,以便成功打印出来。

写程序

为了计算字符串的长度,我们将使用一种称为指针算法的技术。两个寄存器被初始化指向内存中的相同地址。对于输出字符串中的每个字符,一个寄存器(在本例中为 EAX)将向前递增一个字节,直到我们到达字符串的末尾。然后将从 EAX 中减去原始指针。这实际上类似于两个数组之间的减法,结果产生两个地址之间的元素数。然后将此结果传递给 sys_write 以替换我们的硬编码计数。

CMP 指令将左侧与右侧进行比较,并设置一些用于程序流的标志。我们正在检查的标志是 ZF (零标志)。当 EAX 指向的字节等于零时,设置 ZF 标志。然后,如果设置了 ZF 标志,我们将使用 JZ 指令跳转到程序中标记为“完成”的点。这是为了跳出 nextchar 循环并继续执行程序的其余部分。

; Hello World Program (Calculating string length)
; 编译: nasm -f elf helloworld-len.asm
; 链接 (64 bit 系统需要 elf_i386 选项): ld -m elf_i386 helloworld-len.o -o helloworld-len
; 运行: ./helloworld-len
 
SECTION .data
msg     db      'Hello, brave new world!', 0Ah ; 我们现在可以随意更改这个字符串了
 
SECTION .text
global  _start
 
_start:
 
    mov     ebx, msg        ; 将字符串地址移动到 EBX
    mov     eax, ebx        ; 将地址向 EAX 拷贝一份 (使得它们两个指向相同的地址)
 
nextchar:
    cmp     byte [eax], 0   ; 比较 EAX 指向的位置是否为0 (0代表着字符串的结束)
    jz      finished        ; 跳转到 finished (如果0标志被设置)
    inc     eax             ; EAX 自增1 (如果0标志没有被设置)
    jmp     nextchar        ; 跳转到 nextchar
 
finished:
    sub     eax, ebx        ; EBX - EAX,长度保存在EAX中
                            ; 两个寄存器开始时指向同一地址
                            ; 但EAX与msg中的字符对应地递增
                            ; 当同一类型的两个内存地址相减
                            ; 结果就是地址间的段数量,本例中就是字节数
 
    mov     edx, eax        ; EAX 现在的值就是字符串长度
    mov     ecx, msg       
    mov     ebx, 1
    mov     eax, 4
    int     80h
 
    mov     ebx, 0
    mov     eax, 1
    int     80h
~$ nasm -f elf helloworld-len.asm
~$ ld -m elf_i386 helloworld-len.o -o helloworld-len
~$ ./helloworld-len
Hello, brave new world!
posted @ 2023-02-28 16:26  charain_li  阅读(465)  评论(0编辑  收藏  举报