Пытаясь создать свою собственную не-GNU кроссплатформенную среду C ++, я столкнулся с тем фактом, что я не совсем понимаю основы раскрутки стека. Среда, которую я создаю, выглядит следующим образом:
libc++
← libc++abi
← libunwind
(или какой-то другой раскручивать).
Я нашел это libc++abi
уже содержит какой-то libunwind, но не использует его в Linux. Из комментариев я понял, что это специальный libunwind: LLVM Stack Unwinder, который поддерживает только Darwin и ARM, но не x86_64 — и это сбивает с толку. Как получилось, что архитектура процессора влияет на процесс раскручивания стека?
Также я знаю о следующих разматывателях стека:
Я ожидаю получить ответ, который охватывает эту тему в целом, а не только отдельные вопросы по каждому вопросу.
По сути, компоновка стека зависит от компилятора. Он может выложить стек практически любым удобным для него способом. Стандарт языка ничего не говорит о том, как устроен стек.
На практике разные компиляторы размещают стек по-разному, и один и тот же компилятор может также размещать его по-разному при запуске с разными параметрами. Расположение стека будет зависеть от размера типов на целевой платформе (особенно от размера типов указателей), таких опций компилятора, как GCC -fomit-frame-pointer
Требования ABI платформы (например, x64 имеет определенный ABI, а x86 — нет). Способ интерпретации стека также будет зависеть от того, как компилятор хранит соответствующую информацию. Это, в свою очередь, частично зависит от формата исполняемого файла (в наши дни это может быть либо ELF, либо COFF, но на самом деле, пока ОС может загрузить исполняемый файл и найти точку входа, все остальное в значительной степени готово к захвату) и частично на отладке. формат информации — опять же специфичный для используемой комбинации компилятор / отладчик. В конце концов, вполне возможно написать встроенный ассемблер, который управляет стеком и потоком программы таким образом, чтобы нет Размотчик сможет следить. Некоторые компиляторы также позволяют настраивать пролог и эпилог функции, предоставляя вам еще одну возможность запутать любой алгоритм раскрутки.
Общий эффект всего этого заключается в том, что невозможно написать единственный алгоритм раскрутки стека, который будет работать везде. Алгоритм раскручивания должен соответствовать компилятору, ОС и, для большей информации, отладчику. Лучшее, что вы можете сделать, — это написать простой интерфейс для разворачивания стека и реализовать его по-разному для каждой поддерживаемой вами комбинации компилятор / ОС / отладчик.