x86-64 汇编中的数组元素比较(AT&T 语法)

Posted

技术标签:

【中文标题】x86-64 汇编中的数组元素比较(AT&T 语法)【英文标题】:Array element comparison in x86-64 Assembly (AT&T syntax) 【发布时间】:2016-05-04 04:25:43 【问题描述】:

我正在尝试在 x86-64 程序集中编写一个简单的过程,它只返回整数数组的长度。数组中的最后一个元素是 0,不应计算在内。数组作为 int * 从 C 代码传入。

我的汇编代码如下:

f1:
    movq $0, %rax   # zero out %rax
    jmp   test      # jump to test
body:
    incq  %rax      # increment %rax, which is counter and array index

test:
    cmpq   $0, (%rdi,%rax,4)  # compare (rdi + (rax * 4)) to 0
    jne    body   # jump if zero flag is not set
ret

当它运行时,我得到一个不正确的结果,但也不是完全不正确,所以不是 11(传递的数组大小减去结尾 0)我得到 38。我认为正在发生的是我的比较语句是不正确。我的想法是,由于 cmpq 在不更改寄存器的情况下执行 (dest - src),如果数组索引为 0,则 0-0 将产生零,因此将设置零标志,但这似乎没有发生。

我可以任意将数组的任意元素加载到%rax中,返回正确的值:

movq   (%rdi,%rax,4), %rax   # %rax initially 0, so first element loaded into %rax

任何帮助将不胜感激!

【问题讨论】:

做得很好,让你的代码非常简短,只是没有做你认为应该做的部分。为了解释你认为应该发生的事情,所以很容易解释那个具体的事情。 【参考方案1】:

int 在 x86-64 ABI(SystemV 和 Windows)中都是 32 位(4 字节)。 (有关详细信息,请参阅x86 标签 wiki)。

cmpq $0, (%rdi,%rax,4) 正确地将索引缩放 4,但错误地使用了 64 位操作数大小。 (q 代表四字。在英特尔的 x86 术语中,“字”是 16 位。)

cmpq 正在比较两个连续的元素。等效的 C 为 while( 0 != *(int64_t*)&(array[i]) ) ++i;


在 x86 之外,一个字通常是机器的寄存器大小或类似的东西,因此它与 long 的大小匹配。例如一个词在 32 位 MIPS 上是 32 位。

这只是术语,使用方便的名称很方便,例如 word(AT&T 语法 w 后缀)、dword(l 后缀)、qword(q 后缀)。

gdb 中,即使在调试 x86 时,在某些地方“字”也是 32 位(例如,用于转储内存的 x 命令有 b(字节)、h(半字:16b)、@987654335 @ (word) 和 g (giant: 8B) 大小格式说明符。

【讨论】:

非常感谢您,以及额外的琐事。我将指令更改为“cmpl”并返回正确的值,但我不确定我是否理解原因。操作数大小是否影响偏移量的缩放值? @joezuu:不,你的地址总是正确的。用cmpq 的实际操作更新了答案。

以上是关于x86-64 汇编中的数组元素比较(AT&T 语法)的主要内容,如果未能解决你的问题,请参考以下文章

AT&T汇编学习笔记

如何对 AT&T 语法中的标签进行相对 jmp?

X.86 X64 汇编器中的正确堆栈操作

x86-64 汇编器中的无限循环

x86-64的条件跳转如何工作?

如何在 x86-64 汇编中使用堆栈?