Skip to content

unresolved external symbol _round / _trunc #36

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

Closed
otopetrik opened this issue Sep 10, 2024 · 7 comments
Closed

unresolved external symbol _round / _trunc #36

otopetrik opened this issue Sep 10, 2024 · 7 comments
Assignees
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@otopetrik
Copy link

I tried this code:

let a : f64 = 0.75;
println!("1: {}, 0: {}", a.round(), a.trunc());

(minimal example, added to main of rust9x-sample)

I expected to see this happen:

it should still compile and link (cargo +rust9x build --target i586-rust9x-windows-msvc)

Instead, this happened:

rust9x_sample.2zkro5s6070qsnwl.rcgu.o : error LNK2019: unresolved external symbol _round referenced in function __ZN3std3f6421_$LT$impl$u20$f64$GT$5round17hdb8bf8074c9d0b50E
rust9x_sample.2zkro5s6070qsnwl.rcgu.o : error LNK2019: unresolved external symbol _trunc referenced in function __ZN3std3f6421_$LT$impl$u20$f64$GT$5trunc17hd85680ad541ba85dE
<some path>\rust9x-sample\target\i586-rust9x-windows-msvc\debug\deps\rust9x_sample.exe : fatal error LNK1120: 2 unresolved externals

The issue also appears when program depends on crates config and/or time.

Meta

rustc +rust9x --version --verbose:

rustc 1.76.0-dev
binary: rustc
commit-hash: unknown
commit-date: unknown
host: x86_64-pc-windows-msvc
release: 1.76.0-dev
LLVM version: 17.0.6

rust9x-1.76-beta-v5 on Windows 10

Installation uses:

  • "Microsoft Windows SDK for Windows 7" for link.exe (PATH environment variable).
  • "Microsoft Windows SDK for Windows 7" which does not have ntdll.lib and "Windows 10 SDK version 2104 (10.0.20348.0)" for ntdll.lib (LIB environment variable)

Unmodified sample compiled and linked correctly. Minimal reqwest example also successfully compiles, links and runs:

the example from reqwest readme file

use std::collections::HashMap;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let resp = reqwest::get("https://httpbin.org/ip")
        .await?
        .json::<HashMap<String, String>>()
        .await?;
    println!("{resp:#?}");
    Ok(())
}

@seritools
Copy link
Member

Could you try using modern link.exe and use https://github.com/rust9x/rust9x-sample/blob/main/.cargo/config.toml to specify the W7 SDK files and see if that changes anything?

@seritools
Copy link
Member

Another way to try would be to figure out what the exports are called in that SDK version, and tell the linker to look for that alternate name, similar to

// Link to ___CxxFrameHandler (XP and earlier MSVCRT) instead of ___CxxFrameHandler3.
// This cannot be done in the MSVC `eh_personality` handling because LLVM hardcodes SEH
// support based on that name, sadly
"/ALTERNATENAME:___CxxFrameHandler3=___CxxFrameHandler",

@seritools seritools self-assigned this Nov 29, 2024
@seritools seritools added the bug Something isn't working label Nov 29, 2024
@seritools
Copy link
Member

Sooo, MS only added many of the C99 math functions in VS2013: ldc-developers/ldc#822 (comment)

Once cursed way of potentially getting it to work is to link to the Universal C Runtime as well:

  # Add modern universal CRT for missing math functions
  '-Clink-args=libucrt.lib',

It will only fall back to libucrt for functions imported that aren't available in your main linked runtime. I'm 95% sure this has some horrible side effects, but might be worth a shot!

@seritools
Copy link
Member

seritools commented Nov 29, 2024

One problem will likely be that the UCRT relies on the symbol __isa_available, which will not be correctly initialized when imported this way.

EDIT:

Yeah...

libucrt.lib(trunc.obj) : error LNK2001: unresolved external symbol ___isa_available

I guess you could get around it by manually defining it on the rust side x) See https://github.com/huangqinjin/ucrt/blob/d6e817a4cc90f6f1fe54f8a0aa4af4fff0bb647d/inc/corecrt_internal_simd.h#L21 and https://github.com/huangqinjin/ucrt/blob/d6e817a4cc90f6f1fe54f8a0aa4af4fff0bb647d/inc/i386/cruntime.inc#L179

Could export the symbol yourself with the desired feature level:

#[unsafe(no_mangle)] // #[no_mangle] in 1.76, iirc
#[used]
pub static __isa_available: c_int = 0;

@seritools seritools added enhancement New feature or request help wanted Extra attention is needed and removed bug Something isn't working labels Nov 29, 2024
@otopetrik
Copy link
Author

Thanks, already used the previous /ALTERNATENAME suggestion to create my current (even more cursed) workaround for targeting Windows XP. Replacing round with ceil, and trunc with floor!

In my use case, it looks like floating-point is limited to configuring timeouts for reqwest, so precision is not that important.

The following seems to work:

hostlinker.bat

C:\Program Files\LLVM\bin\lld-link.exe" ^
    "/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\Lib\amd64" ^
    "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\Lib\10.0.20348.0\um\x64" ^
    "/ALTERNATENAME:round=ceil" ^
    "/ALTERNATENAME:trunc=floor" ^
    %*

.cargo/config.toml

[target.x86_64-pc-windows-msvc]
linker = './hostlinker.bat'

[target.i586-rust9x-windows-msvc]
linker = "C:/Program Files/LLVM/bin/lld-link.exe"
rustflags = [
    '--print=link-args',
    # Windows 2003 Server SDK
    '-Clink-arg=/LIBPATH:C:\Program Files\Microsoft Platform SDK\Lib',
    # Windows 7 SDK for MSVCRT
    '-Clink-arg=/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\Lib',
]

build.rs

...
    println!("cargo::rustc-link-arg=/ALTERNATENAME:_round=_ceil");
    println!("cargo::rustc-link-arg=/ALTERNATENAME:_trunc=_floor");
    // build libraries like ntdll.lib,... from an empty .c file, and link to them
    println!("cargo:rustc-link-search=native={}", native_libraries_dir.to_string_lossy());
...

It requires:

  • Windows Server 2003 SP1 Platform SDK (WinXP SDK does not work on 64-bit Windows)
  • Windows 7 SDK (for a MSVCRT library, seems to be the latest SDK which includes compiler and CRT library)
  • Windows 10 SDK (10.0.20348.0), version 2104 (needed for dependencies' build.rs/macros, because it has required ntdll.lib, etc...)
  • LLVM (no need to figure out which link.exe is needed for 64-bit host, and which for 32-bit target)

This approach does not require any Visual Studio (not even the Community Edition).
Using patched socket2 and patched fork of mio (and by implementing API functions missing on Windows XP), it is possible to get a version of reqwest crate working on Windows XP (at least in single-threaded tokio new_current_thread runtime).

According to this, it should be theoretically possible to actually use an older version of ucrt as the CRT library on Windows XP (did not explore this path further).

@seritools
Copy link
Member

seritools commented Nov 29, 2024

According to this, it should be theoretically possible to actually use an older version of ucrt as the CRT library on Windows XP (did not explore this path further).

Correct, WinXP in particular should be much more straightforward - you can compile against the modern-ish XP platform toolset (VS2017) and everything should just work there: https://learn.microsoft.com/en-us/cpp/build/configuring-programs-for-windows-xp

@seritools
Copy link
Member

I've added a section on this in the https://github.com/rust9x/rust/wiki/Limitations wiki entry - can't really do much about this otherwise!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

2 participants