第15部分- Linux ARM汇编 ARM32函数调用

第15部分- Linux ARM汇编 ARM32函数调用

函数调用需要遵循函数调用个规则,否则调用之后就无法再回来了。

ARM的规则是:

Procedure Call Standard for the ARM Architecture

简称就是AAPCS了。

32位函数传递

特殊的寄存器,在32位中r15是pc寄存器。

此外,还有r14是lr, r13是sp寄存器。

lr表示link register,调用指令之后的指令地址(我们将在后面看到这是什么)。

sp是堆栈寄存器。

函数的前4个参数通过r0,r1,r2,r3顺序传递。超过4个参数后就会使用堆栈。这个其实就是个约定。可以不遵守但是这样话就会失去通用性了。

函数调用的共识

  • 函数不对cpsr的内容进行任何假设。条件代码N,Z,C和V是未知的。
  • 函数可以自由修改寄存器r0,r1,r2和r3。
  • 函数不能在r0,r1,r2和r3的内容上假设任何内容,除非它们扮演参数的角色。
  • 一个函数可以自由修改lr,但是在离开该函数时将需要输入该函数时的值(因此,该值必须保留在某处)。
  • 一个函数可以修改所有剩余的寄存器,只要它们的值在离开函数时就被恢复即可。 这包括sp和寄存器r4至r11。

所以调用函数后,(仅)寄存器r0,r1,r2,r3和lr被覆盖。

R0寄存器用来存放函数调用的返回值。被调用的函数在返回前无需恢复这些寄存器的内容。

 

调用函数

调用函数有两种方法。 如果函数是静态已知的,该标签是.text部分中定义的标签。可直接(或立即)进行调用。另外,可将函数的地址先存储到寄存器中,然后使用blx Rsource1。

在这两种情况下,行为都如下:函数的地址(在bl中立即编码或使用blx中的寄存器值)存储在pc中。 bl或blx指令之后的指令地址保存在lr中。

 

离开函数

lr的初始值保持在某个位置。

离开函数时,检索该值并将其放入某个寄存器(可以再次使用lr)。 然后将bx Rsource1(也可以使用blx)。

 

返回值

函数使用r0来存储不超过32位的数据。C类型的char,short,int,long(和float类型)将在r0中返回。 对于64位的基本类型,例如long long和double类型的C类型,它们将在r1和r0中返回。 除非它是32位或更少,否则所有其他数据都将通过堆栈返回,并在r0中返回。

 

Hello World示例

只能说来晚了。通常编程语言的第一个才是这个。

.data
 
greeting:
 .asciz "Hello world"

.balign 4
return: .word 0
 
.text
.global main
main:
    ldr r1, address_of_return     /*   r1 ← &address_of_return */
    str lr, [r1]                  /*   *r1 ← lr ,保存lr*/
 
    ldr r0, address_of_greeting   /* r0 ← &address_of_greeting */
                                  /* First parameter of puts */
    bl puts                       /* Call to puts */
                                  /* lr ← address of next instruction */
 
    ldr r1, address_of_return     /* r1 ← &address_of_return */
    ldr lr, [r1]                  /* lr ← *r1 */
    bx lr                         /* return from main */
address_of_greeting: .word greeting
address_of_return: .word return
 
/* External */
.global puts

as -g -o hello.o hello.s

gcc -o hello hello.o


版权声明:本文为notbaron原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。