
一腔熱血勤珍重,灑去猶能化碧濤,
本文出自2020年位元組跳動秋招提前批面試真題,原題面經及本文精講均已收錄在:
GitHub https://github.com/hlwxzmj/Killing-Campus-Interview 與「互聯網校招面經」
微信搜一下「互聯網校招面經」,第一時間訂閱獲取更多精選校招面經與面試真題詳解,
張三轉碼之路
張三同學原本是一名法學專業的研究生,但是由于他自己實在是對法律不是很感興趣,加上天天遭受到某位姓羅的老師的粗暴對待,就想要轉行到互聯網行業,目標的崗位就是當前非常火熱的java工程師,

經過一頓操作猛如虎的各種高級框架學習之后,張三這回覺得自己終于大成,可以在互聯網界重出江湖,來一雪之前在前在法律界被人天天毒打的恥辱,他出山第一個矛頭就直指互聯網界著名幫派之一——位元組派,他覺得以他的實力肯定可以輕松拿下位元組派的入門資格,為他日后東山再起做準備,他當天中午投遞了簡歷,沒想到兩小時后就立刻收到了明天的面試邀請,內心一陣狂喜,頭腦中已經想象出明天跟面試官愉快暢談動人場景,

第二天,他胸有成竹的來到了面試室,坐在對面的面試官是一位非常年輕帥氣,年少有為的小哥哥,
他對張三說:“小伙子我看你簡歷上寫了會很多的東西,很不錯嘛,但是由于你投遞是初級崗位,我就先從一些簡單的基礎知識跟你聊聊吧,”
張三一聽,心中大喜,問基礎是嗎?這回穩了,
面試官:“那我們先來聊聊最基礎的函式呼叫吧,你說一說函式呼叫程序的基本原理吧,”
張三:“ 啊這…”
面試官:”那堆疊幀你有了解過嗎?“
張三:”啊這…“

面試結束

正文
一、在了解函式的呼叫原理之前,首先必須了解,程式運行時記憶體是怎么樣的?
想要了解程式在運行時函式詳細的呼叫程序,首先要對程式運行時的記憶體情況有一個基本的了解,下圖是一個正在運行的程式的經典記憶體布局:

內核區域:是給系統內核使用的記憶體空間,應用程式無法訪問這一區域,
堆疊:是函式呼叫相關的核心記憶體區域,用于維護函式呼叫的背景關系!從上圖中可知,堆疊區域的增長是從上往下的,也就是從高地址向低地址增長,
元件映射區:用于映射裝載的元件,
堆:對是用來存放應用程式動態分配的記憶體區域,比如大家常用的malloc或者new一個物件實體的時候往往就存放在此處的記憶體區域,而堆區域是從低地址向高地址增長,
未初始化區域:存放未初始化的全域變數和靜態變數,
初始化區域:存放已經初始化的全域變數和靜態變數,
保留區:保留區是記憶體中受到保護而禁止訪問的區域,
二、函式呼叫的關鍵,堆疊與堆疊幀!!!
堆疊的基本概念
堆疊是計算機科學中非常重要的的一個概念, 它有兩個基本的含義:
1、是資料結構中的一種,在資料結構中堆疊被定義為一種特殊的容器,可以將資料入堆疊(push),也可以將堆疊中的資料出堆疊(pop),但是堆疊必須遵循一個原則:先入堆疊的資料后出堆疊,
2、在計算機系統中,堆疊則是上面提到的程式運行時用于存盤函式呼叫相關邏輯的記憶體區域,這是我們本文需要重點關注的,
堆疊的結構圖

上圖就是一個計算機系統中堆疊的實體,可以看到堆疊底是位于高地址方向,而堆疊頂是位于低地址方向,
其中esp暫存器一直指向堆疊頂的位置,此時如果往堆疊中壓入資料,會導致esp減小,所指向位置下移,完成資料入堆疊操作后依舊指向堆疊頂位置,而出堆疊操作則剛好與入堆疊操作相反,

? 入堆疊后
堆疊之所以與函式呼叫密切相關,是因為堆疊中保存了一個與函式呼叫息息相關的非常關鍵的資訊,堆疊幀,堆疊幀中一般包含如下幾種資訊:
- 函式的回傳地址,
- 函式的傳入引數,
- 函式的臨時變數:包括函式的非靜態區域變數以及編譯器自動生成的其他臨時變數,
- 保存的背景關系:包括在函式呼叫前后需要保持不變的暫存器,
如下圖就是一個函式堆疊幀結構:

其中esp與ebp暫存器是函式呼叫程序中最重要的兩個暫存器,它們劃定了函式呼叫的記憶體活動范圍,
其中,上文有介紹過,esp暫存器始終指向堆疊記憶體的頂部,同時也指向了當前函式堆疊幀記錄的頂部,
而ebp暫存器則始終指向函式堆疊幀中一個固定位置,在ebp之前首先保存了old epb的值,它的地址是epb+4,這個值是上一個函式堆疊幀的ebp暫存器中應該存盤的值,其次再往前是這個函式的回傳地址,也是上一個函式呼叫當前函式的地址,它的地址是epb+8,后面以此類推,
看到這里一下子就好像明白了函式呼叫其中的奧妙!

三、不明白?六張圖超詳細決議函式呼叫的具體流程:
函式呼叫開頭固定流程:
-
先把所有的函式引數壓入堆疊中
-
把要回傳的函式地址壓入堆疊中
-
跳入到呼叫的函式體中執行
-
push
%ebp: 先把上一個函式的ebp暫存器中的值壓入堆疊中(如之前圖片中的old ebp), 此操作是為了在函式回傳時恢復上一個函式的ebp暫存器中的值,

- mov
%esp,%ebp: 把esp中的資料賦值給ebp,此時esp暫存器剛好指向堆疊頂,堆疊頂就是剛剛壓入的old ebp, 此操作完成后,ebp暫存器中的值被重繪,指向了新的函式的堆疊幀的固定位置,

- 至此函式呼叫開頭固定流程結束,后續就進行函式程序內的各種區域變數的入堆疊,計算等操作…

函式呼叫結尾固定流程:
pop XXX: 把函式程序內的資料都出堆疊,

- mov
%ebp,%esp: 將ebp暫存器中的值賦值給esp,
注意!注意!此時esp只向了跟ebp相同的位置啦!即此時堆疊頂指標暫存器esp剛好指向了old ebp的位置!
? 
- pop
ebp: 然后繼續進行出堆疊操作,將old ebp出堆疊然后賦值給ebp,看到這里是不是恍然大悟啦,ebp暫存器的值在此被重繪,還原成了上一個函式呼叫時應該保存的值,

- ret:此時
esp暫存器指向堆疊頂,而此時的堆疊頂剛好是回傳地址,直接跳轉回去!一次函式的呼叫流程就此結束!
四、來一個小例子?

先看一下樣例源代碼,這是一個比較基礎的c++求和小程式代碼:

我們在用gdb disassemble命令看看呼叫sun函式時,底層匯編層代碼到底都在做什么!看不懂沒關系,可以往下看!

哇,看這個sum函式匯編代碼的開頭結尾代碼流程,是不是感覺非常眼熟?跟上文中所講的幾乎完全一致???
來,首先看第一部分剛進入sum函式的時候:

push %rbp : 先把上一個函式的ebp暫存器中的值壓入堆疊中
mov %esp,%ebp : 然后把esp中的資料賦值給ebp,
? 
然后吶!中間部分,執行函式內計算程序,具體匯編代碼看不懂的同學可以不必深究,

等到函式回傳的時候:

mov %ebp,%esp :將ebp暫存器中的值賦值給esp
pop %ebp: 然后繼續進行出堆疊操作,將old ebp出堆疊然后賦值給ebp,

最后跳轉回回傳地址!!!

小總結
函式大家肯定在熟悉不過了,但是面試官問函式呼叫原理往往是想進一步考察候選人對計算機基礎知識的扎實程度,這個考察這個知識點的類似問題有很多,比如比較常見的函式一直遞回呼叫下去會出現什么問題?(堆疊溢位),程式運行時堆疊你有了解嗎?(上面行程記憶體結構圖)等等,
回答的時候只要對上文所講到的大致程式運行時記憶體結構,函式呼叫基本流程跟面試官說清楚就可以了,如果還能具體的講出ebp,esp相關暫存器的作用那就是了解的非常深入了,會給面試官留下非常好的印象,

這個豬,求關注
如果你能看到這里,那豬真的是超級開心了,最起碼幾天的辛苦畫圖碼字是值得的,
我以后每周都會分享高頻精彩的互聯網大廠技術崗位面試真題,力求用最簡潔的語言,最有趣的風格,最干貨的內容去用心創作優秀的技術文章,豬真的一直覺得:技術本原本枯燥,但是技術文章本不應該同樣枯燥,如果覺得豬的這篇用4天時間寫的文章還不錯的話,求你花2秒鐘的時間給豬唄!第一秒在文章左下角點個贊!第二秒點個關注!如果你還能在評論區夸豬一下,那豬更是樂開了花呢!如果大家還有什么想要深入了解的大廠高頻面試知識,也期待評論區留下你的聲音,
創作辛苦,好心人不要白嫖這個豬,你們的三連就是我繼續更新的最大動力,希望下一篇文章豬還能遇見你!
如果本篇文章內容有任何錯誤,非常歡迎大家評論區直接狂揍我,我把右手剁了請評論的大家吃豬蹄,

技術文章每周持續更新,本文出自2020年位元組跳動秋招提前批面試真題,原題面經及本文精講均已收錄在:
GitHub https://github.com/hlwxzmj/Killing-Campus-Interview 與「互聯網校招面經」,
微信搜一搜「互聯網校招面經」,第一時間訂閱獲取更多精選校招面經與大廠面試真題題解,歡迎同學們關注,star,
同時我還花了很久的時間,從全網路搜集,整理,精選,精裝了位元組跳動2021年校園招聘提前批面試真題,直接分享給大家:
鏈接:https://pan.baidu.com/s/1MPcVH6LvKaicpc7Xtklskg 提取碼:oq6i
我是風口浪尖上的豬,浙江大學計算機碩士,畢業前作業過三家大廠四個部門,
一只致力于用最簡潔的語言,最有趣的風格,最干貨的內容去用心創作優秀技術文章,用心與讀者做朋友的豬,
感謝大家的點贊,收藏與評論,我們下期見!

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/256371.html
標籤:其他
上一篇:學習第一天
下一篇:華為ENSP-單臂路由
