Недавно я разобрал библиотеку DLL (написанную на c / c ++) и заметил, что внутри сегмента кода есть много «заглушек перехода». Эти заглушки не делают ничего, кроме перехода к функции внутри DLL.
например:
jmp foo()
jmp foo2()
...
Почему компилятор (Visual studio 2012) включает эти заглушки функций внутри двоичного файла?
Спасибо!
Есть ли большая куча байтов 0xCC после всех заглушек? Если это так, вы смотрите на код, который был скомпилирован с включенным инкрементным связыванием (по умолчанию для отладочных сборок).
При компиляции для инкрементного связывания компилятор создает заглушку для каждой функции и следит за тем, чтобы все вызовы проходили через заглушку. В случае, если функция должна быть заменена обновленным кодом, новый код может быть добавлен в конец, и только патч перехода должен быть исправлен — все существующие вызовы будут перенаправлены на новый код. Дополнительные CC зарезервированы для большего количества заглушек в случае добавления новых функций.
Для получения дополнительной информации, см MSDN.
Вот как символы для компоновщика и DLL «смешиваются». Это гарантирует, что в таблице символов используется правильный вид смещения, который может быть разрешен загрузчиком, который загружает DLL (и, таким образом, обновляет адрес функций в DLL), и что скомпилированный код все еще может иметь дело, например, с функциональные указатели:
void (*fptr)() = foo;
Если foo
это просто ссылка на место в DLL, то, как этот адрес будет разрешен, будет зависеть от загрузчика. Это гораздо сложнее решить, чем решить проблему «вот точка входа foo (), которая приведет вас к настоящему foo».
DLL могут быть перемещены, что означает, что они могут оказаться где угодно в памяти. Это означает, что все обращения к ним должны быть переписаны. Храня все такие вызовы вместе в небольшой перемычке, нужно переписать только одну страницу в случае перемещения. Это важно, потому что неизменная страница кода может быть общей для всех процессов, но каждый процесс имеет свою собственную копию измененной страницы.