Я искал, но мне не повезло с поиском предполагаемого флага компилятора или чего-то в этом роде, что позволило бы мне собрать мою библиотеку FORTRAN DLL (с использованием компилятора Intel Visual Fortran Composer XE 2013) для ее загрузки со случайным базовым адресом каждый раз. Я явно загружаю свою библиотеку FORTRAN DLL в мой код C ++, и она прекрасно загружается / выгружается, но я только что заметил, что адрес, по которому она загружается каждый раз, — это ТОЧНОЕ местоположение. Интересно, вот почему иногда моя библиотека FORTRAN DLL успешно загружалась, а другие иногда терпели неудачу, когда я запускаю свою программу несколько раз одновременно. Существуют ли какие-либо варианты компилятора случайных базовых адресов для компилятора Intel Fortran? Я прочитал в примечаниях к выпуску для этого, но не удача также.
Чтобы ответить на ваш непосредственный вопрос: да, можно пометить DLL так, чтобы последние версии Windows загружали ее по слегка рандомизированному базовому адресу. Это достигается путем передачи / DYNAMICBASE вариант для компоновщика (link.exe
). Прочитайте связанную страницу для получения информации о том, как включить эту функцию в Visual Studio. Если ifort
используется в командной строке в make-файле, затем /link
опция может быть использована для передачи флагов компоновщику:
ifort.exe ... /link /DYNAMICBASE
Обратите внимание, что /link
Параметр должен быть последним в командной строке, так как все после передается компоновщику. Также обратите внимание, что /DYNAMICBASE
по умолчанию включено, и ваша библиотека должна загружаться по несколько случайным адресам (у вас Windows XP?)
Однако это не совсем необходимо. Объяснение почему следует.
Просто чтобы четко обобщить комментарии. Каждый процесс в Windows (и не только в Windows, но и практически в любой современной ОС, такой как * BSD, Linux, OS X и т. Д.) Имеет свое собственное виртуальное линейное адресное пространство, и вся память в пространстве пользователя управляется с использованием этих виртуальных адресов. , Виртуальная память делится на страницы, которые подкреплены кадрами физической памяти. Один кадр физической памяти может быть сопоставлен со многими страницами виртуальной памяти, даже из адресных пространств различных процессов, что облегчает совместное использование памяти между процессами. Отображение между страницами виртуальной памяти и фреймами физической памяти поддерживается в так называемых таблицах страниц. Они являются локальными для процессов, и, следовательно, отображение является локальным, что означает, что один и тот же адрес виртуальной памяти в двух разных процессах, скорее всего, будет отображаться на совершенно разные адреса физической памяти. Некоторые операционные системы (включая Windows) разделяют виртуальное адресное пространство каждого процесса на две части — нижнюю и верхнюю. Нижняя часть принадлежит процессу, а верхняя часть во всех процессах отображается в область памяти ядра операционной системы. Это не представляет большого интереса для разработчиков приложений, поскольку память ядра недоступна из пользовательского пространства, поскольку у них отсутствуют необходимые привилегии, и, следовательно, это проявляется только в уменьшении доступного пространства виртуальной памяти (например, только 2 или 3 ГБ, доступных из 4 ГиБ в 32-битных системах). Другие операционные системы (с OS X, являющейся самой популярной настольной ОС среди них) имеют все виртуальное адресное пространство, приватное для процесса, и ядро работает в своем собственном отдельном пространстве виртуальной памяти.
Исполняемые файлы в Windows (и в большинстве других ОС, которые реализуют управление виртуальной памятью) обычно состоят из разных разделов, причем разделы сгруппированы в сегменты. Формат исполняемого файла разработан таким образом, что он может быть загружен в память путем непосредственного сопоставления его частей с виртуальным адресным пространством — процесс, известный как отображение памяти. Обычно раздел исполняемого файла, который содержит инструкции программы (часто называемый .text
или что-то подобное) только для чтения и, таким образом, может использоваться всеми процессами, которые созданы из одного и того же исполняемого файла или загружены одной и той же DLL (библиотеки DLL также имеют ту же структуру, что и исполняемые файлы, но содержат различный набор разделов и не являются работает самостоятельно), чтобы сохранить физическую память. Может быть много других разделов, содержащих разные фрагменты данных, например, .data
раздел, который содержит инициализированные статические (также глобальные) переменные, .bss
раздел, содержащий неинициализированные статические переменные, разделы с отладочной информацией, разделы перемещения, таблицы импорта и экспорта и т. д. Разделы чтения / записи (данные) обычно никогда не разделяются между различными процессами, если не были приняты явные меры.
Фортран ОБЩИЕ блоки обычно живут в .bss
раздел, так как они просто неинициализированные статические данные. Если ОБЩИЙ блок инициализируется данными с использованием BLOCK DATA
построить, а затем положить в .data
раздел вместо. В любом случае, блок COMMON заканчивается разделом, который не доступен для разных процессов, которые загружают DLL. В конце концов, когда два процесса загружают DLL, либо неявно как часть ее зависимостей, либо явно используя LoadLibrary()
разделы только для чтения будут разделены между двумя процессами, но разделы данных для чтения и записи (включая ваши ОБЩИЕ блоки) будут отличаться в каждом процессе, а изменения данных в одном процессе не будут видны в другом процессе, даже в DLL загружается по одному базовому адресу в обоих процессах.
Windows DLL имеют функцию, известную как «предпочтительный базовый адрес». Всякий раз, когда ОС загружает такую DLL, она пытается разместить ее по указанному предпочтительному базовому адресу. Если он не может (например, части требуемого виртуального адресного пространства уже заняты), то он перемещает библиотеку на другой базовый адрес. Причиной такого поведения является то, что перемещение DLL является дорогостоящим в Windows, поскольку абсолютная адресация используется для доступа к глобальным символам, и адреса должны быть исправлены (исправлены) загрузчиком при каждом перемещении библиотеки. Напротив, многие системы Unix имеют свои динамические библиотеки в виде PIC (код, независимый от позиции), и они могут быть загружены по любому базовому виртуальному адресу. Но код PIC выполняется немного медленнее, чем обычный код, зависящий от позиции.
В старых версиях Windows есть самые фундаментальные библиотеки, такие как USER32.DLL
а также KERNEL32.DLL
всегда загружается по одному и тому же базовому адресу. Их загрузчики очень предсказуемы, и если при запуске и запуске вы загружаете один и тот же набор библиотек и в одной и той же последовательности, библиотеки обычно загружаются по одному и тому же базовому виртуальному адресу при каждом запуске. Это изменилось с Vista, которая ввела рандомизацию структуры адресного пространства — необязательный функция, позволяющая загружать специально помеченные исполняемые файлы (и библиотеки DLL) по случайному виртуальному базовому адресу, чтобы при удаленных сетевых атаках было сложнее определить правильный адрес различных вызовов ОС или пользовательских API.
Других решений пока нет …