Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 汇编:cmp指令和寻址_Assembly_X86 64_Nasm - Fatal编程技术网

Assembly 汇编:cmp指令和寻址

Assembly 汇编:cmp指令和寻址,assembly,x86-64,nasm,Assembly,X86 64,Nasm,我是asm的新手,很困惑 这是我在nasm组件中工作的strlen函数的循环: .loop: inc rax inc rbx cmp [rbx], byte 0

我是asm的新手,很困惑

这是我在
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
本身不会分支预测失误,但我认为这会阻碍前端。虽然可能不适合短字符串