【发布时间】:2016-06-21 22:13:44
【问题描述】:
今天,我在汇编代码中使用递增函数指针来创建函数的备用入口点:
.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 不允许你增加函数指针,但是还有其他方法可以实现这种事情吗?
【问题讨论】:
-
一般是不行的,因为跳过函数序言会导致各种问题。在更高级别的语言中(甚至在 asm 中),您应该将其拆分为两个单独的函数,一个调用另一个函数,让编译器选择最佳实现。
-
我相信旧版 FORTRAN 支持一个函数的多个入口点,快速谷歌搜索会产生 gcc.gnu.org/onlinedocs/gcc-3.4.4/g77/… 和 docs.oracle.com/cd/E19957-01/805-4939/6j4m0vn99/index.html
-
实际的问题是为什么你想这样做?这是维护的噩梦。如果达到优化:> 99% 的程序不需要这个。其余部分通常可以由编译器优化,并且结构比这种 70/80ies BASIC hacks 好得多。
-
您可以使用不添加中断的 switch() 语句来创建一个在函数中模拟这一点的贯穿表。谷歌“达夫的设备”为什么有人可能想做这样愚蠢的事情:)
-
我刚刚在 FORTRAN 上遇到了一些关于“单进单出”的讨论:programmers.stackexchange.com/a/118793/3601
标签: c assembly function-pointers