Skip to content

Commit 6054608

Browse files
dist: Ensure UEFI rlibs are all COFF
If clang isn't the C compiler used for the UEFI targets, or if the wrong `--target` is passed to clang, we will get ELF objects in some rlibs. This will cause problems at link time when trying to compile a UEFI program that uses any of those objects. Add a check to the dist step for UEFI targets that reads each rlib with the `object` crate and fails with an error if any non-COFF objects are found.
1 parent 01a2a54 commit 6054608

File tree

3 files changed

+49
-0
lines changed

3 files changed

+49
-0
lines changed

src/bootstrap/Cargo.lock

+10
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ dependencies = [
5353
"hex",
5454
"ignore",
5555
"libc",
56+
"object",
5657
"once_cell",
5758
"opener",
5859
"pretty_assertions",
@@ -400,6 +401,15 @@ dependencies = [
400401
"libc",
401402
]
402403

404+
[[package]]
405+
name = "object"
406+
version = "0.29.0"
407+
source = "registry+https://github.com/rust-lang/crates.io-index"
408+
checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
409+
dependencies = [
410+
"memchr",
411+
]
412+
403413
[[package]]
404414
name = "once_cell"
405415
version = "1.12.0"

src/bootstrap/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ getopts = "0.2.19"
4242
cc = "1.0.69"
4343
libc = "0.2"
4444
hex = "0.4"
45+
object = { version = "0.29.0", default-features = false, features = ["archive", "coff", "read_core", "unaligned"] }
4546
serde = { version = "1.0.8", features = ["derive"] }
4647
serde_json = "1.0.2"
4748
sha2 = "0.10"

src/bootstrap/dist.rs

+38
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,14 @@
1010
1111
use std::collections::HashSet;
1212
use std::env;
13+
use std::ffi::OsStr;
1314
use std::fs;
1415
use std::path::{Path, PathBuf};
1516
use std::process::Command;
1617

18+
use object::read::archive::ArchiveFile;
19+
use object::BinaryFormat;
20+
1721
use crate::builder::{Builder, Kind, RunConfig, ShouldRun, Step};
1822
use crate::cache::{Interned, INTERNER};
1923
use crate::channel;
@@ -555,6 +559,39 @@ fn skip_host_target_lib(builder: &Builder<'_>, compiler: Compiler) -> bool {
555559
}
556560
}
557561

562+
/// Check that all objects in rlibs for UEFI targets are COFF. This
563+
/// ensures that the C compiler isn't producing ELF objects, which would
564+
/// not link correctly with the COFF objects.
565+
fn verify_uefi_rlib_format(builder: &Builder<'_>, target: TargetSelection, stamp: &Path) {
566+
if !target.ends_with("-uefi") {
567+
return;
568+
}
569+
570+
for (path, _) in builder.read_stamp_file(stamp) {
571+
if path.extension() != Some(OsStr::new("rlib")) {
572+
continue;
573+
}
574+
575+
let data = t!(fs::read(&path));
576+
let data = data.as_slice();
577+
let archive = t!(ArchiveFile::parse(data));
578+
for member in archive.members() {
579+
let member = t!(member);
580+
let member_data = t!(member.data(data));
581+
582+
let is_coff = match object::File::parse(member_data) {
583+
Ok(member_file) => member_file.format() == BinaryFormat::Coff,
584+
Err(_) => false,
585+
};
586+
587+
if !is_coff {
588+
let member_name = String::from_utf8_lossy(member.name());
589+
panic!("member {} in {} is not COFF", member_name, path.display());
590+
}
591+
}
592+
}
593+
}
594+
558595
/// Copy stamped files into an image's `target/lib` directory.
559596
fn copy_target_libs(builder: &Builder<'_>, target: TargetSelection, image: &Path, stamp: &Path) {
560597
let dst = image.join("lib/rustlib").join(target.triple).join("lib");
@@ -610,6 +647,7 @@ impl Step for Std {
610647

611648
let compiler_to_use = builder.compiler_for(compiler.stage, compiler.host, target);
612649
let stamp = compile::libstd_stamp(builder, compiler_to_use, target);
650+
verify_uefi_rlib_format(builder, target, &stamp);
613651
copy_target_libs(builder, target, &tarball.image_dir(), &stamp);
614652

615653
Some(tarball.generate())

0 commit comments

Comments
 (0)