Обнаружение отсутствующего __declspec (dllimport) в доступе к экспортированным глобальным переменным через границы dll

Я ищу решения для веселой новой морщины в поддержке Windows для проекта PostgreSQL.

Когда DLL-модули плагина загружаются в основной исполняемый файл с вызовом LoadLibrary они ожидают, что динамический компоновщик будет разрешать ссылки на функции и глобальные переменные, открытые postgres.exe .

Легко забыть поставить аннотацию __declspec(dllimport) или, вернее, макрос PGDLLIMPORT который расширяется до него, на extern , доступ к которому осуществляется через DLL, поскольку почти все разработки и тестирование PostgreSQL происходят в Linux и OS X, где ни один из этот материал применяется.

Проект основан на автоматическом тестировании, чтобы обнаружить, когда отсутствует функция __declspec(dllimport) для функции, поскольку это вызывает ошибки компоновщика. До вчерашнего дня предположение заключалось в том, что то же самое верно для глобальных переменных, но это не так; оказывается, что динамическая связь успешно завершается, создавая результат мусора .

Итак, я ищу советы о том, как обнаруживать и предотвращать такие незаконные обращения, где глобальный не является __declspec(dllimport) .

Это осложняется тем, что в Windows система сборки PostgreSQL генерирует файлы .def которые просто экспортируют все. (Не мое занятие, но я не могу его изменить, да, я знаю). Это означает, что даже если PGDLLIMPORT маркирует сайт __declspec(dllexport) во время построения основного исполняемого файла, символ все еще экспортируется.

Идеи? Есть ли способ заставить компоновщик выбросить ошибку времени выполнения, когда extern global определен в другом модуле, а extern не является должным образом __declspec(dllimport) аннотированным?

Если проект прекратил генерировать файлы .def и вместо этого использовал annotations PGDLLIMPORT которые расширяются до __declspec(dllexport) при компиляции .exe и __declspec(dllimport) при компиляции плагинов, которые используют API exe, приведут к возникновению ошибок компоновщика, когда символ isn ‘ t аннотируется правильно? Есть ли альтернатива этому?

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

Лучший способ – это очистить файл .def для компоновщика, который вы экспортируете данные, а не код:

 EXPORTS i1 DATA i2 DATA 

или вообще не использовать .def . Он имеет приоритет и по умолчанию экспортирует символ в code .

Давайте посмотрим, что произойдет, если вы связали свой плагин с таким искаженным .lib файлом. И предположим, что вы заявляете:

  int __declspec(dllimport) i1; extern int i2; 

Это означает, что ваш .obj файл будет иметь внешние зависимости __imp__i1 и _i2 . И пока первый указывает на настоящий импортированный символ, jmp -stub

  jmp [addr] ; FF 25 xx xx xx xx 

будет генерироваться для второго (потому что он считается символом кода), который предназначен для исправления разницы между двумя типами вызовов:

  call [addr] ; FF 15 xx xx xx xx call addr ; E8 xx xx xx xx 

Таким образом, ваш i2 фактически укажет на адрес раздела кода jmp-stub, поэтому его значение будет равным 0x????25ff .