我正在尝试创建一个包含自定义序言/尾声的类,该类应由其他“消费者”类的方法使用。
它应该类似于以下示例。 (请记住,这些示例序言/尾声主体只是用于说明目的的占位符。当然,它们将以纯汇编形式编写)
class foo
{
public:
static inline void prologue(void) __attribute__ ((always_inline))
{
asm("nop");
}
static inline void epilogue(void) __attribute__ ((always_inline))
{
asm("nop");
}
};
现在,在包含使用这些自定义序言/尾声的方法的“消费者”类中,我使用如下所示的 bare 属性。 (请记住,此示例方法主体结构才是最重要的。应在序言/尾声之间放置更多代码,但对于此说明来说不是必需的)
class bar
{
public:
static void method() __attribute__ ((naked))
{
foo::prologue();
//more cpp instructions shall go here
foo::epilogue();
}
};
我面临的问题是 clang 编译器不允许在裸函数中调用像
foo::prologue()
这样的标准 Cpp 代码,并返回以下错误
<source>:23:9: error: non-ASM statement in naked function is not supported
23 | foo::prologue();
| ^
有趣的是,GCC 似乎允许这样做。
我错过了什么吗?有没有其他优雅的方法来做到这一点?
godbolt 测试可以在这里找到:https://godbolt.org/z/YfnvfEM3f
本质上,naked函数不允许使用C++语句,因为你没有任何堆栈、寄存器或地址的设置。
作为解决方法,您可以将函数作为 ARM 指令的 extern C 符号调用,您可以将其传递到裸函数的 ASM.inside 中。
class foo {
public:
static inline void prologue(void) __attribute__((always_inline)) {
asm("nop");
}
static inline void epilogue(void) __attribute__((always_inline)) {
asm("nop");
}
};
extern "C" void foo_prologue_wrapper() {
foo::prologue();
}
extern "C" void foo_epilogue_wrapper() {
foo::epilogue();
}
extern "C" void foo_otherfunctioncall(){
//code the rest here
return;
}
class bar {
public:
static void method() __attribute__((naked)) {
asm volatile(
"bl foo_prologue_wrapper\n"
"bl foo_otherfunctioncall\n"
"bl foo_epilogue_wrapper\n"
"ret\n"
);
}
};
int main(void) {
bar::method();
return 0;
}
有了这个,你应该能够在“foo_otherfunctioncall”函数中访问你的C++。
#include <vector>
extern "C" void foo_otherfunctioncall(){
std::vector<int> a;
return;
}
它确实编译成这样:
foo_prologue_wrapper:
nop
ret
foo_epilogue_wrapper:
nop
ret
foo_otherfunctioncall:
sub sp, sp, #48
stp x29, x30, [sp, #32]
add x29, sp, #32
add x0, sp, #8
str x0, [sp]
bl std::vector<int, std::allocator<int>>::vector() [base object constructor]
ldr x0, [sp]
bl std::vector<int, std::allocator<int>>::~vector() [base object destructor]
ldp x29, x30, [sp, #32]
add sp, sp, #48
ret
main:
sub sp, sp, #32
stp x29, x30, [sp, #16]
add x29, sp, #16
mov w8, wzr
str w8, [sp, #8]
stur wzr, [x29, #-4]
bl bar::method()
ldr w0, [sp, #8]
ldp x29, x30, [sp, #16]
add sp, sp, #32
ret
bar::method():
bl foo_prologue_wrapper
bl foo_otherfunctioncall
bl foo_epilogue_wrapper
ret
__clang_call_terminate:
stp x29, x30, [sp, #-16]!
mov x29, sp
bl __cxa_begin_catch
bl std::terminate()
DW.ref.__gxx_personality_v0:
.xword __gxx_personality_v0