我试着编写了一个ARM-LEGv8 8汇编程序,它计算数组中某一位置上两个值的平均值。它运行在一个覆盆子派与阿姆斯特朗。
伪代码应该如下所示:
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
当我运行我的程序时,我会得到一个分段错误。为什么?
发布于 2022-08-09 01:49:11
(免责声明:以下是基于实际的ARMv8 8-A指令集.)我不知道LEGv8可能做了什么改变。)
LDR X0, myArray不使用标签myArray的地址加载X0。它从该地址加载一个双字(ARM称其为load指令的“文字”形式)。因此,在此指令之后,X0包含0x0000000100000000,这自然会在执行LDR X10, [X9, #0]时导致无效指针。
您可能是指LDR X0, =myArray,它会将指向myArray的指针放置到文字池中,然后从池中的地址组装该指针的文字加载。如果您的系统能够处理这种类型的重新定位,这将是可行的。然而,对于公共操作系统使用的与位置无关的现代可执行文件,首选的方法是
ADR X0, myArray
ADD X0, X0, #:lo12:myArray第一条指令使用来自PC的偏移量,将X0的高52位与myArray地址的这些位进行填充。第二位加低12位。另见Understanding ARM relocation (example: str x0, [tmp, #:lo12:zbi_paddr])
还有其他一些缺陷和评论:
LDR X10, [X9, #0]和LDUR X11, [X9, #-4]是64位负载,因为您使用X寄存器作为目标。而myArray的元素定义为.word,32位。因此,每个寄存器的高32位将包含垃圾,或者如果负载扩展到数组的末尾进入未映射的页面,它们可能会崩溃。为了与32位元素保持一致,将它们加载到W寄存器LDR W10, [X9, #0]和LDUR W11, [X9, #-4]中,然后对W寄存器执行算法。int类型,它被签名了,但是您的代码目前无法正确处理负值(提示:LSR中的L是什么?)。考虑如何修复此问题,或将其更改为unsigned.。
同样,
i声明为int,但您可以将X1作为64位寄存器访问。如果从C调用此函数,则ARM64 ABI允许X1的高比特为垃圾。您可能希望将其声明为size_t或unsigned long。如果您确实将其保持为32位类型,那么很可能unsigned就是您想要的,那么在使用它之前,您需要将W1扩展到X1中。当从函数返回时,
RET而不是BR X30,因为前者为此目的进行了更好的优化。(虽然LEGv8可能没有LEGv8https://stackoverflow.com/questions/73280712
复制相似问题