diff --git a/src/tools/run-make-support/src/clang.rs b/src/tools/run-make-support/src/clang.rs
new file mode 100644
index 00000000000..ed9f8383dc3
--- /dev/null
+++ b/src/tools/run-make-support/src/clang.rs
@@ -0,0 +1,73 @@
+use std::env;
+use std::path::Path;
+use std::process::Command;
+
+use crate::{bin_name, handle_failed_output, tmp_dir};
+
+/// Construct a new `clang` invocation. `clang` is not always available for all targets.
+pub fn clang() -> Clang {
+    Clang::new()
+}
+
+/// A `clang` invocation builder.
+#[derive(Debug)]
+pub struct Clang {
+    cmd: Command,
+}
+
+crate::impl_common_helpers!(Clang);
+
+impl Clang {
+    /// Construct a new `clang` invocation. `clang` is not always available for all targets.
+    pub fn new() -> Self {
+        let clang =
+            env::var("CLANG").expect("`CLANG` not specified, but this is required to find `clang`");
+        let cmd = Command::new(clang);
+        Self { cmd }
+    }
+
+    /// Provide an input file.
+    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg(path.as_ref());
+        self
+    }
+
+    /// Specify the name of the executable. The executable will be placed under `$TMPDIR`, and the
+    /// extension will be determined by [`bin_name`].
+    pub fn out_exe(&mut self, name: &str) -> &mut Self {
+        self.cmd.arg("-o");
+        self.cmd.arg(tmp_dir().join(bin_name(name)));
+        self
+    }
+
+    /// Specify which target triple clang should target.
+    pub fn target(&mut self, target_triple: &str) -> &mut Self {
+        self.cmd.arg("-target");
+        self.cmd.arg(target_triple);
+        self
+    }
+
+    /// Pass `-nostdlib` to disable linking the C standard library.
+    pub fn no_stdlib(&mut self) -> &mut Self {
+        self.cmd.arg("-nostdlib");
+        self
+    }
+
+    /// Specify architecture.
+    pub fn arch(&mut self, arch: &str) -> &mut Self {
+        self.cmd.arg(format!("-march={arch}"));
+        self
+    }
+
+    /// Specify LTO settings.
+    pub fn lto(&mut self, lto: &str) -> &mut Self {
+        self.cmd.arg(format!("-flto={lto}"));
+        self
+    }
+
+    /// Specify which ld to use.
+    pub fn use_ld(&mut self, ld: &str) -> &mut Self {
+        self.cmd.arg(format!("-fuse-ld={ld}"));
+        self
+    }
+}
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 9a4fdff5d15..e723e824ed6 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -4,6 +4,8 @@
 //! as `object` or `wasmparser`, they can be re-exported and be made available through this library.
 
 pub mod cc;
+pub mod clang;
+pub mod llvm_readobj;
 pub mod run;
 pub mod rustc;
 pub mod rustdoc;
@@ -17,6 +19,8 @@ pub use regex;
 pub use wasmparser;
 
 pub use cc::{cc, extra_c_flags, extra_cxx_flags, Cc};
+pub use clang::{clang, Clang};
+pub use llvm_readobj::{llvm_readobj, LlvmReadobj};
 pub use run::{run, run_fail};
 pub use rustc::{aux_build, rustc, Rustc};
 pub use rustdoc::{bare_rustdoc, rustdoc, Rustdoc};
diff --git a/src/tools/run-make-support/src/llvm_readobj.rs b/src/tools/run-make-support/src/llvm_readobj.rs
new file mode 100644
index 00000000000..32ea07e932e
--- /dev/null
+++ b/src/tools/run-make-support/src/llvm_readobj.rs
@@ -0,0 +1,44 @@
+use std::env;
+use std::path::{Path, PathBuf};
+use std::process::Command;
+
+use crate::handle_failed_output;
+
+/// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available
+/// at `$LLVM_BIN_DIR/llvm-readobj`.
+pub fn llvm_readobj() -> LlvmReadobj {
+    LlvmReadobj::new()
+}
+
+/// A `llvm-readobj` invocation builder.
+#[derive(Debug)]
+pub struct LlvmReadobj {
+    cmd: Command,
+}
+
+crate::impl_common_helpers!(LlvmReadobj);
+
+impl LlvmReadobj {
+    /// Construct a new `llvm-readobj` invocation. This assumes that `llvm-readobj` is available
+    /// at `$LLVM_BIN_DIR/llvm-readobj`.
+    pub fn new() -> Self {
+        let llvm_bin_dir = env::var("LLVM_BIN_DIR")
+            .expect("`LLVM_BIN_DIR` not specified, but this is required to find `llvm-readobj`");
+        let llvm_bin_dir = PathBuf::from(llvm_bin_dir);
+        let llvm_readobj = llvm_bin_dir.join("llvm-readobj");
+        let cmd = Command::new(llvm_readobj);
+        Self { cmd }
+    }
+
+    /// Provide an input file.
+    pub fn input<P: AsRef<Path>>(&mut self, path: P) -> &mut Self {
+        self.cmd.arg(path.as_ref());
+        self
+    }
+
+    /// Pass `--file-header` to display file headers.
+    pub fn file_header(&mut self) -> &mut Self {
+        self.cmd.arg("--file-header");
+        self
+    }
+}