从C到ARM汇编的转换——不断出现分段错误,与ldr和str混淆



我是ARM汇编的新手,正在尝试将一些简单的代码片段从C转换为汇编。我不确定我是否正确地使用了ldr和str(尽管我觉得我尝试了所有的东西(,当我尝试运行它时,我总是遇到seg错误。

C代码是

int main() {
int x = 10;
int y = 5;
int z = 20;
int min = y;
if (x < min) {min = x;}
if (z < min) {min = z;}
return min;
}

我的组装代码:

.global main
.text
main:
push {ip, lr}
mov r0, #10
mov r1, #5
mov r2, #20
str r3, [r1]
cmp r0, r3
bge done
str r0, [r3]
cmp r2, r3
bge done
str r2, [r3]
done:
ldr r0, [r3]
pop {ip, pc}

好的,对于每个变量,您必须决定将其存储在哪里:

  • 您可以将其存储在寄存器中,只要您有足够的备用寄存器,就可以
  • 您可以将它存储在一个固定的地址,这对于全局和静态变量来说很好,但对于局部变量来说不好
  • 您可以将其存储在堆栈中,如果没有足够的寄存器进行循环,则通常会在堆栈中存储局部变量。这是更多的工作,因为每次您想访问它时都必须加载并存储它

您的功能正在灾难性地混淆这些。将x,y,z存储在寄存器r0,r1,r2中,但随后将y视为存储在地址5中,而实际上它存储在寄存器r1中。您不想在这里使用内存访问指令str r3, [r1],因为内存中没有任何内容;仅仅CCD_ 7就足够了。

代码的其余部分也同样功能失调,但我不会详细介绍。你的函数很简单,有足够多的寄存器可以循环使用,所以我建议你重写它,为所有变量使用寄存器。根本没有ldr/str指令,只有mov指令。

查看C编译器生成的汇编代码,了解一些或所有变量必须存储在堆栈上的更复杂的情况。

祝你好运!

C代码是

int main() {
int x = 10;
int y = 5;
int z = 20;
int min = y;
if (x < min) {min = x;}
if (z < min) {min = z;}
return min;
}

不要使用ldrstr,因为它们将寄存器值存储到内存中。例如,str rX, [rY]表示使用'rY'的值作为存储'rX'值的内存地址。当您有许多可用的寄存器时,不需要使用内存。例如,

mov   r0, #5    ; min = y = #5
mov   r1, #10   ; x = 10
mov   r2, #20   ; z = 20
cmp   r1, r0    ; if (x < min)
movlt r0, r1    ;  min = x
cmp   r2, r0    ; if (z < min)
movlt r0, r2    ;  min = z
mov   pc, lr    ; return min (is r0)

如果未完成,则为关闭。请查看我的寄存器使用情况,因为有些寄存器可能被调换了。你也可以考虑是否需要签名或未签名。您原来使用的是bge done,如果"x>y>z",它将不起作用。您需要根据"C"代码使用"小于"。

对于像这样非常简单的代码,我建议不要使用编译器开头。如果你有很多变量,那么从编译器开始。尝试某个操作后,看看编译器会做什么。在某些情况下,您可能比编译器有更好的结构思想;可能不是这样的数值问题。如果你马上去编译器那里,就很难想到对函数编码的其他攻击。通常,你最初的尝试和编译器的想法会结合在一起,得到一些非常好的东西。

TonyK的回答很好地涵盖了错误的来源。我突然想到,看看编译器如何处理这样一个简单程序的编译可能会对您有益;看到编译器在堆栈上为这些变量分配空间,以及它如何正确使用LDRSTR,可以很好地帮助您学习。

如果您使用的是gcc,请尝试将-S -O1添加到编译器选项中,以启用轻度优化(-O1(并请求汇编语言作为输出(-S(。输出将把原始的C代码交织到生成的汇编语言中,这有望使其更容易理解。

最新更新