[英]Are “functions” a fundamental part of the x86 hardware?
在流行的x86架構上,可以使用jmp
-type指令之一以及call
指令來控制執行流程。 但是,兩者都是根本的,還是另一種?
例如, push
指令是語法糖: push eax
等效於mov [esp], eax
后跟sub esp, 4
。 因此mov
是唯一的基本數據操作。
但這也可以call
嗎? 還有其他一些指令可以達到相同的目的嗎?
在偽代碼中,如果我可以訪問指令指針,則可以使用jmp
編寫函數調用:
bar:
push eip ;; pseudo-code! ;; call foo
jmp foo
foo:
pop eax ;; ret
jmp [eax]
這是無效的x86,因為不能直接讀取指令指針寄存器eip
。 到目前為止,我所見過的所有獲得eip
值的“技巧”都使用call
。 還是call
實際上是在x86上讀取指令指針的規范方法? 作為一個額外的問題,可以在其上實現C的每個體系結構是否都需要一種讀取指令指針的方式,以便可以實現函數指針?
int main(int argc, char * argv[])
{
int (*p)() = strtoul(argv[1]);
return p(); // how to implement without
// accessing the instruction pointer?
}
[這不是一個深層的問題; 知道函數不僅是高級編程語言引入的抽象,而且實際上是硬件固有的,這簡直讓我激動不已。
機器指令集可能微不足道; 請參閱Wolfram的2狀態,3符號圖靈機。 問題是這種機器很難編程,也很難快速運行。
您可以使用其他說明完全模擬呼叫返回:
; Simulate "call abc":
push offset next_location
jmp abc
next_location:
; Simulate "ret"
pop eax
jmp eax
顯然,您可以使用mov指令和通過添加問題中提到的常量來調整寄存器來模擬push / pop。
人們將指令添加到指令集以使通用序列高效。 因此,“調用”之所以存在是因為它執行了通常有用的任務(“調用/返回”對可以由硬件使用內部返回地址堆棧來優化,以避免指令流水線中斷;這是真正的性能優勢)。
因此,是的,您可以使用計算機提供的最少指令集來實現匯編語言的目的。 但是正確的附加說明在實踐中確實有幫助。 (您可以有意向地添加您認為可能有用的說明。它們通常無濟於事,這是RISC / CISC最初的爭論的源頭 )。
Goofball最小機器:
1970年代生產了真正的微型計算機(“ GRI”),它只有一條指令:MOV LOC1至LOC2; 目標位置是魔術,這就是完成實際工作的方式。 通過將某物移動到位置33(組成),其副作用是將值添加到了可以從位置32讀取的累加器中。它具有許多可以完成有趣且方便的操作的位置,因此,實質上是添加了一個新的有趣寄存器只是添加有用指令的一個奇怪的變體。 我懷疑JMP指令包含將一個常量移動到充當程序計數器的位置。 (如果您覺得這很奇怪,則說明您尚未達到PDP-11)。
一種理論上的機器就是單指令“如果為負,則從LOC2 jmp到LOC3的SUB LOC1”。 這是一台通用的機器,但是在您遇到第一個玩具問題后就很難編程。
有趣的是,這兩個指令集都沒有操作碼位或尋址模式位。 指令解碼器確實很簡單。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.