bss section is set to 0, indicating that this section doesn't take up any space in the file. In the section table, the RawDataOffset field for the. bss sections in the OBJ and LIB files into one. bss section is where any uninitialized static and global variables are stored. Local variables are located on a thread's stack, and take no room in the. data sections from the OBJ and LIB files into one. This data consists of global and static variables that are initialized at compile time. data section is where your initialized data goes. text is the default section for code, the. TLINK32 stores the thunks that it creates in a section named. TLINK32 is therefore responsible for determining which fixups are to external DLLs, and generating an appropriate JMP DWORD PTR thunk for it. The import libraries that the Borland linker uses are really just a list of function names along with the name of the DLL they're in.
The import library is really just some more code and data to link into the PE file.
Because the library manager (LIB32) creates the import library (and the thunk) when you link the external DLL, the linker doesn't have to "know" how to generate these thunks itself. Under the Microsoft system, this thunk comes to the EXE from the. text description, all calls to OBJs go through a JMP DWORD PTR thunk. There is an important difference in how Borland PE files link to other modules. However, if you want to read the bytes at the beginning of GetMessage, you're out of luck (unless you do additional work to follow the. If you wanted to call through the function pointer, things would work as you'd expect.
In 16-bit Windows, this works, while in Win32 it doesn't.In Win32, the variable pfnGetMessage will end up holding the address of the JMP DWORD PTR thunk that I mentioned earlier. Would put the address of GetMessage into the variable pfnGetMessage.
For example, you would think that something like If the segment calls a given DLL function 20 times, the loader must write the address of that function 20 times into the segment.The downside to the PE method is that you can't initialize a variable with the true address of a DLL function. No call instructions need to be patched.This is in marked contrast to NE files, where each segment contains a list of fixups that need to be applied to the segment. All the PE loader has to do is put the correct address of the target function into the DWORD in the.
By funneling all calls to a given DLL function through one location, the loader doesn't need to patch every instruction that calls a DLL. idata section DWORD contains the real address of the operating system function entry point.After thinking about this for a while, I came to understand why DLL calls are implemented this way. The JMP instruction indirects through a DWORD variable in the. Instead, the call instruction transfers control to a In a PE file, when you call a function in another module (for example, GetMessage in USER32.DLL), the CALL instruction emitted by the compiler doesn't transfer control directly to the function in the DLL. PE files produced with Borland C++ have a section named CODE rather than one called. If you use Borland C++ the compiler emits its code to a segment named CODE. text sections from the various OBJs into one big. Instead, the linker concatenates all the. Since PE files run in 32-bit mode and aren't restricted to 16-bit segments, there's no reason to break the code from separate source files into separate sections. text section is where all general-purpose code emitted by the compiler or assembler ends up.