使用__attribute __((section(“STACK”))将变量准确地放在“STACK”部分中可能是什么意思?

时间:2012-03-29 08:32:06

标签: c linux gcc shared-libraries

In gcc doc使用section给出了一个原因。这个原因是to map to special hardware。但这似乎不是我的情况。

所以我已经完成了修改我们在项目中使用的共享库的任务。它是一个Linux库。库中有变量声明让我感到困惑。他们看起来像这样(大致):

static int my_var_1 __attribute__((section("STACK"))) = 0;

<小时/> 更新1:
 以这种方式定义了十几个变量(__attribute__((section("STACK")))


<小时/> 更新2:
my_var_1不是常数。初始化期间代码中可能会更改my_var_1

my_var_1 = atoi(getenv("MY_VAR_1") ? getenv("MY_VAR_1") : "0");

稍后在库中使用它:

inline void do_something() __attribute__((always_inline));
inline void do_something()
{
  if (my_var_1)
    do_something_else();
}


使用__attribute__((section("STACK")))可能有什么意义?我知道section告诉编译器在特定部分放置一个变量。然而,将static int准确地放在“STACK”部分可能是什么意思?

<小时/> 更新3
这些行摘自readelf -t my_lib.so

的输出
  [23] .got.plt
       PROGBITS         00000000002103f0  00000000000103f0  0
       00000000000003a8 0000000000000008  0                 8
       [0000000000000003]: WRITE, ALLOC
  [24] .data
       PROGBITS         00000000002107a0  00000000000107a0  0
       00000000000000b0 0000000000000000  0                 16
       [0000000000000003]: WRITE, ALLOC
  [25] STACK
       PROGBITS         0000000000210860  0000000000010860  0
       00000000000860e0 0000000000000000  0                 32
       [0000000000000003]: WRITE, ALLOC
  [26] .bss
       NOBITS           0000000000296940  0000000000096940  0
       0000000000000580 0000000000000000  0                 32
       [0000000000000003]: WRITE, ALLOC

<小时/> 更新4
管理以从共享库的作者获取信息。 由于他没有设法在Solaris上构建库,因此添加了__attribute__((section("STACK")))。然后他发现了这个解决方法。在解决方法之前,my_var_1的定义类似于:

int my_var_1 = 0;

一切都很好。然后他改变了它,因为my_var_1实际上只需要在这个翻译单元中使用:

static int my_var_1 = 0;

在那次改变之后,他没有设法在Solaris上构建库。所以他添加了__attribute__((section("STACK")))并且它有所帮助。


3 个答案:

答案 0 :(得分:5)

首先STACK部分不是任何正在运行的任务的堆栈。

将变量,函数放在特定的Section中允许为它们选择一个内存区域(感谢链接器脚本)。在某些(主要是嵌入式)架构中,您希望将经常访问的数据放在更快的内存中。

其他解决方案,一些开发后链接脚本会将所有STACK部分设置为1:开发软件将始终do_something_else()。发布的软件可能会保留默认值0。

另一种可能性,如果STACK部分中有其他变量,开发人员希望将它们保持在内存中。 STACK部分中的所有变量都将彼此靠近。可能是缓存优化?

答案 1 :(得分:1)

可能有很多原因,如果没有细节,很难说清楚。一些原因可能是:

  1. 标记为STACK的部分在运行时链接到紧密耦合的内存,访问时间比其他RAM快。将堆栈映射到这样的RAM以避免函数调用期间的停顿是有意义的。现在,如果你突然有一个被大量访问的变量,并且你想将它映射到相同的快速访问RAM,将它放在同一部分,因为堆栈是有意义的。

  2. 标记为STACK的部分可能会映射到内存区域,当内存的其他部分可能不可访问时。例如,引导加载程序需要先启动内存控制器才能访问RAM。但是你真的希望能够编写在C中执行该操作的代码,这需要堆栈。因此,您会找到一些特殊的内存(例如将数据缓存编程为回写模式)并将堆栈映射到那里,这样您就可以运行代码来使内存控制器工作,这样您就可以使用RAM。再一次,如果您现在碰巧有一个在RAM可用之前仍需要访问的全局变量,您可能决定将它放在STACK部分。

  3. 如果不仅仅用于堆栈,更好的程序员会将STACK部分重命名为其他部分。

答案 2 :(得分:0)

在某些操作系统中,每个线程堆栈使用相同的寻址空间区域;当执行在线程之间切换时,该空间的映射相应地改变。在这样的系统上,每个线程都有自己独立的一组位于该地址空间区域内的静态变量。将需要为每个线程单独维护的变量放在这样的地址范围内将避免需要手动将它们与每个任务切换交换。

强制变量进入堆栈区域的另一种偶然用法是添加堆栈标记(可以定期检查变量以查看堆栈溢出是否会破坏它们)。

第三种用途发生在8086和80286平台上(可能不是系列中的后续芯片):8086和80286仅限于有效访问四个段中的内容而无需重新加载段寄存器。如果代码需要做与

等效的事情
for (n=0; n<256; n++)
  *dest++ = xlat[*src++];

并且没有任何项目可以放在代码段中,能够强制其中一个项目进入堆栈段可以使代码更多更快。需要手写的汇编代码来实现加速,但它可能非常庞大(在8086我做过的一些真实情况下几乎是两倍,在80286的某些情况下甚至可能更大)。