【发布时间】:2021-09-10 08:55:34
【问题描述】:
您好,我遇到了一种情况,需要将参数传递给预定义的函数,如下所示:
void dojmp(args...)
{
args[0]->func(args...);
}
与其写多个跳转函数来传递不同的参数,我想用裸跳转,这样跳转后,相关的栈和寄存器数据都不会改变。像下面这样。
void __attribute__((naked)) dojmp(void)
{
__asm__ __volatile__ (
"jmp %%rax \n\t"
:
:"a"(args[0]->func)
:"memory"
);
}
而gcc编译的结果是:
<dojmp>:
mov %rdi,%rax
mov (%rax),%rax
jmpq *%rax
现在我的问题是,使用rax 作为带有void 返回函数的跳转目标(对于gcc)是否安全??
因为通常rax 会存储返回值。但是我调用的所有函数都是无效的......
在这里记住它是为了将相对地址传递给汇编代码,以防我把笔记弄乱了。
#include <stdio.h>
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
struct have_func{
int a;
void* func;
};
int main()
{
printf("hello world\n");
}
void __attribute__((naked)) dojmp(struct have_func * args)
{
asm volatile(
"jmpq *%P0(%%rdi)\n\t"
:
: "i"(offsetof(struct have_func, func))
);
}
【问题讨论】:
-
顺便说一句,
$rax是一个直接操作数,其地址是extern char rax[]或其他地址,而不是寄存器%rax。 -
您要修复标题和其他文本中的
$rax吗?尤其是在第一个代码块中,除非您确实是指$rax而不是%%rax。您在未修复的情况下进行了编辑,这很奇怪。此外,GCC 手册明确警告您的"i"(offsetof(...))不受官方支持。在那个简单的naked函数中,它在实践中可能是安全的,或者至少会以明显的方式中断,但我在更新的答案中引用了它。这就是为什么我还没有在我的回答中使用它,并建议使用 static_assert。
标签: c gcc x86-64 inline-assembly calling-convention