Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

raw-dylib feature does not support all cases for stdcall functions on i686-pc-windows-* #96534

Closed
ricobbe opened this issue Apr 28, 2022 · 3 comments · Fixed by #100732
Closed
Assignees
Labels
C-bug Category: This is a bug. F-raw_dylib `#![feature(raw_dylib)]` O-windows Operating system: Windows T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@ricobbe
Copy link
Contributor

ricobbe commented Apr 28, 2022

Contrary to our original expectations, when an i686 DLL exports a stdcall function, the function's name can appear in the library's export table in one of several different ways. I don't know if this list is exhaustive, but I've seen the following variations:

  • _exported_function@8 (i.e., with leading underscore and trailing argument-list size)
  • exported_function@8 (trailing size only)
  • exported_function (exactly as it appears in the defining source file)
    Which form the symbols take appears to depend on how the DLL is linked. This is another facet of the problem that I don't fully understand, but one variable appears to be whether the function is defined with __declspec(dllexport) or the function is marked for export in a .DEF file provided to the linker invocation that creates the .DLL file.

To successfully link against such a DLL, the import library has to match not only the name of the symbol as it appears in the exporting DLL, but also the reference to the name (usually of the form __imp_exported_function@8, at least with rustc/LLVM) by which the importing library/image refers to it.

In an earlier attempt to solve this problem, we did notice that the three variants of the symbol name in the list above correspond to 3 of the 4 possible values of the IMPORT_NAME_TYPE enum defined in the PE-COFF spec, and I created an earlier proposal for adding a new attribute to specify the IMPORT_NAME_TYPE, but this turns out not to work. In particular, an earlier attempt on my part to have rustc supply the function names to LLVM with the decoration specified by the user doesn't work: specifying NAME_TYPE_UNDECORATE (intended to be the 3rd case above) resulted in an error when attempting to link the .rlib: the symbol __imp__exported_function@8 was not found. To reproduce, run src/test/run-make/raw-dylib-import-name type from the import-name-time branch of my fork of rustc.

@bjorn3 bjorn3 added C-bug Category: This is a bug. F-raw_dylib `#![feature(raw_dylib)]` O-windows Operating system: Windows T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Apr 28, 2022
@dpaoliello
Copy link
Contributor

@rustbot claim

@dpaoliello
Copy link
Contributor

FYI, I've managed to get an implementation of the import_type_name feature working and have re-created the MCP: rust-lang/compiler-team#525

Dylan-DPC added a commit to Dylan-DPC/rust that referenced this issue Aug 25, 2022
…leywiser

Implementation of import_name_type

Fixes rust-lang#96534 by implementing rust-lang/compiler-team#525

Symbols that are exported or imported from a binary on 32bit x86 Windows can be named in four separate ways, corresponding to the [import name types](https://docs.microsoft.com/en-us/windows/win32/debug/pe-format#import-name-type) from the PE-COFF spec. The exporting and importing binaries must use the same name encoding, otherwise mismatches can lead to link failures due to "missing symbols" or to 0xc0000139 (`STATUS_ENTRYPOINT_NOT_FOUND`) errors when the executable/library is loaded. For details, see the comments on the raw-dylib feature's rust-lang#58713. To generate the correct import libraries for these DLLs, therefore, rustc must know the import name type for each `extern` function, and there is currently no way for users to provide this information.

This change adds a new `MetaNameValueStr` key to the `#[link]` attribute called `import_name_type`, and which accepts one of three values: `decorated`, `noprefix`, and `undecorated`.

A single DLL is likely to export all its functions using the same import type name, hence `import_name_type` is a parameter of `#[link]` rather than being its own attribute that is applied per-function. It is possible to have a single DLL that exports different functions using different import name types, but users could express such cases by providing multiple export blocks for the same DLL, each with a different import name type.

Note: there is a fourth import name type defined in the PE-COFF spec, `IMPORT_ORDINAL`. This case is already handled by the `#[link_ordinal]` attribute. While it could be merged into `import_type_name`, that would not make sense as `#[link_ordinal]` provides per-function information (namely the ordinal itself).

Design decisions (these match the MCP linked above):
* For GNU, `decorated` matches the PE Spec and MSVC rather than the default behavior of `dlltool` (i.e., there will be a leading `_` for `stdcall`).
* If `import_name_type` is not present, we will keep our current behavior of matching the environment (MSVC vs GNU) default for decorating.
* Using `import_name_type` on architectures other than 32bit x86 will result in an error.
* Using `import_name_type` with link kinds other than `"raw-dylib"` will result in an error.
@bors bors closed this as completed in 9845f4c Aug 27, 2022
@rodrigocfd
Copy link

I got the following error:

 --- stderr
  thread 'main' panicked at build.rs:15:104:
  Failed to execute nbgv get-version: Error { kind: NotFound, message: "program not found" }
  note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

Which seems to be from Command::new("nbgv"). That means I have to install this program before running your tests?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-bug Category: This is a bug. F-raw_dylib `#![feature(raw_dylib)]` O-windows Operating system: Windows T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants