使用PUSH {lr}和POP {pc}从ARM中的main / _start函数返回

时间:2019-04-13 08:40:06

标签: assembly arm

我试图了解如何从ARM中的基本程序中正确退出,并且我已经看到很多代码使用PUSH {lr}保存调用函数的返回地址(假设调用者使用了BL将寄信人地址保存在lr中,以便以后检索它并使用POP {pc}跳转到寄信人地址。在这些情况下,lr寄存器被BL更改了,因此我可以使用它来处理main / _start函数中的子例程,但是使用下面的代码将值压入堆栈将只是0x0 ,导致退货时出错。

    .text
    .global main

    main:
            PUSH {lr}  
            MOV r0, #42 
            POP {pc}
    .end

我运行了很多外部代码,它们使用此确切方法从主函数中返回而没有Segmentation Fault,但是当我尝试使用gdb调试器运行此基本程序时,很明显{ {1}}在main的第一行中保持为零,从而在返回时产生错误。本质上,我的问题是在将lr推入主函数中的堆栈时如何获取正确的值。

我用过

lr

编译可执行文件。

编辑:我发现使用

     $ as -g ex.s -o ex && ld -e main ex.o -o ex

链接该程序部分地回答了我的问题,看着gdb的输出,我发现 $ gcc ex.o -o ex 似乎用正确的值初始化gcc,从而使示例程序正常退出。但是,我仍然想像以前一样使用lr时是否有一种获取此地址的方法。

1 个答案:

答案 0 :(得分:4)

ELF入口点不是功能,没有用户空间调用者可以返回,并且任何地方都没有返回地址。您所获得的只是指向argc的堆栈指针,然后指向argv[]数组(不是指向它的指针),然后是env[]

您需要进行sys_exit系统调用(例如libc _exit(2)函数)。


ld -e main ex.o -o ex链接将创建一个静态可执行文件,并以main作为ELF入口点。从默认的_start更改名称不会对您有任何帮助,只会让所有人感到困惑。我不推荐。