[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [patch #6448] [MSVC 7/7] Add MSVC Support

From: Brian Dessent
Subject: Re: [patch #6448] [MSVC 7/7] Add MSVC Support
Date: Mon, 11 Aug 2008 17:35:56 -0700

Ralf Wildenhues wrote:

> Oh well; if somebody digs out the auto-import semantics from the list
> archives/manuals, feel free to add a note to so that the next
> person won't be confused again.  (Extra score for putting it in the new
> w32 chapter.  ;-)

The first issue here is that the auto-import mechanism requires that the
reference to the imported data item be in a writable section, because it
tricks the OS loader into making the fixup to the data address as if it
were fixing up an address of a dllimported function call.

The second issue is whether --enable-auto-import was specified to the
linker.  This is a tri-state setting:

(A) If --disable-auto-import is specified, no auto-import functionality
is attempted and link errors will result unless __declspec(dllimport) is
used with all data references.

(B) If --enable-auto-import is specified then the feature is enabled and
the link script is modified to place the contents of .rdata into .data,
in effect making all read-only data writable.

(C) If neither of the above are specified then the auto-import feature
is still enabled, but the link script is unchanged, and anything in
.rdata stays read-only.

The important point here is where the reference to the data item is
located.  Whether the data item itself is const doesn't matter, what
matters is the location from which it's referenced.  For the vast
majority of cases, the reference is in code, and so the linker can just
mark .text as writable -- it can do this without modifying the link
script so this works with both (B) and (C).

And this is the case with v8 in, which can be reduced more or
less to the following, which simply shows that the reference to _v8 is
in .text:

$ echo 'extern const char v8[]; char foo() { return v8[0]; }' | \
    gcc -x c - -c -S -o - -fomit-frame-pointer
        .file   ""
.globl _foo
        .def    _foo;   .scl    2;      .type   32;     .endef
        movsbl  _v8,%eax

In fact the constness of v8 is irrelevant, you get the same output if
you remove 'const'.  What does matter is if the reference to it is

$ echo 'extern char v8[]; const struct { char *ref; } s = { v8 };' |\
    gcc -x c - -c -S -o - -fomit-frame-pointer
        .file   ""
.globl _s
        .section .rdata,"dr"
        .align 4
        .long   _v8

Here you have the _v8 reference inside this struct that lives in .rdata,
so if you want to auto-import v8 you need to pessimize .rdata to be
writable, and thus you need (B).  The nasty part is that auto-import
will still try to do its job in case (C), and the link will succeed, but
you will get an inscrutable STATUS_ACCESS_VIOLATION (0xC0000005)
exception at runtime from the operating system before the process even
starts.  This is what the linker is trying to warn about with the
following diagnostic:

warning: auto-importing has been activated without --enable-auto-import
specified on the command line.
This should work unless it involves constant data structures referencing
symbols from auto-imported DLLs.

N.B. The tri-state behavior is new as of approx 2007-10-01.  Prior to
that, passing --enable-auto-import didn't really have much of an effect
other than suppressing info messages that the linker printed.  And if
you did have the case where you wanted to auto-import a reference in
.rdata as in the last example, you had no choice but to manually hack
your linker script or remove the 'const'.  This changed with the patch
for binutils PR4844:

It's also worth noting that if you do declare v8 as
__declspec(dllimport) then the compiler refuses (with a compile time
error) to let you use its address as a constant initializer as in the
last example.  Since this does work on other platforms like ELF, I
suppose you can view this as another portability tradeoff: you gain the
abililty to port this software as-is without having to modify it, albeit
at the cost of essentially making all const data writable and unable to
be shared with other process instances.

On this subject of the politics of declspec markup vs. auto-import, I
guess it breaks down to this:

For auto-import:
Pro: headers need not be modified/uglified to cater to win32-isms
Con: those headers may already have #defines for declarations using ELF
symbol visibility, in which case it's easy to hook in the equivalent
Win32 declspecs

Pro: support ELFisms like using a var from a shared lib as a const
Con: at the cost of making .rdata writable and unsharable (and a small
startup penalty)

For explicit __declspec(dllimport)
Pro: for function imports, saves an extra jump through the __imp_foo
Pro: for data imports, retains compatibility with MSVC as well as .text
remaining readonly and shareable


reply via email to

[Prev in Thread] Current Thread [Next in Thread]