我目前正在尝试学习汇编语言。但我被困住了。 假设我有这个 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
是你需要做的。