鴻蒙內核源碼分析(匯編傳參篇) | 如何傳遞復雜的參數

匯編如何傳復雜的參數?

匯編基礎篇 中很詳細的介紹了一段具有代表性很經典的匯編代碼,有循環,有判斷,有運算,有多級函數調用。但有一個問題沒有涉及,就是很復雜的參數如何處理?

在實際開發過程中函數參數往往是很復雜的參數,(比如結構體)匯編怎么傳遞呢?

先看一段C語言及匯編代碼,傳遞一個稍微復雜的參數來說明匯編傳參的過程

#include <stdio.h>
#include <math.h>
struct reg{//參數遠超寄存器數量
    int Rn[100]; 
    int pc;
};

int framePoint(reg cpu)
{
    return cpu.Rn[0] * cpu.pc;
}

int main()
{
    reg cpu;
    cpu.Rn[0] = 1;
    cpu.pc = 2;
    return framePoint(cpu);
}


//編譯器: armv7-a gcc (9.2.1)
framePoint(reg):
        sub     sp, sp, #16     @申請棧空間
        str     fp, [sp, #-4]!  @保護main函數棧幀,等同于push {fp}
        add     fp, sp, #0      @fp變成framePoint棧幀,同時也指向了棧頂
        add     ip, fp, #4      @定位到入棧口,讓4個參數依次入棧 
        stm     ip, {r0, r1, r2, r3}@r0-r3入棧保存
        ldr     r3, [fp, #4]    @取值cpu.pc = 2    
        ldr     r2, [fp, #404]  @取值cpu.Rn[0] = 1
        mul     r3, r2, r3      @cpu.Rn[0] * cpu.pc
        mov     r0, r3          @返回值由r0保存
        add     sp, fp, #0      @重置sp,和add     fp, sp, #0配套出現
        ldr     fp, [sp], #4    @恢復main函數棧幀
        add     sp, sp, #16     @歸還棧空間,sp回落到main函數棧頂位置
        bx      lr              @跳回main函數
main:
        push    {fp, lr}        @入棧保存調用函數現場                     
        add     fp, sp, #4      @fp指向sp+4,即main棧幀的底部
        sub     sp, sp, #800    @分配800個線性地址,即main棧幀的頂部
        mov     r3, #1          @r3 = 1
        str     r3, [fp, #-408] @將1放置 fp-408處,即:cpu.Rn[0]處
        mov     r3, #2          @r3 = 2
        str     r3, [fp, #-8]   @將2放置 fp-8處,即:cpu.pc
        mov     r0, sp          @r0 = sp
        sub     r3, fp, #392    @r3 = fp - 392
        mov     r2, #388        @只拷貝388,剩下4個由寄存器傳參
        mov     r1, r3          @保存由r1保存r3,用于memcpy
        bl      memcpy          @拷貝結構體部分內容,將r1的內容拷貝r2的數量到r0
        sub     r3, fp, #408    @定位到結構體剩余未拷貝處
        ldm     r3, {r0, r1, r2, r3} @將剩余結構體內容通過寄存器傳參
        bl      framePoint(reg)         @執行framePoint
        mov     r3, r0          @返回值給r3
        nop @用于程序指令的對齊
        mov     r0, r3          @再將返回值給r0
        sub     sp, fp, #4      @恢復SP值
        pop     {fp, lr}        @出棧恢復調用函數現場
        bx      lr              @跳回調用函數

兩個函數對應兩段匯編,干凈利落,去除中間各項干擾,只有一個結構體reg,以下詳細講解如何傳遞它,以及它在棧中的數據變化是怎樣的?

入參方式

結構體總共101個棧空間(一個棧空間單位四個字節),對應就是404個線性地址.
main上來就申請了 sub sp, sp, #800 @申請800個線性地址給main,即 200個棧空間

int main()
{
    reg cpu;
    cpu.Rn[0] = 1;
    cpu.pc = 2;
    return framePoint(cpu);
}

但main函數只有一個變量,只需101個棧空間,其他都算上也用不了200個.為什么要這么做呢?

而且注意下里面的數字 388, 408, 392 這些都是什么意思?

看完main匯編能得到一個結論是 200個棧空間中除了存放了main函數本身的變量外 ,還存放了要傳遞給framePoint函數的部分參數值,存放了多少個?答案是 388/4 = 97個. 注意變量沒有共用,而是拷貝了一部份出來.如何拷貝的?繼續看

memcpy匯編調用

        mov     r0, sp          @r0 = sp
        sub     r3, fp, #392    @r3 = fp - 392
        mov     r2, #388        @只拷貝388,剩下4個由寄存器傳參
        mov     r1, r3          @保存由r1保存r3,用于memcpy
        bl      memcpy          @拷貝結構體部分內容,將r1的內容拷貝r2的數量到r0
        sub     r3, fp, #408    @定位到結構體剩余未拷貝處
        ldm     r3, {r0, r1, r2, r3} @將剩余結構體內容通過寄存器傳參

看這段匯編拷貝,意思是從r1開始位置拷貝r2數量的數據到r0的位置,注意只拷貝了 388個,也就是 388/4 = 97個棧空間.剩余的4個通過寄存器傳的參數.ldm代表從fp-408的位置將內存地址的值連續的給r0 - r3寄存器,即位置(fp-396,fp-400,fp-404,fp-408)的值.

執行下來的結果就是

r3 = fp-408, r2 = fp-404 ,r1 = fp-400 ,r0 = fp-396 得到虛擬地址的值,這些值整好是memcpy沒有拷貝到變量剩余的值

逐句分析 framePoint

framePoint(reg):
        sub     sp, sp, #16     @申請棧空間
        str     fp, [sp, #-4]!  @保護main函數棧幀,等同于push {fp}
        add     fp, sp, #0      @fp變成framePoint棧幀,同時也指向了棧頂
        add     ip, fp, #4      @定位到入棧口,讓4個參數依次入棧 
        stm     ip, {r0, r1, r2, r3}@r0-r3入棧保存
        ldr     r3, [fp, #4]    @取值cpu.pc = 2    
        ldr     r2, [fp, #404]  @取值cpu.Rn[0] = 1
        mul     r3, r2, r3      @cpu.Rn[0] * cpu.pc
        mov     r0, r3          @返回值由r0保存
        add     sp, fp, #0      @重置sp,和add     fp, sp, #0配套出現
        ldr     fp, [sp], #4    @恢復main函數棧幀
        add     sp, sp, #16     @歸還棧空間,sp回落到main函數棧頂位置
        bx      lr              @跳回main函數

framePoint申請了4個棧空間目的是用來存放四個寄存器值的,以上匯編代碼逐句分析.

第一句: sub     sp, sp, #16     @申請棧空間,用來存放r0-r3四個參數

第二句: str     fp, [sp, #-4]!  @保護main的fp,等同于push {fp},為什么這里要把main函數的fp放到 [sp, #-4]! 位置,注意 !號,表示SP的位置要變動,因為這里必須要保證參數的連續性.

第三句: add     fp, sp, #0      @指定framePoint的棧幀位置,同時指向了棧頂 SP

第四句: add     ip, fp, #4      @很關鍵,用了ip寄存器,因為此時 fp sp 都已經確定了,但別忘了 r0 - r3 還沒有入棧呢.從哪個位置入棧呢, fp+4位置,因為 main函數的棧幀已經入棧了,在已經fp的位置.中間隔了四個空位,就是給 r0-r3留的.

第五句: stm     ip, {r0, r1, r2, r3}@r0-r3入棧,填滿了剩下的四個空位.

第六句: ldr     r3, [fp, #4]    @取的就是cpu.pc = 2的值,因為上一句就是從這里依次入棧的,最后一個當然就是cpu.pc了.

第七句: ldr     r2, [fp, #404]  @取值cpu.Rn[0] = 1,其實這一句已經是跳到了main函數的棧幀取值了,所以看明白了沒有,并不是在傳統意義上理解的在framePoint的棧幀中取值.

第八句: mul     r3, r2, r3      @cpu.Rn[0] * cpu.pc 做乘法運算

第九句: mov     r0, r3          @返回值r0保存運算結構, 目的是return

第十句: add sp, fp, #0          @重置sp,其實這一句可以優化掉,因為此時sp = fp

第十一句: ldr     fp, [sp], #4  @恢復fp,等同于pop {fp},因為函數運行完了,需要回到main函數了,所以要拿到main的棧幀

第十二句: add     sp, sp, #16   @歸還棧空間,等于把四個入參抹掉了.

最后一句: bx      lr            @跳回main函數,如此 fp 和 lr 寄存器中保存的都是 main函數的信息,就可以安全著陸了.

總結

因為寄存器數量有限,所以只能通過這種方式來傳遞大的參數,想想也只能在main函數棧中保存大部分參數,同時又必須確保數據的連續性,好像也只能用這種辦法了,一部分通過寄存器傳,一部分通過拷貝的方式倒是挺有意思的.

寫在最后

  • 如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:
  • 點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力。
  • 關注小編,同時可以期待后續文章ing??,不定期分享原創知識。
  • 想要獲取更多完整鴻蒙最新學習知識點,請移步前往小編:https://gitee.com/MNxiaona/733GH/blob/master/jianshu
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容