Какой смысл помещать переменную точно в раздел «STACK» с помощью __attribute__ ((section («STACK»))? - PullRequest
5 голосов
/ 29 марта 2012

В 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
Удалось получить информацию от автора общей библиотеки. __attribute__((section("STACK"))) был добавлен, так как ему не удалось собрать библиотеку в Solaris. Затем он нашел этот обходной путь. До обходного пути определение my_var_1 было таким:

int my_var_1 = 0;

и все было в порядке. Затем он изменил его, поскольку my_var_1 фактически требовалось только в этом переводе:

static int my_var_1 = 0;

И после этого изменения ему не удалось собрать библиотеку на Solaris. Поэтому он добавил __attribute__((section("STACK"))), и это помогло как-то.

<Ч />

Ответы [ 3 ]

5 голосов
/ 29 марта 2012

Во-первых, секция STACK не будет стеком какой-либо выполняемой задачи.

Помещение переменных, функции в отдельном разделе позволяют выбрать для них область памяти (благодаря скрипту компоновщика).В некоторых (в основном встроенных) архитектурах вы хотите поместить часто используемые данные в более быструю память.

Другое решение, некоторые сценарии пост-линковки для разработки установят для всего раздела STACK значение 1: программное обеспечение для разработки всегдасделать do_something_else().И выпущенное программное обеспечение может сохранять значение по умолчанию 0.

Другая возможность, если в разделе STACK есть другие переменные, разработчик хочет сохранить их в памяти.Все переменные в разделе STACK будут рядом друг с другом.Может быть, оптимизация кэша?

1 голос
/ 29 марта 2012

Причин может быть много, и трудно сказать без подробностей.Причины могут быть следующими:

  1. Секция, помеченная как STACK, связана во время выполнения с тесно связанной памятью с более быстрым временем доступа, чем другие ОЗУ.Имеет смысл отобразить стек в такое ОЗУ, чтобы избежать сбоев во время вызовов функций.Теперь, если у вас внезапно появилась переменная, к которой обращаются много, и вы хотите отобразить ее в ту же оперативную память с быстрым доступом, поместив ее в тот же раздел, что и стек, имеет смысл.

  2. Разделотмеченный STACK может быть сопоставлен с областью памяти, которая доступна, когда другие части памяти могут быть недоступны.Например, загрузчики должны инициировать контроллер памяти, прежде чем они смогут получить доступ к ОЗУ.Но вы действительно хотите иметь возможность писать код, который делает это на C, который требует стек.Таким образом, вы находите некоторую специальную память (например, программируете кэш данных в режиме обратной записи) и отображаете там стек, чтобы вы могли запустить код, чтобы заставить работать контроллер памяти и использовать ОЗУ.Еще раз, если у вас теперь есть глобальная переменная, к которой все еще нужно обращаться до того, как ОЗУ станет доступной, вы можете решить поместить ее в раздел STACK.

Лучший программист будетпереименовали секцию STACK во что-то другое, если она используется не только для стека.

0 голосов
/ 27 июня 2015

В некоторых операционных системах одна и та же область адресного пространства используется для стека каждого потока;когда выполнение переключается между потоками, отображение этого пространства изменяется соответственно.В таких системах каждый поток будет иметь свой собственный независимый набор любых статических переменных, расположенных в этой области адресного пространства.Размещение переменных, которые должны поддерживаться отдельно для каждого потока в таком диапазоне адресов, избавит от необходимости вручную обменивать их при каждом переключении задач.

Еще одно случайное использование для принудительного изменения переменных в области стека - это добавление часовых стеков.(переменные, которые можно периодически проверять, чтобы увидеть, не перекрывает ли их переполнение стека).

Третье использование происходит на платформах 8086 и 80286 (вероятно, не так много более поздних чипов в семействе): 8086 и 80286 ограниченыэффективный доступ к вещам в четырех сегментах без перезагрузки сегментных регистров.Если код должен выполнить что-то, эквивалентное

for (n=0; n<256; n++)
  *dest++ = xlat[*src++];

, и ни один из элементов не может быть помещен в сегмент кода, то возможность принудительно заставить один из элементов в сегменте стека может сделать код большим быстрее.Рукописный ассемблерный код необходим для достижения ускорения, но он может быть чрезвычайно масштабным (почти в два раза в некоторых реальных ситуациях, которые я делал на 8086, и, возможно, даже больше в некоторых ситуациях на 80286).

...