C语言 由 CMP 引起的分段故障



我目前正在尝试学习汇编语言。但我被困住了。 假设我有这个 C 代码:

for ( int i = 100; i > 0; i-- ) {
// Some code
}

现在我想在汇编语言中做同样的事情。我是这样试过的:

__asm__ ("movq $100, %rax;"
".loop:"
//Some code
"decq %rax;"
"cmpq $0, (%rax);"
"jnz .loop;"
);

编译和运行会导致 seg 错误。如果我删除cmpq线,它不会出错。但是,该程序当然不会终止。

所以基本上我的问题是我在这里做错了什么?

cmpq $0, (%rax)

此指令将尝试读取rax中的地址的内存。

rax第一次将是99岁。地址 99 未映射,因此程序出现段错误。

您打算将rax中的值与 0 进行比较,因此请删除括号。

cmpq $0, %rax

以下说明:

cmpq $0, (%rax)

正在访问rax寄存器指定的内存地址,其值为99

映射第一个内存页。该内存地址99属于第一个内存页。因此,上述访问会导致分段错误。


您不想要间接寻址,而是想要:

cmpq $0, %rax

也就是说,您要与rax的内容进行比较,而不是rax指定的内存地址处的内容进行比较。


但是,请考虑优化cmp指令:

decq %rax紧挨着cmp $0, %rax指令的前面,如果rax为零,则设置ZF。然后根据ZF标志的状态执行条件跳转:

decq %rax
cmpq $0, %rax
jnz .loop

dec指令会影响ZF标志(就像cmp一样),因此如果递减rax导致零,则将设置ZF。您可以利用这一事实并直接jnz放在dec之后。你根本不需要cmp

decq %rax
jnz .loop

从 %rax 中删除括号以获取 rax 的值。添加括号基本上告诉汇编程序,"嘿!RAX持有一个地址,请归还该地址中的内容"。

因此

cmpq $0, %rax

是你需要做的。

相关内容

  • 没有找到相关文章

最新更新