C++ try/throw/catch => машинный код
Мысленно мне всегда было интересно, как try/throw/catch выглядит за кулисами, когда компиляция C++ переводит его на ассемблер. Но так как я никогда не использую это, я никогда не удосужился проверить это (некоторые люди сказали бы ленивый).
Нормальный стек используется для отслеживания try
s, или отдельный стек для каждого потока хранится только для этой цели? Является ли реализация между MSVC и g++ большой или маленькой? Пожалуйста, покажите мне немного псевдо-ассма (IA-32 тоже подойдет), поэтому мне никогда не придется проверять это самому!:)
Изменить: Теперь я получаю основы реализации MSVC по обработке IA-32. Кто-нибудь знает g++ на IA-32 или любой другой процессор в этом отношении?
6 ответов
В журнале Microsoft Journal "Under the Hood" подробно рассматривался этот вопрос еще в 1997 году:
Ускоренный курс по глубине структурной обработки исключений Win32™
Плохие реализации обработчиков исключений выдвигают некоторый блок обработчика исключений для каждого предложения try в стеке времени выполнения при вводе предложения try и извлекают его при выходе из предложения try. Местоположение, содержащее адрес самого последнего отправленного блока обработчика исключений, также сохраняется. Как правило, эти обработчики исключений связаны между собой, поэтому их можно найти по ссылкам с самых последних версий до более старых. Когда возникает исключение, обнаруживается указатель на последний обработанный блок обработчика EH, и проверяется обработка случаев EH этого предложения "try". Попадание в дело EH приводит к тому, что очистка стека происходит обратно в точку выдвинутого EH, и управление переходит в дело EH. Отсутствие попаданий в EH приводит к обнаружению следующего EH, и процесс повторяется. Windows 32-битная схема SEH является версией этого.
Это плохая реализация, потому что программа платит цену выполнения за каждое предложение try (push затем pop), даже когда исключение не происходит.
Хорошие реализации просто записывают таблицу диапазонов, в которых встречаются предложения try. Это означает, что для ввода / выхода предложения try нет никаких накладных расходов. (Мой язык программирования PARLANSE Parallell использует эту технику). Исключение ищет ПК точки исключения в таблице и передает управление EH, выбранному таблицей. Код EH сбрасывает стек соответствующим образом. Быстро и красиво. Я думаю, что Windows 64-битная EH относится к этому типу, но я не посмотрел внимательно.
Это очень ценная статья на эту тему: Как компилятор C++ реализует обработку исключений
Комитет по стандартизации C++ опубликовал технический отчет о "производительности C++", чтобы развенчать множество мифов о том, как функции C++, возможно, замедляют вас. Это также включает подробности о том, как можно реализовать обработку исключений. Проект этого технического отчета доступен бесплатно. Проверьте раздел 5.4.1. "Проблемы и методы реализации обработки исключений".
Asm из проводника компилятора Godbolt, для соглашения о вызовах System V в x86-64 с C++ABI g ++ 8.2, для функции, которая перехватывает, и функции, которая выдает.
x86-64 System V использует .eh_frame
раздел для метаданных по разложению стека, поэтому библиотечные функции-помощники исключений знают, как обходить стек и восстанавливать регистры. Это то что .cfi
Директивы делают.
Взгляните на этот документ, который довольно хорошо описывает внутреннюю структуру обработки исключений.