Re: problem with msvc linker - cannot build orafce

From: Craig Ringer <craig(at)2ndquadrant(dot)com>
To: Chapman Flack <chap(at)anastigmatix(dot)net>
Cc: Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, Pavel Stehule <pavel(dot)stehule(at)gmail(dot)com>, PostgreSQL Hackers <pgsql-hackers(at)postgresql(dot)org>
Subject: Re: problem with msvc linker - cannot build orafce
Date: 2015-11-25 03:57:47
Message-ID: CAMsr+YFjHG8ROjZsCaQ3vQ5RXt+XghH_LtFSQ4CtTV=a0rxbfw@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

On 24 November 2015 at 07:12, Chapman Flack <chap(at)anastigmatix(dot)net> wrote:

>
> What I (think I) took away from it was:
>
> 1. Un-PGDLLIMPORTed references to global *functions* work ok.
> Maybe they are thunked and a little less efficient, but they work.
>
> 2. Un-PGDLLIMPORTed references to global *variables*, not so much.
> They used to silently link (at least on some buildfarm critters)
> but hold bogus data (maybe a thunk, taken as data?).
>
> 3. The one concrete *action* taken in the course of that thread was to
> tweak the build process to make sure such cases at least *fail*
> because that's better than silent bogosity.
>

Correct on all points.

The question that interests me most right now: how, if at all, can the
> extension author/maintainer work around this issue when it crops up?
>

AFAIK the only way to do it is to use the .pdb files to find the address of
the variable's storage, then create a pointer-to-var that way, after
adjusting for the DLL/EXE's base load address - which on some Windows
versions is randomized.

You might be able to do it with dbghelp.dll . I haven't looked into it
properly.

> Obviously, the Right Thing To Do is report it and get the PGDLLIMPORT
> added here, but still for years to come the extension will have to cope
> with being built against PG distributions that lack it.

It's safe to add in a point-release because nobody could've been using it
before, so all you have to do is require a certain minimum point release.
We all know how easy it is to get users to apply point releases ;)

If we annotated extern functions too, we could build on UNIX with
-fvisibility=hidden and get immediate linker errors on *nix too. As far as
I can tell gcc doesn't have the option to control default visibility
separately for functions and data exports. We do that on Windows by
generating a .DEF file, since Windows doesn't support it directly either.
Doing that on *nix would require using readelf then
using --retain-symbols-file at link time. Imagine how popular that'd be.

So currently we rely on the buildfarm complaining if things are broken on
Windows, but of course that only works for core and in-tree extensions.
(Who cares about anything else, right?).

See https://gcc.gnu.org/wiki/Visibility for details on visibility.

Now, I thought I spotted, somewhere in that long thread, the hint of an
> idea that the magic works as long as the *extension* has the variable
> declared PGDLLIMPORT, even if it wasn't declared that way when the PG
> executable itself was built. Anybody else remember that, or did I
> imagine it?
>

I haven't tested, but I believe you can declare it with an extra level of
pointer indirection, without __declspec(dllimport), and chase the pointer.

As I understand it (and I'm far from an expert here) the symbol in the PE
symbol table points to the address of a pointer to the data. MSVC doesn't
know if your "extern" references a variable in the same module (in which
case you don't have that indirection) or will be resolved by dynamic
linking to point to a pointer to the data. I find this bizarre, given that
ELF "just does it"... but PE is pretty weird and a fair bit older, a
hacked-up variant of COFF. Anyway, __declspec(dllimport) tells MSVC "I'm
going to be linking this from an external DLL, do the pointer chasing for
me please".

See https://msdn.microsoft.com/en-us/library/aa271769(v=vs.60).aspx "Using
__declspec(dllexport) and __declspec(dllimport) on Data".

I *think* it's safe to do this even if the var is declared
__declspec(dllexport). The dllexport declaration makes sure the export is
present without the use of a .DEF file to force it. You can
__declspec(dllimport) whether it was __declspec(dllexported)'ed or exported
via a .DEF file.

We auto-export functions in our DEF files, but not variables.

> You *might* get away with creating a separate C file (how about
> chamberofhorrors.c?) that, rather revoltingly, *doesn't* include the
> proper PostgreSQL .h files, only duplicates the necessary declarations
> with PGDLLIMPORT added, and exports some getter/setter methods
> to the rest of the extension code. (I like the idea of one
> chamberofhorrors
> better than scattering such rubbish all over the project.)
>

I don't think that's necessary, per above. You just have to access the vars
via pointer indirection always, so long as *any* Pg version you support has
ever lacked dllexport or DEF entry, so you can't dllimport the var.

You could enable direct dllimport if PG_VERSION_NUM shows you're on a new
enough version, but you'd need to use conditionally compiled inlines or
something to switch between the methods of accessing it, so there's not
much point. You just declare

extern int* log_min_messages_p;

... and use that, probably also #define'ing log_min_messages away after
including the Pg headers so that you can't reference it accidentally.

--
Craig Ringer http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services

In response to

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Pavel Stehule 2015-11-25 04:57:57 Re: custom function for converting human readable sizes to bytes
Previous Message Amit Langote 2015-11-25 02:43:51 Re: Minor comment edits in nodeGather.c