获取C(gcc)中当前函数的指针?

Get a pointer to the current function in C (gcc)?

gcc中是否有一个保存当前函数指针的魔力变量?

我想要一种表,其中为每个函数指针包含一组信息。

我知道有一个变量包含当前函数的名称作为字符串,而不是作为函数指针。

这不是调用函数,而是用作索引。

编辑基本上,我想做的是能够在当前函数执行之前运行嵌套函数(同时捕获返回以执行某些操作)。基本上,这就像uucyg_profile_func_enter和ucyg_profile_func_exit(仪器功能)。但问题是这些工具函数是全局的,而不是专用的函数。

编辑在Linux内核中,您可以使用include/linux/kallsyms.h中的unsigned long kallsyms_lookup_name(const char *name)…注意,必须激活CONFIG_KALLSYMS选项。


1
2
3
void f() {
   void (*fpointer)() = &f;
}


1
#define FUNC_ADDR (dlsym(dlopen(NULL, RTLD_NOW), __func__))

像这样编译你的程序

1
gcc -rdynamic -o foo foo.c -ldl


我认为您可以使用字符串(函数名)作为键来构建表,然后通过与__func__内置变量进行比较来查找。

要强制使用有效的函数名,可以使用获取函数指针的宏,对其执行一些虚拟操作(例如,将其分配给兼容的函数类型临时变量),以检查它是否确实是有效的函数标识符,然后在用作键之前对函数名进行字符串化(使用)。

更新:

我的意思是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
typedef struct {
  char[MAX_FUNC_NAME_LENGTH] func_name;
  //rest of the info here
} func_info;

func_info table[N_FUNCS];

#define CHECK_AND_GET_FUNC_NAME(f) ({void (*tmp)(int); tmp = f; #f})

void fill_it()
{
  int i = -1;
  strcpy(table[++i].func_name, CHECK_AND_GET_FUNC_NAME(foo));
  strcpy(table[++i].func_name, CHECK_AND_GET_FUNC_NAME(bar));
  //fill the rest
}

void lookup(char *name) {
  int i = -1;
  while(strcmp(name, table[++i]));
  //now i points to your entry, do whatever you need
}

void foo(int arg) {
  lookup(__func__);
  //do something
}

void bar(int arg) {
  lookup(__func__);
  //do something
}

(代码可能需要一些修改,我没有试图编译它,只是为了说明这个想法)


这是一个获取调用者地址的技巧,它可能会被清除一点。依赖GCC扩展来获取标签的值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>

#define MKLABEL2(x) label ## x
#define MKLABEL(x) MKLABEL2(x)
#define CALLFOO do { MKLABEL(__LINE__): foo(&&MKLABEL(__LINE__));} while(0)

void foo(void *addr)
{
    printf("Caller address %p
"
, addr);
}

int main(int argc, char **argv)
{
    CALLFOO;
    return 0;
}


如果你选择C++,下面的信息可能会帮助你:

对象被类型化,函数被包装为对象,rtti允许在运行时标识类型。

函数会带来运行时开销,如果这对您来说是个问题,我建议使用代码生成或利用函数的OO继承性对知识进行硬编码。


埃多克斯1〔5〕

__FUNCTION__将存储在二进制文件的文本段中,指针始终是唯一有效的。


如果您想生成代码,我建议您从IMATIX中修改GSLGen。它使用XML来构建代码模型,然后使用一种简单的类似于PHP的自顶向下生成语言来输出代码——它被用来生成C代码。

我个人一直在玩弄Lua来生成代码。


您可以使用setjmp()捕获此信息。由于它保存了足够的信息以返回到当前函数,因此必须在提供的jmp_buf中包含这些信息。

这个结构是高度不可移植的,但是您明确地提到了GCC,所以这可能不是一个阻塞问题。请参阅这个gcc/x86示例,了解它的大致工作原理。


如果你想用一种"通用"的方式来做这件事,那么你应该使用你已经提到过的设施(__cyg_profile_func*),因为这正是它们的设计目的。其他任何事情都必须像你的个人资料一样特别。

老实说,用常规方法(使用过滤器)进行操作可能比您将要即时插入的任何新方法都不容易出错。


不,函数本身不知道。您必须构建您正在谈论自己的表,然后如果您想要一个函数了解它自己,您必须将索引作为参数传递到全局表(或函数的指针)中。

注意:如果您想这样做,您应该有一个一致的参数命名方案。


如果可移植性不是一个问题,另一个选择是调整gcc源代码…有志愿者吗?!


如果您所需要的只是每个函数的唯一标识符,那么在每个函数的开头,请将其放在:

1
static const void * const cookie = &cookie;

然后保证EDOCX1的值(0)是唯一标识该函数的值。