當前我正在使用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> |
但是,這是相當多了。任何人都可以指出,這是如何安排的,以及這兩個列表(函數調用)如何相關?
您的評論正好指出,我錯過了什麼。因此,$ s0寄存器(幀指針(RISC-V ISA的93頁))將被相對尋址使用,以在函數調用後恢復參數(我嘗試使用基於$ sp的相對尋址,這導致模擬器當我輸入函數的新上下文時,我可以使用$ s0(frame pointer)來恢復所有必要的參數,請原諒我的不確定性,但我顯然沒有完全理解這個概念。) – Kennerd
Since相對於'$ sp'的尋址是有效的,如果你撞毀了模擬器,我想這意味着你搞砸了偏移量。它應該工作。 – Jester