从内存位置调用函数指针
Calling function pointer from memory location
我正在尝试调用存储为 uint64_t 值的函数指针并传递其地址存储在 uint64_t 结构中的参数。
这是代码。
double sum(double *a, long len){
double tmp = 0;
for(size_t i=0;i<len;i++){
tmp += a[i];
}
return tmp;
}
int main(){
long size = 1000;
double *a = new double[size];
for(int i=0;i<size;i++){
a[i] = i*1.0;
}
struct __attribute__ ((aligned(16))) args_t {
double *a_func;
long len_func;
} args;
args.a_func = a;
args.len_func = size;
double ret;
uint64_t arg_ptr = reinterpret_cast<uint64_t>(&args);
uint64_t arg_size = sizeof(args);
uint64_t func_ptr = reinterpret_cast<uint64_t>(&sum);
uint64_t func_ret = reinterpret_cast<uint64_t>(&ret);
// How should I call the function with arguments passed to it and get a return value?
}
Moto: 我正在尝试构建一个库,它接受任何函数指针、它的参数和 return 它执行函数的地址和 return s 通过 return 地址的值。
谢谢! :)
试试这个。您在结构中缺少函数指针声明。
此外,您的 func_ptr 和 func_ret 电话输入不正确。我不会在 uint64_t 中保存指针类型,我建议使用 void *
,因为它是适合您的体系结构的正确长度。您绝对不应该在 uint64_t 中保存函数指针,因为标准无法保证 sizeof(funcptr) == sizeof(void *)
.
double sum( double * a, long len )
{
//...
return 0.0;
}
int main(int argc, char const *argv[])
{
long size = 1000;
double * a = new double[size];
struct args_t
{
/** you need a ptr declaration */
double (*func_hsa)(double *, long );
double * a_hsa;
long len_hsa;
} args;
args.func_hsa = sum;
args.a_hsa = a;
args.len_hsa = size;
double ret;
ret = args.func_hsa(args.a_hsa, args.len_hsa);
return 0;
}
Moto: I am trying to build a library which takes any function pointer, its arguments and return address where it executes the function and returns the value through return address.
您至少需要在运行时动态地知道被调用函数的 signature。
由于 Linux/x86-64 ABI 的各种 application binary interface (ABI) conventions dictate different and incompatible calling conventions (e.g. a double
argument is passed in floating point register, but a int
value is passed in some integer register, and this is processor & ABI specific and followed by compilers and linkers, etc...), you should use a specific library for that (which contains some processor & ABI specific assembler code). The libffi is such a library and you should use it. If you can't use it, study the ABI of your implementation, e.g. this。
I am trying to call function pointer stored as a uint64_t value and pass arguments whose address are stored in a structure of uint64_t.
你不能这样做(如果不使用 libffi ...) in a portable way (i.e. you need some processor&ABI specific code, perhaps in assembler). You are implicitly supposing that arguments are passed on some stack, or at least thru addressable memory, and this is generally wrong, and is wrong for most x86-64 systems: most arguments are often passed in processor registers 之类的东西(细节是处理器和 ABI 特定的,所以在 Windows 和 Linux 上是不同的)。
问题不在于函数指针,而是调用约定和参数传递(以及结果传递)。
顺便说一句,在 C 和 C++ 中,可转换为指针的整数类型是 intptr_t
(来自 C 中的 <stdint.h>
,来自 C++ 中的 <cstdint>
);在 ARM 和 x86 等 32 位架构上使用(并来回转换函数指针 from/to)int64_t
是不合适的。
正如我所说,如果您负担得起,使用 C++11 at least, closures (i.e. lambda functions) and std::function
非常有帮助。读
还有关于 callbacks.
另请参阅 constructing function calls 的 GCC 内置函数。
所以,
终于成功了。
double sum(double *a, long len){
double tmp = 0;
for(size_t i=0;i<len;i++){
tmp += a[i];
}
return tmp;
}
int main(){
long size = 1000;
double *a = new double[size];
for(int i=0;i<size;i++){
a[i] = i*1.0;
}
struct __attribute__ ((aligned(16))) args_t {
double *a_func;
long len_func;
} args;
args.a_func = a;
args.len_func = size;
double ret;
uint64_t arg_ptr = reinterpret_cast<uint64_t>(&args);
uint64_t arg_size = sizeof(args);
uint64_t func_ptr = reinterpret_cast<uint64_t>(&sum);
uint64_t func_ret = reinterpret_cast<uint64_t>(&ret);
// We are trying to make a generic function caller
size_t num_args = arg_size/8; // as elements of struct are 64bit long
uint64_t *varg = reinterpret_cast<uint64_t*>(arg_ptr);
switch(num_args){
case 2:
{
void* (*fun)(void*, void*) = reinterpret_cast<void* (*)(void*, void*)>(func_ptr);
uint64_t *ret_add = reinterpret_cast<uint64_t*>(func_ret);
*ret_add = reinterpret_cast<uint64_t>(fun((void*)varg[0], (void*)varg[1]));
break;
}
default:
break;
}
}
使用 switch case 不是正确的方法,但是没有更好的方法来构建展开而不使用任何包或不采用最新标准。尽管 C++14 具有将元组作为参数列表传递的功能,但并未完全实现。开关案例可以扩展到多个参数。
我正在尝试调用存储为 uint64_t 值的函数指针并传递其地址存储在 uint64_t 结构中的参数。 这是代码。
double sum(double *a, long len){
double tmp = 0;
for(size_t i=0;i<len;i++){
tmp += a[i];
}
return tmp;
}
int main(){
long size = 1000;
double *a = new double[size];
for(int i=0;i<size;i++){
a[i] = i*1.0;
}
struct __attribute__ ((aligned(16))) args_t {
double *a_func;
long len_func;
} args;
args.a_func = a;
args.len_func = size;
double ret;
uint64_t arg_ptr = reinterpret_cast<uint64_t>(&args);
uint64_t arg_size = sizeof(args);
uint64_t func_ptr = reinterpret_cast<uint64_t>(&sum);
uint64_t func_ret = reinterpret_cast<uint64_t>(&ret);
// How should I call the function with arguments passed to it and get a return value?
}
Moto: 我正在尝试构建一个库,它接受任何函数指针、它的参数和 return 它执行函数的地址和 return s 通过 return 地址的值。 谢谢! :)
试试这个。您在结构中缺少函数指针声明。
此外,您的 func_ptr 和 func_ret 电话输入不正确。我不会在 uint64_t 中保存指针类型,我建议使用 void *
,因为它是适合您的体系结构的正确长度。您绝对不应该在 uint64_t 中保存函数指针,因为标准无法保证 sizeof(funcptr) == sizeof(void *)
.
double sum( double * a, long len )
{
//...
return 0.0;
}
int main(int argc, char const *argv[])
{
long size = 1000;
double * a = new double[size];
struct args_t
{
/** you need a ptr declaration */
double (*func_hsa)(double *, long );
double * a_hsa;
long len_hsa;
} args;
args.func_hsa = sum;
args.a_hsa = a;
args.len_hsa = size;
double ret;
ret = args.func_hsa(args.a_hsa, args.len_hsa);
return 0;
}
Moto: I am trying to build a library which takes any function pointer, its arguments and return address where it executes the function and returns the value through return address.
您至少需要在运行时动态地知道被调用函数的 signature。
由于 Linux/x86-64 ABI 的各种 application binary interface (ABI) conventions dictate different and incompatible calling conventions (e.g. a double
argument is passed in floating point register, but a int
value is passed in some integer register, and this is processor & ABI specific and followed by compilers and linkers, etc...), you should use a specific library for that (which contains some processor & ABI specific assembler code). The libffi is such a library and you should use it. If you can't use it, study the ABI of your implementation, e.g. this。
I am trying to call function pointer stored as a uint64_t value and pass arguments whose address are stored in a structure of uint64_t.
你不能这样做(如果不使用 libffi ...) in a portable way (i.e. you need some processor&ABI specific code, perhaps in assembler). You are implicitly supposing that arguments are passed on some stack, or at least thru addressable memory, and this is generally wrong, and is wrong for most x86-64 systems: most arguments are often passed in processor registers 之类的东西(细节是处理器和 ABI 特定的,所以在 Windows 和 Linux 上是不同的)。
问题不在于函数指针,而是调用约定和参数传递(以及结果传递)。
顺便说一句,在 C 和 C++ 中,可转换为指针的整数类型是 intptr_t
(来自 C 中的 <stdint.h>
,来自 C++ 中的 <cstdint>
);在 ARM 和 x86 等 32 位架构上使用(并来回转换函数指针 from/to)int64_t
是不合适的。
正如我所说,如果您负担得起,使用 C++11 at least, closures (i.e. lambda functions) and std::function
非常有帮助。读
还有关于 callbacks.
另请参阅 constructing function calls 的 GCC 内置函数。
所以, 终于成功了。
double sum(double *a, long len){
double tmp = 0;
for(size_t i=0;i<len;i++){
tmp += a[i];
}
return tmp;
}
int main(){
long size = 1000;
double *a = new double[size];
for(int i=0;i<size;i++){
a[i] = i*1.0;
}
struct __attribute__ ((aligned(16))) args_t {
double *a_func;
long len_func;
} args;
args.a_func = a;
args.len_func = size;
double ret;
uint64_t arg_ptr = reinterpret_cast<uint64_t>(&args);
uint64_t arg_size = sizeof(args);
uint64_t func_ptr = reinterpret_cast<uint64_t>(&sum);
uint64_t func_ret = reinterpret_cast<uint64_t>(&ret);
// We are trying to make a generic function caller
size_t num_args = arg_size/8; // as elements of struct are 64bit long
uint64_t *varg = reinterpret_cast<uint64_t*>(arg_ptr);
switch(num_args){
case 2:
{
void* (*fun)(void*, void*) = reinterpret_cast<void* (*)(void*, void*)>(func_ptr);
uint64_t *ret_add = reinterpret_cast<uint64_t*>(func_ret);
*ret_add = reinterpret_cast<uint64_t>(fun((void*)varg[0], (void*)varg[1]));
break;
}
default:
break;
}
}
使用 switch case 不是正确的方法,但是没有更好的方法来构建展开而不使用任何包或不采用最新标准。尽管 C++14 具有将元组作为参数列表传递的功能,但并未完全实现。开关案例可以扩展到多个参数。