Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 无论如何,是否需要知道Linux符号表中的条目是函数还是变量?_C_Linux_Symbols - Fatal编程技术网

C 无论如何,是否需要知道Linux符号表中的条目是函数还是变量?

C 无论如何,是否需要知道Linux符号表中的条目是函数还是变量?,c,linux,symbols,C,Linux,Symbols,Linux命令nm可以列出符号表。然而,我不知道里面的符号类型 nm命令不区分符号是函数还是全局值 目前,我正在构建一个符号表,以启用固件中的模块支持,但如果我不知道符号是否表示功能或价值,则无法正确初始化 例如,假设我的符号表结构为: struct symtab { const char *name; void *addr; int isfunc; }; 然后我想添加一个关于“printk”的条目。我知道printk是一个函数,所以条目是{“printk”,printk,

Linux命令
nm
可以列出符号表。然而,我不知道里面的符号类型

nm
命令不区分符号是函数还是全局值

目前,我正在构建一个符号表,以启用固件中的模块支持,但如果我不知道符号是否表示功能或价值,则无法正确初始化

例如,假设我的符号表结构为:

struct symtab { 
  const char *name; 
  void *addr; 
  int isfunc; 
};
然后我想添加一个关于“printk”的条目。我知道printk是一个函数,所以条目是{“printk”,printk,1}。但是,如果我不知道这一点,并将
printk
视为一个变量,那么问题就来了。条目{“printk”,&printk,0}将导致错误

我研究了GRUB2.00的代码,发现函数原型中使用了一些标记,如“EXPORT_FUNC”或“EXPORT_VAR”(如
void EXPORT_FUNC(usb_open)(void)
),因此一些脚本可以使用这些标记生成正确的符号表

我的问题是,我当前的项目没有这些标记


有没有办法知道一个符号是否是函数

您使用的是Linux,所以您的对象文件是ELF格式的,对吗?如果是这样,请使用
objdump-t
,这样您就可以看到每个符号所在的标志和部分。手册页中描述了输出,在
-t
选项下,大约向下四分之三

例如,请考虑以下文件:

extern int reference;

int initialized_variable = 1;

static int static_initialized_variable = 2;

const int const_variable = 3;

static const int static_const_variable = 4;

int variable;

static int static_variable;

int function(void)
{
    return 5;
}

static int static_function(void)
{
    return 6;
}
在x86-64上使用gcc-4.6.3,使用gcc-c example.c编译,
objdump-t example.o

example.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 example.c
0000000000000000 l    d  .text  0000000000000000 .text
0000000000000000 l    d  .data  0000000000000000 .data
0000000000000000 l    d  .bss   0000000000000000 .bss
0000000000000004 l     O .data  0000000000000004 static_initialized_variable
0000000000000000 l    d  .rodata    0000000000000000 .rodata
0000000000000004 l     O .rodata    0000000000000004 static_const_variable
0000000000000000 l     O .bss   0000000000000004 static_variable
000000000000000b l     F .text  000000000000000b static_function
0000000000000000 l    d  .note.GNU-stack    0000000000000000 .note.GNU-stack
0000000000000000 l    d  .eh_frame  0000000000000000 .eh_frame
0000000000000000 l    d  .comment   0000000000000000 .comment
0000000000000000 g     O .data  0000000000000004 initialized_variable
0000000000000000 g     O .rodata    0000000000000004 const_variable
0000000000000004       O *COM*  0000000000000004 variable
0000000000000000 g     F .text  000000000000000b function
第二列实际上是固定宽度的七个标志字符:

                 ^^^^^^^
中的标志字符描述如下:

The flag characters are divided into 7 groups as follows:

       "l"
       "g"
       "u"
       "!" The symbol is a local (l), global (g), unique global (u),
           neither global nor local (a space) or both global and local
           (!).  A symbol can be neither local or global for a variety
           of reasons, e.g., because it is used for debugging, but it is
           probably an indication of a bug if it is ever both local and
           global.  Unique global symbols are a GNU extension to the
           standard set of ELF symbol bindings.  For such a symbol the
           dynamic linker will make sure that in the entire process
           there is just one symbol with this name and type in use.

       "w" The symbol is weak (w) or strong (a space).

       "C" The symbol denotes a constructor (C) or an ordinary symbol (a
           space).

       "W" The symbol is a warning (W) or a normal symbol (a space).  A
           warning symbol's name is a message to be displayed if the
           symbol following the warning symbol is ever referenced.

       "I"
       "i" The symbol is an indirect reference to another symbol (I), a
           function to be evaluated during reloc processing (i) or a
           normal symbol (a space).

       "d"
       "D" The symbol is a debugging symbol (d) or a dynamic symbol (D)
           or a normal symbol (a space).

       "F"
       "f"
       "O" The symbol is the name of a function (F) or a file (f) or an
           object (O) or just a normal symbol (a space).
您可以依赖于标志,也可以根据以下事实推断符号类型:代码通常位于
.text
节中,只读数据位于
.rodata
节中,初始化数据位于
.data
节中,未初始化数据位于
.bss
节中。注意,使用GCC扩展,节名可能会得到后缀;例如,要在启动时自动执行的函数(
\uuuu属性(构造函数))
)通常会在
.text.startup
部分结束。因此,对节名称进行前缀匹配,而不是精确匹配


对于自定义固件,有几种方法可用于提供模块支持。如果固件二进制文件使用ELF格式,则可以直接解析上述信息。例如,Linux内核使用这种方法。(为了好玩,可以在
/lib/modules/$(uname-r)/
中的内核
.ko
模块上尝试
objdump-t

对于微控制器来说,ELF支持是过分的。如果您希望固件能够按需加载模块,那么您仍然需要一个动态链接器(以及固件二进制文件的比ELF更简单的格式)。瓶颈通常是可用RAM的数量。如果您有很多,并且您需要固件能够在运行时加载新模块,请使用ELF


能够将工作站上的不同模块(甚至可能是静态配置数据)链接在一起,以“构造”一个完整的新固件映像,然后将该blob加载到设备上,通常效率更高。(BLB通常是一个带有CRC校验的内存映像,然后)为此,GUI应用程序用C、C++编写,或者甚至在一个更高级的可移植语言中,比如Python(它有许多ELF模块,你可以使用它)以便携的方式来完成它。一个“配置器”应用程序,如果你愿意的话。开发人员将使用普通的工具链生成ELF格式的二进制模块,最终用户可以在configurator应用程序中组合这些模块以生成固件映像。

使用readelf实用程序获取有关对象文件的所有详细信息。有关readelf
man readelf
的更多信息,请参阅符号表中关于符号的所有详细信息。

非常感谢您的回复!这对我帮助很大。非常感谢。此命令也适用:readelf-s elf文件