2015-12-09 175 views
1

當前我正在使用RISC-V處理器實現。我需要運行部分手工彙編代碼。 (最後會有動態代碼注入。)爲此,我必須瞭解RISC-V彙編中函數調用的基礎知識。RISC-V彙編 - 堆棧佈局 - 函數調用

,我發現這個話題非常有幫助:confusion about function call stack

但我仍然有一個函數調用堆棧佈局掙扎。請考慮以下c代碼:

void some_func(int a, int b, int* c){ 
    int cnt = a; 
    for(;cnt > 0;cnt--){ 
     *c += b; 
    } 
} 

void main(){ 
    int a = 5; 
    int b = 6; 
    int c = 0; 

    some_func(a,b,&c); 
} 

該程序通過一系列加法實現基本乘法。派生的彙編代碼(riscv64未知的小精靈 - GCC -nostartfiles mul.c -o MUL & & riscv64未知的小精靈 - objdump的-D MUL)看起來是這樣的:

0000000000010000 <some_func>: 
    10000: fd010113   addi sp,sp,-48 
    10004: 02813423   sd s0,40(sp) 
    10008: 03010413   addi s0,sp,48 
    1000c: fca42e23   sw a0,-36(s0) 
    10010: fcb42c23   sw a1,-40(s0) 
    10014: fcc43823   sd a2,-48(s0) 
    10018: fdc42783   lw a5,-36(s0) 
    1001c: fef42623   sw a5,-20(s0) 
    10020: 0280006f   j 10048 <some_func+0x48> 
    10024: fd043783   ld a5,-48(s0) 
    10028: 0007a703   lw a4,0(a5) 
    1002c: fd842783   lw a5,-40(s0) 
    10030: 00f7073b   addw a4,a4,a5 
    10034: fd043783   ld a5,-48(s0) 
    10038: 00e7a023   sw a4,0(a5) 
    1003c: fec42783   lw a5,-20(s0) 
    10040: fff7879b   addiw a5,a5,-1 
    10044: fef42623   sw a5,-20(s0) 
    10048: fec42783   lw a5,-20(s0) 
    1004c: fcf04ce3   bgtz a5,10024 <some_func+0x24> 
    10050: 00000013   nop 
    10054: 02813403   ld s0,40(sp) 
    10058: 03010113   addi sp,sp,48 
    1005c: 00008067   ret 

0000000000010060 <main>: 
    10060: fe010113   addi sp,sp,-32 
    10064: 00113c23   sd ra,24(sp) 
    10068: 00813823   sd s0,16(sp) 
    1006c: 02010413   addi s0,sp,32 
    10070: 00500793   li a5,5 
    10074: fef42623   sw a5,-20(s0) 
    10078: 00600793   li a5,6 
    1007c: fef42423   sw a5,-24(s0) 
    10080: fe042223   sw zero,-28(s0) 
    10084: fe440793   addi a5,s0,-28 
    10088: 00078613   mv a2,a5 
    1008c: fe842583   lw a1,-24(s0) 
    10090: fec42503   lw a0,-20(s0) 
    10094: f6dff0ef   jal 10000 <some_func> 
    10098: 00000013   nop 
    1009c: 01813083   ld ra,24(sp) 
    100a0: 01013403   ld s0,16(sp) 
    100a4: 02010113   addi sp,sp,32 
    100a8: 00008067   ret 

的重要步驟,是需要澄清如下:(some_func(INT,INT,INT))

10060: fe010113   addi sp,sp,-32 
    10064: 00113c23   sd ra,24(sp) 
    10068: 00813823   sd s0,16(sp) 
    1006c: 02010413   addi s0,sp,32 

和:(主())

10000: fd010113   addi sp,sp,-48 
    10004: 02813423   sd s0,40(sp) 
    10008: 03010413   addi s0,sp,48 

從我的理解:本stackpointer移到作出換貨政空間地址和參數。 (Main在這裏可能是一個特殊情況。)如何在堆棧中處理傳遞的參數?他們如何獲得回來?總的來說,這個方法對我來說很清楚,但是我將如何手動編碼這個部分才能工作。

關於相關主題,堆棧看起來應該有點像

| ???       | 
| params for some_func() <???> | 
| ra of some_func()    | 
| locals of main()  <int c> | 
| locals of main()  <int b> | 
| locals of main()  <int a> | 
| params for main()  <None> | 

但是,這是相當多了。任何人都可以指出,這是如何安排的,以及這兩個列表(函數調用)如何相關?

回答

1

類型允許的前幾個參數被傳入寄存器,所以它們甚至不出現在堆棧上。除此之外,目前還不清楚你真的想知道什麼。如果你確實得到了堆棧中的一些參數,那麼即使你調整了堆棧指針後,它們仍然停留在那裏,所以你仍然可以根據調整後的堆棧指針或幀指針(這裏顯然是$s0)來解決它們。

的重要步驟,需要澄清的是:

10060: fe010113   addi sp,sp,-32 # allocate space 
    10064: 00113c23   sd ra,24(sp)  # save $ra 
    10068: 00813823   sd s0,16(sp)  # save $s0 
    1006c: 02010413   addi s0,sp,32 # set up $s0 as frame pointer 
+0

您的評論正好指出,我錯過了什麼。因此,$ s0寄存器(幀指針(RISC-V ISA的93頁))將被相對尋址使用,以在函數調用後恢復參數(我嘗試使用基於$ sp的相對尋址,這導致模擬器當我輸入函數的新上下文時,我可以使用$ s0(frame pointer)來恢復所有必要的參數,請原諒我的不確定性,但我顯然沒有完全理解這個概念。) – Kennerd

+0

Since相對於'$ sp'的尋址是有效的,如果你撞毀了模擬器,我想這意味着你搞砸了偏移量。它應該工作。 – Jester