天天看點

ARM學習(17)ARM函數調用規則

筆者來聊聊ARM的函數的調用規則

1、ARM函數調用規則介紹

首先介紹幾個術語,

  • AAPCS:Procedure Call Standard for the ARM Architecture
  • APCS:ARM Procedure Call Standard
  • TPCS:Thumb Procedure Call Standard
  • ATPCS:ARM-Thumb Procedure Call Standard
  • ABI:Application Binary Interface
  • EABI:Embedded Application Binary Interface

前三個基本就是ARM 架構的程式調用标準(包括ARM指令以及thumb指令),最後兩個是程式二進制接口,描述是彙編下面寄存器名使用、函數調用、壓棧、參數傳遞以及程式傳回等一系列接口标準。

比如x86與arm架構的ABI 就不相容,寄存器都不一樣,肯定就是無法互相使用,包括最近比較火熱的RISC-V架構。

2、ARM32/64 函數調用規則

ARM架構下面分為32位以及64位的程式,其标準有些不同以及擴充,可分開來講。

2.1、ARM

  • 機器寄存器

    對于ARM以及thumb指令集來說,總有16個寄存器使用,不管大小寫,在彙編語言裡面都是可以識别的,一般來說大寫的有特殊用途,詳情見下文。

    • R0-R3 作為函數參數傳遞以及傳回值使用,也可以在程式中儲存立即數。
    • R12 (IP)連結器使用的暫存器
    • R9 平台寄存器,ARM不推薦使用,避免平台依賴
    • R4-R8,R10,R11 暫存器
    • R11 作為棧指針,指向程式調用中開辟空間的棧底,可用來棧回溯,具體可以參考ARMARM學習(1) 寄存器的了解 ===》FP、SP、LR寄存器。
    • R13 SP 棧指針
    • R14 LR 連結寄存器
    • R15 PC 程式計數器
    • CPSR 狀态寄存器 詳情介紹見ARM學習(2) 寄存器的了解 ===》通用寄存器及狀态寄存器。
    • cp15 協處理 監控通用寄存器的使用
      ARM學習(17)ARM函數調用規則
  • 程式處理、記憶體以及棧

    一個程式的記憶體通常會劃分為幾部分:Code、read-only static data、writeable static data、heap and stack,Code段裡面會包括read-only static data,DATA段會包括初始化好的全局變量,BSS包括堆棧以及未初始化和初始化為0的全局變量

    • stack 臨時存儲變量以及傳遞額外的參數(程式調用時寄存器數量不足),
    • 棧有範圍限制,Limit < SP < Base
    • 其次必須4 byte對齊,
    • 程式必須通路棧的部分範圍内區域(SP ,base-1),不能通路之外的區域,
      ARM學習(17)ARM函數調用規則
  • 子程式調用
    • BL指令會跳到目标程式,并且修改LR為目前PC的按順序下一條指令位址,指的是沒跳轉之前的PC的下一條。
    • 需要注意修改LR最低位表示目前為什麼狀态,,0:是arm狀态,無需修改(因為位址都是word 2Byte對齊的),1:是thumb狀态,需要修改,
      ARM學習(17)ARM函數調用規則
      可以看到R14以及PC的值都是奇數,代表是thumb指令。
      ARM學習(17)ARM函數調用規則
      ARM學習(17)ARM函數調用規則

      R15(PC):0x0801247E 位于 DMA_GetFlagStatus,

      R14:0x08014ECB 位于 UART1_SentMsgL,儲存了其傳回的位址。

  • 傳回值
    • R0:傳回值是D-Word(32 bit),或者是單精度浮點型float,
    • R0-R1:傳回值是Q-Word(64 bit),或者雙精度浮點型double
    • R0-R3:傳回值是128bit的向量
      ARM學習(17)ARM函數調用規則
      調用GetSysTime之後,r0則擷取到值,然後r1計算好之後,則cmp進行比較r0,r1.
  • 參數傳遞
    • R0-R3 和棧進行傳遞
    • 參數少的函數,隻用寄存器就可以了,減少通路記憶體帶來的負載
    • 優先寄存器,然後棧,寄存器從小到大,棧位址從小到大。

      1、函數聲明:void OLED_DrawBMP_test(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[],unsigned char state1,unsigned char state2);

      2、共用7個參數:x0,y0,x1,y1,BMP[],state1,state2

      3、前四個參數都分别存儲在r0-r3,

      4、後面三個參數存儲在棧中,strd r7,r6,[r13] 以及str r6,[r13,#0x8] ,前面指令存儲r7 r6 兩個參數,後面位址偏移8之後,又存儲一個參數,總計三個參數,存儲順序依次都是參數從左向右去存儲。

      5、不符合__cdecl、__stdcall、__fastcall這三種調用标準。

      ARM學習(17)ARM函數調用規則
  • 内部聯合工作(ARM與Thumb指令)
    • 子程式調用和程式傳回支援兩張狀态切換。bx或者blx都可以切換狀态。

2.2、ARM64

參考文檔

1、ARM Procedure Call Standard

2、Procedure Call Standard for the ARM 64-bit Architecture (AArch64)