1. 程式人生 > >彙編呼叫c函式為什麼要設定棧

彙編呼叫c函式為什麼要設定棧

4.舉例分析C語言函式呼叫是如何使用棧的
對於上面的解釋的棧的作用顯得有些抽象,此處再用例子來簡單說明一下,就容易明白了:用:arm-inux-objdump–d u-boot >dump_u-boot.txt可以得到dump_u-boot.txt檔案。該檔案就是中,包含了u-boot中的程式的可執行的彙編程式碼,其中我們可以看到C語言的函式的原始碼,到底對應著那些彙編程式碼。
下面貼出兩個函式的彙編程式碼,一個是clock_init,另一個是與clock_init在同一C原始檔中的,另外一個函式CopyCode2Ram:
33d0091c<CopyCode2Ram>:
33d0091c:  e92d4070  push   {r4, r5, r6, lr}
33d00920:  e1a06000  mov r6, r0
33d00924:  e1a05001  mov r5, r1
33d00928:  e1a04002  mov r4, r2
33d0092c:  ebffffef  bl  33d008f0 <bBootFrmNORFlash>
......
33d00984:  ebffff14  bl  33d005dc <nand_read_ll>
......
33d009a8:  e3a00000  mov r0, #0 ; 0x0
33d009ac:  e8bd8070  pop {r4, r5, r6, pc}
33d009b0<clock_init>:
33d009b0:  e3a02313  mov r2, #1275068416   ;0x4c000000
33d009b4:  e3a03005  mov r3, #5 ; 0x5
33d009b8:  e5823014  str r3,
......
33d009f8:  e1a0f00e  mov pc, lr
(1)clock_init部分的程式碼可以看到該函式第一行:33d009b0:  e3a02313  mov r2, #1275068416   ;0x4c000000就沒有我們所期望的push指令,沒有去將一些暫存器的值放到棧中。這是因為,我們clock_init這部分的內容,所用到的r2,r3等等暫存器,和前面呼叫clock_init之前所用到的暫存器r0,沒有衝突,所以此處可以不用push去儲存這類暫存器的值,不過有個暫存器要注意,那就是r14,即lr,其是在前面呼叫clock_init的時候,用的是bl指令,所以會自動把跳轉時候的pc的值賦值給lr,所以也不需要push指令去將PC的值儲存到棧中。而clock_init的程式碼的最後一行:33d009f8:e1a0f00e mov pc, lr就是我們常見的movpc,lr,把lr的值,即之前儲存的函式呼叫時候的PC值,賦值給現在的PC,這樣就實現了函式的正確的返回,即返回到了函式呼叫時候下一個指令的位置。這樣CPU就可以繼續執行原先函式內剩下那部分的程式碼了。
(2)CopyCode2Ram部分的程式碼其第一行:33d0091c:e92d4070 push {r4, r5, r6, lr}就是我們所期望的,用push指令,儲存了r4,r5,r以及lr。用push去儲存r4,r5,r6,那是因為所謂的儲存現場,以後後續函式返回時候再恢復現場,而用push去儲存lr,那是因為此函式裡面,還有其他函式呼叫:33d0092c:  ebffffef  bl  33d008f0 <bBootFrmNORFlash>
......
33d00984:  ebffff14  bl  33d005dc <nand_read_ll>
......也用到了bl指令,會改變我們最開始進入clock_init時候的lr的值,所以我們要用push也暫時儲存起來。而對應地,CopyCode2Ram的最後一行:33d009ac:e8bd8070 pop {r4, r5, r6,pc}就是把之前push的值,給pop出來,還給對應的暫存器,其中最後一個是將開始push的lr的值,pop出來給賦給PC,因為實現了函式的返回。另外,我們注意到,在CopyCode2Ram的倒數第二行是:33d009a8:e3a00000 mov r0, #0 ;0x0是把0賦值給r0暫存器,這個就是我們所謂返回值的傳遞,是通過r0暫存器的。此處的返回值是0,也對應著C語言的原始碼中的“return0”.
對於使用哪個暫存器來傳遞返回值:當然你也可以用其他暫時空閒沒有用到的暫存器來傳遞返回值,但是這些處理方式,本身是根據ARM的APCS的暫存器的使用的約定而設計的,你最好不要隨便改變使用方式,最好還是按照其約定的來處理,這樣程式更加符合規範。

相關推薦

彙編呼叫c函式為什麼設定

4.舉例分析C語言函式呼叫是如何使用棧的 對於上面的解釋的棧的作用顯得有些抽象,此處再用例子來簡單說明一下,就容易明白了:用:arm-inux-objdump–d u-boot >dump_u-boot.txt可以得到dump_u-boot.txt檔案。該檔案就是中,包含了u-boot中的程式的可執行的

ARM彙編C語言混合程式設計之彙編呼叫C函式

呼叫沒有引數的函式 呼叫有引數的函式 總結 本文所用硬體平臺為S3C2440開發板。通過一個點亮數碼管的程式說明ARM彙編呼叫C函式的方法。 根據C語言中函式引數的個數,可以將彙編呼叫C函式分為兩種情況,呼叫沒有引數的函式和呼叫有引數的

在keil中,彙編呼叫c函式

今天遇到個問題,以為是彙編中呼叫C函式的原因,其實不是這個原因,在這裡也溫習一下在ARM彙編呼叫C函式的方式。若在彙編中呼叫C檔案中的函式 void fun_c(void),只需要在呼叫之前,IMPORT fun_c ,其中 keil工具是不允許彙編語句頂格寫,不然會報錯。

c呼叫c++函式,為什麼加extern c

首先,作為extern是C/C++語言中表明函式和全域性變數作用範圍(可見性)的關鍵字,該關鍵字告訴編譯器,其宣告的函式和變數可以在本模組或其它模組中使用。 通常,在模組的標頭檔案中對本模組提供給其它模組引用的函式和全域性變數以關鍵字extern宣告。例如,如果模組B欲引

C#呼叫C++函式來與串列埠通訊

前些日子幫朋友寫個小軟體,要求用C#來實現主程式,主要的功能是與一些通訊裝置打交道,當然就是通過串列埠了,以十進位制傳送和讀取串列埠 的資料,考慮到C#呼叫API並沒有C++來得方便,因此,我用C++封裝了一個讀寫串列埠的DLL,只提供一個函式供外部呼叫,這樣的好處在於,C# 只要呼叫這個函式傳

python呼叫c函式引數型別問題

我的理解: python通過ctypes模組做了型別的對應。 參考ctypes文件:https://docs.python.org/3/library/ctypes.html python語言 ctype模組 c語言

node.js呼叫C++函式

新手寫的不好勿噴要想node.js呼叫C++的函式等,須先將C++程式碼編譯成二進位制的.node檔案。node.js官方文件https://nodejs.org/dist/lates... 中的C++ addons介紹瞭如何將C++的程式碼編譯為二進位制的.nod

常用的ARM彙編指令集與彙編呼叫C語言

***指令與偽指令: 指令:CPU機器指令的助記符,經過編譯後得到一串10組成的機器碼,可以被CPU直接讀取執行。 偽指令:編譯器環境提供,用來指導編譯過程,最終不會生成機器碼。 ***LDR/STR架構: CPU不能直接對記憶體的內容進行操作,必須藉助CPU

如何用C語言封裝 C++的類(C呼叫C++函式)、(C++呼叫C函式

1、C呼叫C++ 本文給出了一種方法。基本思想是,寫一個 wrapper檔案,把 C++類封裝起來,對外只提供C語言的介面,和 C++i相關的都在  wrapper的實現檔案裡實現。 //------apple.h #ifndef __APPLE_H__ #define

cocos2d-js-v3.0-rc2:js繫結呼叫c++函式 1

分享一種簡單的js呼叫c++程式碼的繫結方法、 首先用c++寫一個方法,為了簡便就在CCSprite裡面寫個一個sumTwonum(兩個數相加) 在CCSprite.h裡新增 public:     int sumTwonum(int a,int b); 在CCSprit

Android NDK(JNI)學習總結一:Java程式碼中申明native函式-Java呼叫C函式,並在C函式中訪問java類和方法、屬性

本文不涉及android-ndk開發環境搭。 步驟一:新建一個APP,名稱為HelloJNI,然後定義一個類(將會在native程式碼中呼叫和訪問該類): package com.example.hellojni; public class JNITe

duilib CWebBrowser控制元件 C++呼叫js函式&&js中呼叫C++函式

C++和js相互呼叫是個有意思的事情。 一、js中呼叫C++函式。函式原型 int g_FunSub(int x,int y); 呼叫方式如下: <html> <head&g

Step By Step(Lua呼叫C函式)

Lua可以呼叫C函式的能力將極大的提高Lua的可擴充套件性和可用性。對於有些和作業系統相關的功能,或者是對效率要求較高的模組,我們完全可以通過C函式來實現,之後再通過Lua呼叫指定的C函式。對於那些可被Lua呼叫的C函式而言,其介面必須遵循Lua要求的形式,即typedef

C語言調用匯編和彙編呼叫C語言

1.C語言調用匯編 程式的入口是main,在main裡調用匯編的函式。 在C語言中,要extern 一個函式宣告即可,然後這個函式在彙編裡面實現。 在彙編裡面,用EXPORT 把C語言定義的函式名引進來,再開始編寫函式名開始的段 #include<stdio.h

VS中c++檔案呼叫c 函式 ,fatal error C1853 預編譯標頭檔案來自編譯器的早期版本,或者預編譯頭為 C++ 而在 C 中使用它(或相反)

出現錯誤:error C1853: “Debug\ConsoleApplication1.pch”預編譯標頭檔案來自編譯器的早期版本,或者預編譯頭為 C++ 而在 C 中使用它(或相反) 相關資料:

呼叫C#函式Timeout研究

做了一個函式timeout的簡單研究,程式碼如下: private void button1_Click(object sender, RoutedEventArgs e) { CallFunctionWithTimeout(GetR

arm c函式呼叫過程arm組合語言呼叫C函式之引數傳遞

;將lr裝進pc(返回main函式)         END test_c_args.c //-------------------------------------------------------------------------------- void test_c_args(int a,int

arm彙編程式呼叫C函式之引數傳遞

對於ARM體系來說,不同語言撰寫的函式之間相互呼叫(mix calls)遵循的是 ATPCS(ARM-Thumb Procedure Call Standard),ATPCS主要是定義了函式呼叫時引數的傳遞規則以及如何從函式返回,在彙編程式中呼叫C函式的引數傳遞

8、Lua中呼叫C++函式

    來往來往,有來有往才能叫做來往。既然C/C++和lua是好親戚,那就會有來有往。之前,我們一直在討論在C/C++中如何使用Lua提供的變數和函式。從這篇文章開始,咱們來討論一下如何在Lua中使用C/C++提供的變數、函式甚至類。     當然,我們還是

C++程式中如何呼叫C函式

C++語言支援函式過載,C 語言不支援函式過載。函式被C++編譯後在庫中的名字與C 語言的不同。假設某個C函式的宣告如下:void foo(int x, int y);該函式被C編譯器編譯後在庫中的名字為_foo,而C++編譯器則會產生像_foo_int_int之類的名字用