Assembly 汇编:cmp指令和寻址
我是asm的新手,很困惑 这是我在Assembly 汇编:cmp指令和寻址,assembly,x86-64,nasm,Assembly,X86 64,Nasm,我是asm的新手,很困惑 这是我在nasm组件中工作的strlen函数的循环: .loop: inc rax inc rbx cmp [rbx], byte 0
nasm
组件中工作的strlen
函数的循环:
.loop: inc rax
inc rbx
cmp [rbx], byte 0
jne .loop
ret
然而,我在教程中看到了类似于cmpbl,0
的内容,但是当我尝试时,我得到了错误的长度
我尝试了cmp[bl],0
,但在汇编时出现无效有效地址
错误
我还尝试了cmp-rbx,0
。但节目从未停止,所以我最好的猜测是我是
将一个非常大的地址与0进行比较,这是永远不会发生的
人们如何理解这种行为?为什么我不能使用cmp rbx,0
人们能够使用cmp bl,0
如果您找到更具描述性的标题,请随意编辑。要比较地址处的字节,我建议将字节移动到正确大小的寄存器中,然后进行比较。根据您正在使用的调用约定,但假设字符串的地址是在rdi中传递的,我建议如下所示
.loop: inc rax
mov bl, [rdi + rax]
cmp bl, byte 0
jne .loop
ret
编辑:意识到您试图确定给定地址处字符串的长度要比较地址处的字节,我建议将字节移动到正确大小的寄存器中,然后进行比较。根据您正在使用的调用约定,但假设字符串的地址是在rdi中传递的,我建议如下所示
.loop: inc rax
mov bl, [rdi + rax]
cmp bl, byte 0
jne .loop
ret
编辑:意识到您试图确定给定地址处字符串的长度您能否显示您所做的完整的
strlen
过程,以及您看到的使用cmp bl,0
的示例?如果您将字符加载到寄存器中,您可以将其与0进行比较。如果否,则需要为cmp
创建内存操作数。顺便说一句,您是正确的,cmprbx,0
将指针与NULL进行比较;在将指针环绕到0之前,您将遇到一个未映射的页面。您是否确切理解cmp byte[rbx],0
的含义?应该有很多教程来解释寻址模式和内存与寄存器的关系,例如,找到链接的教程或指南并阅读。这也应该清楚地说明为什么cmp[bl],0
甚至不能组装(x86不允许8位地址),以及为什么它即使可以运行也不能做您想要的事情。还有另一种搜索NUL终止符的方法:。您不需要inc rax
,只需将字符串的开头移到rax即可,然后减去你刚刚找到的0字节的地址,得到长度。你能展示你所做的完整strlen
过程,以及你所看到的使用CMPBL,0
的例子吗?如果你把字符加载到寄存器中,你可以将其与0进行比较。如果否,则需要为cmp
创建内存操作数。顺便说一句,您是正确的,cmprbx,0
将指针与NULL进行比较;在将指针环绕到0之前,您将遇到一个未映射的页面。您是否确切理解cmp byte[rbx],0
的含义?应该有很多教程来解释寻址模式和内存与寄存器的关系,例如,找到链接的教程或指南并阅读。这也应该清楚地说明为什么cmp[bl],0
甚至不能组装(x86不允许8位地址),以及为什么它即使可以运行也不能做您想要的事情。还有另一种搜索NUL终止符的方法:。您不需要inc rax
,只需将字符串的开头移到rax即可,然后减去刚刚找到的0字节的地址,得到长度。rax被初始化为.loop上面的零。请注意,您没有修复OP不检查第一个字节的错误(可能是[rdi+rax-1]
,或者在循环之前将rax初始化为-1
)。这是合理的,但通常您希望使用movzx ecx,byte[rdi+rax]
进行字节加载,而不是创建一个虚假的依赖项,并通过合并到RBX的低位字节来获取ALU uop。(或RCX,这是strlen的更好选择,因为调用约定允许您在不保存的情况下修改它)。当然,与SIMD相比,一次运行1字节的速度非常慢,所以这只是一个初学者练习。@PeterCordes:我通常会编写rep scasb,但我再也不会为了性能而编写asm了。@Joshua:是的,对于代码大小和简单性来说,这是可以的,但其他的就不多了。它一次只运行1个字节;只有rep MOV和rep STO具有快速字符串微码;遗憾的是,条件repe/repne指令不在当前CPU中repne scasb
本身不会分支预测失误,但我认为这会阻碍前端。虽然可能不适用于UOP的初始突发覆盖长度的短字符串。rax初始化为.loop上方的零。请注意,您没有修复OP不检查第一个字节的错误(可能是[rdi+rax-1]
,或者在循环之前将rax初始化为-1
)。这是合理的,但通常您希望使用movzx ecx,byte[rdi+rax]
进行字节加载,而不是创建一个虚假的依赖项,并通过合并到RBX的低位字节来获取ALU uop。(或RCX,这是strlen的更好选择,因为调用约定允许您在不保存的情况下修改它)。当然,与SIMD相比,一次运行1字节的速度非常慢,所以这只是一个初学者练习。@PeterCordes:我通常会编写rep scasb,但我再也不会为了性能而编写asm了。@Joshua:是的,对于代码大小和简单性来说,这是可以的,但其他的就不多了。它一次只运行1个字节;只有rep MOV和rep STO具有快速字符串微码;遗憾的是,条件repe/repne指令不在当前CPU中repne scasb
本身不会分支预测失误,但我认为这会阻碍前端。虽然可能不适合短字符串