LDR X10处的分段故障,[X9,#0]



我曾尝试编写一个ARM-LEGv8汇编程序,用于计算数组中某个位置的两个值的平均值。它运行在树莓派与亚美尼亚。

伪代码应该是这样的:

int average(int v[], int i){
int average = (v[i] + v[i-1])/2;
return average;
}

数组位于X0,i位于X1。

我的汇编代码如下:

.globl _start
.data
myArray: .word 0, 1, 2, 3, 35, 5
.text

average:
LSL X9, X1, #2
ADD X9, X9, X0
LDR X10, [X9, #0] // guess Segmentation Fault 
LDUR X11, [X9, #-4]
ADD X3, X10, X11  
LSR X3, X3, #1 
BR X30
_start:
LDR X0, myArray
MOV X1, #5
BL mittelwert

MOV X8, #0x5d
MOV X0, X3
SVC 0

我用这些命令来构建它:

as average.s -o average.o

gcc average.o -o average -nostdlib -static

当我运行我的程序时,我会遇到分段故障。为什么?

(免责声明:以下内容基于实际的ARMv8-A指令集。我不确定LEGv8可能做了什么更改。(

CCD_ 3不加载具有标签CCD_ 5的地址的CCD_。它从该地址的加载一个双字(ARM称之为加载指令的"文字"形式(。因此,在该指令之后,X0包含0x0000000100000000,这自然会在执行LDR X10, [X9, #0]时导致一个无效指针。

您可能指的是LDR X0, =myArray,它将把指向myArray的指针放入文字池,然后从该指针在池中的地址组装该指针的文字负载。假设您的系统能够处理这种类型的重新定位,这将起作用。然而,对于普通操作系统使用的现代位置无关的可执行程序,首选方法是

ADR X0, myArray
ADD X0, X0, #:lo12:myArray

第一条指令使用来自PC的偏移量,用myArray地址的那些位填充X0的高52位。第二条指令加上低12位。另请参阅了解ARM重新定位(例如:str x0,[tmp,#:lo12:zbi_paddr](


其他几个错误和备注:

  • 您的LDR X10, [X9, #0]LDUR X11, [X9, #-4]是64位加载,因为您使用了X寄存器作为目标。但myArray的元素是用32位的.word定义的。因此,每个寄存器的高32位将包含垃圾,或者如果负载超出数组的末尾而扩展到未映射的页面,则它们可能会崩溃。为了与32位元素保持一致,请将它们加载到W寄存器LDR W10, [X9, #0]LDUR W11, [X9, #-4]中,然后在W寄存器上进行运算。

  • 您认为您的数组元素是类型int,它是有符号的,但您的代码目前无法正确处理负值(提示:LSR中的L是什么?(。考虑如何解决此问题,或者将其更改为unsigned

  • 同样,i在C中被声明为int,但您访问X1时将其作为64位寄存器。如果您从C调用此函数,ARM64ABI将允许X1的高位成为垃圾。您可能希望将其声明为size_tunsigned long。如果您确实将其保留为32位类型,那么很可能unsigned就是您想要的,然后您需要在使用它之前将W1零扩展到LDR X0, myArray0

  • 从函数返回时,更喜欢RET而不是BR X30,因为前者更适合用于此目的。(尽管LEGv8可能没有RET?(

最新更新