该问题与我发布的here相似。我试图在c/c++
中编写以下程序的汇编版本:
int x[10];
for (int i = 0; i < 10; i++){
x[i] = i;
}
本质上,创建一个存储值1
至9
的数组。
我当前的逻辑是创建一个循环到10
的标签(调用它直到达到最终值)。在标签中,我放置了用于在当前迭代索引处更新数组的指令。但是,在使用gcc filename.s
进行编译并使用./a.out
运行之后,错误Segmentation fault: 11
被打印到控制台。我的代码如下:
.data
x:.fill 10, 4
index:.int 0
end:.int 10
.text
.globl _main
_main:
pushq %rbp
movq %rsp, %rbp
subq $16, %rsp
jmp outer_loop
leave
ret
outer_loop:
movl index(%rip), %eax;
cmpl end(%rip), %eax
jge end_loop
lea x(%rip), %rdi;
mov index(%rip), %rsi;
movl index(%rip), %eax;
movl %eax, (%rdi, %rsi, 4)
incl index(%rip)
jmp outer_loop
leave
ret
end_loop:
leave
ret
奇怪的是下面的代码
lea x(%rip), %rdi;
mov index(%rip), %rsi;
movl index(%rip), %eax;
movl %eax, (%rdi, %rsi, 4)
仅当它不在重复调用的标签中时才起作用。有谁知道如何在不引发Segmentation fault: 11
的情况下循环实现上述代码?我在MacOS上使用x86
语法和GNU GAS
编译的gcc
汇编程序。
请注意,此问题不是this问题的重复,因为正在使用不同的汇编语法,并且问题的范围也不同。
答案 0 :(得分:3)
您使用的是64位指令来访问32位内存区域:
mov index(%rip), %rsi;
这导致%rsi
被分配了从index
到end
结束的内存内容(我假设没有对齐,尽管我不记得GAS关于它的规则)。因此,%rsi
被有效地分配了值0xa00000000
(假设循环的第一次迭代),执行以下movl %eax, (%rdi, %rsi, 4)
会导致CPU尝试访问进程未映射的地址
解决方案是删除分配,然后将其后的行替换为movl index(%rip), %esi
。确保32位操作始终清除64位寄存器的高位,因此您可以安全地在地址计算中使用%rsi
,因为它将包含当前索引,仅此而已。
您的调试器会告诉您这一点,因此请下次使用它。