Fix for raw-dylib when linking with MinGW BFD#88801
Fix for raw-dylib when linking with MinGW BFD#88801mati865 wants to merge 4 commits intorust-lang:masterfrom
Conversation
|
r? @nagisa (rust-highfive has picked a reviewer for you, use r? to override) |
|
This approach is admirable in its simplicity, but unfortunately, I don't think it supports all of the cases specified in the RFC. To the best of my knowledge, there is no way to specify stdcall, fastcall, or vectorcall functions in a .DEF file, and stdcall in particular is required in order to link against the Windows API on 32-bit Intel. |
|
Right, I tend to forget i686 targets still do exist. I think there is no problem with most of calling conventions as long as we properly save them into // $ cat calling_conventions.c
__cdecl __declspec(dllexport) int cdeclSum(int a, int b)
{
return a + b;
}
__stdcall __declspec(dllexport) int stdcallSum(int a, int b)
{
return a + b;
}
__fastcall __declspec(dllexport) int fastcallSum(int a, int b)
{
return a + b;
}Compile, link and check the symbols: $ gcc -shared calling_conventions.c -o calling_conventions.dll
$ nm calling_conventions.dll | rg Sum
64ec14fc T @fastcallSum@8
64ec14e0 T _cdeclSum
64ec14ed T _stdcallSum@8So far so good, now $ gendef calling_conventions.dll
* [calling_conventions.dll] Found PE image
$ cat calling_conventions.def
;
; Definition file of calling_conventions.dll
; Automatic generated by gendef
; written by Kai Tietz 2008
;
LIBRARY "calling_conventions.dll"
EXPORTS
@fastcallSum@8
cdeclSum
stdcallSum@8@8Now the import library: $ dlltool -d calling_conventions.def -l calling_conventions.dll.a
$ nm calling_conventions.dll.a | rg Sum
00000000 I __imp__stdcallSum@8@8
00000000 T _stdcallSum@8@8
00000000 I __imp__cdeclSum
00000000 T _cdeclSum
00000000 T @fastcallSum@8
00000000 I __imp_@fastcallSum@8I'm not an Windows expert but seems fine for me. Now the hard part for GNU toolchain, __vectorcall __declspec(dllexport) int vectorcallSum(int a, int b)
{
return a + b;
}Let's build, link and see the symbols: $ gcc -shared calling_conventions.c -o calling_conventions.dll
calling_conventions.c:16:1: warning: data definition has no type or storage class
16 | __vectorcall __declspec(dllexport) int vectorcallSum(int a, int b)
| ^~~~~~~~~~~~
calling_conventions.c:16:1: warning: type defaults to 'int' in declaration of '__vectorcall' [-Wimplicit-int]
calling_conventions.c:16:36: error: expected ',' or ';' before 'int'
16 | __vectorcall __declspec(dllexport) int vectorcallSum(int a, int b)
| ^~~
# GCC didn't work, trying Clang
$ clang -shared calling_conventions.c -o calling_conventions.dll
D:/msys64/mingw32/bin/ld: cannot export vectorcallSum@@8: symbol not found
clang: error: linker command failed with exit code 1 (use -v to see invocation)
# Which failed because of BFD..., now LLD
$ clang -fuse-ld=lld -shared calling_conventions.c -o calling_conventions.dll
$ nm calling_conventions.dll | rg Sum
10001520 T @fastcallSum@8
100014e0 T _cdeclSum
10001500 T _stdcallSum@8
10001540 T vectorcallSum@@8So Clang + LLD worked, let's see about GNU dlltool: $ gendef calling_conventions.dll
* [calling_conventions.dll] Found PE image
$ cat calling_conventions.def
;
; Definition file of calling_conventions.dll
; Automatic generated by gendef
; written by Kai Tietz 2008
;
LIBRARY "calling_conventions.dll"
EXPORTS
@fastcallSum@8
cdeclSum
stdcallSum@8@8
vectorcallSum@@8
$ dlltool -d calling_conventions.def -l calling_conventions.dll.a
$ nm calling_conventions.dll.a | rg Sum
00000000 I __imp__vectorcallSum@@8
00000000 T _vectorcallSum@@8
00000000 I __imp__stdcallSum@8@8
00000000 T _stdcallSum@8@8
00000000 I __imp__cdeclSum
00000000 T _cdeclSum
00000000 T @fastcallSum@8
00000000 I __imp_@fastcallSum@8It worked I guess. |
|
So this has almost worked, the main raw-dylib test passes on i686, alt calling convections not so much: So far I had no success getting debuggers on Windows to help me with that but I wouldn't be surprised if it's alignment issue. |
|
A bit cleaned up the implementation and added 2 MinGW builders to the CI. That way I can test Linux -> Windows and {i686,x86_64} Windows -> {i686,x86_64} Windows cross builds. Can I have |
|
@bors try |
|
⌛ Trying commit 83c2fea with merge 5e9549d92c173bb99ee4c50a87b6199ac57d62a6... |
|
☀️ Try build successful - checks-actions |
|
It works in all cases except self-contained mode because it's not added to the PATH (even with |
|
|
||
| fn find_dlltool(sess: &Session) -> OsString { | ||
| // When cross-compiling first try binary prefixed with target triple | ||
| if sess.host.llvm_target != sess.target.llvm_target { |
There was a problem hiding this comment.
llvm_target is probably not the best way to check for this. There are many llvm target triples that are actually equivalent in the end. (e.g. i686-pc-windows-gnu and i686-unknown-windows-gnu and e.g. json targets could specify either).
| } else { | ||
| prefixed_dlltool.to_string() | ||
| }; | ||
| for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { |
There was a problem hiding this comment.
This should also either verify that the binary is executable at all in some way or provide a way to override this detection. Right now if the system is borked enough to have a non-working i686-w64-mingw32-dlltool but a working dlltool, then there is fairly little the user user can do to work around the problem.
There was a problem hiding this comment.
TBH the more I think about this approach the more hacky it seems.
| # Test the behavior of #[link(.., kind = "raw-dylib")] with alternative calling conventions. | ||
|
|
||
| # only-i686-pc-windows-msvc | ||
| # only-i686-pc-windows-gnu |
There was a problem hiding this comment.
These tests are supposed to eventually test both architectures, right?
There was a problem hiding this comment.
Yeah, I just didn't want to make spend time on proper fix yet.
|
With #89025 it's clear how this approach is lacking and won't help much to stabilise |
Can you not use just the syntax
As a separate point, we should probably double-quote the func_name, in case func_name is a def-file keyword. |
…woerister Implement raw-dylib support for windows-gnu Add support for `#[link(kind = "raw-dylib")]` on windows-gnu targets. Work around binutils's linker's inability to read import libraries produced by LLVM by calling out to the binutils `dlltool` utility to create an import library from a temporary .DEF file; this approach is effectively a slightly refined version of `@mati865's` earlier attempt at this strategy in PR rust-lang#88801. (In particular, this attempt at this strategy adds support for `#[link_ordinal(...)]` as well.) In support of rust-lang#58713.
…woerister Implement raw-dylib support for windows-gnu Add support for `#[link(kind = "raw-dylib")]` on windows-gnu targets. Work around binutils's linker's inability to read import libraries produced by LLVM by calling out to the binutils `dlltool` utility to create an import library from a temporary .DEF file; this approach is effectively a slightly refined version of ``@mati865's`` earlier attempt at this strategy in PR rust-lang#88801. (In particular, this attempt at this strategy adds support for `#[link_ordinal(...)]` as well.) In support of rust-lang#58713.
…woerister Implement raw-dylib support for windows-gnu Add support for `#[link(kind = "raw-dylib")]` on windows-gnu targets. Work around binutils's linker's inability to read import libraries produced by LLVM by calling out to the binutils `dlltool` utility to create an import library from a temporary .DEF file; this approach is effectively a slightly refined version of ```@mati865's``` earlier attempt at this strategy in PR rust-lang#88801. (In particular, this attempt at this strategy adds support for `#[link_ordinal(...)]` as well.) In support of rust-lang#58713.
…woerister Implement raw-dylib support for windows-gnu Add support for `#[link(kind = "raw-dylib")]` on windows-gnu targets. Work around binutils's linker's inability to read import libraries produced by LLVM by calling out to the binutils `dlltool` utility to create an import library from a temporary .DEF file; this approach is effectively a slightly refined version of `@mati865's` earlier attempt at this strategy in PR rust-lang#88801. (In particular, this attempt at this strategy adds support for `#[link_ordinal(...)]` as well.) In support of rust-lang#58713.
…dylib, r=michaelwoerister Fix MinGW target detection in raw-dylib LLVM target doesn't have to be the same as Rust target so relying on it is wrong. It was one of concerns in rust-lang#88801 that was not fixed in rust-lang#90782.
Basically a proof of concept right now, needs more work/thoughts.