x86汇编中AL、BL、CL寄存器表现异常原因咨询
先贴出原实现代码:
section .data format db '%d', 0x0a, 0 section .text global ft_strlen ft_strlen: push ebp mov ebp, esp mov ecx, [ebp + 8] mov eax, 0 loop: mov cl, [ecx + eax] inc eax cmp cl, 0 jne loop mov esp, ebp pop ebp ret
替换为AL寄存器导致无限循环的原因
AL是32位寄存器EAX的低8位,而EAX在这段代码里是字符串长度计数器。当执行mov al, [ecx + eax]时,你把内存中字符串的当前字节加载到AL,这会直接修改EAX的低8位——也就是破坏了计数器的当前值。
举个例子:假设EAX当前值是0x00000005,此时加载字符串中一个值为0x41(字符'A')的字节到AL,EAX会变成0x00000041,之后执行inc eax,EAX变成0x00000042,完全偏离了原本应该递增的计数逻辑。这种情况下,计数器永远无法正常走到字符串的终止符0的位置,自然会进入无限循环。
替换为BL寄存器触发段错误(SEGV)的原因
BL是32位寄存器EBX的低8位,而在x86的C调用约定中,EBX属于被调用者保存寄存器(callee-saved)。这意味着:调用你的ft_strlen函数的代码可能正在使用EBX存储重要数据(比如某个内存地址),你的函数在修改BL(即修改EBX)之前,没有先保存EBX的值,也没有在函数返回前恢复它。
当ft_strlen返回后,调用者的代码会继续使用EBX,但此时EBX的值已经被破坏,后续的内存访问操作会使用错误的地址,最终触发段错误。
使用CL寄存器正常的原因
CL是32位寄存器ECX的低8位,ECX属于调用者保存寄存器(caller-saved)。按照调用约定,函数可以随意修改这类寄存器的值,不需要保存和恢复。同时,原代码中ECX被用来存储字符串的首地址,修改CL不会影响ECX的高24位,因此字符串地址不会被破坏,计数器EAX也能正常递增,整个逻辑可以正确执行。
内容的提问来源于stack exchange,提问作者Erhouni Soufian

