精品国产人成在线_亚洲高清无码在线观看_国产在线视频国产永久2021_国产AV综合第一页一个的一区免费影院黑人_最近中文字幕MV高清在线视频

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

透徹的理解機(jī)器代碼層面的函數(shù)調(diào)用

Linux閱碼場(chǎng) ? 來(lái)源:未知 ? 作者:胡薇 ? 2018-05-25 14:40 ? 次閱讀

我是CPU阿甘, 上次我給大家承諾過(guò),要講一講函數(shù)調(diào)用的秘密, 這個(gè)確實(shí)有點(diǎn)復(fù)雜, 想透徹的理解機(jī)器代碼層面的函數(shù)調(diào)用不容易。

我也是從無(wú)數(shù)的指令中悟出這個(gè)函數(shù)調(diào)用的秘密的, 所以慢慢來(lái),不要急。 放松心情, 慢慢的品味,你可能需要多看幾遍才能明白。

但是你一旦理解了,絕對(duì)物超所值,因?yàn)槟銜?huì)了解到匯編,寄存器,指針,以及他們?cè)谝黄鸬降资窃趺垂ぷ鞯摹?/p>

首先, 一個(gè)程序一條一條的指令都的老老實(shí)實(shí)的放在內(nèi)存的一個(gè)地方,這個(gè)地方是Linux老大分配的, 我干涉不了, 但是這些指令都是我打電話(huà)給硬盤(pán), 讓他給運(yùn)輸?shù)絻?nèi)存的。然后Linux老大就會(huì)告訴我程序的入口點(diǎn), 其實(shí)就是第一條指令的存放地址, 我就打電話(huà)問(wèn)內(nèi)存要這個(gè)指令, 取到指令以后就開(kāi)始執(zhí)行。這些指令當(dāng)中無(wú)非有這么幾類(lèi):1. 把數(shù)據(jù)從內(nèi)存加載我的寄存器里什么? 你不知道啥是寄存器? 寄存器就是我內(nèi)部的一個(gè)臨時(shí)的數(shù)據(jù)存儲(chǔ)空間了2. 對(duì)寄存器的數(shù)據(jù)進(jìn)行運(yùn)算, 例如把兩個(gè)寄存器的數(shù)加起來(lái)3. 把我寄存器的數(shù)據(jù)再寫(xiě)到內(nèi)存里但是我一旦遇到像這樣的指令。"把寄存器ebp的值壓到棧里去“我就知道好戲要上場(chǎng)了, 函數(shù)調(diào)用就會(huì)開(kāi)始。我們這些x86體系的機(jī)器有個(gè)特點(diǎn),就是每個(gè)函數(shù)調(diào)用都會(huì)創(chuàng)建一個(gè)所謂的“幀”哈哈, 不要被這些術(shù)語(yǔ)嚇壞, 其實(shí)幀也就是我哥們內(nèi)存中的一段連續(xù)的空間而已。像這樣:

現(xiàn)在這個(gè)指令來(lái)了:"把寄存器ebp的值壓到棧里去“"把esp的值賦給ebp"

"把esp 的值減去24”

“把10放到ebp 減去4的地址” (其實(shí)就是796嘛)“把20放到ebp減去8的地址” (其實(shí)就是792嘛)

" 把地址796作為數(shù)據(jù)放到 esp指向的地址“ (其實(shí)就是776嘛)" 把地址792作為數(shù)據(jù)放到 esp+4指向的地址" (其實(shí)就是780嘛)

這其實(shí)就相當(dāng)于把 x 的指針 &x和 y 的指針 &y ,放到了特定的地方, 準(zhǔn)備著要做什么事情 , 可能要調(diào)用函數(shù)了。

所以,所謂的指針就是地址而已。

我猜程序員寫(xiě)的代碼應(yīng)該是這樣:int x = 10;int y = 20;int sum= add(&x, &y);接下來(lái)的指令是這樣:“調(diào)用函數(shù) add”我看到這樣的函數(shù)就需要特別小心, 因?yàn)槲冶仨氁业?add函數(shù)返回以后的那條指令的地址, 把它也壓到棧里去。int x = 10;int y = 20;int sum = add(&x, &y);printf("the sum is %d\n",sum);假設(shè)這條指令的地址是100

注意啊, 把函數(shù)調(diào)用結(jié)束的以后的返回地址100壓入棧以后, esp 也發(fā)生變化了, 指向了772的位置我會(huì)找到函數(shù)Add 的指令,繼續(xù)執(zhí)行"把寄存器ebp的值壓到棧里去“"把esp的值賦給ebp""把寄存器ebx的值壓入?!蹦憧疵總€(gè)函數(shù)的開(kāi)始指令都是這樣, 我猜這應(yīng)該是一種約定吧這里額外把ebx這個(gè)寄存器壓入棧, 是因?yàn)閑bx可能被上個(gè)函數(shù)使用, 但是在add函數(shù)中也會(huì)用 , 為了不破壞之前的值, 只有先委屈一下暫時(shí)放到內(nèi)存里吧。

“把ebp 加8的數(shù)據(jù)取出來(lái)放到 edx 寄存器” (ebp+8 不就是地址776嘛, 其中存放的是&x的地址, 這就是取參數(shù)了)“把ebp 加12的數(shù)據(jù)取出來(lái)放到 ecx 寄存器” (ebp+12 不就是地址780嘛, 其中存放的是&y的地址)注意啊, 現(xiàn)在edx的值是796, ecx的值是792 , 但他們?nèi)匀徊皇钦嬲臄?shù)據(jù), 而是指針(地址)!“把edx 指向的內(nèi)存地址(796)的數(shù)據(jù)取出來(lái),放到ebx 寄存器”“把ecx 指向的內(nèi)存地址(792)的數(shù)據(jù)取出來(lái),放到eax寄存器”此時(shí)此刻, 終于取到了真正的值, ebx = 10, eax = 20你暈了沒(méi)有? 如果你到此已經(jīng)暈了, 建議你再讀一遍。 我想源代碼應(yīng)該非常的簡(jiǎn)單,就是這樣:int add(int *xp , int *yp){ int x = *xp; int y = *yp; ....}“把ebx 和 eax 的值加起來(lái),放到 eax寄存器中”這個(gè)指令我最擅長(zhǎng)做了。接下來(lái)的指令也很關(guān)鍵, add 函數(shù)已經(jīng)調(diào)用完成, 準(zhǔn)備返回了“把esp 指向的數(shù)據(jù)彈出的ebx寄存器”“把esp 指向的數(shù)據(jù)彈出到ebp寄存器”

"返回"我就會(huì)取出那個(gè)返回地址, 也就是 100, 去這里找指令接著執(zhí)行其實(shí)就是這條語(yǔ)句:printf("the sum is %d\n",sum);問(wèn)你一個(gè)問(wèn)題, sum的值在那里保存著呢?對(duì), 是在eax寄存器里 !搞定了,看著很復(fù)雜, 其實(shí)看透了也挺簡(jiǎn)單吧。 函數(shù)調(diào)用,關(guān)鍵就是(1)把參數(shù)和返回地址準(zhǔn)備好,(2)然后大家都遵循約定, 每次新函數(shù)都要建立新的函數(shù)幀: "把寄存器ebp的值壓到棧里去“ "把esp的值賦給ebp"(3) 函數(shù)調(diào)用完了, 重置 ebp 和esp ,讓他們重新指向調(diào)用著的棧幀。好了,今天就到此為止 , 把我也累壞了, 主人又要關(guān)機(jī)了,留一個(gè)問(wèn)題吧:C語(yǔ)言編譯,鏈接以后直接就是機(jī)器碼, 那函數(shù)調(diào)用的操作都是上面講的。但是對(duì)于Python, Ruby 這樣的解釋型語(yǔ)言, 或者對(duì)于java 這樣的有虛擬機(jī)的語(yǔ)言, 他們的函數(shù)調(diào)用是什么樣的? 和上面講的有什么關(guān)系?

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 寄存器
    +關(guān)注

    關(guān)注

    31

    文章

    5317

    瀏覽量

    120008
  • 匯編
    +關(guān)注

    關(guān)注

    2

    文章

    214

    瀏覽量

    25902
  • 函數(shù)調(diào)用
    +關(guān)注

    關(guān)注

    0

    文章

    19

    瀏覽量

    2584

原文標(biāo)題:CPU阿甘:函數(shù)調(diào)用的秘密

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    C函數(shù)調(diào)用機(jī)制與棧幀原理詳解

    當(dāng)一個(gè)C函數(shù)調(diào)用時(shí),函數(shù)的參數(shù)如何傳遞、堆棧指針如何變化、棧幀是如何被建立以及如何被消除的,一直缺乏系統(tǒng)性的理解,因此決定花時(shí)間學(xué)習(xí)下函數(shù)
    發(fā)表于 06-08 10:49 ?1217次閱讀
    C<b class='flag-5'>函數(shù)</b><b class='flag-5'>調(diào)用</b>機(jī)制與棧幀原理詳解

    如何查看及更改函數(shù)/函數(shù)塊的調(diào)用環(huán)境

    模塊化設(shè)計(jì)的思想是把一些相似的功能(比如電機(jī)控制、閥控制)設(shè)計(jì)成函數(shù)函數(shù)塊,這樣就可以反復(fù)調(diào)用。其優(yōu)點(diǎn)是:使程序架構(gòu)更加清晰,避免重復(fù)編寫(xiě)相似功能的代碼。不過(guò)可能會(huì)產(chǎn)生一個(gè)疑惑:既然
    的頭像 發(fā)表于 11-17 09:08 ?893次閱讀
    如何查看及更改<b class='flag-5'>函數(shù)</b>/<b class='flag-5'>函數(shù)</b>塊的<b class='flag-5'>調(diào)用</b>環(huán)境

    時(shí)鐘軟件層面和硬件層面的問(wèn)題解釋

    前言說(shuō)實(shí)話(huà),我剛開(kāi)始學(xué)的時(shí)候也沒(méi)咋的學(xué)明白,都是拿著別人的代碼抄一抄。那時(shí)我連軟件層面和硬件層面有時(shí)候都會(huì)搞混,所以我還是建議初學(xué)者多做筆記,多看看手冊(cè)。沒(méi)事也可以翻翻我的博客,如果在169芯片遇到
    發(fā)表于 11-29 07:08

    硬件層面的堆和?;窘榻B

    堆和棧!基本介紹在嵌入式和單片機(jī)開(kāi)發(fā)領(lǐng)域中,堆和棧是非常重要的基礎(chǔ)知識(shí),但對(duì)于許多開(kāi)發(fā)者來(lái)說(shuō),對(duì)這方面的概念還是非常的模糊,甚至基本沒(méi)了解過(guò)。棧:基本上可以理解為,函數(shù)的局部變量都是存放...
    發(fā)表于 03-01 07:40

    CodeViz--一款分析C/C++源代碼函數(shù)調(diào)用關(guān)系的調(diào)用

    程序開(kāi)發(fā)中,有時(shí)候需要閱讀別人的代碼,這時(shí)理解代碼的組織結(jié)構(gòu)就顯得非常重要。CodeViz是一款分析C/C++函數(shù)調(diào)用關(guān)系的
    發(fā)表于 04-04 20:50 ?85次下載
    CodeViz--一款分析C/C++源<b class='flag-5'>代碼</b>中<b class='flag-5'>函數(shù)</b><b class='flag-5'>調(diào)用</b>關(guān)系的<b class='flag-5'>調(diào)用</b>

    如何在函數(shù)庫(kù)中調(diào)用指令?

    函數(shù)是一段可復(fù)用的代碼。我們通常把重復(fù)的代碼放進(jìn)函數(shù)中并且在不同的地方去調(diào)用它。庫(kù)是函數(shù)的集合。
    的頭像 發(fā)表于 08-31 15:51 ?3781次閱讀

    關(guān)于DSP中fft函數(shù)調(diào)用方法

    以下主要是通過(guò)代碼調(diào)用ftf函數(shù)
    發(fā)表于 01-01 08:35 ?8211次閱讀

    C代碼與javaScript函數(shù)的相互調(diào)用問(wèn)題應(yīng)該如何解決

    本文檔的主要內(nèi)容詳細(xì)介紹的是C代碼與javaScript函數(shù)的相互調(diào)用問(wèn)題應(yīng)該如何解決。
    發(fā)表于 03-05 11:47 ?17次下載

    系統(tǒng)調(diào)用與普通的函數(shù)調(diào)用之間的區(qū)別

    函數(shù)之間是可以相互調(diào)用的,這很簡(jiǎn)單很happy有沒(méi)有。 要知道是代碼、是函數(shù)就可以相互調(diào)用,不管你用什么語(yǔ)言寫(xiě)的。
    的頭像 發(fā)表于 02-15 11:47 ?3394次閱讀
    系統(tǒng)<b class='flag-5'>調(diào)用</b>與普通的<b class='flag-5'>函數(shù)</b><b class='flag-5'>調(diào)用</b>之間的區(qū)別

    嵌入式軟件架構(gòu)設(shè)計(jì)之函數(shù)調(diào)用

    函數(shù)調(diào)用很好理解,即使剛學(xué)沒(méi)多久的朋友也知道函數(shù)調(diào)用是怎么實(shí)現(xiàn)的,即調(diào)用一個(gè)已經(jīng)封裝好的
    的頭像 發(fā)表于 02-15 14:48 ?1062次閱讀
    嵌入式軟件架構(gòu)設(shè)計(jì)之<b class='flag-5'>函數(shù)</b><b class='flag-5'>調(diào)用</b>

    函數(shù)調(diào)用時(shí)底層會(huì)發(fā)生什么

    如果你懂得用箱子打包東西,你就能明白函數(shù)調(diào)用是怎么一回事。 原來(lái),在程序運(yùn)行時(shí)每個(gè)被調(diào)用函數(shù)都有自己的一個(gè)箱子,假設(shè)這段代碼是這樣寫(xiě)
    的頭像 發(fā)表于 02-17 14:47 ?630次閱讀
    <b class='flag-5'>函數(shù)</b><b class='flag-5'>調(diào)用</b>時(shí)底層會(huì)發(fā)生什么

    什么是函數(shù)調(diào)用?

    函數(shù)調(diào)用,就是使用我們已經(jīng)定義好的函數(shù),或者C語(yǔ)言自帶的庫(kù)函數(shù)
    的頭像 發(fā)表于 04-04 17:21 ?5666次閱讀

    SCL中調(diào)用函數(shù)的示例

    在此,可插入函數(shù) (FC) 調(diào)用函數(shù)塊 (FB) 調(diào)用函數(shù)塊可作為單實(shí)例、多重實(shí)例或參數(shù)實(shí)例進(jìn)行調(diào)用
    的頭像 發(fā)表于 06-06 10:18 ?2093次閱讀

    python函數(shù)函數(shù)之間的調(diào)用

    函數(shù)函數(shù)之間的調(diào)用 3.1 第一種情況 程序代碼如下: def x ( f ): def y (): print ( 1 ) return y def f (): print ( 2
    的頭像 發(fā)表于 10-04 17:17 ?566次閱讀

    linux用gdb調(diào)試遇到函數(shù)調(diào)用怎么辦?

    linux用gdb調(diào)試遇到函數(shù)調(diào)用怎么辦? 在Linux上使用GDB調(diào)試時(shí),遇到函數(shù)調(diào)用是一個(gè)常見(jiàn)的情況。函數(shù)
    的頭像 發(fā)表于 01-31 10:33 ?688次閱讀