[英]Is there any operation in C analogous to this assembly code?
今天,我在匯編代碼中使用遞增的函數指針來創建函數的備用入口點:
.386
.MODEL FLAT, C
.DATA
INCLUDELIB MSVCRT
EXTRN puts:PROC
HLO DB "Hello!", 0
WLD DB "World!", 0
.CODE
dentry PROC
push offset HLO
call puts
add esp, 4
push offset WLD
call puts
add esp, 4
ret
dentry ENDP
main PROC
lea edx, offset dentry
call edx
lea edx, offset dentry
add edx, 13
call edx
ret
main ENDP
END
(我知道,從技術上講,此代碼無效,因為它在未初始化CRT的情況下調用puts
,但至少在MSVC 2010 SP1上,它沒有任何匯編或運行時錯誤,但可以正常工作。)
請注意,在第二次調用dentry
的過程中,像以前一樣,我將函數的地址保存在edx
寄存器中,但是這次我在調用函數之前將其地址增加了13個字節。
因此,該程序的輸出為:
C:\Temp>dblentry
Hello!
World!
World!
C:\Temp>
“ Hello!\\nWorld!
”的第一個輸出是從調用到函數的最開始,而第二個輸出是從以“ push offset WLD
”指令開始的調用。
我想知道這種語言是否存在於要比C,Pascal或FORTRAN之類的匯編程序更高級的語言中。 我知道C不允許您增加函數指針,但是還有其他方法可以實現這種功能嗎?
您可以使用longjmp函數: http ://www.cplusplus.com/reference/csetjmp/longjmp/
這是一個非常可怕的功能,但是它將滿足您的要求。
AFAIK,您只能在asm中編寫具有多個入口點的函數。
您可以在所有入口點上放置標簽,因此可以使用常規的直接調用,而不用硬編碼與第一個函數名稱的偏移量。
這使得從C或任何其他語言正常調用它們變得容易。
如果您擔心使功能主體重疊的工具(或人員)混亂,則較早的入口點的工作方式就像插入其他功能主體的功能一樣。
如果早期的入口點做了一點點額外的工作,然后落入主函數中,則可以執行此操作。 這主要是一種節省代碼大小的技術(這可能會提高I-cache / uop-cache命中率)。
編譯器傾向於在函數之間復制代碼,而不是在稍有不同的函數之間共享大量的公共實現。
但是,您可能只用一個額外的jmp
就可以完成它,例如:
int foo(int a) { return bigfunc(a + 1); }
int bar(int a) { return bigfunc(a + 2); }
int bigfunc(int x) { /* a lot of code */ }
在Godbolt編譯器瀏覽器上查看真實示例
foo
和bar
bigfunc
,這比讓bar
掉進bigfunc
。 (將foo
跳過bar
進入bigfunc
還是不錯的,尤其是如果bar
不是那么簡單的話。)
一般而言,跳入函數中間並不安全,因為非平凡的函數通常需要保存/恢復某些注冊表。 因此,序言推動了它們,而序言使它們流行了。 如果您跳入中間位置,則序幕中的pop
將使堆棧不平衡。 (即,將返回地址彈出到寄存器中,然后返回到垃圾地址)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.