On Sun, 9 Oct 2022, LIU Hao wrote:
在 2022/10/9 18:05, Pali Rohár 写道:
Ok, I see.
Anyway, I quite do not understand why some crt exported functions are
marked with _CRTIMP (as it is empty during CRT build) and some exported
variables use __MINGW_IMP_SYMBOL. I would expect that all exported
functions and variables (from dll) would use same "syntax" and same
"behavior". Is not this a bug?
And why is not used directly __desclspec(dllimport)? I think that
specifying dllimport is same as using __MINGW_IMP_SYMBOL and then
defining a new macro with pointer dereferencing of defined symbol.
Or not and is there something special why "more complicated" approach
via __MINGW_IMP_SYMBOL is required?
Because sometimes we would like to override them, for example, in
'ucrtbase_compat.c'.
This
```
void __attribute__((__dllimport__)) _tzset(void);
void (*__imp__tzset)(void) = _tzset;
int
main(void)
{
_tzset();
}
```
will cause an error, as the function call to dllimport'd function in `main()`
pulls it from 'libmsvcrt.a', which also brings its own pointer:
```
$ x86_64-w64-mingw32-gcc -Wall -Wextra test.c
/usr/bin/x86_64-w64-mingw32-ld: /usr/lib/gcc/x86_64-w64-mingw32/10-w
in32/../../../../x86_64-w64-mingw32/lib/libmsvcrt.a(libmsvcrt-oss007
17.o):(.idata$5+0x0): multiple definition of `__imp__tzset'; /tmp/cc
1GlQ7e.o:test.c:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status
```
I think this example kinda misses the point; here you already do have an
__imp__tzset elsewhere (from the import library) - but we only do manually
define e.g. __imp__tzset when we're in a configuration where the import
library doesn't provide it (or we've commented it out from the def file).
Historically, the _CRTIMP macro comes from how it is used in upstream
msvcrt; you can link the CRT either statically or dynamically. If
intending to link statically, _CRTIMP expands to nothing, while if
intending to link dyanmically, _CRTIMP expands to dllimport. For
mingw-w64, there's no option to link the full CRT statically, so from user
code point of view, there's only the dllimport case to care about.
But when building code within mingw-w64-crt, _CRTIMP expands to nothing. I
guess this is generally desireable when implementing some of the functions
that are marked _CRTIMP (we generally shouldn't have a dllimport
declaration of the function visible when we're implementing it).
However this can also be tricky, because if it indeed is a data symbol
that we're overriding/providing in mingw-w64-crt, then having it visible
without dllimport is fine (when other object files in mingw-w64-crt
reference it, and both of them will be linked statically, but if it is a
symbol that will be imported from a DLL file, via the def files, then
accessing it without dllimport is going to cause unnecessary auto imports
and runtime pseudo relocs.
So in short, the following two are functionally exactly equivalent - they
generate the same code in a compiler when you reference it:
extern int * __MINGW_IMP_SYMBOL(someDataSymbol);
#define someDataSymbol (* __MINGW_IMP_SYMBOL(someDataSymbol))
and
extern int __declspec(dllimport) someDataSymbol;
However if you make it
extern int _CRTIMP someDataSymbol;
then you lose the dllimport for any code within mingw-w64-crt that is
accessing it - leading to unnecessary auto imports and runtime pseudo
relocs.
I think the common pattern within mingw-w64-headers is to simply use the
first form via the explicit __MINGW_IMP_SYMBOL redirection for any data
symbols, while _CRTIMP is used for functions only. Exported data symbols
in the CRT interface generally are problematic anyway. And the define
form, while kinda unwieldy, gives you a bit more freedoms to check for it
with ifdef, work around it with undef, etc.
// Martin
_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public