在米切爾的書(在編程語言概念)的6.2.1章中,提到:類型轉換在C和類型安全
類型轉換。類型轉換允許將一種類型的值用作另一種類型。特別是在C中,可以將整數轉換爲函數,從而允許跳轉到不包含正確形式的指令的位置作爲C函數。
所以我是爲使用這種非安全性,做一些不尋常的 我想是這樣的(僞代碼):
int x = 0;
print "loop";
x();
創建一個無限循環。我嘗試了改變和測試,但我無法應付這種情況。 我該如何做這樣的事情或其他一切?
在此先感謝
在米切爾的書(在編程語言概念)的6.2.1章中,提到:類型轉換在C和類型安全
類型轉換。類型轉換允許將一種類型的值用作另一種類型。特別是在C中,可以將整數轉換爲函數,從而允許跳轉到不包含正確形式的指令的位置作爲C函數。
所以我是爲使用這種非安全性,做一些不尋常的 我想是這樣的(僞代碼):
int x = 0;
print "loop";
x();
創建一個無限循環。我嘗試了改變和測試,但我無法應付這種情況。 我該如何做這樣的事情或其他一切?
在此先感謝
@Soroush,這裏是一個例子,可以幫助你更好的理解這是怎麼回事幕後:
#include <stdio.h>
int main(void)
{
printf("begin\n");
printf("loop\n");
// declare a function pointer
int (*loopPtr)();
// set the function pointer to the current function
loopPtr = main;
// skip over the first printf();
loopPtr += 22;
// call the new location
loopPtr();
}
對我來說,當clang -O0
(當然,它的工作原理,直到堆棧是編譯它工作在x86_64耗盡,因爲這是無限遞歸,每個函數調用通過棧空間咀嚼)。
我通過編譯確定了偏移量22,然後分解並從第二個printf()
的地址中減去main()
的起始地址。
首先,我編譯它:
clang -O0 test.c
然後拆開它:
otool -tv a.out
...它生產的輸出:
[...]
_main:
0000000100000ee0 pushq %rbp
0000000100000ee1 movq %rsp,%rbp
0000000100000ee4 subq $0x20,%rsp
0000000100000ee8 leaq 0x00000073(%rip),%rdi
0000000100000eef movb $0x00,%al
0000000100000ef1 callq 0x100000f40
0000000100000ef6 leaq 0x0000006c(%rip),%rdi
0000000100000efd movl %eax,0xf4(%rbp)
0000000100000f00 movb $0x00,%al
0000000100000f02 callq 0x100000f40
[...]
_main:
表示main()
的入口點函數,其首地址是0x100000ee0。第一個callq
指令對應於第一個printf()
調用,我想跳過,所以我選擇了剛纔的地址:0x100000ef6。 0x100000ef6減去0x100000ee0是十進制22。
這不是它的工作原理。
在C語言中,你可以施放一個整數值函數指針的值,然後調用這樣一個函數指針
void (*ptr)() = (void (*)())42;
ptr();
但這可能只是導致崩潰,除非你知道自己在做什麼,即你已經以某種方式知道在地址42處開始一個帶有該簽名的函數;在這個例子中有一個固定的地址可能發生在系統編程中,而在應用程序編程中這是非常罕見的。
什麼實際上發生往往比人們希望(尤其是在Windows編程)是通過圍繞鑄造一些整數函數指針(回調在LPARAM
/WPARAM
人?),然後抹上他們回到函數指針以實際使用它們。
此外,執行此類強制轉換/調用時發生的情況超出了C標準的範圍,這使得實現可以在這方面自由地執行所需操作。
那麼,x()
不會神奇地調用該地址的函數。我認爲他的意思是這樣的:
typedef void (*functionPtr)();
int x;
//...
functionPtr foo = (functionPtr)x;
//or
functionPtr goo = (functionPtr)&x;
foo();
你的書是有誤導性的。標準允許的唯一事情就是投射操作,而且只有在該值適合的情況下。在大多數情況下,執行這樣的函數指針是未定義的行爲。你必須非常瞭解你的系統才能做到這一點。所以你引用段落的第二部分:
在C特別整數可以轉換爲一個功能,允許 跳轉到一個位置不包含的 指令的正確形式爲C功能。
只是不正確的形式。特別是所有體面的現代系統都不允許你執行數據,你必須爲頁面設置特殊標誌,以便它可以被認爲包含可執行代碼。
它編譯?如果答案是「否」,我建議你刻錄這本書。 – wildplasser
沒有將對象指針轉換爲函數指針的標準符合方式。但是,可能存在特定於平臺的填充具有特定值的函數指針的方法。 –
即使您設法將代碼中該點的地址轉換爲變量,然後將其轉換爲函數,然後調用它,它也不會是無限循環,就像無限遞歸一樣。無論如何,這隻會填滿整個堆棧並崩潰。 – JasonD