我有一個在 x64 上運行的小程式呼叫系統函式,其引數足夠長,這意味著據我所知,他將被推送到堆疊上運行。
#include <stdlib.h>
int main(void) {
char command[] = "/bin/sh -c whoami";
system(command);
return EXIT_SUCCESS;
}
當我在 GDB 中檢查正在發生的事情時,我可以確認我的引數在 2 個字的堆疊上。

我想知道 CPU 是如何知道它需要讀取 2 個單詞并且之后不再繼續的。什么將函式引數與其余引數分隔?
我在處理緩沖區溢位時問這個問題,雖然我在堆疊上遇到同樣的情況,但 CPU 只選擇一個詞(/bin/sh)而不是我想要的兩個詞。輸出sh: line 1: $'?\310\367\377\177': command not found

uj5u.com熱心網友回復:
處理器如何知道從堆疊中讀取多少函式引數(x64)
CPU不知道。我的意思是,它沒有收到一條指令說“從堆疊中檢索下一個引數,無論大小可能是什么。” 它接收指令以從特定位置檢索特定大小的資料,并對該資料進行操作,或將其放入暫存器中,或將其存盤在其他位置。這些指令是由編譯器根據程式源代碼生成的,它們是程式二進制檔案的一部分。
我想知道 CPU 是如何知道它需要讀取 2 個單詞并且之后不再繼續的。什么將函式引數與其余引數分隔?
沒有任何東西可以將一個函式引數與下一個函式引數分隔——既不在堆疊上,也不在一般情況下。程式(通常)不會通過內省資料來即時計算出這些事情。相反,函式需要以特定方式設定引數,該方式由一組稱為“應用程式二進制介面”(ABI) 的約定管理,并且它們在資料確實以這種方式設定的假設下運行。如果這些假設被證明是無效的,那么或多或少都會發生任何事情。
我在處理緩沖區溢位時問這個問題,雖然我在堆疊上遇到同樣的情況,但 CPU 只選擇一個詞(/bin/sh)而不是我想要的兩個詞。
函式將從堆疊中消耗的字數及其賦予它們的重要性是函式的特征,而不是(通常)堆疊上的資料。
uj5u.com熱心網友回復:
取決于為函式實作的呼叫約定。通過指定 none,您可以讓編譯器做出決定,并且它可以發揮創意,有時甚至會因為分支預測優化而消失,否則您可以從大量指定這些呼叫約定如何的檔案源中call準確地了解期望什么應該作業。
uj5u.com熱心網友回復:
處理器非常非常愚蠢。他們全部。這就像問你如何駕駛火車......你沒有。它只是跟隨軌道。處理器只是跟隨它前面的位,如果它們是錯誤的或做壞事,那么處理器就會崩潰,就像如果軌道壞了火車會脫軌一樣。
變數的大小不是由處理器型別、x86、arm 等決定的。對于 C 也不是由語言決定的,x86 的 int 的大小不假定為一種大小。像這樣的假設是不好的。編譯器作者為該目標選擇該編譯器。并且沒有理由假設同一目標處理器的任何兩個 C 編譯器使用相同的大小。
同樣,編譯器作者最終決定呼叫約定,暫存器中的內容,堆疊中的內容,堆疊中的順序,暫存器等。
編譯器作者還選擇堆疊的對齊或不對齊。
編譯器作者選擇使用或不使用堆疊幀或允許用戶選擇,但在任一選擇中,有或沒有仍然選擇如何使用堆疊或堆疊指標。
編譯器作者使用他們的呼叫約定、他們對變數大小的選擇等,然后作為編譯程序的一部分來決定使用哪些指令。應根據上述選擇來選擇說明。因此,一個兩位元組大小的變數應該在堆疊中,這是基于編譯器根據編譯器選擇和可能的用戶選項相對于堆疊指標或堆疊幀指標做出的決定。
處理器不知道,它只是簡單地吸收位元并按照他們所說的去做,如果編譯器、匯編器和聯結器已經完成了他們的作業,最終是程式員的責任,那么處理器就會按照它的指示去做,包括讀取正確數量的特定專案的位元組。
由于在這個網站上被打死,檢查 main() 的堆疊往往會令人困惑,因為添加了神秘的填充,理想情況下你想用其他函式名編譯它并看到它。編譯器選項也可以確定代碼的構建方式、使用的指令以及堆疊(如果有)。優化級別。沒有理由假設任何兩個編譯器都會從某個 C 源代碼生成相同的代碼,同樣沒有理由假設一個編譯器會根據編譯器選項生成相同的代碼。
所以堆疊在哪里,堆疊上有多少位元組等是由程式員加上編譯器、匯編器和聯結器的多層決定的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/486333.html
上一篇:程式集顯示大量重復代碼?
