Skip to content

Commit 1fcce64

Browse files
committed
Ensure that the bitcode was compiled with the supported LLVM version
Linking bitcode produced by different LLVM versions can lead either to: - The backend failing to lower the IR to bytecode (an easier-to-debug scenario that throws a descriptive error). - "Successful" compilation but with broken BTF (DI sanitization modifies DI operands, which have incompatibilities across versions). To prevent both cases, throw an error when the bitcode is incompatible with a more descriptive error message.
1 parent 0758647 commit 1fcce64

File tree

5 files changed

+597
-9
lines changed

5 files changed

+597
-9
lines changed

Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ clap = { workspace = true }
2222
tracing-appender = "0.2"
2323
tracing-subscriber = { version = "0.3", features = ["env-filter", "registry"] }
2424
tracing-tree = "0.4"
25+
rustversion = { version = "1.0.17", default-features = false }
2526

2627
# lib deps
2728
ar = { version = "0.9.0" }
@@ -36,6 +37,7 @@ thiserror = { version = "2.0.12" }
3637
tracing = "0.1"
3738

3839
[dev-dependencies]
40+
assert_matches = "1.5.0"
3941
compiletest_rs = { version = "0.11.0" }
4042
regex = { version = "1.11.1", default-features = false }
4143
rustc-build-sysroot = { workspace = true }

src/linker.rs

Lines changed: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,29 @@ use llvm_sys::{
1818
use thiserror::Error;
1919
use tracing::{debug, error, info, warn};
2020

21-
use crate::llvm::{self, LLVMContext, LLVMModule, LLVMTargetMachine, MemoryBuffer};
21+
use crate::llvm::{
22+
self, LLVMContext, LLVMModule, LLVMTargetMachine, LlvmVersionDetectionError, MemoryBuffer,
23+
};
24+
25+
#[cfg(feature = "llvm-19")]
26+
const SUPPORTED_LLVM_MAJOR: u32 = 19;
27+
#[cfg(feature = "llvm-20")]
28+
const SUPPORTED_LLVM_MAJOR: u32 = 20;
29+
#[cfg(feature = "llvm-21")]
30+
const SUPPORTED_LLVM_MAJOR: u32 = 21;
31+
32+
#[cfg(any(
33+
all(feature = "llvm-19", not(feature = "rust-llvm-19")),
34+
all(feature = "llvm-20", not(feature = "rust-llvm-20")),
35+
all(feature = "llvm-21", not(feature = "rust-llvm-21")),
36+
))]
37+
const SUGGESTED_FEATURE_PREFIX: &str = "llvm-";
38+
#[cfg(any(
39+
feature = "rust-llvm-19",
40+
feature = "rust-llvm-20",
41+
feature = "rust-llvm-21",
42+
))]
43+
const SUGGESTED_FEATURE_PREFIX: &str = "rust-llvm-";
2244

2345
/// Linker error
2446
#[derive(Debug, Error)]
@@ -74,6 +96,27 @@ pub enum LinkerError {
7496
/// LLVM cannot create a module for linking.
7597
#[error("failed to create module")]
7698
CreateModuleError,
99+
100+
/// The LLVM version embedded in the input bitcode is not supported.
101+
#[error(
102+
"bitcode {path} was built with LLVM {bitcode_version}, but this bpf-linker
103+
supports LLVM {linker_version}; please re-install bpf-linker with
104+
`cargo install --force bpf-linker --no-default-features --features
105+
{SUGGESTED_FEATURE_PREFIX}{bitcode_version}`"
106+
)]
107+
LlvmVersionMismatch {
108+
path: PathBuf,
109+
bitcode_version: String,
110+
linker_version: u32,
111+
},
112+
113+
/// Failed to determine the LLVM version for a bitcode input.
114+
#[error("failed to determine LLVM version for `{path}`: {kind}")]
115+
LlvmVersionDetectionError {
116+
path: PathBuf,
117+
#[source]
118+
kind: LlvmVersionDetectionError,
119+
},
77120
}
78121

79122
/// BPF Cpu type
@@ -602,11 +645,21 @@ fn link_reader<'ctx>(
602645
InputType::Archive => panic!("nested archives not supported duh"),
603646
};
604647

605-
if !llvm::link_bitcode_buffer(context, module, &bitcode) {
606-
return Err(LinkerError::LinkModuleError(path.to_owned()));
648+
match llvm::link_bitcode_buffer(context, module, &bitcode, Some(SUPPORTED_LLVM_MAJOR)) {
649+
Ok(true) => Ok(()),
650+
Ok(false) => Err(LinkerError::LinkModuleError(path.to_owned())),
651+
Err(LlvmVersionDetectionError::VersionMismatch {
652+
bitcode_version, ..
653+
}) => Err(LinkerError::LlvmVersionMismatch {
654+
path: path.to_owned(),
655+
bitcode_version,
656+
linker_version: SUPPORTED_LLVM_MAJOR,
657+
}),
658+
Err(kind) => Err(LinkerError::LlvmVersionDetectionError {
659+
path: path.to_owned(),
660+
kind,
661+
}),
607662
}
608-
609-
Ok(())
610663
}
611664

612665
fn create_target_machine(

0 commit comments

Comments
 (0)