繁体   English   中英

C中是否有任何类似于此汇编代码的操作?

[英]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编译器浏览器上查看真实示例

foobar bigfunc ,这比让bar掉进bigfunc (将foo跳过bar进入bigfunc还是不错的,尤其是如果bar不是那么简单的话。)


一般而言,跳入函数中间并不安全,因为非平凡的函数通常需要保存/恢复某些注册表。 因此,序言推动了它们,而序言使它们流行了。 如果您跳入中间位置,则序幕中的pop将使堆栈不平衡。 (即,将返回地址弹出到寄存器中,然后返回到垃圾地址)。

另请参见在入口点标签前使用说明的功能是否会引起任何问题(链接)?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM