2016-06-08 1 views
2

Используя gcc, мне нужно отслеживать существование некоторых специальных типов переменных, выделенных в различных процедурах, в качестве локальных переменных. Чтобы сделать это, я думал, чтобы сигнализировать о своем существовании во время компиляции. Поэтому мне нужно во время компиляции метод получить смещение автоматической переменной (переменной с локальной областью) относительно фрейма стека (относительно регистра rbp в архитектурах x86).Как получить смещение автоматической (локальной) переменной относительно фрейма стека (__builtin_frame_address)

Я уже в состоянии получить его следующим образом:

(char*)&a - (char*)__builtin_frame_address(0) 

проблема заключается в том, что НКУ не достаточно умна, и генерирует много инструкций для того, что должно быть просто нагрузка постоянная. Так что мне интересно, если случайно есть скрытый макрос или встроенный, который дает мне это прямо, поскольку это тоже самое простое решение.

+3

насчет старого доброго трюка - имея манекен вар первый и принимая разницу в адресах между манекеном и вашей переменной –

+0

Что ты предлагаешь похож к коду, который я включил.Дело в том, что для этого требуется указатель фрейма, который добавляет к нему известное фиксированное смещение переменной (чтобы получить его адрес), а затем вычитает указатель кадра, чтобы найти уже известное фиксированное смещение. Я думаю, что должен быть лучший способ. –

+1

Это очень опасная функция, она совершенно несовместима с оптимизатором. Это действительно нужно MCVE, но длинное представление состоит в том, что вы либо получаете много кода, потому что вы правильно отключили оптимизатор, либо ему нужно много кода, потому что оптимизатор устранил указатель на фрейм. Обязательно выполните компиляцию с -Wframe-адресом. –

ответ

5

Использование GCC, мне нужно отслеживать наличие некоторого специального вида переменных, выделенных в различных подпрограммах как локальные переменные

Просто потому, что переменная имеет автоматическое хранение не означает, что она будет существовать на стек. Компилятор может просто вставить его в регистр в зависимости от того, как он используется.

Так что во время компиляции мне нужен метод получения смещения автоматической переменной (переменной с локальной областью) относительно фрейма стека (относительно регистра rbp в архитектурах x86).

Это не имеет никакого смысла. Фрейм стека не существует во время компиляции. Что произойдет, если компилятор решит встроить вашу функцию? Где кадр стека времени компиляции?

Я уже в состоянии получить его следующим образом:

(char*)&a - (char*)__builtin_frame_address(0) 

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

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

Это потому, что это не постоянная. Рамка стека - не BSS. Адреса не могут быть рассчитаны во время соединения. Опять же, inliner полностью нарушает ваши предубеждения относительно того, что представляет собой стек стека. Вы можете прочитать the docs по телефону __builtin_return_address.


Самым простым решением является тот, который предложил Северин Pappadeux:

void foo() { 
    int base = 0; 
    // do stuff 
    float my_special_var = 42.0f; 
    std::ptrdiff_t special_var_offset = reinterpret_cast<char*>(&base) - reinterpret_cast<char*>(&my_special_var); 
    std::cout << special_var_offset << std::endl; 
} 
+0

a) Когда я получаю адрес переменной (как в случае с указанным кодом), компилятор обязан хранить его в адресе, доступном для местоположения, или, по крайней мере, вести себя так, как если бы он был. б) Что касается вложения, действительно, компилятор может выбрать встроенный. Мне это удалось, используя __attribute __ ((noinline)). –

+0

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

+0

Что касается вашей фразы «Фрейм стека - это не BSS. Адреса не могут быть рассчитаны во время связи». Я думаю, что это неверно, потому что если адрес переменной не вычисляется во время компиляции, почему компилятор способен скомпилировать правильные инструкции, ссылаясь на переменные как места с фиксированным смещением от базового указателя? (или, по крайней мере, как перемещение смещений из SP, если базовый указатель не используется). –

Смежные вопросы