나는 검색을 해왔지만 예상 컴파일러 플래그 또는 무작위로로드 할 수 있도록 FORTRAN DLL (인텔 Visual Fortran Composer XE 2013 컴파일러 사용)을 빌드 할 수있는 종류의 유틸리티를 찾지 못한 데는 행운이 없었습니다. 기본 주소. 내 C++ 코드에서 FORTRAN DLL을 명시 적으로로드하고 있으며로드/언로드가 잘되지만 각 시간에로드되는 주소가 정확히 같은 위치라는 것을 눈치 챘습니다. 이유는 내 FORTRAN DLL을 성공적으로로드하고 여러 번 내 프로그램을 여러 번 동시에 실행할 때 다른 시간에 실패하는지 궁금해. 인텔 포트란 컴파일러에 임의의 기본 주소 컴파일러 옵션이 있습니까? 나는 그것에 대한 릴리즈 노트를 읽었지만 행운은 없다.FORTRAN DLL을 매번 임의의 주소로로드 할 수 있습니까?
답변
즉각적인 질문에 대답하십시오 : 예, DLL을 표시하여 최신 Windows 버전에서 약간 임의의 기본 주소로로드 할 수 있습니다. 이것은 /DYNAMICBASE 옵션을 링커 (link.exe
)에 전달하면됩니다. Visual Studio에서이 기능을 활성화하는 방법에 대한 정보는 링크 된 페이지를 읽으십시오. /link
옵션은 모두 같은 명령 행의 마지막이 될 것을
ifort.exe ... /link /DYNAMICBASE
참고 : ifort
는 메이크에 명령 줄에서 사용되는 경우, /link
옵션은 링커에 플래그를 전달하는 데 사용할 수 있습니다 이후 링커에 전달됩니다. 또한 기본적으로 /DYNAMICBASE
이 ON이고 라이브러리가 약간 임의의 주소로로드되어야합니다 (Windows XP를 실행하고 있습니까?)
그러나 실제로는 필요하지 않습니다. 이유는 다음과 같습니다.
의견을 명확하게 요약하십시오. Windows뿐만 아니라 Windows, BSD, Linux, OS X 등과 같은 거의 모든 최신 OS에서도 각 프로세스는 고유 한 가상 선형 주소 공간을 가지고 있으며 사용자 공간의 모든 메모리는 해당 가상 주소를 사용하여 작동합니다 . 가상 메모리는 물리적 메모리의 프레임으로 뒷받침되는 페이지로 나뉩니다. 하나의 물리적 메모리 프레임은 다른 프로세스의 주소 공간에서도 많은 가상 메모리 페이지에 매핑 될 수 있으므로 프로세스 간의 메모리 공유가 용이합니다. 가상 메모리 페이지와 물리적 메모리 프레임 간의 매핑은 소위 페이지 테이블에 유지됩니다. 그것들은 프로세스에 국한되어 있으므로 매핑은 로컬입니다. 즉, 서로 다른 두 프로세스의 동일한 가상 메모리 주소가 완전히 다른 실제 메모리 주소에 매핑 될 가능성이 높습니다. 일부 운영 체제 (Windows 포함)는 각 프로세스의 가상 주소 공간을 하위와 상위의 두 부분으로 나눕니다. 하단 부분은 프로세스에 속하며 모든 프로세스의 상단 부분은 운영 체제의 커널 메모리 영역에 매핑됩니다. 커널 메모리는 필요한 권한이 없기 때문에 사용 가능한 가상 메모리 공간을 줄이기 때문에 사용자 공간에서 액세스 할 수 없으므로 응용 프로그램 개발자에게는 거의 관심이 없습니다 (예 : GiB가 2 ~ 3 개 밖에 액세스 할 수 없음). 32 비트 시스템에서 4 GiB). 다른 운영 체제 (OS X가 그 중에서도 가장 많이 사용되는 데스크탑 OS 임)는 프로세스에 대한 전체 가상 주소 공간을 가지며 커널은 별도의 가상 메모리 공간에서 실행됩니다.
Windows (및 가상 메모리 관리를 구현하는 대부분의 다른 OS)의 실행 파일은 일반적으로 여러 섹션으로 구성되며 섹션은 세그먼트로 그룹화됩니다. 실행 파일 형식은 메모리 매핑으로 알려진 프로세스 인 가상 주소 공간에 직접 매핑하여 메모리에로드 할 수 있도록 설계되었습니다. 일반적으로 프로그램 지침 (종종 .text
또는 이와 비슷한 이름)을 포함하는 실행 파일의 섹션은 읽기 전용이므로 동일한 실행 파일에서 생성되거나 동일한 DLL을로드 한 모든 프로세스간에 공유 될 수 있습니다 (DLL에는 또한 실행 파일과 동일한 구조이지만 섹션 집합이 다르며 자체적으로 실행 가능하지 않습니다.) 실제 메모리를 절약 할 수 있습니다.데이터의 다른 부분을 포함하는 다른 많은 섹션이있을 수 있습니다. 초기화 된 정적 변수 (전역 변수)가 포함 된 .data
섹션, 초기화되지 않은 정적 변수, 디버그 정보가있는 섹션, 재배치 섹션, 가져 오기 및 내보내기 테이블 등을 포함하는 .bss
섹션. 일반적으로 읽기/쓰기 (데이터) 섹션은 명백한 조치가 취해지지 않으면 다른 프로세스.
일반적으로 FORTRAN COMMON 블록은 초기화되지 않은 정적 데이터이기 때문에 .bss
섹션에 있습니다. COMMON 블록이 BLOCK DATA
구문을 사용하여 데이터로 초기화되면 대신 .data
섹션에 저장됩니다. 어느 쪽이든 공통 블록은 DLL을로드하는 여러 프로세스간에 공유 할 수없는 섹션에서 종료됩니다. 결국 두 프로세스가 DLL을로드 할 때 암시 적으로 종속성의 일부로 명시 적으로 LoadLibrary()
을 사용하면 읽기 전용 섹션이 두 프로세스간에 공유되지만 읽기 - 쓰기 데이터 섹션 (COMMON 블록 포함)은 각 프로세스마다 다르며 하나의 프로세스에서 데이터 수정이 다른 프로세스에서 볼 수 없으며 DLL이 두 프로세스의 동일한 기본 주소에로드 되어도 마찬가지입니다.
Windows DLL에는 "기본 설정 주소"라는 기능이 있습니다. OS가 이러한 DLL을로드 할 때마다 지정된 기본 주소에 배치하려고 시도합니다. 불가능한 경우 (예 : 필요한 가상 주소 공간의 일부가 이미 점유 된 경우) 라이브러리를 다른 기본 주소로 재배치합니다. 이러한 동작의 이유는 절대 주소 지정을 사용하여 전역 기호에 액세스하고 라이브러리를 재배치해야 할 때마다 주소가 로더에 패치 (고정식)되어야하므로 DLL 재배치는 Windows에서 비용이 많이 듭니다. 반대로, 많은 유닉스 시스템은 동적 라이브러리를 PIC (위치 독립적 코드)로 가지고 있으며 모든 기본 가상 주소에서로드 할 수 있습니다. 그러나 PIC 코드는 정상 위치 종속 코드보다 약간 느리게 실행됩니다.
구형 Windows 버전은 USER32.DLL
및 KERNEL32.DLL
과 같은 가장 기본적인 라이브러리가 항상 동일한 기본 주소에로드됩니다. 로더는 매우 예측 가능하며 실행 및 실행시 동일한 일련의 라이브러리를 같은 순서로로드하면 일반적으로 라이브러리는 각 실행시 동일한 기본 가상 주소에로드됩니다. 이것은 주소 공간 레이아웃의 무작위 화를 도입 한 Vista 이후로 변경되었습니다. 선택 사항 인 기능으로 원격 네트워크 공격을 더욱 어렵게 만들기 위해 특별히 표시된 실행 파일 (및 DLL)을 임의의 가상 기본 주소에로드 할 수 있습니다. 다양한 OS 또는 사용자 API 호출의 정확한 주소를 찾으십시오.
왜 메모리가로드되는지 신경 씁니까? –
내 C++ 프로그램에서 FORTRAN 공용 블록을 사용하여 계산을 수행하기 때문에. 공용 블록에서 그 값이 남아있을 때마다 동일한 위치로로드되고 결과적으로 문제가 발생하는 것이 두렵습니다. – user1496542
Windows의 PE 로더가 동적으로 DLL을로드하고 주소를 패치 할 위치를 결정합니다. 일반적으로 귀하의 코드 크기 IIRC에 따라 계산됩니다. 너에게 보이는 주소가 "동일하다"고해도, GDTR과 LDTR은 바뀌었을 것이다. 따라서 실행 파일을 여러 번로드하더라도 공통 블록 코드가 매번 다시로드됩니다. –