Вывести значение указателя стека

Как распечатать текущее значение в указателе стека в C в Linux (Debian и Ubuntu)?

Я попробовал google, но не нашел никаких результатов.

Ответ 1

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

void print_stack_pointer() {
  void* p = NULL;
  printf("%p", (void*)&p);
}

Это будет по существу печатать адрес p, который является хорошим приближением текущего указателя стека

Ответ 2

Нет портативного способа сделать это.

В GNU C это может работать для целевых ISA, имеющих регистр с именем SP, включая x86, где gcc распознает "SP" как сокращение от ESP или RSP.

// broken with clang, but usually works with GCC
register void *sp asm ("sp");
printf("%p", sp);

Такое использование локальных переменных регистра теперь не рекомендуется GCC:

Единственное поддерживаемое использование этой функции - указание регистров для операндов ввода и вывода при вызове Extended asm.

Определение переменной регистра не резервирует регистр. За исключением случаев, когда вызывается Extended asm, содержимое указанного регистра не гарантируется. По этой причине следующее использование явно не поддерживается. Если они работают, это всего лишь случайность, и она может перестать работать, как задумано, из-за (казалось бы) несвязанных изменений в окружающем коде или даже незначительных изменений в оптимизации будущей версии gcc....

На практике это также не работает с clang, где sp обрабатывается как любая другая неинициализированная переменная.

Ответ 3

В дополнение к duedl0r answer с помощью специально GCC вы можете использовать __builtin_frame_address(0), который специфичен для GCC (но не для x86).

Это также должно работать на Clang (но есть некоторые bugs об этом).

Принимая адрес локального (как JaredPar ответил), также является решением.

Обратите внимание, что в стандарте AFAIK C не требуется никакого стека вызовов в теории.

Помните бумагу с надписью: сбор мусора может быть быстрее, чем распределение стека; Очень странная реализация C могла использовать такую ​​технику! Но AFAIK он никогда не использовался для C.

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

Ответ 4

В Linux вы можете использовать псевдофайловую систему proc для печати указателя стека.

Загляните сюда, в псевдофайл /proc/your-pid/stat, в поля 28, 29.

starttack% lu Адрес начала (т.е. дна) стека.

kstkesp% lu Текущее значение ESP (указатель стека), найденное на странице стека ядра для процесса.

Вам просто нужно разобрать эти два значения!

Ответ 5

u также может использовать расширенную инструкцию ассемблера, например

#include <stdint.h>

uint64_t getsp( void )
{
    uint64_t sp;
    asm( "mov %%rsp, %0" : "=rm" ( sp ));
    return sp;
}

для 32-битной системы 64 необходимо заменить 32 и rsp с помощью esp

Ответ 6

Эта информация хранится в файле /proc/<your-process-id>/maps, в той же строке, что и строка [stack] (так что она не зависит от компилятора или машины). Единственным недостатком этого подхода является то, что для чтения этого файла он должен быть root.