Skip to content

Build script executes illegal instructions when cross-compiling #353

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
jw1912 opened this issue May 4, 2025 · 2 comments
Closed

Build script executes illegal instructions when cross-compiling #353

jw1912 opened this issue May 4, 2025 · 2 comments

Comments

@jw1912
Copy link

jw1912 commented May 4, 2025

The build script executes a total_cmp, which appears to compile with whatever target features are passed, rather than the host target, meaning that when cross-compiling anything that has num-traits as a dependency the build may fail due to encountering an illegal instruction.

Steps to reproduce:
Compile targeting an instruction set that your CPU does not support.

E.g:
On an AMD Ryzen 5 5500U (x86-64-v3) CPU:

RUSTFLAGS="target-cpu=x86-64-v3" cargo b -r

Compiles fine, as the CPU supports the necessary instructions.

RUSTFLAGS="target-cpu=x86-64-v4" cargo b -r

Results in

$ RUSTFLAGS="-Ctarget-cpu=x86-64-v4" cargo b -r
   Compiling autocfg v1.4.0
   Compiling num-traits v0.2.19 (/home/repos/num-traits)
error: failed to run custom build command for `num-traits v0.2.19 (/home/repos/num-traits)`

Caused by:
  process didn't exit successfully: `/home/repos/num-traits/target/release/build/num-traits-a3ee22140a8ef772/build-script-build` (signal: 4, SIGILL: illegal instruction)

Relevant godbolt for total_cmp (usage of vpsraq):

@cuviper
Copy link
Member

cuviper commented May 4, 2025

ac.emit_expression_cfg("1f64.total_cmp(&2f64)", "has_total_cmp"); // 1.62

This autocfg line is only compiles an object, not linked to a binary and certainly not executed, so I think this is a red herring. Your result also show the build script itself hitting SIGILL, not the secondary code it compiles.

I can reproduce the crash, and at least with my version, it's coming from a hash set used by autocfg:

Program received signal SIGILL, Illegal instruction.
0x000055971b503c43 in core::core_arch::x86::sse2::_mm_movemask_epi8 ()
(gdb) display/i $pc
1: x/i $pc
=> 0x55971b503c43 <_ZN4core9core_arch3x864sse217_mm_movemask_epi817ha4c6d733ff085a27E+163>:     vpmovb2m %xmm0,%k0
(gdb) bt
#0  0x000055971b503c43 in core::core_arch::x86::sse2::_mm_movemask_epi8 ()
#1  0x000055971b4ff3ec in hashbrown::raw::RawTable<T,A>::reserve_rehash ()
#2  0x000055971b4ffbb6 in hashbrown::raw::RawTable<T,A>::reserve ()
#3  0x000055971b4fa2a0 in <hashbrown::map::HashMap<K,V,S,A> as core::iter::traits::collect::Extend<(K,V)>>::extend ()
#4  0x000055971b508de1 in <hashbrown::set::HashSet<T,S,A> as core::iter::traits::collect::Extend<T>>::extend ()
#5  0x000055971b508f8e in <std::collections::hash::set::HashSet<T,S> as core::iter::traits::collect::FromIterator<T>>::from_iter ()
#6  0x000055971b5037fe in core::iter::traits::iterator::Iterator::collect ()
#7  0x000055971b4f9f4e in autocfg::new_uuid ()
#8  0x000055971b4f8753 in autocfg::AutoCfg::with_dir ()
#9  0x000055971b4f8246 in autocfg::AutoCfg::new ()
#10 0x000055971b4f80bc in autocfg::new ()

But even that is just a symptom. The problem is that Cargo is applying your "cross" RUSTFLAGS to code that does need to execute on the current host, which may be any build script or proc-macro. There's a workaround though, because it will separate those flags if you explicitly set the --target option, even when it's otherwise the same as the host.

$ RUSTFLAGS="-Ctarget-cpu=x86-64-v4" cargo b -r --target x86_64-unknown-linux-gnu

https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags

If the --target flag (or build.target) is used, then the flags will only be passed to the compiler for the target. Things being built for the host, such as build scripts or proc macros, will not receive the args. Without --target, the flags will be passed to all compiler invocations (including build scripts and proc macros) because dependencies are shared. If you have args that you do not want to pass to build scripts or proc macros and are building for the host, pass --target with the host triple.

@cuviper cuviper closed this as not planned Won't fix, can't repro, duplicate, stale May 4, 2025
@tarcieri
Copy link
Contributor

tarcieri commented May 4, 2025

possibly related: rust-lang/cargo#4423

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants