从全局内联汇编调用静态函数

8
我试图定义一个没有前奏/后续的函数,即“着陆地址”,以便可以调用由编译器正确管理的内部函数(对于调用者清除环境非常有用)。
我发现我可以使用内联汇编创建一个全局标签,但是我在调用同一文件中的另一个函数时遇到了问题。当我按照这里列出的代码进行编译时,我收到一个警告:
“WARNING: "handle_vmexit" [/Code/hyper/kernel/hyper.ko] undefined!”
当我去掉static修饰符时,就没有问题了。
所以我的问题是,为什么内联汇编无法与静态的handle_vmexit链接,以及如何使其调用静态的handle_vmexit。
这是相关代码:
static void handle_vmexit(void){
    ...
}

__asm__(".handle_vmexit: \n\t"
    "call handle_vmexit"
);

2
编译器可能会决定省略未使用的静态函数。你可以尝试使用__attribute__((used))。另外,将其地址作为输入传递给内联汇编也应该能够起到作用。 - Jester
你可以将.handle_vmexit设置为handle_vmexit的别名,而不是使用额外的调用来实现。或者你需要这个返回地址在堆栈上吗? - Peter Cordes
没有理由将handle_vmexit()声明为静态的。请自己开心一点,把它变成全局函数。你不需要使用__attribute__((used)),并且可以将内联汇编移动到单独的、更易于维护的汇编源文件中。 - Ross Ridge
1个回答

9
当一个C函数被声明为static时,它对其他翻译单元不可见,因此C编译器假定它可以看到其每个使用并根据该假设做出优化决策。如果该函数未被使用,则编译器可能完全不会生成代码;如果仅使用一次,则可能被内联到其唯一的调用者中,并且不会单独发出其符号(GCC选项-finline-functions-called-once),等等。即使您没有使用inline关键字,编译器甚至可以决定内联所有调用(选项-finline-functions)。

然而,GCC无法检测内联汇编中的用法;汇编代码对GCC来说是完全不透明的。要强制编译器为此函数分别发出代码,请使用__attribute__((used));该属性是专门为此目的添加的。手册 描述了该属性 如下:

used
该属性应用于函数,意味着即使函数看起来没有被引用,也必须为其生成代码。例如,当函数仅在内联汇编中引用时非常有用。

当应用于C ++类模板的成员函数时,该属性还意味着如果实例化了类本身,则会实例化该函数。


* 严格来说,即使函数的代码是单独生成的,编译器也可以完全不在生成的汇编文件中声明常规命名符号,而是像处理标签那样通过一些不透明的、人为生成的标识符引用函数。但我认为GCC永远不会利用这种自由,特别是如果应用了这里给出的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接