rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
94.84k stars 12.22k forks source link

export_name works for msvc x86_64 toolchain, but not i686 #44282

Open elitak opened 6 years ago

elitak commented 6 years ago

I'm trying to build a simple dll and export a function with a pre-mangled name. I have crate-type set to cdylib and my function decorated like so:

#[allow(non_snake_case)]
#[export_name="?Hook@@YAXXZ"] // This is how MSVC mangles this name.
pub fn Hook() {

I'm using MSVC 2017 Community edition v14.10.25017; toggling between these two toolchains using rustup: nightly-x86_64-pc-windows-msvc unchanged - rustc 1.22.0-nightly (f861b6ee4 2017-09-01) nightly-i686-pc-windows-msvc unchanged - rustc 1.22.0-nightly (f861b6ee4 2017-09-01)

The former links fine, the latter gives this error: mydll.dll.exp: error LNK2001: unresolved external symbol "void __cdecl Hook(void)" (?Hook@@YAXXZ) fatal error LNK1120: 1 unresolved externals

alexcrichton commented 6 years ago

Perhaps try using #[export_name="\x01?Hook@@YAXXZ"]? (an LLVM-ism)

elitak commented 6 years ago

Same deal. I tried a bunch of different combinations and it looks like "\x01" and "@" anywhere in the string trips it up (e.g. "a@b"). Again, this is only on the x86 and not the equivalent x64 toolchain, which seems pretty inexplicable to me, but then I know very little about LLVM.

alexcrichton commented 6 years ago

Does making it pub extern help vs pub fn?

elitak commented 6 years ago

I already guessed all sorts of extern types, to no avail. Even if I could trick it into working, it wouldn't explain why the x64 toolchain has no problem with the simpler form. Shouldn't the function compile and link without any changes to its annotations?

Are you able to reproduce the problem? I'll make a simple example project if you can't.

elitak commented 6 years ago

Here, try building this with the two distinct toolchains mentioned in OP: https://github.com/elitak/rust-issue44282

The x86_64 will link and the i686 won't.

alexcrichton commented 6 years ago

Sorry no I haven't been trying to reproduce locally, just throwing out some suggestions I could think of

elitak commented 6 years ago

Not even with that demo project? Both toolchains can build it for you?

On Fri, Sep 8, 2017 at 11:24 AM, Alex Crichton notifications@github.com wrote:

Sorry no I haven't been trying to reproduce locally, just throwing out some suggestions I could think of

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/rust-lang/rust/issues/44282#issuecomment-328179016, or mute the thread https://github.com/notifications/unsubscribe-auth/AAu8MYAOf0fdYrV_d3itPbCBV553FnQ5ks5sgYZugaJpZM4PLFoN .

retep998 commented 6 years ago

I've experienced this issue before and as far as I can tell it occurs due to the combination of 32-bit name decoration (which 64-bit doesn't have), and the fact that Rust uses a .DEF file for exports, Specifically I believe it is interpreting @ as signifying stdcall, so it tries makes the .dll export the symbol without the @whatever suffix but then something goes wrong and it fails to resolve it. I'm not entirely sure.

super-continent commented 4 years ago

This is an old issue but has anyone figured out a solution? I have this issue when compiling something for i686-pc-windows-msvc and haven't been able to fix it.

It seems I'm getting decorations from MSVC on the name. I don't know if that would be fixable from a rust command or if i would need to edit something else.

Just for clarification, I've gotten this issue on using #[no_mangle], #[link_name], and the #[export_name="\x01whatever_name"] trick

elitak commented 4 years ago

I never found a workaround, but I also didn't try diving into the generated .def files or anything as was suggested at the end.

brandonros commented 1 year ago

I found a workaround.

ordinals.def:

LIBRARY "redacted.dll"
EXPORTS
  _Java_redacted@32

lib.rs:

#[export_name = "Java_redacted"]
pub unsafe extern "stdcall" fn Java_redacted(unk1: c_void, unk2: c_void, unk3: c_void, unk4: c_void, unk5: c_void, unk6: c_void, unk7: c_void, unk8: c_void) {
  panic!("TODO");
}

build.rs:

fn main() {
  println!("cargo:rustc-cdylib-link-arg=/DEF:./hook/ordinals.def");
}

Cargo.toml:

[package]
name = "hook"
version = "0.1.0"
edition = "2021"

[dependencies]
...

[lib]
crate-type = ["cdylib"]
ultimaweapon commented 3 days ago

Just stumbled upon this issue on a static item. My use case is I need to define a C++ variable on Rust side like this:

extern CModeMgr *g_modeMgr;
#[export_name = "?g_modeMgr@@3PAVCModeMgr@@A"]
static mut G_MODE_MGR: usize = 0;

This will cause the following error:

symbols.o : error LNK2001: unresolved external symbol _?g_modeMgr@@3PAVCModeMgr@@A

I was tried to prefix the export_name with \x01 and the error is still the same:

#[export_name = "\x01?g_modeMgr@@3PAVCModeMgr@@A"]
static mut G_MODE_MGR: usize = 0;