From a85700a1a8f5aa729bd19e5a2a78f8a80d623093 Mon Sep 17 00:00:00 2001 From: matt rice Date: Fri, 23 Feb 2024 16:05:28 -0800 Subject: [PATCH 01/17] Handle .init_array link_section specially on wasm --- compiler/rustc_codegen_llvm/src/consts.rs | 10 ++++++++-- compiler/rustc_hir_analysis/src/check/mod.rs | 20 +++++++++++++------- 2 files changed, 21 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs index ec2fb2c6e546b..55477ff5d297f 100644 --- a/compiler/rustc_codegen_llvm/src/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -481,8 +481,14 @@ impl<'ll> StaticMethods for CodegenCx<'ll, '_> { } // Wasm statics with custom link sections get special treatment as they - // go into custom sections of the wasm executable. - if self.tcx.sess.target.is_like_wasm { + // go into custom sections of the wasm executable. The exception to this + // is the `.init_array` section which are treated specially by the wasm linker. + if self.tcx.sess.target.is_like_wasm + && attrs + .link_section + .map(|link_section| !link_section.as_str().starts_with(".init_array")) + .unwrap_or(true) + { if let Some(section) = attrs.link_section { let section = llvm::LLVMMDStringInContext2( self.llcx, diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 36a92a4cf7cc0..16a1a41eb19f3 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -159,21 +159,27 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { return; } - // For the wasm32 target statics with `#[link_section]` are placed into custom - // sections of the final output file, but this isn't link custom sections of - // other executable formats. Namely we can only embed a list of bytes, - // nothing with provenance (pointers to anything else). If any provenance - // show up, reject it here. + // For the wasm32 target statics with `#[link_section]` other than `.init_array` + // are placed into custom sections of the final output file, but this isn't link + // custom sections of other executable formats. Namely we can only embed a list + // of bytes, nothing with provenance (pointers to anything else). If any + // provenance show up, reject it here. // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is // the consumer's responsibility to ensure all bytes that have been read // have defined values. if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) && alloc.inner().provenance().ptrs().len() != 0 { - let msg = "statics with a custom `#[link_section]` must be a \ + if attrs + .link_section + .map(|link_section| !link_section.as_str().starts_with(".init_array")) + .unwrap_or(true) + { + let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ extra levels of indirection such as references"; - tcx.dcx().span_err(tcx.def_span(id), msg); + tcx.dcx().span_err(tcx.def_span(id), msg); + } } } From 395ea03ec51e91e91107d47c04a9aabad55e5a39 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Wed, 27 Mar 2024 01:07:39 +0530 Subject: [PATCH 02/17] uefi: Add process Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/helpers.rs | 72 +++++- library/std/src/sys/pal/uefi/mod.rs | 1 - library/std/src/sys/pal/uefi/process.rs | 328 ++++++++++++++++++++++++ 3 files changed, 399 insertions(+), 2 deletions(-) create mode 100644 library/std/src/sys/pal/uefi/process.rs diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index 23aa4da14a763..97dd90716bbb0 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -12,7 +12,7 @@ use r_efi::efi::{self, Guid}; use r_efi::protocols::{device_path, device_path_to_text}; -use crate::ffi::OsString; +use crate::ffi::{OsString, OsStr}; use crate::io::{self, const_io_error}; use crate::mem::{size_of, MaybeUninit}; use crate::os::uefi::{self, env::boot_services, ffi::OsStringExt}; @@ -221,3 +221,73 @@ pub(crate) fn runtime_services() -> Option> let runtime_services = unsafe { (*system_table.as_ptr()).runtime_services }; NonNull::new(runtime_services) } + +pub(crate) struct DevicePath(NonNull); + +impl DevicePath { + pub(crate) fn from_text(p: &OsStr) -> io::Result { + fn inner( + p: &OsStr, + protocol: NonNull, + ) -> io::Result { + let path_vec = p.encode_wide().chain(Some(0)).collect::>(); + let path = + unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) }; + + NonNull::new(path).map(DevicePath).ok_or_else(|| { + const_io_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path") + }) + } + + static LAST_VALID_HANDLE: AtomicPtr = + AtomicPtr::new(crate::ptr::null_mut()); + + if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) { + if let Ok(protocol) = open_protocol::( + handle, + r_efi::protocols::device_path_from_text::PROTOCOL_GUID, + ) { + return inner(p, protocol); + } + } + + let handles = locate_handles(r_efi::protocols::device_path_from_text::PROTOCOL_GUID)?; + for handle in handles { + if let Ok(protocol) = open_protocol::( + handle, + r_efi::protocols::device_path_from_text::PROTOCOL_GUID, + ) { + LAST_VALID_HANDLE.store(handle.as_ptr(), Ordering::Release); + return inner(p, protocol); + } + } + + io::Result::Err(const_io_error!( + io::ErrorKind::NotFound, + "DevicePathFromText Protocol not found" + )) + } +} + +impl AsRef for DevicePath { + fn as_ref(&self) -> &r_efi::protocols::device_path::Protocol { + unsafe { self.0.as_ref() } + } +} + +impl AsMut for DevicePath { + fn as_mut(&mut self) -> &mut r_efi::protocols::device_path::Protocol { + unsafe { self.0.as_mut() } + } +} + +impl Drop for DevicePath { + fn drop(&mut self) { + if let Some(bt) = boot_services() { + let bt: NonNull = bt.cast(); + unsafe { + ((*bt.as_ptr()).free_pool)(self.0.as_ptr() as *mut crate::ffi::c_void); + } + } + } +} diff --git a/library/std/src/sys/pal/uefi/mod.rs b/library/std/src/sys/pal/uefi/mod.rs index 48b74df138439..27b7049ac54dd 100644 --- a/library/std/src/sys/pal/uefi/mod.rs +++ b/library/std/src/sys/pal/uefi/mod.rs @@ -24,7 +24,6 @@ pub mod net; pub mod os; #[path = "../unsupported/pipe.rs"] pub mod pipe; -#[path = "../unsupported/process.rs"] pub mod process; pub mod stdio; pub mod thread; diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs new file mode 100644 index 0000000000000..e85fc209c0e18 --- /dev/null +++ b/library/std/src/sys/pal/uefi/process.rs @@ -0,0 +1,328 @@ +use crate::ffi::OsStr; +use crate::ffi::OsString; +use crate::fmt; +use crate::io; +use crate::marker::PhantomData; +use crate::num::NonZero; +use crate::num::NonZeroI32; +use crate::path::Path; +use crate::sys::fs::File; +use crate::sys::pipe::AnonPipe; +use crate::sys::unsupported; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; + +pub use crate::ffi::OsString as EnvKey; + +//////////////////////////////////////////////////////////////////////////////// +// Command +//////////////////////////////////////////////////////////////////////////////// + +pub struct Command { + prog: OsString, +} + +// passed back to std::process with the pipes connected to the child, if any +// were requested +pub struct StdioPipes { + pub stdin: Option, + pub stdout: Option, + pub stderr: Option, +} + +// FIXME: This should be a unit struct, so we can always construct it +// The value here should be never used, since we cannot spawn processes. +pub enum Stdio { + Inherit, + Null, + MakePipe, +} + +impl Command { + pub fn new(program: &OsStr) -> Command { + Command { prog: program.to_os_string() } + } + + pub fn arg(&mut self, _arg: &OsStr) { + panic!("unsupported") + } + + pub fn env_mut(&mut self) -> &mut CommandEnv { + panic!("unsupported") + } + + pub fn cwd(&mut self, _dir: &OsStr) { + panic!("unsupported") + } + + pub fn stdin(&mut self, _stdin: Stdio) { + panic!("unsupported") + } + + pub fn stdout(&mut self, _stdout: Stdio) { + panic!("unsupported") + } + + pub fn stderr(&mut self, _stderr: Stdio) { + panic!("unsupported") + } + + pub fn get_program(&self) -> &OsStr { + panic!("unsupported") + } + + pub fn get_args(&self) -> CommandArgs<'_> { + panic!("unsupported") + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + panic!("unsupported") + } + + pub fn get_current_dir(&self) -> Option<&Path> { + None + } + + pub fn spawn( + &mut self, + _default: Stdio, + _needs_stdin: bool, + ) -> io::Result<(Process, StdioPipes)> { + unsupported() + } + + pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { + let cmd = uefi_command_internal::Command::load_image(&self.prog)?; + let stat = cmd.start_image()?; + Ok((ExitStatus(stat), Vec::new(), Vec::new())) + } +} + +impl From for Stdio { + fn from(pipe: AnonPipe) -> Stdio { + pipe.diverge() + } +} + +impl From for Stdio { + fn from(_: io::Stdout) -> Stdio { + // FIXME: This is wrong. + // Instead, the Stdio we have here should be a unit struct. + panic!("unsupported") + } +} + +impl From for Stdio { + fn from(_: io::Stderr) -> Stdio { + // FIXME: This is wrong. + // Instead, the Stdio we have here should be a unit struct. + panic!("unsupported") + } +} + +impl From for Stdio { + fn from(_file: File) -> Stdio { + // FIXME: This is wrong. + // Instead, the Stdio we have here should be a unit struct. + panic!("unsupported") + } +} + +impl fmt::Debug for Command { + fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + Ok(()) + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[non_exhaustive] +pub struct ExitStatus(r_efi::efi::Status); + +impl ExitStatus { + pub fn exit_ok(&self) -> Result<(), ExitStatusError> { + if self.0 == r_efi::efi::Status::SUCCESS { Ok(()) } else { Err(ExitStatusError(self.0)) } + } + + pub fn code(&self) -> Option { + Some(self.0.as_usize() as i32) + } +} + +impl fmt::Display for ExitStatus { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let err_str = super::os::error_string(self.0.as_usize()); + write!(f, "{}", err_str) + } +} + +impl Default for ExitStatus { + fn default() -> Self { + ExitStatus(r_efi::efi::Status::SUCCESS) + } +} + +#[derive(Clone, Copy, PartialEq, Eq)] +pub struct ExitStatusError(r_efi::efi::Status); + +impl fmt::Debug for ExitStatusError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let err_str = super::os::error_string(self.0.as_usize()); + write!(f, "{}", err_str) + } +} + +impl Into for ExitStatusError { + fn into(self) -> ExitStatus { + ExitStatus(self.0) + } +} + +impl ExitStatusError { + pub fn code(self) -> Option> { + NonZeroI32::new(self.0.as_usize() as i32) + } +} + +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ExitCode(bool); + +impl ExitCode { + pub const SUCCESS: ExitCode = ExitCode(false); + pub const FAILURE: ExitCode = ExitCode(true); + + pub fn as_i32(&self) -> i32 { + self.0 as i32 + } +} + +impl From for ExitCode { + fn from(code: u8) -> Self { + match code { + 0 => Self::SUCCESS, + 1..=255 => Self::FAILURE, + } + } +} + +pub struct Process(!); + +impl Process { + pub fn id(&self) -> u32 { + self.0 + } + + pub fn kill(&mut self) -> io::Result<()> { + self.0 + } + + pub fn wait(&mut self) -> io::Result { + self.0 + } + + pub fn try_wait(&mut self) -> io::Result> { + self.0 + } +} + +pub struct CommandArgs<'a> { + _p: PhantomData<&'a ()>, +} + +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + None + } + fn size_hint(&self) -> (usize, Option) { + (0, Some(0)) + } +} + +impl<'a> ExactSizeIterator for CommandArgs<'a> {} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().finish() + } +} + +mod uefi_command_internal { + use super::super::helpers; + use crate::ffi::OsStr; + use crate::io::{self, const_io_error}; + use crate::mem::MaybeUninit; + use crate::os::uefi::env::{boot_services, image_handle}; + use crate::ptr::NonNull; + + pub struct Command { + handle: NonNull, + } + + impl Command { + const fn new(handle: NonNull) -> Self { + Self { handle } + } + + pub fn load_image(p: &OsStr) -> io::Result { + let mut path = helpers::DevicePath::from_text(p)?; + let boot_services: NonNull = boot_services() + .ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))? + .cast(); + let mut child_handle: MaybeUninit = MaybeUninit::uninit(); + let image_handle = image_handle(); + + let r = unsafe { + ((*boot_services.as_ptr()).load_image)( + r_efi::efi::Boolean::FALSE, + image_handle.as_ptr(), + path.as_mut(), + crate::ptr::null_mut(), + 0, + child_handle.as_mut_ptr(), + ) + }; + + if r.is_error() { + Err(io::Error::from_raw_os_error(r.as_usize())) + } else { + let child_handle = unsafe { child_handle.assume_init() }; + let child_handle = NonNull::new(child_handle).unwrap(); + Ok(Self::new(child_handle)) + } + } + + pub fn start_image(&self) -> io::Result { + let boot_services: NonNull = boot_services() + .ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))? + .cast(); + let mut exit_data_size: MaybeUninit = MaybeUninit::uninit(); + let mut exit_data: MaybeUninit<*mut u16> = MaybeUninit::uninit(); + + let r = unsafe { + ((*boot_services.as_ptr()).start_image)( + self.handle.as_ptr(), + exit_data_size.as_mut_ptr(), + exit_data.as_mut_ptr(), + ) + }; + + // Drop exitdata + unsafe { + exit_data_size.assume_init_drop(); + exit_data.assume_init_drop(); + } + + Ok(r) + } + } + + impl Drop for Command { + fn drop(&mut self) { + if let Some(bt) = boot_services() { + let bt: NonNull = bt.cast(); + unsafe { + ((*bt.as_ptr()).unload_image)(self.handle.as_ptr()); + } + } + } + } +} From ed2dca207e455386fa96bd72c610d392fae5387a Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 29 Mar 2024 17:13:16 +0530 Subject: [PATCH 03/17] uefi: process: Add support to capture stdout Use a custom simple_text_output protocol to capture output. Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/helpers.rs | 76 +++++++++- library/std/src/sys/pal/uefi/process.rs | 190 +++++++++++++++++++++++- 2 files changed, 258 insertions(+), 8 deletions(-) diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index 97dd90716bbb0..c2419bbb58573 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -12,10 +12,10 @@ use r_efi::efi::{self, Guid}; use r_efi::protocols::{device_path, device_path_to_text}; -use crate::ffi::{OsString, OsStr}; +use crate::ffi::{OsStr, OsString}; use crate::io::{self, const_io_error}; use crate::mem::{size_of, MaybeUninit}; -use crate::os::uefi::{self, env::boot_services, ffi::OsStringExt}; +use crate::os::uefi::{self, env::boot_services, ffi::OsStrExt, ffi::OsStringExt}; use crate::ptr::NonNull; use crate::slice; use crate::sync::atomic::{AtomicPtr, Ordering}; @@ -291,3 +291,75 @@ impl Drop for DevicePath { } } } + +pub(crate) struct Protocol { + guid: r_efi::efi::Guid, + handle: NonNull, + protocol: Box, +} + +impl Protocol { + const fn new( + guid: r_efi::efi::Guid, + handle: NonNull, + protocol: Box, + ) -> Self { + Self { guid, handle, protocol } + } + + pub(crate) fn create(protocol: T, mut guid: r_efi::efi::Guid) -> io::Result { + let boot_services: NonNull = + boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast(); + let mut protocol = Box::new(protocol); + let mut handle: r_efi::efi::Handle = crate::ptr::null_mut(); + + let r = unsafe { + ((*boot_services.as_ptr()).install_protocol_interface)( + &mut handle, + &mut guid, + r_efi::efi::NATIVE_INTERFACE, + protocol.as_mut() as *mut T as *mut crate::ffi::c_void, + ) + }; + + if r.is_error() { + return Err(crate::io::Error::from_raw_os_error(r.as_usize())); + }; + + let handle = NonNull::new(handle) + .ok_or(io::const_io_error!(io::ErrorKind::Uncategorized, "found null handle"))?; + + Ok(Self::new(guid, handle, protocol)) + } + + pub(crate) fn handle(&self) -> NonNull { + self.handle + } +} + +impl Drop for Protocol { + fn drop(&mut self) { + if let Some(bt) = boot_services() { + let bt: NonNull = bt.cast(); + unsafe { + ((*bt.as_ptr()).uninstall_protocol_interface)( + self.handle.as_ptr(), + &mut self.guid, + self.protocol.as_mut() as *mut T as *mut crate::ffi::c_void, + ) + }; + } + } +} + +impl AsRef for Protocol { + fn as_ref(&self) -> &T { + &self.protocol + } +} + +impl AsMut for Protocol { + fn as_mut(&mut self) -> &mut T { + &mut self.protocol + } +} diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index e85fc209c0e18..7abacc7c12e96 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -91,9 +91,11 @@ impl Command { } pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - let cmd = uefi_command_internal::Command::load_image(&self.prog)?; + let mut cmd = uefi_command_internal::Command::load_image(&self.prog)?; + cmd.stdout_init()?; let stat = cmd.start_image()?; - Ok((ExitStatus(stat), Vec::new(), Vec::new())) + let stdout = cmd.stdout()?; + Ok((ExitStatus(stat), stdout, Vec::new())) } } @@ -246,20 +248,30 @@ impl<'a> fmt::Debug for CommandArgs<'a> { } mod uefi_command_internal { + use r_efi::protocols::{loaded_image, simple_text_output}; + use super::super::helpers; - use crate::ffi::OsStr; + use crate::ffi::{OsStr, OsString}; use crate::io::{self, const_io_error}; use crate::mem::MaybeUninit; use crate::os::uefi::env::{boot_services, image_handle}; + use crate::os::uefi::ffi::OsStringExt; use crate::ptr::NonNull; + use crate::slice; + use crate::sys_common::wstr::WStrUnits; pub struct Command { handle: NonNull, + stdout: Option>, + st: Box, } impl Command { - const fn new(handle: NonNull) -> Self { - Self { handle } + const fn new( + handle: NonNull, + st: Box, + ) -> Self { + Self { handle, stdout: None, st } } pub fn load_image(p: &OsStr) -> io::Result { @@ -286,7 +298,17 @@ mod uefi_command_internal { } else { let child_handle = unsafe { child_handle.assume_init() }; let child_handle = NonNull::new(child_handle).unwrap(); - Ok(Self::new(child_handle)) + + let loaded_image: NonNull = + helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap(); + let mut st: Box = + Box::new(unsafe { crate::ptr::read((*loaded_image.as_ptr()).system_table) }); + + unsafe { + (*loaded_image.as_ptr()).system_table = st.as_mut(); + } + + Ok(Self::new(child_handle, st)) } } @@ -313,6 +335,32 @@ mod uefi_command_internal { Ok(r) } + + pub fn stdout_init(&mut self) -> io::Result<()> { + let mut protocol = + helpers::Protocol::create(PipeProtocol::new(), simple_text_output::PROTOCOL_GUID)?; + + self.st.console_out_handle = protocol.handle().as_ptr(); + self.st.con_out = + protocol.as_mut() as *mut PipeProtocol as *mut simple_text_output::Protocol; + + self.stdout = Some(protocol); + + Ok(()) + } + + pub fn stdout(&self) -> io::Result> { + if let Some(stdout) = &self.stdout { + stdout + .as_ref() + .utf8() + .into_string() + .map_err(|_| const_io_error!(io::ErrorKind::Other, "utf8 conversion failed")) + .map(Into::into) + } else { + Err(const_io_error!(io::ErrorKind::NotFound, "stdout not found")) + } + } } impl Drop for Command { @@ -325,4 +373,134 @@ mod uefi_command_internal { } } } + + #[repr(C)] + struct PipeProtocol { + reset: simple_text_output::ProtocolReset, + output_string: simple_text_output::ProtocolOutputString, + test_string: simple_text_output::ProtocolTestString, + query_mode: simple_text_output::ProtocolQueryMode, + set_mode: simple_text_output::ProtocolSetMode, + set_attribute: simple_text_output::ProtocolSetAttribute, + clear_screen: simple_text_output::ProtocolClearScreen, + set_cursor_position: simple_text_output::ProtocolSetCursorPosition, + enable_cursor: simple_text_output::ProtocolEnableCursor, + mode: *mut simple_text_output::Mode, + _mode: Box, + _buffer: Vec, + } + + impl PipeProtocol { + fn new() -> Self { + let mut mode = Box::new(simple_text_output::Mode { + max_mode: 0, + mode: 0, + attribute: 0, + cursor_column: 0, + cursor_row: 0, + cursor_visible: r_efi::efi::Boolean::FALSE, + }); + Self { + reset: Self::reset, + output_string: Self::output_string, + test_string: Self::test_string, + query_mode: Self::query_mode, + set_mode: Self::set_mode, + set_attribute: Self::set_attribute, + clear_screen: Self::clear_screen, + set_cursor_position: Self::set_cursor_position, + enable_cursor: Self::enable_cursor, + mode: mode.as_mut(), + _mode: mode, + _buffer: Vec::new(), + } + } + + fn utf8(&self) -> OsString { + OsString::from_wide(&self._buffer) + } + + extern "efiapi" fn reset( + proto: *mut simple_text_output::Protocol, + _: r_efi::efi::Boolean, + ) -> r_efi::efi::Status { + let proto: *mut PipeProtocol = proto.cast(); + unsafe { + (*proto)._buffer.clear(); + } + r_efi::efi::Status::SUCCESS + } + + extern "efiapi" fn output_string( + proto: *mut simple_text_output::Protocol, + buf: *mut r_efi::efi::Char16, + ) -> r_efi::efi::Status { + let proto: *mut PipeProtocol = proto.cast(); + let buf_len = unsafe { + if let Some(x) = WStrUnits::new(buf) { + x.count() + } else { + return r_efi::efi::Status::INVALID_PARAMETER; + } + }; + let buf_slice = unsafe { slice::from_raw_parts(buf, buf_len) }; + + unsafe { + (*proto)._buffer.extend_from_slice(buf_slice); + }; + + r_efi::efi::Status::SUCCESS + } + + extern "efiapi" fn test_string( + _: *mut simple_text_output::Protocol, + _: *mut r_efi::efi::Char16, + ) -> r_efi::efi::Status { + r_efi::efi::Status::SUCCESS + } + + extern "efiapi" fn query_mode( + _: *mut simple_text_output::Protocol, + _: usize, + _: *mut usize, + _: *mut usize, + ) -> r_efi::efi::Status { + r_efi::efi::Status::UNSUPPORTED + } + + extern "efiapi" fn set_mode( + _: *mut simple_text_output::Protocol, + _: usize, + ) -> r_efi::efi::Status { + r_efi::efi::Status::UNSUPPORTED + } + + extern "efiapi" fn set_attribute( + _: *mut simple_text_output::Protocol, + _: usize, + ) -> r_efi::efi::Status { + r_efi::efi::Status::UNSUPPORTED + } + + extern "efiapi" fn clear_screen( + _: *mut simple_text_output::Protocol, + ) -> r_efi::efi::Status { + r_efi::efi::Status::UNSUPPORTED + } + + extern "efiapi" fn set_cursor_position( + _: *mut simple_text_output::Protocol, + _: usize, + _: usize, + ) -> r_efi::efi::Status { + r_efi::efi::Status::UNSUPPORTED + } + + extern "efiapi" fn enable_cursor( + _: *mut simple_text_output::Protocol, + _: r_efi::efi::Boolean, + ) -> r_efi::efi::Status { + r_efi::efi::Status::UNSUPPORTED + } + } } From 3c478805206a55e93dfa7222907d3c0178095231 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 29 Mar 2024 17:20:50 +0530 Subject: [PATCH 04/17] uefi: process: Add stderr support Implement stderr support in similar fashion. Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/process.rs | 36 +++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index 7abacc7c12e96..06ce542b0be1f 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -92,10 +92,15 @@ impl Command { pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { let mut cmd = uefi_command_internal::Command::load_image(&self.prog)?; + cmd.stdout_init()?; + cmd.stderr_init()?; + let stat = cmd.start_image()?; let stdout = cmd.stdout()?; - Ok((ExitStatus(stat), stdout, Vec::new())) + let stderr = cmd.stderr()?; + + Ok((ExitStatus(stat), stdout, stderr)) } } @@ -263,6 +268,7 @@ mod uefi_command_internal { pub struct Command { handle: NonNull, stdout: Option>, + stderr: Option>, st: Box, } @@ -271,7 +277,7 @@ mod uefi_command_internal { handle: NonNull, st: Box, ) -> Self { - Self { handle, stdout: None, st } + Self { handle, stdout: None, stderr: None, st } } pub fn load_image(p: &OsStr) -> io::Result { @@ -349,6 +355,19 @@ mod uefi_command_internal { Ok(()) } + pub fn stderr_init(&mut self) -> io::Result<()> { + let mut protocol = + helpers::Protocol::create(PipeProtocol::new(), simple_text_output::PROTOCOL_GUID)?; + + self.st.standard_error_handle = protocol.handle().as_ptr(); + self.st.std_err = + protocol.as_mut() as *mut PipeProtocol as *mut simple_text_output::Protocol; + + self.stderr = Some(protocol); + + Ok(()) + } + pub fn stdout(&self) -> io::Result> { if let Some(stdout) = &self.stdout { stdout @@ -361,6 +380,19 @@ mod uefi_command_internal { Err(const_io_error!(io::ErrorKind::NotFound, "stdout not found")) } } + + pub fn stderr(&self) -> io::Result> { + if let Some(stderr) = &self.stderr { + stderr + .as_ref() + .utf8() + .into_string() + .map_err(|_| const_io_error!(io::ErrorKind::Other, "utf8 conversion failed")) + .map(Into::into) + } else { + Err(const_io_error!(io::ErrorKind::NotFound, "stdout not found")) + } + } } impl Drop for Command { From 8ee24d371424c098ce82a918f9ed8227ebbcb521 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 29 Mar 2024 18:36:52 +0530 Subject: [PATCH 05/17] uefi: process: Add null protocol Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/process.rs | 138 +++++++++++++++++------- 1 file changed, 100 insertions(+), 38 deletions(-) diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index 06ce542b0be1f..fc96f382650e5 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -1,3 +1,5 @@ +use r_efi::protocols::simple_text_output; + use crate::ffi::OsStr; use crate::ffi::OsString; use crate::fmt; @@ -13,12 +15,16 @@ use crate::sys_common::process::{CommandEnv, CommandEnvs}; pub use crate::ffi::OsString as EnvKey; +use super::helpers; + //////////////////////////////////////////////////////////////////////////////// // Command //////////////////////////////////////////////////////////////////////////////// pub struct Command { prog: OsString, + stdout: Option, + stderr: Option, } // passed back to std::process with the pipes connected to the child, if any @@ -39,7 +45,7 @@ pub enum Stdio { impl Command { pub fn new(program: &OsStr) -> Command { - Command { prog: program.to_os_string() } + Command { prog: program.to_os_string(), stdout: None, stderr: None } } pub fn arg(&mut self, _arg: &OsStr) { @@ -58,12 +64,20 @@ impl Command { panic!("unsupported") } - pub fn stdout(&mut self, _stdout: Stdio) { - panic!("unsupported") + pub fn stdout(&mut self, stdout: Stdio) { + self.stdout = match stdout { + Stdio::MakePipe => Some(uefi_command_internal::PipeProtocol::new()), + Stdio::Null => Some(uefi_command_internal::PipeProtocol::null()), + _ => None, + }; } - pub fn stderr(&mut self, _stderr: Stdio) { - panic!("unsupported") + pub fn stderr(&mut self, stderr: Stdio) { + self.stderr = match stderr { + Stdio::MakePipe => Some(uefi_command_internal::PipeProtocol::new()), + Stdio::Null => Some(uefi_command_internal::PipeProtocol::null()), + _ => None, + }; } pub fn get_program(&self) -> &OsStr { @@ -93,8 +107,26 @@ impl Command { pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { let mut cmd = uefi_command_internal::Command::load_image(&self.prog)?; - cmd.stdout_init()?; - cmd.stderr_init()?; + let stdout: helpers::Protocol = + match self.stdout.take() { + Some(s) => helpers::Protocol::create(s, simple_text_output::PROTOCOL_GUID), + None => helpers::Protocol::create( + uefi_command_internal::PipeProtocol::new(), + simple_text_output::PROTOCOL_GUID, + ), + }?; + + let stderr: helpers::Protocol = + match self.stderr.take() { + Some(s) => helpers::Protocol::create(s, simple_text_output::PROTOCOL_GUID), + None => helpers::Protocol::create( + uefi_command_internal::PipeProtocol::new(), + simple_text_output::PROTOCOL_GUID, + ), + }?; + + cmd.stdout_init(stdout)?; + cmd.stderr_init(stderr)?; let stat = cmd.start_image()?; let stdout = cmd.stdout()?; @@ -342,10 +374,10 @@ mod uefi_command_internal { Ok(r) } - pub fn stdout_init(&mut self) -> io::Result<()> { - let mut protocol = - helpers::Protocol::create(PipeProtocol::new(), simple_text_output::PROTOCOL_GUID)?; - + pub fn stdout_init( + &mut self, + mut protocol: helpers::Protocol, + ) -> io::Result<()> { self.st.console_out_handle = protocol.handle().as_ptr(); self.st.con_out = protocol.as_mut() as *mut PipeProtocol as *mut simple_text_output::Protocol; @@ -355,10 +387,10 @@ mod uefi_command_internal { Ok(()) } - pub fn stderr_init(&mut self) -> io::Result<()> { - let mut protocol = - helpers::Protocol::create(PipeProtocol::new(), simple_text_output::PROTOCOL_GUID)?; - + pub fn stderr_init( + &mut self, + mut protocol: helpers::Protocol, + ) -> io::Result<()> { self.st.standard_error_handle = protocol.handle().as_ptr(); self.st.std_err = protocol.as_mut() as *mut PipeProtocol as *mut simple_text_output::Protocol; @@ -368,29 +400,17 @@ mod uefi_command_internal { Ok(()) } - pub fn stdout(&self) -> io::Result> { - if let Some(stdout) = &self.stdout { - stdout - .as_ref() - .utf8() - .into_string() - .map_err(|_| const_io_error!(io::ErrorKind::Other, "utf8 conversion failed")) - .map(Into::into) - } else { - Err(const_io_error!(io::ErrorKind::NotFound, "stdout not found")) + pub fn stderr(&self) -> io::Result> { + match &self.stderr { + Some(stderr) => stderr.as_ref().utf8(), + None => Ok(Vec::new()), } } - pub fn stderr(&self) -> io::Result> { - if let Some(stderr) = &self.stderr { - stderr - .as_ref() - .utf8() - .into_string() - .map_err(|_| const_io_error!(io::ErrorKind::Other, "utf8 conversion failed")) - .map(Into::into) - } else { - Err(const_io_error!(io::ErrorKind::NotFound, "stdout not found")) + pub fn stdout(&self) -> io::Result> { + match &self.stdout { + Some(stdout) => stdout.as_ref().utf8(), + None => Ok(Vec::new()), } } } @@ -407,7 +427,7 @@ mod uefi_command_internal { } #[repr(C)] - struct PipeProtocol { + pub struct PipeProtocol { reset: simple_text_output::ProtocolReset, output_string: simple_text_output::ProtocolOutputString, test_string: simple_text_output::ProtocolTestString, @@ -423,7 +443,7 @@ mod uefi_command_internal { } impl PipeProtocol { - fn new() -> Self { + pub fn new() -> Self { let mut mode = Box::new(simple_text_output::Mode { max_mode: 0, mode: 0, @@ -448,8 +468,36 @@ mod uefi_command_internal { } } - fn utf8(&self) -> OsString { + pub fn null() -> Self { + let mut mode = Box::new(simple_text_output::Mode { + max_mode: 0, + mode: 0, + attribute: 0, + cursor_column: 0, + cursor_row: 0, + cursor_visible: r_efi::efi::Boolean::FALSE, + }); + Self { + reset: Self::reset_null, + output_string: Self::output_string_null, + test_string: Self::test_string, + query_mode: Self::query_mode, + set_mode: Self::set_mode, + set_attribute: Self::set_attribute, + clear_screen: Self::clear_screen, + set_cursor_position: Self::set_cursor_position, + enable_cursor: Self::enable_cursor, + mode: mode.as_mut(), + _mode: mode, + _buffer: Vec::new(), + } + } + + pub fn utf8(&self) -> io::Result> { OsString::from_wide(&self._buffer) + .into_string() + .map(Into::into) + .map_err(|_| const_io_error!(io::ErrorKind::Other, "utf8 conversion failed")) } extern "efiapi" fn reset( @@ -463,6 +511,13 @@ mod uefi_command_internal { r_efi::efi::Status::SUCCESS } + extern "efiapi" fn reset_null( + _: *mut simple_text_output::Protocol, + _: r_efi::efi::Boolean, + ) -> r_efi::efi::Status { + r_efi::efi::Status::SUCCESS + } + extern "efiapi" fn output_string( proto: *mut simple_text_output::Protocol, buf: *mut r_efi::efi::Char16, @@ -484,6 +539,13 @@ mod uefi_command_internal { r_efi::efi::Status::SUCCESS } + extern "efiapi" fn output_string_null( + _: *mut simple_text_output::Protocol, + _: *mut r_efi::efi::Char16, + ) -> r_efi::efi::Status { + r_efi::efi::Status::SUCCESS + } + extern "efiapi" fn test_string( _: *mut simple_text_output::Protocol, _: *mut r_efi::efi::Char16, From 588881b8251903400110d8b40d383496a10db122 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 29 Mar 2024 19:07:46 +0530 Subject: [PATCH 06/17] uefi: process Implement inherit Only tested in 2 levels right now. Need args support for 3 levels Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/process.rs | 57 ++++++++++++++++--------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index fc96f382650e5..ed25ad81bbdc9 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -23,8 +23,8 @@ use super::helpers; pub struct Command { prog: OsString, - stdout: Option, - stderr: Option, + stdout: Option, + stderr: Option, } // passed back to std::process with the pipes connected to the child, if any @@ -65,19 +65,11 @@ impl Command { } pub fn stdout(&mut self, stdout: Stdio) { - self.stdout = match stdout { - Stdio::MakePipe => Some(uefi_command_internal::PipeProtocol::new()), - Stdio::Null => Some(uefi_command_internal::PipeProtocol::null()), - _ => None, - }; + self.stdout = Some(stdout); } pub fn stderr(&mut self, stderr: Stdio) { - self.stderr = match stderr { - Stdio::MakePipe => Some(uefi_command_internal::PipeProtocol::new()), - Stdio::Null => Some(uefi_command_internal::PipeProtocol::null()), - _ => None, - }; + self.stderr = Some(stderr); } pub fn get_program(&self) -> &OsStr { @@ -104,31 +96,56 @@ impl Command { unsupported() } + fn create_pipe( + s: Stdio, + ) -> io::Result>> { + match s { + Stdio::MakePipe => helpers::Protocol::create( + uefi_command_internal::PipeProtocol::new(), + simple_text_output::PROTOCOL_GUID, + ) + .map(Some), + Stdio::Null => helpers::Protocol::create( + uefi_command_internal::PipeProtocol::null(), + simple_text_output::PROTOCOL_GUID, + ) + .map(Some), + Stdio::Inherit => Ok(None), + } + } + pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { let mut cmd = uefi_command_internal::Command::load_image(&self.prog)?; - let stdout: helpers::Protocol = + let stdout: Option> = match self.stdout.take() { - Some(s) => helpers::Protocol::create(s, simple_text_output::PROTOCOL_GUID), + Some(s) => Self::create_pipe(s), None => helpers::Protocol::create( uefi_command_internal::PipeProtocol::new(), simple_text_output::PROTOCOL_GUID, - ), + ) + .map(Some), }?; - let stderr: helpers::Protocol = + let stderr: Option> = match self.stderr.take() { - Some(s) => helpers::Protocol::create(s, simple_text_output::PROTOCOL_GUID), + Some(s) => Self::create_pipe(s), None => helpers::Protocol::create( uefi_command_internal::PipeProtocol::new(), simple_text_output::PROTOCOL_GUID, - ), + ) + .map(Some), }?; - cmd.stdout_init(stdout)?; - cmd.stderr_init(stderr)?; + if let Some(stdout) = stdout { + cmd.stdout_init(stdout)?; + } + if let Some(stderr) = stderr { + cmd.stderr_init(stderr)?; + } let stat = cmd.start_image()?; + let stdout = cmd.stdout()?; let stderr = cmd.stderr()?; From 6ce936aa76d9a5b728b7607c5e41f41c97f69a65 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 29 Mar 2024 19:44:37 +0530 Subject: [PATCH 07/17] uefi: process: Add support for args Also fix stdio inherit Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/process.rs | 76 ++++++++++++++++++------- 1 file changed, 55 insertions(+), 21 deletions(-) diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index ed25ad81bbdc9..6b431553f8aa8 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -23,6 +23,7 @@ use super::helpers; pub struct Command { prog: OsString, + args: OsString, stdout: Option, stderr: Option, } @@ -45,11 +46,17 @@ pub enum Stdio { impl Command { pub fn new(program: &OsStr) -> Command { - Command { prog: program.to_os_string(), stdout: None, stderr: None } + Command { + prog: program.to_os_string(), + args: program.to_os_string(), + stdout: None, + stderr: None, + } } - pub fn arg(&mut self, _arg: &OsStr) { - panic!("unsupported") + pub fn arg(&mut self, arg: &OsStr) { + self.args.push(" "); + self.args.push(arg); } pub fn env_mut(&mut self) -> &mut CommandEnv { @@ -137,11 +144,17 @@ impl Command { .map(Some), }?; - if let Some(stdout) = stdout { - cmd.stdout_init(stdout)?; - } - if let Some(stderr) = stderr { - cmd.stderr_init(stderr)?; + match stdout { + Some(stdout) => cmd.stdout_init(stdout), + None => cmd.stdout_inherit(), + }; + match stderr { + Some(stderr) => cmd.stderr_init(stderr), + None => cmd.stderr_inherit(), + }; + + if !self.args.is_empty() { + cmd.set_args(&self.args); } let stat = cmd.start_image()?; @@ -308,8 +321,8 @@ mod uefi_command_internal { use crate::ffi::{OsStr, OsString}; use crate::io::{self, const_io_error}; use crate::mem::MaybeUninit; - use crate::os::uefi::env::{boot_services, image_handle}; - use crate::os::uefi::ffi::OsStringExt; + use crate::os::uefi::env::{boot_services, image_handle, system_table}; + use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; use crate::ptr::NonNull; use crate::slice; use crate::sys_common::wstr::WStrUnits; @@ -319,6 +332,7 @@ mod uefi_command_internal { stdout: Option>, stderr: Option>, st: Box, + args: Option>, } impl Command { @@ -326,7 +340,7 @@ mod uefi_command_internal { handle: NonNull, st: Box, ) -> Self { - Self { handle, stdout: None, stderr: None, st } + Self { handle, stdout: None, stderr: None, st, args: None } } pub fn load_image(p: &OsStr) -> io::Result { @@ -391,30 +405,34 @@ mod uefi_command_internal { Ok(r) } - pub fn stdout_init( - &mut self, - mut protocol: helpers::Protocol, - ) -> io::Result<()> { + pub fn stdout_init(&mut self, mut protocol: helpers::Protocol) { self.st.console_out_handle = protocol.handle().as_ptr(); self.st.con_out = protocol.as_mut() as *mut PipeProtocol as *mut simple_text_output::Protocol; self.stdout = Some(protocol); + } - Ok(()) + pub fn stdout_inherit(&mut self) { + let st: NonNull = system_table().cast(); + + self.st.console_out_handle = unsafe { (*st.as_ptr()).console_out_handle }; + self.st.con_out = unsafe { (*st.as_ptr()).con_out }; } - pub fn stderr_init( - &mut self, - mut protocol: helpers::Protocol, - ) -> io::Result<()> { + pub fn stderr_init(&mut self, mut protocol: helpers::Protocol) { self.st.standard_error_handle = protocol.handle().as_ptr(); self.st.std_err = protocol.as_mut() as *mut PipeProtocol as *mut simple_text_output::Protocol; self.stderr = Some(protocol); + } + + pub fn stderr_inherit(&mut self) { + let st: NonNull = system_table().cast(); - Ok(()) + self.st.standard_error_handle = unsafe { (*st.as_ptr()).standard_error_handle }; + self.st.std_err = unsafe { (*st.as_ptr()).std_err }; } pub fn stderr(&self) -> io::Result> { @@ -430,6 +448,22 @@ mod uefi_command_internal { None => Ok(Vec::new()), } } + + pub fn set_args(&mut self, args: &OsStr) { + let loaded_image: NonNull = + helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap(); + + let mut args = args.encode_wide().collect::>(); + let args_size = (crate::mem::size_of::() * args.len()) as u32; + + unsafe { + (*loaded_image.as_ptr()).load_options = + args.as_mut_ptr() as *mut crate::ffi::c_void; + (*loaded_image.as_ptr()).load_options_size = args_size; + } + + self.args = Some(args); + } } impl Drop for Command { From c05a9b1e02f33bd723ff7ae9f1bd71a5a077da74 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 29 Mar 2024 20:31:56 +0530 Subject: [PATCH 08/17] uefi: process: Add CommandArgs support Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/process.rs | 40 ++++++++++++++++--------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index 6b431553f8aa8..2a32341bf6372 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -4,7 +4,6 @@ use crate::ffi::OsStr; use crate::ffi::OsString; use crate::fmt; use crate::io; -use crate::marker::PhantomData; use crate::num::NonZero; use crate::num::NonZeroI32; use crate::path::Path; @@ -23,7 +22,7 @@ use super::helpers; pub struct Command { prog: OsString, - args: OsString, + args: Vec, stdout: Option, stderr: Option, } @@ -48,15 +47,14 @@ impl Command { pub fn new(program: &OsStr) -> Command { Command { prog: program.to_os_string(), - args: program.to_os_string(), + args: Vec::from([program.to_os_string()]), stdout: None, stderr: None, } } pub fn arg(&mut self, arg: &OsStr) { - self.args.push(" "); - self.args.push(arg); + self.args.push(arg.to_os_string()); } pub fn env_mut(&mut self) -> &mut CommandEnv { @@ -80,11 +78,11 @@ impl Command { } pub fn get_program(&self) -> &OsStr { - panic!("unsupported") + self.prog.as_ref() } pub fn get_args(&self) -> CommandArgs<'_> { - panic!("unsupported") + CommandArgs { iter: self.args.iter() } } pub fn get_envs(&self) -> CommandEnvs<'_> { @@ -153,8 +151,15 @@ impl Command { None => cmd.stderr_inherit(), }; - if !self.args.is_empty() { - cmd.set_args(&self.args); + if self.args.len() > 1 { + let args = self.args.iter().fold(OsString::new(), |mut acc, arg| { + if !acc.is_empty() { + acc.push(" "); + } + acc.push(arg); + acc + }); + cmd.set_args(&args); } let stat = cmd.start_image()?; @@ -293,24 +298,31 @@ impl Process { } pub struct CommandArgs<'a> { - _p: PhantomData<&'a ()>, + iter: crate::slice::Iter<'a, OsString>, } impl<'a> Iterator for CommandArgs<'a> { type Item = &'a OsStr; fn next(&mut self) -> Option<&'a OsStr> { - None + self.iter.next().map(|x| x.as_ref()) } fn size_hint(&self) -> (usize, Option) { - (0, Some(0)) + self.iter.size_hint() } } -impl<'a> ExactSizeIterator for CommandArgs<'a> {} +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} impl<'a> fmt::Debug for CommandArgs<'a> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().finish() + f.debug_list().entries(self.iter.clone()).finish() } } From a1e344fc26605b149ebe247c49bb977fd59855aa Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Fri, 29 Mar 2024 20:51:48 +0530 Subject: [PATCH 09/17] uefi: process: Final Touchups Signed-off-by: Ayush Singh --- library/std/src/sys/pal/uefi/process.rs | 38 ++++++++++++------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index 2a32341bf6372..7075af186f9bd 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -35,8 +35,6 @@ pub struct StdioPipes { pub stderr: Option, } -// FIXME: This should be a unit struct, so we can always construct it -// The value here should be never used, since we cannot spawn processes. pub enum Stdio { Inherit, Null, @@ -45,12 +43,7 @@ pub enum Stdio { impl Command { pub fn new(program: &OsStr) -> Command { - Command { - prog: program.to_os_string(), - args: Vec::from([program.to_os_string()]), - stdout: None, - stderr: None, - } + Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None } } pub fn arg(&mut self, arg: &OsStr) { @@ -122,6 +115,7 @@ impl Command { pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { let mut cmd = uefi_command_internal::Command::load_image(&self.prog)?; + /* Setup Stdout */ let stdout: Option> = match self.stdout.take() { Some(s) => Self::create_pipe(s), @@ -131,7 +125,12 @@ impl Command { ) .map(Some), }?; + match stdout { + Some(stdout) => cmd.stdout_init(stdout), + None => cmd.stdout_inherit(), + }; + /* Setup Stderr */ let stderr: Option> = match self.stderr.take() { Some(s) => Self::create_pipe(s), @@ -141,21 +140,15 @@ impl Command { ) .map(Some), }?; - - match stdout { - Some(stdout) => cmd.stdout_init(stdout), - None => cmd.stdout_inherit(), - }; match stderr { Some(stderr) => cmd.stderr_init(stderr), None => cmd.stderr_inherit(), }; - if self.args.len() > 1 { - let args = self.args.iter().fold(OsString::new(), |mut acc, arg| { - if !acc.is_empty() { - acc.push(" "); - } + /* No reason to set args if only program name is preset */ + if !self.args.is_empty() { + let args = self.args.iter().fold(OsString::from(&self.prog), |mut acc, arg| { + acc.push(" "); acc.push(arg); acc }); @@ -202,7 +195,11 @@ impl From for Stdio { } impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.prog.fmt(f)?; + for arg in &self.args { + arg.fmt(f)?; + } Ok(()) } } @@ -303,9 +300,11 @@ pub struct CommandArgs<'a> { impl<'a> Iterator for CommandArgs<'a> { type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { self.iter.next().map(|x| x.as_ref()) } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } @@ -315,6 +314,7 @@ impl<'a> ExactSizeIterator for CommandArgs<'a> { fn len(&self) -> usize { self.iter.len() } + fn is_empty(&self) -> bool { self.iter.is_empty() } From 1de046fa24a8a0304be274963b43819cfe56013a Mon Sep 17 00:00:00 2001 From: matt rice Date: Fri, 14 Jun 2024 07:53:37 -0700 Subject: [PATCH 10/17] Update for review --- compiler/rustc_hir_analysis/src/check/mod.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 16a1a41eb19f3..9ce60bffea629 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -160,20 +160,35 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) { } // For the wasm32 target statics with `#[link_section]` other than `.init_array` - // are placed into custom sections of the final output file, but this isn't link + // are placed into custom sections of the final output file, but this isn't like // custom sections of other executable formats. Namely we can only embed a list // of bytes, nothing with provenance (pointers to anything else). If any // provenance show up, reject it here. // `#[link_section]` may contain arbitrary, or even undefined bytes, but it is // the consumer's responsibility to ensure all bytes that have been read // have defined values. + // + // The `.init_array` section is left to go through the normal custom section code path. + // When dealing with `.init_array` wasm-ld currently has several limitations. This manifests + // in workarounds in user-code. + // + // * The linker fails to merge multiple items in a crate into the .init_array section. + // To work around this, a single array can be used placing multiple items in the array. + // #[link_section = ".init_array"] + // static FOO: [unsafe extern "C" fn(); 2] = [ctor, ctor]; + // * Even symbols marked used get gc'd from dependant crates unless at least one symbol + // in the crate is marked with an `#[export_name]` + // + // Once `.init_array` support in wasm-ld is complete, the user code workarounds should + // continue to work, but would no longer be necessary. + if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id()) && alloc.inner().provenance().ptrs().len() != 0 { if attrs .link_section .map(|link_section| !link_section.as_str().starts_with(".init_array")) - .unwrap_or(true) + .unwrap() { let msg = "statics with a custom `#[link_section]` must be a \ simple list of bytes on the wasm target with no \ From 4a868f41520c20553869299b7735025b1ddd7e71 Mon Sep 17 00:00:00 2001 From: Ayush Singh Date: Sun, 31 Mar 2024 01:06:33 +0530 Subject: [PATCH 11/17] uefi: process: Fixes from PR - Update system table crc32 - Fix unsound use of Box - Free exit data - Code improvements - Introduce OwnedTable - Update r-efi to latest version - Use extended_varargs_abi_support for install_multiple_protocol_interfaces and uninstall_multiple_protocol_interfaces - Fix comments - Stub out args implementation Signed-off-by: Ayush Singh --- Cargo.lock | 4 +- library/std/Cargo.toml | 2 +- library/std/src/lib.rs | 1 + library/std/src/sys/pal/uefi/helpers.rs | 131 +++++++++---- library/std/src/sys/pal/uefi/process.rs | 250 +++++++++++++----------- 5 files changed, 234 insertions(+), 154 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c0d1337ef93a2..166da5e09ed97 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3052,9 +3052,9 @@ dependencies = [ [[package]] name = "r-efi" -version = "4.4.0" +version = "4.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c47196f636c4cc0634b73b0405323d177753c2e15e866952c64ea22902567a34" +checksum = "e9e935efc5854715dfc0a4c9ef18dc69dee0ec3bf9cc3ab740db831c0fdd86a3" dependencies = [ "compiler_builtins", "rustc-std-workspace-core", diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index 79a504c5a5e2c..7badf23c3f135 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -56,7 +56,7 @@ hermit-abi = { version = "0.3.9", features = ['rustc-dep-of-std'], public = true wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false } [target.'cfg(target_os = "uefi")'.dependencies] -r-efi = { version = "4.2.0", features = ['rustc-dep-of-std'] } +r-efi = { version = "4.5.0", features = ['rustc-dep-of-std'] } r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std'] } [features] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 9d6576fa84117..bc6360d24f551 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -292,6 +292,7 @@ #![feature(doc_masked)] #![feature(doc_notable_trait)] #![feature(dropck_eyepatch)] +#![feature(extended_varargs_abi_support)] #![feature(f128)] #![feature(f16)] #![feature(if_let_guard)] diff --git a/library/std/src/sys/pal/uefi/helpers.rs b/library/std/src/sys/pal/uefi/helpers.rs index c2419bbb58573..a61673c39885b 100644 --- a/library/std/src/sys/pal/uefi/helpers.rs +++ b/library/std/src/sys/pal/uefi/helpers.rs @@ -21,6 +21,12 @@ use crate::slice; use crate::sync::atomic::{AtomicPtr, Ordering}; use crate::sys_common::wstr::WStrUnits; +type BootInstallMultipleProtocolInterfaces = + unsafe extern "efiapi" fn(_: *mut r_efi::efi::Handle, _: ...) -> r_efi::efi::Status; + +type BootUninstallMultipleProtocolInterfaces = + unsafe extern "efiapi" fn(_: r_efi::efi::Handle, _: ...) -> r_efi::efi::Status; + const BOOT_SERVICES_UNAVAILABLE: io::Error = const_io_error!(io::ErrorKind::Other, "Boot Services are no longer available"); @@ -231,6 +237,13 @@ impl DevicePath { protocol: NonNull, ) -> io::Result { let path_vec = p.encode_wide().chain(Some(0)).collect::>(); + if path_vec[..path_vec.len() - 1].contains(&0) { + return Err(const_io_error!( + io::ErrorKind::InvalidInput, + "strings passed to UEFI cannot contain NULs", + )); + } + let path = unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) }; @@ -267,17 +280,9 @@ impl DevicePath { "DevicePathFromText Protocol not found" )) } -} - -impl AsRef for DevicePath { - fn as_ref(&self) -> &r_efi::protocols::device_path::Protocol { - unsafe { self.0.as_ref() } - } -} -impl AsMut for DevicePath { - fn as_mut(&mut self) -> &mut r_efi::protocols::device_path::Protocol { - unsafe { self.0.as_mut() } + pub(crate) fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol { + self.0.as_ptr() } } @@ -292,44 +297,42 @@ impl Drop for DevicePath { } } -pub(crate) struct Protocol { +pub(crate) struct OwnedProtocol { guid: r_efi::efi::Guid, handle: NonNull, - protocol: Box, + protocol: *mut T, } -impl Protocol { - const fn new( - guid: r_efi::efi::Guid, - handle: NonNull, - protocol: Box, - ) -> Self { - Self { guid, handle, protocol } - } - - pub(crate) fn create(protocol: T, mut guid: r_efi::efi::Guid) -> io::Result { - let boot_services: NonNull = +impl OwnedProtocol { + // FIXME: Consider using unsafe trait for matching protocol with guid + pub(crate) unsafe fn create(protocol: T, mut guid: r_efi::efi::Guid) -> io::Result { + let bt: NonNull = boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast(); - let mut protocol = Box::new(protocol); + let protocol: *mut T = Box::into_raw(Box::new(protocol)); let mut handle: r_efi::efi::Handle = crate::ptr::null_mut(); + // FIXME: Move into r-efi once extended_varargs_abi_support is stablized + let func: BootInstallMultipleProtocolInterfaces = + unsafe { crate::mem::transmute((*bt.as_ptr()).install_multiple_protocol_interfaces) }; + let r = unsafe { - ((*boot_services.as_ptr()).install_protocol_interface)( + func( &mut handle, - &mut guid, - r_efi::efi::NATIVE_INTERFACE, - protocol.as_mut() as *mut T as *mut crate::ffi::c_void, + &mut guid as *mut _ as *mut crate::ffi::c_void, + protocol as *mut crate::ffi::c_void, + crate::ptr::null_mut() as *mut crate::ffi::c_void, ) }; if r.is_error() { + drop(Box::from_raw(protocol)); return Err(crate::io::Error::from_raw_os_error(r.as_usize())); }; let handle = NonNull::new(handle) .ok_or(io::const_io_error!(io::ErrorKind::Uncategorized, "found null handle"))?; - Ok(Self::new(guid, handle, protocol)) + Ok(Self { guid, handle, protocol }) } pub(crate) fn handle(&self) -> NonNull { @@ -337,29 +340,79 @@ impl Protocol { } } -impl Drop for Protocol { +impl Drop for OwnedProtocol { fn drop(&mut self) { + // Do not deallocate a runtime protocol if let Some(bt) = boot_services() { let bt: NonNull = bt.cast(); - unsafe { - ((*bt.as_ptr()).uninstall_protocol_interface)( + // FIXME: Move into r-efi once extended_varargs_abi_support is stablized + let func: BootUninstallMultipleProtocolInterfaces = unsafe { + crate::mem::transmute((*bt.as_ptr()).uninstall_multiple_protocol_interfaces) + }; + let status = unsafe { + func( self.handle.as_ptr(), - &mut self.guid, - self.protocol.as_mut() as *mut T as *mut crate::ffi::c_void, + &mut self.guid as *mut _ as *mut crate::ffi::c_void, + self.protocol as *mut crate::ffi::c_void, + crate::ptr::null_mut() as *mut crate::ffi::c_void, ) }; + + // Leak the protocol in case uninstall fails + if status == r_efi::efi::Status::SUCCESS { + let _ = unsafe { Box::from_raw(self.protocol) }; + } } } } -impl AsRef for Protocol { +impl AsRef for OwnedProtocol { fn as_ref(&self) -> &T { - &self.protocol + unsafe { self.protocol.as_ref().unwrap() } + } +} + +pub(crate) struct OwnedTable { + layout: crate::alloc::Layout, + ptr: *mut T, +} + +impl OwnedTable { + pub(crate) fn from_table_header(hdr: &r_efi::efi::TableHeader) -> Self { + let header_size = hdr.header_size as usize; + let layout = crate::alloc::Layout::from_size_align(header_size, 8).unwrap(); + let ptr = unsafe { crate::alloc::alloc(layout) as *mut T }; + Self { layout, ptr } + } + + pub(crate) const fn as_ptr(&self) -> *const T { + self.ptr + } + + pub(crate) const fn as_mut_ptr(&self) -> *mut T { + self.ptr } } -impl AsMut for Protocol { - fn as_mut(&mut self) -> &mut T { - &mut self.protocol +impl OwnedTable { + pub(crate) fn from_table(tbl: *const r_efi::efi::SystemTable) -> Self { + let hdr = unsafe { (*tbl).hdr }; + + let owned_tbl = Self::from_table_header(&hdr); + unsafe { + crate::ptr::copy_nonoverlapping( + tbl as *const u8, + owned_tbl.as_mut_ptr() as *mut u8, + hdr.header_size as usize, + ) + }; + + owned_tbl + } +} + +impl Drop for OwnedTable { + fn drop(&mut self) { + unsafe { crate::alloc::dealloc(self.ptr as *mut u8, self.layout) }; } } diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs index 7075af186f9bd..5c7c8415ee295 100644 --- a/library/std/src/sys/pal/uefi/process.rs +++ b/library/std/src/sys/pal/uefi/process.rs @@ -20,9 +20,9 @@ use super::helpers; // Command //////////////////////////////////////////////////////////////////////////////// +#[derive(Debug)] pub struct Command { prog: OsString, - args: Vec, stdout: Option, stderr: Option, } @@ -35,6 +35,7 @@ pub struct StdioPipes { pub stderr: Option, } +#[derive(Copy, Clone, Debug)] pub enum Stdio { Inherit, Null, @@ -43,11 +44,12 @@ pub enum Stdio { impl Command { pub fn new(program: &OsStr) -> Command { - Command { prog: program.to_os_string(), args: Vec::new(), stdout: None, stderr: None } + Command { prog: program.to_os_string(), stdout: None, stderr: None } } - pub fn arg(&mut self, arg: &OsStr) { - self.args.push(arg.to_os_string()); + // FIXME: Implement arguments as reverse of parsing algorithm + pub fn arg(&mut self, _arg: &OsStr) { + panic!("unsupported") } pub fn env_mut(&mut self) -> &mut CommandEnv { @@ -75,7 +77,7 @@ impl Command { } pub fn get_args(&self) -> CommandArgs<'_> { - CommandArgs { iter: self.args.iter() } + panic!("unsupported") } pub fn get_envs(&self) -> CommandEnvs<'_> { @@ -96,65 +98,47 @@ impl Command { fn create_pipe( s: Stdio, - ) -> io::Result>> { + ) -> io::Result>> { match s { - Stdio::MakePipe => helpers::Protocol::create( - uefi_command_internal::PipeProtocol::new(), - simple_text_output::PROTOCOL_GUID, - ) + Stdio::MakePipe => unsafe { + helpers::OwnedProtocol::create( + uefi_command_internal::PipeProtocol::new(), + simple_text_output::PROTOCOL_GUID, + ) + } .map(Some), - Stdio::Null => helpers::Protocol::create( - uefi_command_internal::PipeProtocol::null(), - simple_text_output::PROTOCOL_GUID, - ) + Stdio::Null => unsafe { + helpers::OwnedProtocol::create( + uefi_command_internal::PipeProtocol::null(), + simple_text_output::PROTOCOL_GUID, + ) + } .map(Some), Stdio::Inherit => Ok(None), } } pub fn output(&mut self) -> io::Result<(ExitStatus, Vec, Vec)> { - let mut cmd = uefi_command_internal::Command::load_image(&self.prog)?; - - /* Setup Stdout */ - let stdout: Option> = - match self.stdout.take() { - Some(s) => Self::create_pipe(s), - None => helpers::Protocol::create( - uefi_command_internal::PipeProtocol::new(), - simple_text_output::PROTOCOL_GUID, - ) - .map(Some), - }?; - match stdout { - Some(stdout) => cmd.stdout_init(stdout), - None => cmd.stdout_inherit(), + let mut cmd = uefi_command_internal::Image::load_image(&self.prog)?; + + // Setup Stdout + let stdout = self.stdout.unwrap_or(Stdio::MakePipe); + let stdout = Self::create_pipe(stdout)?; + if let Some(con) = stdout { + cmd.stdout_init(con) + } else { + cmd.stdout_inherit() }; - /* Setup Stderr */ - let stderr: Option> = - match self.stderr.take() { - Some(s) => Self::create_pipe(s), - None => helpers::Protocol::create( - uefi_command_internal::PipeProtocol::new(), - simple_text_output::PROTOCOL_GUID, - ) - .map(Some), - }?; - match stderr { - Some(stderr) => cmd.stderr_init(stderr), - None => cmd.stderr_inherit(), + // Setup Stderr + let stderr = self.stderr.unwrap_or(Stdio::MakePipe); + let stderr = Self::create_pipe(stderr)?; + if let Some(con) = stderr { + cmd.stderr_init(con) + } else { + cmd.stderr_inherit() }; - /* No reason to set args if only program name is preset */ - if !self.args.is_empty() { - let args = self.args.iter().fold(OsString::from(&self.prog), |mut acc, arg| { - acc.push(" "); - acc.push(arg); - acc - }); - cmd.set_args(&args); - } - let stat = cmd.start_image()?; let stdout = cmd.stdout()?; @@ -194,16 +178,6 @@ impl From for Stdio { } } -impl fmt::Debug for Command { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.prog.fmt(f)?; - for arg in &self.args { - arg.fmt(f)?; - } - Ok(()) - } -} - #[derive(PartialEq, Eq, Clone, Copy, Debug)] #[non_exhaustive] pub struct ExitStatus(r_efi::efi::Status); @@ -326,6 +300,7 @@ impl<'a> fmt::Debug for CommandArgs<'a> { } } +#[allow(dead_code)] mod uefi_command_internal { use r_efi::protocols::{loaded_image, simple_text_output}; @@ -337,26 +312,20 @@ mod uefi_command_internal { use crate::os::uefi::ffi::{OsStrExt, OsStringExt}; use crate::ptr::NonNull; use crate::slice; + use crate::sys::pal::uefi::helpers::OwnedTable; use crate::sys_common::wstr::WStrUnits; - pub struct Command { + pub struct Image { handle: NonNull, - stdout: Option>, - stderr: Option>, - st: Box, + stdout: Option>, + stderr: Option>, + st: OwnedTable, args: Option>, } - impl Command { - const fn new( - handle: NonNull, - st: Box, - ) -> Self { - Self { handle, stdout: None, stderr: None, st, args: None } - } - + impl Image { pub fn load_image(p: &OsStr) -> io::Result { - let mut path = helpers::DevicePath::from_text(p)?; + let path = helpers::DevicePath::from_text(p)?; let boot_services: NonNull = boot_services() .ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))? .cast(); @@ -367,7 +336,7 @@ mod uefi_command_internal { ((*boot_services.as_ptr()).load_image)( r_efi::efi::Boolean::FALSE, image_handle.as_ptr(), - path.as_mut(), + path.as_ptr(), crate::ptr::null_mut(), 0, child_handle.as_mut_ptr(), @@ -382,69 +351,93 @@ mod uefi_command_internal { let loaded_image: NonNull = helpers::open_protocol(child_handle, loaded_image::PROTOCOL_GUID).unwrap(); - let mut st: Box = - Box::new(unsafe { crate::ptr::read((*loaded_image.as_ptr()).system_table) }); + let st = OwnedTable::from_table(unsafe { (*loaded_image.as_ptr()).system_table }); - unsafe { - (*loaded_image.as_ptr()).system_table = st.as_mut(); - } - - Ok(Self::new(child_handle, st)) + Ok(Self { handle: child_handle, stdout: None, stderr: None, st, args: None }) } } - pub fn start_image(&self) -> io::Result { + pub fn start_image(&mut self) -> io::Result { + self.update_st_crc32()?; + + // Use our system table instead of the default one + let loaded_image: NonNull = + helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap(); + unsafe { + (*loaded_image.as_ptr()).system_table = self.st.as_mut_ptr(); + } + let boot_services: NonNull = boot_services() .ok_or_else(|| const_io_error!(io::ErrorKind::NotFound, "Boot Services not found"))? .cast(); - let mut exit_data_size: MaybeUninit = MaybeUninit::uninit(); + let mut exit_data_size: usize = 0; let mut exit_data: MaybeUninit<*mut u16> = MaybeUninit::uninit(); let r = unsafe { ((*boot_services.as_ptr()).start_image)( self.handle.as_ptr(), - exit_data_size.as_mut_ptr(), + &mut exit_data_size, exit_data.as_mut_ptr(), ) }; // Drop exitdata - unsafe { - exit_data_size.assume_init_drop(); - exit_data.assume_init_drop(); + if exit_data_size != 0 { + unsafe { + let exit_data = exit_data.assume_init(); + ((*boot_services.as_ptr()).free_pool)(exit_data as *mut crate::ffi::c_void); + } } Ok(r) } - pub fn stdout_init(&mut self, mut protocol: helpers::Protocol) { - self.st.console_out_handle = protocol.handle().as_ptr(); - self.st.con_out = - protocol.as_mut() as *mut PipeProtocol as *mut simple_text_output::Protocol; + fn set_stdout( + &mut self, + handle: r_efi::efi::Handle, + protocol: *mut simple_text_output::Protocol, + ) { + unsafe { + (*self.st.as_mut_ptr()).console_out_handle = handle; + (*self.st.as_mut_ptr()).con_out = protocol; + } + } + + fn set_stderr( + &mut self, + handle: r_efi::efi::Handle, + protocol: *mut simple_text_output::Protocol, + ) { + unsafe { + (*self.st.as_mut_ptr()).standard_error_handle = handle; + (*self.st.as_mut_ptr()).std_err = protocol; + } + } + pub fn stdout_init(&mut self, protocol: helpers::OwnedProtocol) { + self.set_stdout( + protocol.handle().as_ptr(), + protocol.as_ref() as *const PipeProtocol as *mut simple_text_output::Protocol, + ); self.stdout = Some(protocol); } pub fn stdout_inherit(&mut self) { let st: NonNull = system_table().cast(); - - self.st.console_out_handle = unsafe { (*st.as_ptr()).console_out_handle }; - self.st.con_out = unsafe { (*st.as_ptr()).con_out }; + unsafe { self.set_stdout((*st.as_ptr()).console_out_handle, (*st.as_ptr()).con_out) } } - pub fn stderr_init(&mut self, mut protocol: helpers::Protocol) { - self.st.standard_error_handle = protocol.handle().as_ptr(); - self.st.std_err = - protocol.as_mut() as *mut PipeProtocol as *mut simple_text_output::Protocol; - + pub fn stderr_init(&mut self, protocol: helpers::OwnedProtocol) { + self.set_stderr( + protocol.handle().as_ptr(), + protocol.as_ref() as *const PipeProtocol as *mut simple_text_output::Protocol, + ); self.stderr = Some(protocol); } pub fn stderr_inherit(&mut self) { let st: NonNull = system_table().cast(); - - self.st.standard_error_handle = unsafe { (*st.as_ptr()).standard_error_handle }; - self.st.std_err = unsafe { (*st.as_ptr()).std_err }; + unsafe { self.set_stderr((*st.as_ptr()).standard_error_handle, (*st.as_ptr()).std_err) } } pub fn stderr(&self) -> io::Result> { @@ -476,9 +469,37 @@ mod uefi_command_internal { self.args = Some(args); } + + fn update_st_crc32(&mut self) -> io::Result<()> { + let bt: NonNull = boot_services().unwrap().cast(); + let st_size = unsafe { (*self.st.as_ptr()).hdr.header_size as usize }; + let mut crc32: u32 = 0; + + // Set crc to 0 before calcuation + unsafe { + (*self.st.as_mut_ptr()).hdr.crc32 = 0; + } + + let r = unsafe { + ((*bt.as_ptr()).calculate_crc32)( + self.st.as_mut_ptr() as *mut crate::ffi::c_void, + st_size, + &mut crc32, + ) + }; + + if r.is_error() { + Err(io::Error::from_raw_os_error(r.as_usize())) + } else { + unsafe { + (*self.st.as_mut_ptr()).hdr.crc32 = crc32; + } + Ok(()) + } + } } - impl Drop for Command { + impl Drop for Image { fn drop(&mut self) { if let Some(bt) = boot_services() { let bt: NonNull = bt.cast(); @@ -501,13 +522,12 @@ mod uefi_command_internal { set_cursor_position: simple_text_output::ProtocolSetCursorPosition, enable_cursor: simple_text_output::ProtocolEnableCursor, mode: *mut simple_text_output::Mode, - _mode: Box, _buffer: Vec, } impl PipeProtocol { pub fn new() -> Self { - let mut mode = Box::new(simple_text_output::Mode { + let mode = Box::new(simple_text_output::Mode { max_mode: 0, mode: 0, attribute: 0, @@ -525,14 +545,13 @@ mod uefi_command_internal { clear_screen: Self::clear_screen, set_cursor_position: Self::set_cursor_position, enable_cursor: Self::enable_cursor, - mode: mode.as_mut(), - _mode: mode, + mode: Box::into_raw(mode), _buffer: Vec::new(), } } pub fn null() -> Self { - let mut mode = Box::new(simple_text_output::Mode { + let mode = Box::new(simple_text_output::Mode { max_mode: 0, mode: 0, attribute: 0, @@ -550,8 +569,7 @@ mod uefi_command_internal { clear_screen: Self::clear_screen, set_cursor_position: Self::set_cursor_position, enable_cursor: Self::enable_cursor, - mode: mode.as_mut(), - _mode: mode, + mode: Box::into_raw(mode), _buffer: Vec::new(), } } @@ -660,4 +678,12 @@ mod uefi_command_internal { r_efi::efi::Status::UNSUPPORTED } } + + impl Drop for PipeProtocol { + fn drop(&mut self) { + unsafe { + let _ = Box::from_raw(self.mode); + } + } + } } From 9dc08e30bd0668396dee18eacbcb96dc6d0ddda3 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 11 Jul 2024 14:01:37 -0400 Subject: [PATCH 12/17] Rewrite and rename issue-22131 to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/issue-22131/Makefile | 8 -------- .../foo.rs | 0 .../run-make/rustdoc-cfgspec-parsing/rmake.rs | 19 +++++++++++++++++++ 4 files changed, 19 insertions(+), 9 deletions(-) delete mode 100644 tests/run-make/issue-22131/Makefile rename tests/run-make/{issue-22131 => rustdoc-cfgspec-parsing}/foo.rs (100%) create mode 100644 tests/run-make/rustdoc-cfgspec-parsing/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 745f00c4f5276..7a787255da6d4 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -38,7 +38,6 @@ run-make/interdependent-c-libraries/Makefile run-make/issue-107094/Makefile run-make/issue-14698/Makefile run-make/issue-15460/Makefile -run-make/issue-22131/Makefile run-make/issue-26006/Makefile run-make/issue-28595/Makefile run-make/issue-33329/Makefile diff --git a/tests/run-make/issue-22131/Makefile b/tests/run-make/issue-22131/Makefile deleted file mode 100644 index 4f33a4659cc1e..0000000000000 --- a/tests/run-make/issue-22131/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: foo.rs - $(RUSTC) --cfg 'feature="bar"' --crate-type lib foo.rs - $(RUSTDOC) --test --cfg 'feature="bar"' \ - -L $(TMPDIR) foo.rs |\ - $(CGREP) 'foo.rs - foo (line 1) ... ok' diff --git a/tests/run-make/issue-22131/foo.rs b/tests/run-make/rustdoc-cfgspec-parsing/foo.rs similarity index 100% rename from tests/run-make/issue-22131/foo.rs rename to tests/run-make/rustdoc-cfgspec-parsing/foo.rs diff --git a/tests/run-make/rustdoc-cfgspec-parsing/rmake.rs b/tests/run-make/rustdoc-cfgspec-parsing/rmake.rs new file mode 100644 index 0000000000000..7cb66575c5481 --- /dev/null +++ b/tests/run-make/rustdoc-cfgspec-parsing/rmake.rs @@ -0,0 +1,19 @@ +// A rustdoc bug caused the `feature=bar` syntax for the cfg flag to be interpreted +// wrongly, with `feature=bar` instead of just `bar` being understood as the feature name. +// After this was fixed in #22135, this test checks that this bug does not make a resurgence. +// See https://github.com/rust-lang/rust/issues/22131 + +//FIXME(Oneirical): try test-various + +use run_make_support::{rustc, rustdoc}; + +fn main() { + rustc().cfg(r#"feature="bar""#).crate_type("lib").input("foo.rs").run(); + rustdoc() + .arg("--test") + .arg("--cfg") + .arg(r#"feature="bar""#) + .input("foo.rs") + .run() + .assert_stdout_contains("foo.rs - foo (line 1) ... ok"); +} From fc4404c230c2a7a818e73255d3ceb877b30b592f Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 11 Jul 2024 14:48:33 -0400 Subject: [PATCH 13/17] Rewrite and rename issue-26006 to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - .../invalid-symlink-search-path/in/bar/lib.rs | 5 +++ .../invalid-symlink-search-path/in/foo/lib.rs | 3 ++ .../invalid-symlink-search-path/rmake.rs | 33 +++++++++++++++++++ tests/run-make/issue-26006/Makefile | 17 ---------- tests/run-make/issue-26006/in/libc/lib.rs | 3 -- tests/run-make/issue-26006/in/time/lib.rs | 4 --- .../run-make/rustdoc-cfgspec-parsing/rmake.rs | 6 ++-- 8 files changed, 45 insertions(+), 27 deletions(-) create mode 100644 tests/run-make/invalid-symlink-search-path/in/bar/lib.rs create mode 100644 tests/run-make/invalid-symlink-search-path/in/foo/lib.rs create mode 100644 tests/run-make/invalid-symlink-search-path/rmake.rs delete mode 100644 tests/run-make/issue-26006/Makefile delete mode 100644 tests/run-make/issue-26006/in/libc/lib.rs delete mode 100644 tests/run-make/issue-26006/in/time/lib.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 7a787255da6d4..c49684b45cbcc 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -38,7 +38,6 @@ run-make/interdependent-c-libraries/Makefile run-make/issue-107094/Makefile run-make/issue-14698/Makefile run-make/issue-15460/Makefile -run-make/issue-26006/Makefile run-make/issue-28595/Makefile run-make/issue-33329/Makefile run-make/issue-35164/Makefile diff --git a/tests/run-make/invalid-symlink-search-path/in/bar/lib.rs b/tests/run-make/invalid-symlink-search-path/in/bar/lib.rs new file mode 100644 index 0000000000000..58c3e33bb6ca6 --- /dev/null +++ b/tests/run-make/invalid-symlink-search-path/in/bar/lib.rs @@ -0,0 +1,5 @@ +extern crate foo; + +pub fn main() { + let _ = foo::hello_world(); +} diff --git a/tests/run-make/invalid-symlink-search-path/in/foo/lib.rs b/tests/run-make/invalid-symlink-search-path/in/foo/lib.rs new file mode 100644 index 0000000000000..07b66f8ca454a --- /dev/null +++ b/tests/run-make/invalid-symlink-search-path/in/foo/lib.rs @@ -0,0 +1,3 @@ +pub fn hello_world() -> i32 { + 42 +} diff --git a/tests/run-make/invalid-symlink-search-path/rmake.rs b/tests/run-make/invalid-symlink-search-path/rmake.rs new file mode 100644 index 0000000000000..ed2cd9c4bd265 --- /dev/null +++ b/tests/run-make/invalid-symlink-search-path/rmake.rs @@ -0,0 +1,33 @@ +// In this test, the symlink created is invalid (valid relative to the root, but not +// relatively to where it is located), and used to cause an internal +// compiler error (ICE) when passed as a library search path. This was fixed in #26044, +// and this test checks that the invalid symlink is instead simply ignored. +// See https://github.com/rust-lang/rust/issues/26006 + +//@ needs-symlink +//Reason: symlink requires elevated permission in Windows + +use run_make_support::{rfs, rustc}; + +fn main() { + // We create two libs: `bar` which depends on `foo`. We need to compile `foo` first. + rfs::create_dir("out"); + rfs::create_dir("out/foo"); + rustc() + .input("in/foo/lib.rs") + .crate_name("foo") + .crate_type("lib") + .metadata("foo") + .output("out/foo/libfoo.rlib") + .run(); + rfs::create_dir("out/bar"); + rfs::create_dir("out/bar/deps"); + rfs::create_symlink("out/foo/libfoo.rlib", "out/bar/deps/libfoo.rlib"); + // Check that the invalid symlink does not cause an ICE + rustc() + .input("in/bar/lib.rs") + .library_search_path("dependency=out/bar/deps") + .run_fail() + .assert_exit_code(1) + .assert_stderr_not_contains("internal compiler error"); +} diff --git a/tests/run-make/issue-26006/Makefile b/tests/run-make/issue-26006/Makefile deleted file mode 100644 index b679c121530ad..0000000000000 --- a/tests/run-make/issue-26006/Makefile +++ /dev/null @@ -1,17 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# ignore-windows - -OUT := $(TMPDIR)/out - -all: time - -time: libc - mkdir -p $(OUT)/time $(OUT)/time/deps - ln -sf $(OUT)/libc/liblibc.rlib $(OUT)/time/deps/ - $(RUSTC) in/time/lib.rs -Ldependency=$(OUT)/time/deps/ - -libc: - mkdir -p $(OUT)/libc - $(RUSTC) in/libc/lib.rs --crate-name=libc -Cmetadata=foo -o $(OUT)/libc/liblibc.rlib diff --git a/tests/run-make/issue-26006/in/libc/lib.rs b/tests/run-make/issue-26006/in/libc/lib.rs deleted file mode 100644 index bad155a99bd61..0000000000000 --- a/tests/run-make/issue-26006/in/libc/lib.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![crate_type = "rlib"] - -pub fn something() {} diff --git a/tests/run-make/issue-26006/in/time/lib.rs b/tests/run-make/issue-26006/in/time/lib.rs deleted file mode 100644 index 51ed27cd713f9..0000000000000 --- a/tests/run-make/issue-26006/in/time/lib.rs +++ /dev/null @@ -1,4 +0,0 @@ -#![feature(rustc_private)] -extern crate libc; - -fn main() {} diff --git a/tests/run-make/rustdoc-cfgspec-parsing/rmake.rs b/tests/run-make/rustdoc-cfgspec-parsing/rmake.rs index 7cb66575c5481..9c8c71b19a620 100644 --- a/tests/run-make/rustdoc-cfgspec-parsing/rmake.rs +++ b/tests/run-make/rustdoc-cfgspec-parsing/rmake.rs @@ -3,9 +3,10 @@ // After this was fixed in #22135, this test checks that this bug does not make a resurgence. // See https://github.com/rust-lang/rust/issues/22131 -//FIXME(Oneirical): try test-various +//@ ignore-cross-compile +// Reason: rustdoc fails to find the "foo" crate -use run_make_support::{rustc, rustdoc}; +use run_make_support::{cwd, rustc, rustdoc}; fn main() { rustc().cfg(r#"feature="bar""#).crate_type("lib").input("foo.rs").run(); @@ -13,6 +14,7 @@ fn main() { .arg("--test") .arg("--cfg") .arg(r#"feature="bar""#) + .library_search_path(cwd()) .input("foo.rs") .run() .assert_stdout_contains("foo.rs - foo (line 1) ... ok"); From 741cf9167849d39cc31edf27a11c7f77da437445 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 18 Jul 2024 13:42:15 -0400 Subject: [PATCH 14/17] rewrite lto-smoke-c to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/lto-smoke-c/Makefile | 12 ----------- tests/run-make/lto-smoke-c/rmake.rs | 20 +++++++++++++++++++ 3 files changed, 20 insertions(+), 13 deletions(-) delete mode 100644 tests/run-make/lto-smoke-c/Makefile create mode 100644 tests/run-make/lto-smoke-c/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 745f00c4f5276..8b847771e7f31 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -62,7 +62,6 @@ run-make/long-linker-command-lines-cmd-exe/Makefile run-make/long-linker-command-lines/Makefile run-make/lto-linkage-used-attr/Makefile run-make/lto-no-link-whole-rlib/Makefile -run-make/lto-smoke-c/Makefile run-make/macos-deployment-target/Makefile run-make/macos-fat-archive/Makefile run-make/manual-link/Makefile diff --git a/tests/run-make/lto-smoke-c/Makefile b/tests/run-make/lto-smoke-c/Makefile deleted file mode 100644 index f1ba3d95da292..0000000000000 --- a/tests/run-make/lto-smoke-c/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Apparently older versions of GCC segfault if -g is passed... -CC := $(CC:-g=) - -all: - $(RUSTC) foo.rs -C lto - $(CC) bar.c $(call STATICLIB,foo) \ - $(call OUT_EXE,bar) \ - $(EXTRACFLAGS) $(EXTRACXXFLAGS) - $(call RUN,bar) diff --git a/tests/run-make/lto-smoke-c/rmake.rs b/tests/run-make/lto-smoke-c/rmake.rs new file mode 100644 index 0000000000000..66e19ae748242 --- /dev/null +++ b/tests/run-make/lto-smoke-c/rmake.rs @@ -0,0 +1,20 @@ +// LLVM's link-time-optimization (LTO) is a useful feature added to Rust in response +// to #10741. This test uses this feature with `-C lto` alongside a native C library, +// and checks that compilation and execution is successful. +// See https://github.com/rust-lang/rust/issues/10741 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{cc, extra_c_flags, extra_cxx_flags, run, rustc, static_lib_name}; + +fn main() { + rustc().input("foo.rs").arg("-Clto").run(); + cc().input("bar.c") + .arg(static_lib_name("foo")) + .out_exe("bar") + .args(&extra_c_flags()) + .args(&extra_cxx_flags()) + .run(); + run("bar"); +} From 9387a7523ec4a3668159aa2d9eff8d7a1cb8700b Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 18 Jul 2024 15:00:56 -0500 Subject: [PATCH 15/17] Change `binary_asm_labels` to only fire on x86 and x86_64 In , the `binary_asm_labels` lint was added which flags labels such as `0:` and `1:`. Before that change, LLVM was giving a confusing error on x86/x86_64 because of an incorrect interpretation. However, targets other than x86 and x86_64 never had the error message and have not been a problem. This means that the lint was causing code that previously worked to start failing (e.g. `compiler_builtins`), rather than only providing a more clear messages where there has always been an error. Adjust the lint to only fire on x86 and x86_64 assembly to avoid this regression. --- compiler/rustc_lint/src/builtin.rs | 25 +++++++++++++++-------- tests/ui/asm/binary_asm_labels_allowed.rs | 17 +++++++++++++++ 2 files changed, 33 insertions(+), 9 deletions(-) create mode 100644 tests/ui/asm/binary_asm_labels_allowed.rs diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index 485c214ac9def..9fba53196f636 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -66,6 +66,7 @@ use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, InnerSpan, Span}; use rustc_target::abi::Abi; +use rustc_target::asm::InlineAsmArch; use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy}; @@ -2908,16 +2909,22 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels { InvalidAsmLabel::FormatArg { missing_precise_span }, ); } - AsmLabelKind::Binary => { - // the binary asm issue only occurs when using intel syntax - if !options.contains(InlineAsmOptions::ATT_SYNTAX) { - cx.emit_span_lint( - BINARY_ASM_LABELS, - span, - InvalidAsmLabel::Binary { missing_precise_span, span }, - ) - } + // the binary asm issue only occurs when using intel syntax on x86 targets + AsmLabelKind::Binary + if !options.contains(InlineAsmOptions::ATT_SYNTAX) + && matches!( + cx.tcx.sess.asm_arch, + Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) | None + ) => + { + cx.emit_span_lint( + BINARY_ASM_LABELS, + span, + InvalidAsmLabel::Binary { missing_precise_span, span }, + ) } + // No lint on anything other than x86 + AsmLabelKind::Binary => (), }; } } diff --git a/tests/ui/asm/binary_asm_labels_allowed.rs b/tests/ui/asm/binary_asm_labels_allowed.rs new file mode 100644 index 0000000000000..a21ab8d70f5b4 --- /dev/null +++ b/tests/ui/asm/binary_asm_labels_allowed.rs @@ -0,0 +1,17 @@ +//@ build-pass +//@ only-aarch64 + +// The `binary_asm_labels` lint should only be raised on `x86`. Make sure it +// doesn't get raised on other platforms. + +use std::arch::asm; + +fn main() { + unsafe { + asm!("0: bl 0b"); + asm!("1: bl 1b"); + asm!("10: bl 10b"); + asm!("01: bl 01b"); + asm!("1001101: bl 1001101b"); + } +} From 730313227f8ab7cb75efb775a5f152c340ac3957 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Thu, 18 Jul 2024 14:10:01 -0400 Subject: [PATCH 16/17] rewrite link-path-order to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/link-path-order/Makefile | 19 ----------- tests/run-make/link-path-order/rmake.rs | 33 +++++++++++++++++++ tests/run-make/lto-smoke-c/rmake.rs | 4 +-- 4 files changed, 35 insertions(+), 22 deletions(-) delete mode 100644 tests/run-make/link-path-order/Makefile create mode 100644 tests/run-make/link-path-order/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 8b847771e7f31..e9f5e24f31281 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -56,7 +56,6 @@ run-make/libtest-junit/Makefile run-make/libtest-thread-limit/Makefile run-make/link-cfg/Makefile run-make/link-framework/Makefile -run-make/link-path-order/Makefile run-make/linkage-attr-on-static/Makefile run-make/long-linker-command-lines-cmd-exe/Makefile run-make/long-linker-command-lines/Makefile diff --git a/tests/run-make/link-path-order/Makefile b/tests/run-make/link-path-order/Makefile deleted file mode 100644 index a3831a63ac7e5..0000000000000 --- a/tests/run-make/link-path-order/Makefile +++ /dev/null @@ -1,19 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Verifies that the -L arguments given to the linker is in the same order -# as the -L arguments on the rustc command line. - -CORRECT_DIR=$(TMPDIR)/correct -WRONG_DIR=$(TMPDIR)/wrong - -F := $(call NATIVE_STATICLIB_FILE,foo) - -all: $(call NATIVE_STATICLIB,correct) $(call NATIVE_STATICLIB,wrong) - mkdir -p $(CORRECT_DIR) $(WRONG_DIR) - mv $(call NATIVE_STATICLIB,correct) $(CORRECT_DIR)/$(F) - mv $(call NATIVE_STATICLIB,wrong) $(WRONG_DIR)/$(F) - $(RUSTC) main.rs -o $(TMPDIR)/should_succeed -L $(CORRECT_DIR) -L $(WRONG_DIR) - $(call RUN,should_succeed) - $(RUSTC) main.rs -o $(TMPDIR)/should_fail -L $(WRONG_DIR) -L $(CORRECT_DIR) - $(call FAIL,should_fail) diff --git a/tests/run-make/link-path-order/rmake.rs b/tests/run-make/link-path-order/rmake.rs new file mode 100644 index 0000000000000..c8e41b2bcf8ac --- /dev/null +++ b/tests/run-make/link-path-order/rmake.rs @@ -0,0 +1,33 @@ +// The order in which "library search path" `-L` arguments are given to the command line rustc +// is important. These arguments must match the order of the linker's arguments. In this test, +// fetching the Wrong library before the Correct one causes a function to return 0 instead of the +// expected 1, causing a runtime panic, as expected. +// See https://github.com/rust-lang/rust/pull/16904 + +//@ ignore-cross-compile +// Reason: the compiled binary is executed + +use run_make_support::{build_native_static_lib, path, rfs, run, run_fail, rustc, static_lib_name}; + +fn main() { + build_native_static_lib("correct"); + build_native_static_lib("wrong"); + rfs::create_dir("correct"); + rfs::create_dir("wrong"); + rfs::rename(static_lib_name("correct"), path("correct").join(static_lib_name("foo"))); + rfs::rename(static_lib_name("wrong"), path("wrong").join(static_lib_name("foo"))); + rustc() + .input("main.rs") + .output("should_succeed") + .library_search_path("correct") + .library_search_path("wrong") + .run(); + run("should_succeed"); + rustc() + .input("main.rs") + .output("should_fail") + .library_search_path("wrong") + .library_search_path("correct") + .run(); + run_fail("should_fail"); +} diff --git a/tests/run-make/lto-smoke-c/rmake.rs b/tests/run-make/lto-smoke-c/rmake.rs index 66e19ae748242..70760f730c05f 100644 --- a/tests/run-make/lto-smoke-c/rmake.rs +++ b/tests/run-make/lto-smoke-c/rmake.rs @@ -13,8 +13,8 @@ fn main() { cc().input("bar.c") .arg(static_lib_name("foo")) .out_exe("bar") - .args(&extra_c_flags()) - .args(&extra_cxx_flags()) + .args(extra_c_flags()) + .args(extra_cxx_flags()) .run(); run("bar"); } From 8410348b1c0981b60500ec1f571f6ed8fc075fc8 Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Thu, 18 Jul 2024 15:12:28 -0500 Subject: [PATCH 17/17] Update the `binary_asm_label` message The link pointed to a closed issue. Create a new one and point the link to it. Also add a help message to hint what change the user could make. Fixes: https://github.com/rust-lang/rust/issues/127821 --- compiler/rustc_lint/messages.ftl | 5 +++-- compiler/rustc_lint/src/lints.rs | 4 +++- tests/ui/asm/binary_asm_labels.stderr | 20 +++++++++++++++----- 3 files changed, 21 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl index de04d882f5163..e8b155def3562 100644 --- a/compiler/rustc_lint/messages.ftl +++ b/compiler/rustc_lint/messages.ftl @@ -403,8 +403,9 @@ lint_inner_macro_attribute_unstable = inner macro attributes are unstable lint_invalid_asm_label_binary = avoid using labels containing only the digits `0` and `1` in inline assembly .label = use a different label that doesn't start with `0` or `1` - .note = an LLVM bug makes these labels ambiguous with a binary literal number - .note = see for more information + .help = start numbering with `2` instead + .note1 = an LLVM bug makes these labels ambiguous with a binary literal number on x86 + .note2 = see for more information lint_invalid_asm_label_format_arg = avoid using named labels in inline assembly .help = only local labels of the form `:` should be used in inline asm diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs index 308bb73f4cea6..52968faa0b5e2 100644 --- a/compiler/rustc_lint/src/lints.rs +++ b/compiler/rustc_lint/src/lints.rs @@ -2066,7 +2066,9 @@ pub enum InvalidAsmLabel { missing_precise_span: bool, }, #[diag(lint_invalid_asm_label_binary)] - #[note] + #[help] + #[note(lint_note1)] + #[note(lint_note2)] Binary { #[note(lint_invalid_asm_label_no_span)] missing_precise_span: bool, diff --git a/tests/ui/asm/binary_asm_labels.stderr b/tests/ui/asm/binary_asm_labels.stderr index 1f2943084f1eb..206d2da177982 100644 --- a/tests/ui/asm/binary_asm_labels.stderr +++ b/tests/ui/asm/binary_asm_labels.stderr @@ -4,7 +4,9 @@ error: avoid using labels containing only the digits `0` and `1` in inline assem LL | asm!("0: jmp 0b"); | ^ use a different label that doesn't start with `0` or `1` | - = note: an LLVM bug makes these labels ambiguous with a binary literal number + = help: start numbering with `2` instead + = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86 + = note: see for more information = note: `#[deny(binary_asm_labels)]` on by default error: avoid using labels containing only the digits `0` and `1` in inline assembly @@ -13,7 +15,9 @@ error: avoid using labels containing only the digits `0` and `1` in inline assem LL | asm!("1: jmp 1b"); | ^ use a different label that doesn't start with `0` or `1` | - = note: an LLVM bug makes these labels ambiguous with a binary literal number + = help: start numbering with `2` instead + = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86 + = note: see for more information error: avoid using labels containing only the digits `0` and `1` in inline assembly --> $DIR/binary_asm_labels.rs:13:15 @@ -21,7 +25,9 @@ error: avoid using labels containing only the digits `0` and `1` in inline assem LL | asm!("10: jmp 10b"); | ^^ use a different label that doesn't start with `0` or `1` | - = note: an LLVM bug makes these labels ambiguous with a binary literal number + = help: start numbering with `2` instead + = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86 + = note: see for more information error: avoid using labels containing only the digits `0` and `1` in inline assembly --> $DIR/binary_asm_labels.rs:14:15 @@ -29,7 +35,9 @@ error: avoid using labels containing only the digits `0` and `1` in inline assem LL | asm!("01: jmp 01b"); | ^^ use a different label that doesn't start with `0` or `1` | - = note: an LLVM bug makes these labels ambiguous with a binary literal number + = help: start numbering with `2` instead + = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86 + = note: see for more information error: avoid using labels containing only the digits `0` and `1` in inline assembly --> $DIR/binary_asm_labels.rs:15:15 @@ -37,7 +45,9 @@ error: avoid using labels containing only the digits `0` and `1` in inline assem LL | asm!("1001101: jmp 1001101b"); | ^^^^^^^ use a different label that doesn't start with `0` or `1` | - = note: an LLVM bug makes these labels ambiguous with a binary literal number + = help: start numbering with `2` instead + = note: an LLVM bug makes these labels ambiguous with a binary literal number on x86 + = note: see for more information error: aborting due to 5 previous errors