Чтобы ответить на ваш первый вопрос, конечно, он содержит инструкции вашей программы: вы можете выполнить только то, к чему у вас есть доступ. Чтобы попасть по адресу ваших инструкций, вы можете взять адрес функции и начать печать оттуда. Затем вы можете использовать библиотеку типа udis86 , чтобы разобрать их. Однако обратите внимание, что ваш компилятор не обязан упорядочивать функции каким-либо особым образом, поэтому начиная с main
и считывание оттуда не гарантирует получение всего, может растоптать нераспределенную память.
Чтобы получить доступ ко всему диапазону памяти команд (вы ищете сегмент .text
), вы можете найти адрес + размер в вашей операционной системе (в Linux эта информация будет в /proc/[pid]/maps
, в OS X вы можете использовать vmmap
или запросить ядро через ловушку ядра mach_vm_region()
, а затем просто прочитать память напрямую. Вы также можете использовать nm
, чтобы вывести символы вашей программы, изолировать все, что указывает на сегмент .text
(они должны быть помечены T
в выводе nm
), и вывести их. Это не очень хороший метод, так как вам придется разбирать все, чтобы определить, где они заканчиваются, в случае, если между ними есть отступы.
Доступна вся отображенная память, но не вся она будет доступна для записи (сегмент .text
не будет). Следует иметь в виду, что адреса, вероятно, не будут стабильными при вызове, если ваша операционная система реализует ASLR.
Чтобы ответить на второй вопрос, да, вы можете напечатать свой собственный стек и обозначить его с помощью сторонних библиотек, но не так, как вы пытаетесь это сделать. Стек обычно увеличивается на вниз (т. Е. Начинается с высокого адреса и перемещается к младшим адресам. В качестве упражнения для читателя разберите одну из своих функций с помощью gdb
или другого дизассемблера и посмотрите, как память в стеке становится выделяется во время пролога функции), поэтому цикл for никогда не будет работать, так как BASE
, вероятно, всегда будет больше, чем адрес sentinel
.