汇编:cmp指令和寻址

Posted

技术标签:

【中文标题】汇编:cmp指令和寻址【英文标题】:Assembly : cmp instruction and addressing 【发布时间】:2021-05-09 13:01:52 【问题描述】:

我是 asm 新手,很困惑...

这是我在nasm 程序集中工作的strlen 函数的循环:

        .loop:      inc rax                                                         
                    inc rbx                                                         
                    cmp [rbx], byte 0                                               
                    jne .loop                                                       
                    ret 

但是我在教程中看到过 cmp bl, 0 这样的东西,但是当我尝试时,我得到了错误的长度。

我尝试过cmp [bl],0,但在组装时出现invalid effective address 错误。

我也试过cmp rbx, 0。但是程序永远不会停止所以我最好的猜测是我 将一个非常大的地址与永远不会发生的 0 进行比较。

如何理解这种行为?为什么我不能使用cmp rbx, 0 但有些 人们可以使用cmp bl, 0 吗?

如果您找到更具描述性的标题,请随时编辑标题。

【问题讨论】:

您能否展示您创建的完整strlen 过程,以及您看到的使用cmp bl, 0 的示例? 如果将字符加载到寄存器中,则可以将其与 0 进行比较。如果不是,则需要 cmp 的内存操作数。顺便说一句,cmp rbx,0 将指针与 NULL 进行比较是正确的;在将指针环绕到 0 之前,您会点击一个未映射的页面。 你明白cmp byte [rbx], 0是什么意思吗?应该有很多教程来解释寻址模式和内存与寄存器,例如找到链接自***.com/tags/x86/info 的教程或指南并阅读。这也应该清楚为什么cmp [bl], 0 甚至不能汇编(x86 不允许 8 位地址),以及为什么即使它可以运行它也不会做你想做的事情。 还有另一种搜索 NUL 终止符的方法:REPNE SCAS。 你不用inc rax,把字符串的开头移到rax中,然后减去你刚刚找到的0-Byte的地址,就可以得到长度了。 【参考方案1】:

要比较地址处的字节,我建议将字节移动到正确大小的寄存器中,然后进行比较。根据您使用的调用约定,但假设字符串的地址在 rdi 中传递,我会建议以下内容。

        .loop:      inc rax                                                         
                    mov bl, [rdi + rax]                                                      
                    cmp bl, byte 0                                               
                    jne .loop                                                       
                    ret 

编辑:意识到您正在尝试确定给定地址处字符串的长度

【讨论】:

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 movs 和 rep stos 有快速字符串微码;不幸的是,条件重复/重复指令在当前的 CPU 中没有。 repne scasb 本身不会分支错误预测,但我认为往往会使前端停滞不前。虽然可能不适用于最初爆发的 uops 覆盖长度的短字符串。

以上是关于汇编:cmp指令和寻址的主要内容,如果未能解决你的问题,请参考以下文章

汇编语言 CMP指令

汇编 - CMP 后的 JZ 指令

《汇编语言(第三版)》cmp指令

Android 逆向x86 汇编 ( cmp 比较指令 | test 比较指令 )

Android 逆向x86 汇编 ( cmp 比较指令 | test 比较指令 )

汇编指令之CMP, TEST指令