ARM 汇编程序的异常行为

Unusual behavior of ARM assembly program

我一直在为简单的表达式编写 JIT ARM 编译器。我的即时编译器获得了将在表达式和表达式本身中使用的函数和变量的地址。并生成计算表达式的 ARM 代码。

这是我的编译器对表达式 inc(1) + 1:

的输出
start:
    push    {r4}        //saving r4
 
    ldr     r0, [pc]    //writing the constant into r0
    b       skip0       //skipping data line
    .word   0x1
 
skip0:
    push    {r0}        //saving the constant
 
 
    pop     {r0}        //fucntion time. Let's pop the argument
    ldr     r4, [pc]    //Let's get function address
    b       skip1       //skipping data line
    .word   0x13050
 
skip1:
    bx      r4          //jumping to function
    push    {r0}        //saving the output of it
 
 
    ldr     r0, [pc]    //writing the constant into r0
    b       skip2       //skipping data line
    .word   0x1
 
skip2:
    push    {r0}        //saving the constant
    pop     {r0-r1}     //getting function result and the constant

    add     r0, r1, r0  //adding them to each other
    push    {r0}        //saving the result
 
    pop     {r0}        //work done, popping the result to r0 in order to return it
    pop     {r4}        //placing r4 back
    bx      lr

inc(x) 是一个外部函数,只是 returns ++x0x13050是函数执行时的地址。

问题是 - 输出是 2,但它必须是 3。我找不到错误,你能帮我吗?

有趣的事实:如果我将 bx 更改为 blx,我会遇到段错误

答案在最后一行:blx 覆盖 lr
并且由于您在开始时没有保留 lr,所以最后的 bx lr 会导致分支回到 blx r4 之后的行 push {r0},从而导致无限循环。
而且由于每次迭代弹出的次数比推送的次数多,堆栈指针有时会指向无效地址 => segfault

使用 bx r4 时,子函数 inc(x) 不会 return 您的函数,而是 return 值 2 的调用函数以及不正确的堆栈指针。

start:
    push    {r4, lr}        //saving r4 AND lr
 
    ldr     r0, [pc]    //writing the constant into r0
    b       skip0       //skipping data line
    .word   0x1
 
skip0:
    push    {r0}        //saving the constant
 
 
    pop     {r0}        //fucntion time. Let's pop the argument
    ldr     r4, [pc]    //Let's get function address
    b       skip1       //skipping data line
    .word   0x13050
 
skip1:
    blx      r4          //jumping to function
    push    {r0}        //saving the output of it
 
 
    ldr     r0, [pc]    //writing the constant into r0
    b       skip2       //skipping data line
    .word   0x1
 
skip2:
    push    {r0}        //saving the constant
    pop     {r0-r1}     //getting function result and the constant

    add     r0, r1, r0  //adding them to each other
    push    {r0}        //saving the result
 
    pop     {r0}        //work done, popping the result to r0 in order to return it
    pop     {r4, pc}        //placing r4 back AND return