Определение того, принадлежит ли адрес куче, стеку или регистрам

У меня есть указатель на переменную C/C++. Можно ли точно определить, какому сегменту памяти принадлежит эта переменная? Если да, то как?

Примечание. У меня есть только адрес этой переменной, никакой дополнительной информации, является ли переменная локальной/глобальной и т. д.


person Amit Tomar    schedule 06.08.2012    source источник
comment
Невозможно, по крайней мере, переносным способом.   -  person juanchopanza    schedule 06.08.2012
comment
Какую проблему ты пытаешься решить? Вам нужно решение времени выполнения или времени компиляции? регистры не имеют адресов.   -  person Maksim Burnin    schedule 06.08.2012
comment
У нас только что был спор о том, будет ли глобальная переменная принадлежать стеку или куче, мы хотели подтвердить это сами: P   -  person Amit Tomar    schedule 06.08.2012
comment
@Amit - Чтобы ответить на реальный вопрос: глобальные переменные являются отдельными, а не стеком и не кучей.   -  person Bo Persson    schedule 06.08.2012
comment
@BradTilley: не указано, использует ли статическое хранилище кучу, и Undefined Behavior, если вы полагались на него в любом случае. Статическое хранилище не может использовать стек, потому что последний навязывает семантику порядка уничтожения, которая несовместима с первой. Куча, однако, не накладывает таких ограничений и поэтому может лежать в основе как статического хранилища, так и стека.   -  person MSalters    schedule 06.08.2012
comment
Спасибо @BoPersson и Максиму. Надо узнать что-то новое :-)   -  person Amit Tomar    schedule 08.08.2012


Ответы (4)


Узнайте, есть ли в вашей архитектуре указатели на область кучи или стека. Обычно есть несколько указателей стека или указателей фрейма.

Затем сравните свой фактический адрес с этими адресами и решите, где они принадлежат.

person duedl0r    schedule 06.08.2012
comment
хе-хе, да, ты прав ;) Но если говорить об экзотических архитектурах, глобальные переменные также можно помещать в стек или кучу. Это также зависит от архитектуры. - person duedl0r; 06.08.2012
comment
Я упоминал, что у оборудования Univac также не было стека? .-) - person Bo Persson; 06.08.2012
comment
Я верю только в то, что изобретено после 1981 года, хе-хе-хе :D - person duedl0r; 06.08.2012
comment
@BoPersson: Только если стопки перфокарт не считаются :P - person Damon; 06.08.2012

Если вы используете Linux (не уверен насчет других Unices), вы можете найти информацию в файле /proc/<pid>/maps

person doron    schedule 06.08.2012

Сначала вы можете определить, что является началом и концом различных разделов в вашем исполняемом файле. Для этого вам нужно в конце концов добавить некоторые переменные в скрипт компоновщика вокруг каждого раздела, например:

SECTIONS {
    [...]
    .data : {
        data_start = .;
        *(.data)
        data_end = .;
    }
    [...]
}

Затем вы можете объявить эти переменные как внешние в своем коде C/C++ и использовать их напрямую для сравнения адреса, который вы хотите идентифицировать.

Может быть непросто настроить скрипт компоновщика. С gcc вы можете сбросить его с помощью:

gcc -Wl,-verbose whatever.c

затем попытайтесь найти переменные, уже определенные в (беспорядочном) выводе.

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

Наконец, для кучи у меня нет хитрости. Я бы просто предположил, что переменная не в data/bss/derivated и не в стеке будет в куче (исключая регистры, но если вы можете получить адрес, я бы поспорил, что компилятор никогда не будет использовать хранилище только для регистров ).

person calandoa    schedule 06.08.2012

Я точно не знаю, подходит ли это к вашей ситуации, но вы можете попробовать objdump -t посмотреть таблицу символов файла elf. Все, что вам нужно, это адрес вашей переменной. Там вы можете найти флаги, которые показывают раздел для каждой переменной. Дополнительные сведения см. на справочной странице objdump.

Пример вывода:

0804a020 g     O .bss   00000004              var

Он говорит, что var является gлобальным Oобъектом по адресу 0804a020, раздел .bss

person Rsh    schedule 06.08.2012