當前位置:才華齋>IT認證>華為認證>

華為面試題:怎樣判斷棧的增長方向

華為認證 閱讀(2.24W)

在華為面試中有這麼一道考試,請給出棧增長方向的判斷方法。下面一起來看看這道題的參考答案,僅供大家參考!

華為面試題:怎樣判斷棧的增長方向

題目屬於考查計算機組成原理中棧結構知識的題目。其參考答案如下:

可以編寫一個帶有過程(函式)呼叫的C程式,然後按照以下方法進行判斷(採用類似思想,還可以寫出許多答案)。

方法一:通過比較被呼叫過程中的入口引數所在地址和區域性變數所在地址之間的大小來判斷。若入口引數所在地址大於區域性變數所在地址,則棧是向低地址增長的。

方法二:直接閱讀彙編指令來判斷。例如,在IA-32中,如果在一個過程的開始階段(準備段)出現類似“sub $0x10,%esp”指令,說明棧頂指標(%esp)是變小的,因此棧是向低地址增長的。

方法三:顯示棧頂指標暫存器的內容。在某個過程的開始階段和結束階段分別顯示棧頂指標暫存器的內容,比較它們的大小。若開始處的值比結束處的.大,則說明棧是向低地址增長的。

後面兩種方法,需要對程式的機器級程式碼(彙編指令)進行除錯,例如,利用Linux系統中的程式除錯工具軟體GDB進行除錯。

該題是開放題目,答案應該沒有唯一性。通過這個題目的回答可以考查出學生對計算機系統中棧結構的掌握情況。

棧是儲存空間中的一個區域,分使用者棧和核心棧兩種型別。使用者棧主要用來存放使用者程序每次過程(函式)呼叫時,在被呼叫過程中使用的區域性資訊,每次過程呼叫都在棧中生長出一個新的棧幀,因此,棧幀是通過執行相應的指令動態生長出來的;核心棧是作業系統核心中的動態儲存區域,用於儲存作業系統核心和硬體所需要的動態資訊。

在採用虛擬儲存管理機制的系統中,核心棧和使用者棧都是虛擬地址空間中的一個儲存區。每個源程式經編譯、彙編、連結等處理生成可執行的二進位制機器目標程式碼時,每個程式的目的碼都被對映到同樣的虛擬地址空間,所有使用者程序的虛擬地址空間是一致的。例如,圖1給出了在IA32/Linux作業系統下hello程式的一個程序對應的虛擬地址空間映像。它分為兩大部分:核心區(kernelarea)和使用者區(userarea)。

從圖1可以看出,核心區在0xC0000000以上的高階地址上,用來存放作業系統核心程式碼和資料以及與每個程序相關的資料結構(如程序標識資訊、程序現場資訊、頁表等程序控制資訊以及核心棧等),其中核心程式碼和資料區在每個程序的地址空間中都相同。使用者程式沒有許可權訪問核心區。

使用者區用來存放使用者程序的程式碼和資料,它被分為以下幾個區域。

(1) 使用者棧。用來存放程式執行時過程呼叫的引數、返回值、返回地址、過程區域性變數等,隨著程式的執行,該區會不斷動態地從高地址向低地址增長或向反方向減退。

(2) 共享庫。用來存放公共的共享函式庫程式碼,如hello中的printf( )函式等。

(3) 堆。用於動態申請儲存區,例如,C語言中用malloc()函式分配的儲存區,或C++中用new操作符分配的儲存區。申請一塊記憶體時,動態地從低地址向高地址增長,用free( )函式或delete操作符釋放一塊記憶體時,動態地從高地址向低地址減退。

(4) 可讀寫資料區。存放使用者程序中的靜態全域性變數,堆區從該區域的結尾處開始向高地址增長。

(5) 只讀資料和程式碼區。存放使用者程序中的程式碼和只讀資料,如hello程序中的程式程式碼和字串“hello,worldn”。

每個區域都有相應的起始位置,堆區和棧區相向生長,棧區從核心起始位置0xC0000000開始向低地址增長,堆疊中的共享庫程式碼區從0x40000000開始向高地址增長。程式碼和只讀資料區從0x08048000開始向高地址增長。

對於棧的訪問操作,有些指令集系統結構提供了專門的入棧和出棧指令,例如Intel架構中的push指令和pop指令分別用於入棧和出棧操作;有些架構則不提供專門的入棧和出棧指令,而是通過訪存指令和加/減指令來實現入棧和出棧操作,例如,MIPS架構中用sw指令和add或sub指令實現入棧操作,用lw指令和add或sub指令實現出棧操作。

對於像Intel這樣提供專門入棧和出棧指令的情況,棧的增長方向可以根據入棧、出棧指令的功能來確定,例如,IA-31架構中的push指令自動將棧頂指標減4,而pop指令則自動將棧頂指標加4。因而,棧總是從高地址向低地址增長。

對於像MIPS架構這種沒有專門入棧和出棧指令的情況,棧的增長方向就不一定,可能是高地址向低地址增長,或是相反。

因為棧是通過執行指令動態增長的,所以,最直接的判斷辦法就是在機器級程式碼層面(通常是彙編指令)來閱讀或除錯程式。

當一個過程P呼叫一個被呼叫過程Q,則P中傳遞給Q的引數會先入棧,然後執行呼叫指令(如IA-32中的call指令),跳轉到Q執行,在被呼叫過程Q中,再將Q的區域性變數入棧,因此,通過比較Q過程的入口引數所在地址和區域性變數所在地址之間的大小,可以判斷出棧的增長方向。