0

I have been searching but have gotten no luck with finding a supposed compiler flag or something of the sorts that would allow me to build my FORTRAN DLL (using Intel Visual Fortran Composer XE 2013 compiler) in order for it to load with a random base address each time. I am explicitly loading my FORTRAN DLL in my C++ code and it loads/unloads fine but I just noticed that the address in which it loads to each time is the EXACT same location. I wonder if that is why at times my FORTRAN DLL would load successfully and other times fail when I run my program multiple times simultaneously. Does there exist any random base address compiler options for the Intel Fortran compiler? I have read in the release notes for it but no luck either.

user1496542
  • 539
  • 2
  • 6
  • 14
  • why do you care where in memory it loads? – Aniket Inge Jan 17 '13 at 14:21
  • Because I am using some FORTRAN common blocks to do calculations in my c++ program. I'm afraid if it loads to the same location each time those values from the common blocks would remain and consequently cause issues... – user1496542 Jan 17 '13 at 14:23
  • Windows' PE loader decides where to dynamically load a DLL and patches the address. Usually its computed based on your code size IIRC. BTW no, even if the address seen to you is "same", the GDTR and LDTR would've changed. So even if you load the executable multiple times, the common blocks code would reload each time. – Aniket Inge Jan 17 '13 at 14:25
  • 1
    There is a separation of one process's memory from another process's memory. – Aniket Inge Jan 17 '13 at 14:25
  • What would happen if the c++ executable is not being loaded multiple times? and it's just loading/unloading the fortran dll would that affect anything you mentioned above? – user1496542 Jan 17 '13 at 14:27
  • I am not sure how fortran's common blocks code works in assembly level, but I am pretty sure that the common blocks would have no effect, even if its loaded/unloaded multiple times – Aniket Inge Jan 17 '13 at 14:29
  • hmm.. alrighty. thank you for the replies. :) – user1496542 Jan 17 '13 at 14:40
  • :) You're welcome. I guess you can debug your Fortran code or C++ code to find why your program crashes occasionally – Aniket Inge Jan 17 '13 at 14:41

1 Answers1

2

To answer your immediate question: yes, it is possible to mark a DLL so that recent Windows versions would load it at a slightly randomised base address. This is achieved by passing the /DYNAMICBASE option to the linker (link.exe). Read the linked page for information on how to enable this feature in Visual Studio. If ifort is used on the command line on in a makefile, then the /link option could be used to pass flags to the linker:

ifort.exe ... /link /DYNAMICBASE

Note that the /link option should be the last one on the command line as everything after is passed to the linker. Also note that /DYNAMICBASE by default is ON and your ibrary should load at slightly random addresses (are you running Windows XP?)

However it is not really necessary. Explanation why follows.


Just to clearly summarise the comments. Each process on Windows (and not only on Windows, but also on virtually any modern OS like *BSD, Linux, OS X, etc.) has its own virtual linear address space and all memory in user-space is operated using those virtual addresses. Virtual memory is divided into pages, which are backed by frames of physical memory. One physical memory frame might be mapped to many virtual memory pages, even from the address spaces of different processes, thus facilitating memory sharing between processes. The mapping between virtual memory pages and physical memory frames is maintained in the so-called page tables. Those are local to the processes and hence the mapping is local, meaning that the same virtual memory address in two different processes would most likely map to completely different physical memory addresses. Some operating systems (Windows included) split the virtual address space of each process in two parts - lower and upper. The lower part belongs to the process while the upper part in all processes maps to the operating system's kernel memory area. This is of little interest to the application developers since the kernel memory is not accessible from user-space because they lack the necessary privileges and hence only manifests itself as a reduction of the available virtual memory space (e.g. only 2 or 3 GiB accessible out of 4 GiB on 32-bit systems). Other operating systems (with OS X being the most popular desktop OS among them) have the entire virtual address space private to the process and the kernel runs in its own separate virtual memory space.

Executables on Windows (and most other OSes that implement virtual memory management) generally consists of different sections, with sections being grouped into segments. The executable file format is designed so that it can be loaded in memory by directly mapping parts of it into the virtual address space - a process know as memory mapping. Usually the section of the executable that contain program instructions (often named .text or something similar) is read-only and thus can be shared between all processes that are created from the same executable or that have loaded the same DLL (DLLs are also have the same structure as the executables but contain different set of sections and are not runnable on their own) in order to save physical memory. There could be many other sections containing different pieces of data, e.g. the .data section that contains initialised static (also global) variables, the .bss section that contains uninitialised static variables, sections with debug information, relocation sections, import and export tables, etc. Read/write (data) sections are usually never shared among the different processes unless explicit measures were taken.

Fortran COMMON blocks usually live in the .bss section since they are just uninitialised static data. If a COMMON block is initialised with data using a BLOCK DATA construct, then it is put in the .data section instead. Either way, the COMMON block ends in a section that is not shareable among the different processes that load the DLL. In the end, when two processes load the DLL, either implicitly as part of its dependencies or explicitly using LoadLibrary(), the read-only sections would get shared between the two processes but the read-write data sections (your COMMON blocks included) would be different in each process and modifications to the data in one process would not be visible in the other process, even in the DLL is loaded at the same base address in both processes.

Windows DLLs have a feature known as "preferred base address". Whenever the OS loads such DLL, it tries to place it at the specified preferred base address. If it can not (e.g. parts of the required virtual address space are already occupied), then it relocates the library to a different base address. The reason for that behaviour is that DLL relocation is expensive on Windows since absolute addressing is used to access global symbols and addresses must be patched (fixed-up) by the loader whenever the library has to be relocated. In contrast, many Unix systems have their dynamic libraries as PICs (position-independent code) and those can be loaded at any base virtual address. But PIC code execute a bit slower than normal position-dependent code.

Older Windows versions have their most fundamental libraries like USER32.DLL and KERNEL32.DLL always loaded at the same base address. Their loaders are very predictable and if you load the same set of libraries and in the same sequence when launching and executable, usually libraries are loaded at the same base virtual address at each run. This has changed since Vista, which introduced randomisation of the address space layout - an optional feature that allows for specially marked executables (and DLLs) to be loaded at a randomised virtual base address in order to make it harder for remote network attacks to find out the correct address of various OS or user API calls.

Hristo Iliev
  • 72,659
  • 12
  • 135
  • 186