c语言 - 'nm' 报告相同类型的变量的不同大小。我如何找出它们的真实大小?



我试图找出我的程序中使用nm变量的地址和大小,我刚刚意识到我的一大堆变量出乎意料地大。我创建了一个测试文件"test.c":

static char test1 = 0;
static char test2 = 0;
char test_f(void)
{
test1 = test2;
return test2;
}
int main(void)
{
return test_f();
}

然后运行以下命令:

gcc test.c
nm -C -S --size-sort a.exe | findstr /rc:"test"

输出为

0000000140007040 0000000000000001 b test1
0000000140007041 000000000000000f b test2
0000000140001540 000000000000001a T test_f

我假设某种填充/对齐在这里起作用,但我不明白为什么填充成为符号的一部分。是否有一种方法来产生一个类似的文本日志,其中test1test2都有1的大小?

…我不明白为什么填充符会成为符号的一部分。

nm手册页说:"大小计算为符号值与下一个高值的符号值之间的差值。"因此,如果在变量A之后和变量B之前有填充,则填充将作为A大小的一部分出现。

在您的示例中,test1显然紧随test2之后,因此test1的大小被计算为一个字节。test2的程序段后面没有任何显式符号;nm使用的下一个"符号"可能是下一节的开始或其中的第一个符号。下一节有一些对齐要求,所以在test2之后和下一节之前有未使用的空间,也称为填充。所以test2和下一个"符号"之间的差异包括填充,它显示在test2的"大小"中,如手册页所述。

我不明白为什么填充符会成为符号的一部分

根据手册页:https://man7.org/linux/man-pages/man1/nm.1.html

ELF格式记录符号的大小,其他格式(如EXE)将只报告大小为从这个符号开始到下一个符号开始的间隔。

是否有一种方法可以生成一个类似的文本日志,其中test1和test2都是1的大小吗?

在使用ELF二进制文件的Linux中执行相同的步骤。

0000000000004011 0000000000000001 b test1
0000000000004012 0000000000000001 b test2

最后,如果没有调试信息,似乎没有办法知道PE中的符号大小。使用调试信息,可以使用objdump -W a.exe提取它,然后使用DW_AT_type查找符号类型,然后使用DW_AT_byte_size查找该类型的大小:

<1><28ce>: Abbrev Number: 2 (DW_TAG_variable)
<28cf>   DW_AT_name        : test1
<28d5>   DW_AT_decl_file   : 1
<28d6>   DW_AT_decl_line   : 3
<28d7>   DW_AT_decl_column : 13
<28d8>   DW_AT_type        : <0x28e6>
<28dc>   DW_AT_location    : 9 byte block: 3 40 70 0 40 1 0 0 0     (DW_OP_addr: 140007040)
<1><28e6>: Abbrev Number: 3 (DW_TAG_base_type)
<28e7>   DW_AT_byte_size   : 1
<28e8>   DW_AT_encoding    : 6  (signed char)
<28e9>   DW_AT_name        : char
<1><28ee>: Abbrev Number: 2 (DW_TAG_variable)
<28ef>   DW_AT_name        : test2
<28f5>   DW_AT_decl_file   : 1
<28f6>   DW_AT_decl_line   : 4
<28f7>   DW_AT_decl_column : 13
<28f8>   DW_AT_type        : <0x28e6>
<28fc>   DW_AT_location    : 9 byte block: 3 41 70 0 40 1 0 0 0     (DW_OP_addr: 140007041)

最新更新