日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

一步步编写操作系统 65 标准调用约定stdcall 汇编实战

發布時間:2023/12/10 windows 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 一步步编写操作系统 65 标准调用约定stdcall 汇编实战 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

因為c語言遵循的調用約定是cdecl,咱們也自然要遵守cdecl約定了。不過為了起到對比的作用,除了介紹cdecl外,也會介紹下stdcall。

既然咱們用的是調用約定是cdecl,那對它的介紹最好讓它離下一節的內容近一些,所以先說一下咱們不用的stdcall吧^_^,其實這兩個差別就在于由誰來回收棧空間。

stdcall的調用約定意味著:

  • 調用者將所有參數從右向左入棧;
  • 被調用者清理參數所占的棧空間;
  • 這兩點在上文的表中大家已有所了解,下面咱們將理論實踐一下,還是拿上面說過的函數舉例:

    1 int subtract(int a, int b); //被調用者 2 int sub = subtract (3,2); //主調用者

    第1行是個函數聲明,其實現已經在前面看到了,就是“return a-b”。

    第2行進行函數調用,實參分別是3和2。在實際調用中,參數按照從右向左的順序,參數b會先被壓入棧,然后是參數a壓入棧。在stdcall調用約定下,這個c代碼被編譯后的匯編語句是:

    主調用者:

    ; 從右到左將參數入棧 1 push 2 ;壓入參數b 2 push 3 ;壓入參數a 3 call subtract ;調用函數subtract

    以上是主調函數,現在看下被調函數subtract中做了什么。

    被調用者:

    1 push ebp ;壓入ebp備份。 2 mov ebp,esp ;將esp賦值給ebp, ;用ebp做為基址來訪問棧中參數。 3 mov eax,[ebp+0x8] ;偏移8字節處為第1個參數a。 4 add eax,[ebp+0xc] ;偏移0xc字節處是第2個參數b, ;參數a和b相加后存入eax。 5 mov esp,ebp ;為防止中間有入棧操作,用ebp恢復esp。 ;本句在此例子中可有可無,屬于通用代碼。 6 pop ebp ;將ebp恢復 7 ret 8 ;數字8表示返回后使esp+8。;函數返回時由被調函數清理了棧中參數。

    當執行流進入到subtract后,在它的內部為了用ebp做為基址引用棧中參數,先執行了push ebp來備份ebp,再將棧指針賦給了ebp。目前棧中布局如圖

    ?

    大家根據上圖很容易地看出ebp偏移為8字節是參數a,偏移12字節是參數b。以上代碼值得說一下的是ret 8這句。stdcall是被調用者負責清理棧空間,這里的被調用者是函數subtract。也就是說,subtract需要在返回前或返回時完成。在返回前清理棧相對困難一些,清理棧是指將棧頂回退到參數之前。因為返回地址在參數之下,ret指令執行時必須保證當前棧頂是返回地址。所以通常在返回時“順便”完成。于是ret指令便有了這樣的變體,其格式為:

    ret 16位立即數

    這是允許在返回時順便再將棧指針esp修改的指令。順便說一句,由于32位下push指令不是壓入字就是壓入雙字,所以ret的參數必須是偶數。在ret 8執行之前,當前棧頂必須是返回地址,即使沒有第5行的代碼,當前esp也是等同于ebp,因為之前沒有任何push壓棧操作,這是編譯器為了通用性而加進去的,所以我們在注釋中寫到,此句可有可無。在經過第6行將棧頂(當前esp指向的內存)彈出到ebp之后,ebp被恢復,此時esp指向了+4字節的位置。即當前棧頂為主調函數的返回地址。結合上圖,ret指令將棧頂的數據彈出到寄存器eip后,棧指針esp自加4,由于還有個參數8,所以esp又被加了8,從而跳過了參數a和b,順利地完成了被調用者清理棧的任務。

    stdcall是調用者在棧中壓入參數,由被調用者回收棧空間。貌似分工很明確,配合很默契。因為被調用者知道自己需要幾個參數,所以知道要回收多少棧空間。 但轉念一想,凡事都要自己親力親為才放心,調用者壓入的參數,萬一被調用者忘記回收棧空間該怎么辦(這一點由高級語言編譯器保證,一般不會,大伙兒放心,本段這么寫是為了表述下一種調用約定方式的特點),參數多了棧會溢出的。下面咱們就要介紹這種“親力親為”的調用約定,即:調用者自己向棧中壓入參數,還是由調用者自己回收棧空間。

    好啦,stdcall調用約定就到此為止。大爺再來玩哦。

    總結

    以上是生活随笔為你收集整理的一步步编写操作系统 65 标准调用约定stdcall 汇编实战的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。