8

我试图了解.rdata部分与.text部分的含义。我正在尝试一个简单的程序如下

int main()
{
    const int a = 10;
    printf("%d\n", a);
    return 0;
}

当我构建和转储map文件gcc -o a.out sample.c -Wl,Map,test.map并搜索时sample.o,我发现以下分配

.text          0x0040138c       0x34 sample.o
.data          0x00402000        0x0 sample.o
.rdata         0x00403064        0x8 sample.o
.eh_frame      0x00404060       0x38 sample.o
.bss           0x00405020        0x0 sample.o

现在,如果我稍微修改我的程序以使a全局变量为

const int a = 10;
int main()
{
     printf("%d\n", a);
     return 0;
}

通过重复与上述相同的步骤,我观察到分配如下

.text          0x0040138c       0x2c sample.o
.data          0x00402000        0x0 sample.o
.rdata         0x00403064        0xc sample.o
.eh_frame      0x00404060       0x38 sample.o
.bss           0x00405020        0x0 sample.o

其中清楚地表明a被分配到.rdata部分为

.rdata         0x00403064        0xc sample.o
               0x00403064            a

从这些实验中,我了解到global const被分配到.rdata部分中,而.text部分大小已经下降。因此,我假设在第一个示例中a已分配到.text部分中。

我的问题是:

  1. const在确定变量的位置时是否考虑变量的范围.rdataor .text

  2. .text从我的实验中,我观察到变量在分配到部分时需要 8 个字节,而在部分中需要 4 个字节.rdata。造成这种差异的原因是什么?

  3. 如果局部变量过多const,则相应.text部分的大小会显着增加。在这种情况下推荐的编程实践是什么?

提前谢谢了。

4

2 回答 2

9

在第一种情况下,变量被声明为局部变量。它具有“自动”存储持续时间,这意味着它会在封闭范围结束时消失。由于其存储持续时间,它不能永久占用任何内存(无论 是否都是如此const)。因此,它通常存储在堆栈或寄存器中。

在第二种情况下,变量被声明为全局变量。它具有静态存储持续时间,因此它会在程序的生命周期内持续存在。这可以存储在许多地方,例如.data.bss.text.rdata( 或.rodata)。

.data通常用于具有一些预定义(非零)内容的可写静态数据,例如全局int foo = 42;. .bss用于初始化为零(或未初始化)的可写静态数据。rdata用于常量静态数据,如字符串和const变量。当然,这些用途都是“一般的”,并且可能因编译器而异。

那么为什么.text在第一种情况下会变大呢?这是因为编译器必须生成一些额外的指令才能加载10到堆栈或寄存器中。

于 2013-04-16T00:27:02.997 回答
2

此行为因目标而异。在第一个示例中,您认为a最终出现在.text部分中的10是(可能)最终出现在文本部分中并被加载到a堆栈中。某些具有例如 pc 相对寻址的体系结构会将此类常量放置在代码之间的某个位置。其他架构将编码10为立即寻址模式,这也会导致代码大小稍大。

在第二个示例a中,创建了一个全局变量,并将位于.data您所观察到的部分中。

因此,让我们根据上述情况回答您的问题。

  1. const在 C 中并不意味着它是一个常量(uuh??),这意味着程序员承诺不会编写它。编译器会在您执行此操作或您有执行此操作的危险时发出警告,但仍会编译。因此,您的案例之间的区别实际上a是第一个示例中的局部变量和第二个示例中的全局变量。嗯,我只是尝试公然写 a const int,它确实给出了一个错误,而不仅仅是一个警告。但是,可以const通过引用将更改它的函数来传递这样的 a。跨单元的东西甚至可能未被编译器检测到。

  2. 如果它位于该.data部分中,则它是对象的大小,在您的情况下为 4 个字节。如果10它位于代码中,无论是在常量表中还是作为立即寻址模式,那么它实际上将取决于体系结构它将变得多大以及对周围代码的影响。

  3. 如果您的代码中有许多常量并且架构支持 pc 相对寻址(如 ARM),那么它可能会将所有这些常量定位在靠近使用它们的代码的某个位置,但所有这些都在一起,所以一次跳转就足够了在它上面,或者如果有一个可以隐藏常量表的自然分支,则没有。因此,常数占用了它们需要的空间,而不是(更多)。如果它们都被实现为立即寻址,那么如果有更有效的方法以这种方式获取常量,编译器仍可能决定从中制作一个表。

于 2013-04-15T23:38:56.683 回答