I'm looking for solutions to a fun new wrinkle in Windows support for the PostgreSQL project.
When plugin DLLs are loaded into the main executable with a LoadLibrary
call they expect the dynamic linker to resolve references to functions and global variables exposed by postgres.exe
.
It's easy to forget to put a __declspec(dllimport)
annotation, or rather, the PGDLLIMPORT
macro that expands to it, on an extern
that's accessed via a DLL, since almost all PostgreSQL development and testing happens on Linux and OS X, where none of this stuff applies.
The project relies on automated testing to detect when a __declspec(dllimport)
is missing on a function, as this causes linker errors. Until yesterday the assumption was that the same was true for global variables, but it isn't; it turns out that dynamic linkage succeeds silently, producing a garbage result.
So - I'm looking for advice on how to detect and prevent such illegal accesses, where a global is not __declspec(dllimport)
'ed.
This is complicated by the fact that on Windows, PostgreSQL's build system generates .def
files that just export everything. (Not my doing, but I can't change it, yes, I know). This means that even if there's no PGDLLIMPORT
marking the site __declspec(dllexport)
during building of the main executable, the symbol is still exported.
Ideas? Is there any way to get the linker to throw a runtime error when an extern
global is defined in another module and the extern
isn't properly __declspec(dllimport)
annotated?
If the project stopped generating .def files and instead used PGDLLIMPORT
annotations that expand to __declspec(dllexport)
when compiling the .exe, and __declspec(dllimport)
when compiling plugins that use the exe's API, would that produce linker errors when a symbol isn't annotated properly? Is there any alternative to that?
I'm currently looking for more info and I'm going to be writing a few test programs to try to test ideas, but I'm far from an expert on Windows development and I'm looking for an authoritative "the right way to do it" if possible.
The best way is to make it clear in
.def
file to linker that you export data, not code:or not use
.def
at all. It takes precedence and defaults exported symbol tocode
.Let's look what happens when you link your plugin to such malformed
.lib
file. And assume you declare:This means your
.obj
file will have external dependencies__imp__i1
and_i2
. And while the first one will point to the real imported symbol,jmp
-stubwill be generated for the second one ('cause it considered to be the code symbol) which is meant to fix difference between two kinds of call:
Thus, your
i2
will actually point to code section address of jmp-stub, so its value gonna be0x????25ff
.