MS link создает дубликаты функций
От: gear nuke  
Дата: 12.11.09 16:22
Оценка:
Есть специфичный для windows код (устанавливает Structured Exception Handler для треда и вызывает произвольную функцию).

struct cxxrecord
{
    static
      exception_disposition __cdecl catchguardhandler();

#pragma warning(disable:4733)//Inline asm assigning to 'FS:0' : handler not registered as safe handler
    generic_function_t *
      callcatchblockhelper(
      cxxregistration *     const cxxreg)
    {
      volatile catchguard guard;
      guard.next        = nt::teb::get(&nt::teb::ExceptionList);
      guard.handler     = catchguardhandler;
      nt::teb::set(&nt::teb::ExceptionList, &guard);
      generic_function_t * const continuation = cxxreg->callsettingframe(); // может сгенерировать исключение
      nt::teb::set(&nt::teb::ExceptionList, guard.next);
      return continuation;
    }
    
};
Смысл его не особо важен, код рабочий.

Если исполняемый файл собирается с ключем /SAFESEH, то линкер добавляет в него таблицу с safe exception handlers. В неё помещаюся адреса обработчиков для catch и __except. Поскольку выше хендлер устанавливается вручную, приходится добавлять адрес обработчика в таблицу самостоятельно, что делается компиляцией и линковкой такого asm файла:
?catchguardhandler@cxxrecord@cxxruntime@ntl@@SA?AW4disposition@exception@nt@3@PAUrecord@563@PAUregistration@563@PAUcontext@63@PAUdispatcher_context@563@@Z PROTO SYSCALL
.safeseh ?catchguardhandler@cxxrecord@cxxruntime@ntl@@SA?AW4disposition@exception@nt@3@PAUrecord@563@PAUregistration@563@PAUcontext@63@PAUdispatcher_context@563@@Z

Это всё тоже раболтает без проблем.


Проблемы начинаются, если линкеру указать /OPT:NOICF.

В этом случае в таблицу safeseh помещается реальный адрес catchguardhandler,
однако, код
guard.handler     = catchguardhandler;
помещает в guard.handler адрес переходника
jmp catchguardhandler

Соответственно, если при вызове callsettingframe() происходит исключение, диспетчер исключений ОС не находит адрес этого thunk в таблице безопасных обработчиков, и не вызывает его.

Анализ показал, что в объектниках тело catchguardhandler находится всего один раз. Советы делать это свободными функциями, переносить в cpp можно не предлагать — пробовали, не помогает.

Переходник генерируется именно линкером, насколько я понимаю, нужны они для поддержки Edit&Continue. Само Edit&Continue несовместимо с /SAFESEH и отключает его. Однако переходники продолжают генерироваться пока не укажешь /OPT:ICF.

Собственно вопрос, зачем это делает линкер? Версии самые разные, по 2010beta2. Сами Microsoft похоже знают об этой проблеме, поскольку они реализовали вышеприведённые функции на ассемблере. Такой workarround мне не нравится, поскольку неясно, где ещё может всплыть проблема из-за подобных дубликатов (а их море — размер бинарника попросту удваивается). Понятно, что в релизном билде проблемы быть не должно, не понятно, что делать с отладочными.
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re: MS link создает дубликаты функций
От: byleas  
Дата: 12.11.09 16:28
Оценка:
Не совсем дубликаты функций — речь идёт о переходниках на них.

В общем, уточню вопрос: можно ли пометить произвользую функцию в С++, чтобы на неё не генерировался переходник? Либо получить средствами языка адрес реальной функции.

Собственно, ответы есть, но не совсем подходящие:
1) переходник не генерируется на свободную статическую функцию (но её тогда нельзя пометить для SAFESEH);
2) адрес реальной функции таки можно получить с помощью хака — дизасмом адреса переходника и вычислением реального адреса.
Re: MS link создает дубликаты функций
От: Кодт Россия  
Дата: 13.11.09 12:04
Оценка:
Наивный вопрос: а зачем реализовывать __try-__except вручную?
Казалось бы
generic_function_t* callandcatchblockhelper(cxxregistration* cxxreg)
{
    __try
    {
        return cxxreg->callsettingframe();
    }
    __except(EXCEPTION_EXECUTE_HANDLER) // ну или более изощрённую логику фильтрования...
    {
        catchguardhandler();
        return 0; // если возникло исключение, cxxreg->callsettingframe() всяко вернул мусор. облагородим его!
    }
}
... << RSDN@Home 1.2.0 alpha 4 rev. 1237>>
Перекуём баги на фичи!
Re[2]: MS link создает дубликаты функций
От: byleas  
Дата: 15.11.09 10:52
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Наивный вопрос: а зачем реализовывать __try-__except вручную?

Не __try/__except, а try/catch. А вручную потому, что из-под SEH не получить доступа к информации о С++ исключении (в х86).
Re[3]: MS link создает дубликаты функций
От: Кодт Россия  
Дата: 15.11.09 19:58
Оценка:
Здравствуйте, byleas, Вы писали:

B>Не __try/__except, а try/catch. А вручную потому, что из-под SEH не получить доступа к информации о С++ исключении (в х86).


Синтаксис запрещает мешать в одной функции блоки try/catch и __try/__except, но можно сделать вложенный вызов.
void* sehsafe()
{
  __try { return cppsafe(); } __except( sehfiter() ) { sehhandler(); return 0; }
}

void* cppsafe()
{
  try { unsafe(); } catch(...) { cpphandler(); return 0; }
}

где
— sehfilter() проверяет код и информацию SEH-исключения и возвращает EXCEPTION_EXECUTE_HANDLER либо (видимо, тебе это не надо) EXCEPTION_CONTINUE_SEARCH;
— sehhandler() делает что-то полезное наподобие записи в журнал
— cpphandler() может техникой try{throw;}catch/catch/catch уточнить тип исключения и сделать что-то полезное по каждому типу самостоятельно

Кстати! Может быть, тебе вообще необходимо было этот трюк с try-throw сделать? Вместо того, чтобы ковыряться в потрохах механизма исключений?
Перекуём баги на фичи!
Re[4]: MS link создает дубликаты функций
От: gear nuke  
Дата: 16.11.09 01:37
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Кстати! Может быть, тебе вообще необходимо было этот трюк с try-throw сделать? Вместо того, чтобы ковыряться в потрохах механизма исключений?


Дело в том, что это как раз фрагмент потрохов механизма исключений, выполняет вызов catch блока. И вопрос насчет __try/__except на самом деле довольно сложный, его можно свести к "почему MS так сделал".

__try грубо аналогично следущему
      volatile catchguard guard;
      guard.next        = nt::teb::get(&nt::teb::ExceptionList);
      guard.handler     = __except_handler3; // стандартный SE handler
      nt::teb::set(&nt::teb::ExceptionList, &guard);

В настоящем коде в catchguard есть ещё поля для сохранения некоторого контекста С++ исключения, которые catchguardhandler передаст в хендлер С++ исключений. Последний, в зависимости от типа исключения и ключа /EHa /EHs, либо будет искать следующий catch, либо вызовет __except_handler3.

Предположим, что проблем с рекурсией и контекстом не окажется. Тогда вариант с __try добавляет лишний диспетчерезующий вызов __except_handler3, то есть немного утяжелит С++ RTL. В общем, пока нашел только наивный ответ Для дебаг сборки впринципе не важно, но там проще проверять первый байт catchguardhandler на предмет jmp.

В релизе не хочется лишних оверхедов, хочется обезопасить пользователя от линковки с /OPT:NOICF (хотя смысл такой сборки сомнителен). Идеалный вариант — свалить все на баг в линкере и попытаться его засабмитить. При сборке с Edit&Continue выдается предупреждение, если указать /SAFESEH, и последний отключается. Выдавало бы еще на /OPT:NOICF, и нет проблем
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[5]: MS link создает дубликаты функций
От: Erop Россия  
Дата: 16.11.09 01:56
Оценка:
Здравствуйте, gear nuke, Вы писали:

GN>В релизе не хочется лишних оверхедов, хочется обезопасить пользователя от линковки с /OPT:NOICF (хотя смысл такой сборки сомнителен). Идеалный вариант — свалить все на баг в линкере и попытаться его засабмитить. При сборке с Edit&Continue выдается предупреждение, если указать /SAFESEH, и последний отключается. Выдавало бы еще на /OPT:NOICF, и нет проблем


А зачем все эти навороты вообще нужны? Ты чего, собственно, добиться пытаешься?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: MS link создает дубликаты функций
От: gear nuke  
Дата: 16.11.09 09:06
Оценка:
Здравствуйте, Erop,

Мы добиваемся работоспособности С++ в OS Windows не только в пределах подсистемы Win32. То есть реализуем С++ runtime которому достаточно зависимостей от ntdll.lib или ntoskrnl.lib.
.
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Re[4]: MS link создает дубликаты функций
От: byleas  
Дата: 20.11.09 08:27
Оценка:
Здравствуйте, Кодт, Вы писали:

К>Кстати! Может быть, тебе вообще необходимо было этот трюк с try-throw сделать? Вместо того, чтобы ковыряться в потрохах механизма исключений?

Мне вообще необходимо _реализовать_ это Точнее, это давно реализовано, просто идёт вылизывание и доработка.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.