第三节
计算字符串长度
背景知识
为什么我们需要计算字符串的长度?
好吧,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!
标签:eax,汇编语言,mov,helloworld,EAX,len,字符串,长度
From: https://www.cnblogs.com/chai-yuan/p/17164792.html