[英]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.