分段错误:11 使用 x86 GNU GAS 程序集在循环中进行数组分配
Segmentation fault: 11 With Array Assignment in Loop Using x86 GNU GAS Assembly
这个问题类似于我发布的另一个问题 。我正在尝试在 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 , %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 问题的重复,因为使用了不同的汇编语法,问题的范围也不同。
您正在使用 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
,因为它将包含当前索引,仅此而已。
你的调试器会告诉你这个,所以请下次使用它。
这个问题类似于我发布的另一个问题 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 , %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 问题的重复,因为使用了不同的汇编语法,问题的范围也不同。
您正在使用 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
,因为它将包含当前索引,仅此而已。
你的调试器会告诉你这个,所以请下次使用它。