Что именно происходит при компиляции с -funwind-tables?

От: https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html

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

-funwind-tables Аналогично -fexceptions, за исключением того, что он просто генерирует любые необходимые статические данные, но никак не влияет на сгенерированный код. Обычно вам не нужно включать эту опцию; вместо этого языковой процессор, который нуждается в этой обработке, включает его от вашего имени.

Может ли кто-нибудь объяснить из -funwind-tables, что это означает под "любыми необходимыми статическими данными". На какие данные они ссылаются. И почему данные должны быть сгенерированы? Что произойдет, если эти данные не генерируются? Где эти данные используются для?

И это также говорит "похоже на -fexception ". Так что я думаю, что он также генерирует информацию о раскручивании кадров. Что такое кадр для размотки информации? Кто использует информацию о кадре и как?

В некоторых сообщениях SO я читал, что программы должны компилироваться с этим флагом, чтобы _Unwind_Backtrace работал должным образом. Пожалуйста, объясните, как _Unwind_Backtrace использует информацию, генерируемую -funwind-tables.

Ответ 1

Статические данные, упомянутые для -funwind-tables представляют собой информацию о -funwind-tables фрейма, то есть данные, которые позволяют работающей программе вернуться назад к стеку вызовов функций из заданной точки выполнения. Возвращение к стеку вызовов функций означает переход из контекста выполнения вызываемой функции в контекст вызывающей стороны, то есть то, что обычно происходит, когда вы возвращаетесь из функции, за исключением того, что информация о разворачивании кадра позволяет вам делать это из произвольной точки внутри тело функции; Кроме того, вы не обязаны фактически выходить из вызываемой функции, вы можете просто "заглянуть" внутрь контекста вызывающей стороны (например, чтобы извлечь местоположение, из которого была вызвана вызываемая функция), также рекурсивно, но затем продолжить нормальный поток выполнения в вызываемая функция.

Для того, чтобы сделать это, вам нужно иметь доступ к большему количеству информации о скомпилированном коде, чем то, что строго необходимо для того, чтобы программа следовала "нормальному" потоку выполнения. Эта информация (то есть информация о разворачивании фрейма) помещается компоновщиком в специальные разделы компоновщика (например, раздел .eh_frame для платформы x86 или разделы ARM.exidx и .ARM.extab для платформы ARM), предназначенные для этой цели; эти секции компоновщика такие же, которые необходимы в таких языках, как C++ для реализации обработки исключений, когда поток выполнения может перейти от вызываемой функции к вызывающей стороне в результате создания исключения. Если вы отключите генерацию этих данных с помощью параметра -fno-unwind-tables, вы не сможете вернуться назад к стеку вызовов функций или использовать исключения C++.

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

_Unwind_Backtrace() - это функция, реализованная в базовых библиотеках GCC (точнее, в libgcc_s), которая позволяет выполнять функцию обратного вызова (предоставляется в качестве аргумента) для каждого кадра в стеке вызовов, то есть начиная с контекста функции вызывающего, переход к его вызывающий и так далее. См. Https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/baselib--unwind-backtrace.html. Опять же, эта функция, чтобы иметь возможность выполнять свои функции, должна получить доступ к информации о разворачивании фрейма из соответствующих разделов компоновщика.