Skip to content

Commit 0cb871d

Browse files
committed
Auto merge of #127941 - GuillaumeGomez:rollup-s5eqz72, r=GuillaumeGomez
Rollup of 5 pull requests Successful merges: - #121533 (Handle .init_array link_section specially on wasm) - #123196 (Add Process support for UEFI) - #127621 (Rewrite and rename `issue-22131` and `issue-26006` `run-make` tests to rmake) - #127928 (Migrate `lto-smoke-c` and `link-path-order` `run-make` tests to rmake) - #127935 (Change `binary_asm_labels` to only fire on x86 and x86_64) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 5affbb1 + fb751e0 commit 0cb871d

File tree

26 files changed

+1093
-97
lines changed

26 files changed

+1093
-97
lines changed

compiler/rustc_codegen_llvm/src/consts.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -495,8 +495,14 @@ impl<'ll> CodegenCx<'ll, '_> {
495495
}
496496

497497
// Wasm statics with custom link sections get special treatment as they
498-
// go into custom sections of the wasm executable.
499-
if self.tcx.sess.target.is_like_wasm {
498+
// go into custom sections of the wasm executable. The exception to this
499+
// is the `.init_array` section which are treated specially by the wasm linker.
500+
if self.tcx.sess.target.is_like_wasm
501+
&& attrs
502+
.link_section
503+
.map(|link_section| !link_section.as_str().starts_with(".init_array"))
504+
.unwrap_or(true)
505+
{
500506
if let Some(section) = attrs.link_section {
501507
let section = llvm::LLVMMDStringInContext2(
502508
self.llcx,

compiler/rustc_hir_analysis/src/check/mod.rs

+28-7
Original file line numberDiff line numberDiff line change
@@ -166,21 +166,42 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
166166
return;
167167
}
168168

169-
// For the wasm32 target statics with `#[link_section]` are placed into custom
170-
// sections of the final output file, but this isn't link custom sections of
171-
// other executable formats. Namely we can only embed a list of bytes,
172-
// nothing with provenance (pointers to anything else). If any provenance
173-
// show up, reject it here.
169+
// For the wasm32 target statics with `#[link_section]` other than `.init_array`
170+
// are placed into custom sections of the final output file, but this isn't like
171+
// custom sections of other executable formats. Namely we can only embed a list
172+
// of bytes, nothing with provenance (pointers to anything else). If any
173+
// provenance show up, reject it here.
174174
// `#[link_section]` may contain arbitrary, or even undefined bytes, but it is
175175
// the consumer's responsibility to ensure all bytes that have been read
176176
// have defined values.
177+
//
178+
// The `.init_array` section is left to go through the normal custom section code path.
179+
// When dealing with `.init_array` wasm-ld currently has several limitations. This manifests
180+
// in workarounds in user-code.
181+
//
182+
// * The linker fails to merge multiple items in a crate into the .init_array section.
183+
// To work around this, a single array can be used placing multiple items in the array.
184+
// #[link_section = ".init_array"]
185+
// static FOO: [unsafe extern "C" fn(); 2] = [ctor, ctor];
186+
// * Even symbols marked used get gc'd from dependant crates unless at least one symbol
187+
// in the crate is marked with an `#[export_name]`
188+
//
189+
// Once `.init_array` support in wasm-ld is complete, the user code workarounds should
190+
// continue to work, but would no longer be necessary.
191+
177192
if let Ok(alloc) = tcx.eval_static_initializer(id.to_def_id())
178193
&& alloc.inner().provenance().ptrs().len() != 0
179194
{
180-
let msg = "statics with a custom `#[link_section]` must be a \
195+
if attrs
196+
.link_section
197+
.map(|link_section| !link_section.as_str().starts_with(".init_array"))
198+
.unwrap()
199+
{
200+
let msg = "statics with a custom `#[link_section]` must be a \
181201
simple list of bytes on the wasm target with no \
182202
extra levels of indirection such as references";
183-
tcx.dcx().span_err(tcx.def_span(id), msg);
203+
tcx.dcx().span_err(tcx.def_span(id), msg);
204+
}
184205
}
185206
}
186207

compiler/rustc_lint/messages.ftl

+3-2
Original file line numberDiff line numberDiff line change
@@ -403,8 +403,9 @@ lint_inner_macro_attribute_unstable = inner macro attributes are unstable
403403
404404
lint_invalid_asm_label_binary = avoid using labels containing only the digits `0` and `1` in inline assembly
405405
.label = use a different label that doesn't start with `0` or `1`
406-
.note = an LLVM bug makes these labels ambiguous with a binary literal number
407-
.note = see <https://bugs.llvm.org/show_bug.cgi?id=36144> for more information
406+
.help = start numbering with `2` instead
407+
.note1 = an LLVM bug makes these labels ambiguous with a binary literal number on x86
408+
.note2 = see <https://github.com/llvm/llvm-project/issues/99547> for more information
408409
409410
lint_invalid_asm_label_format_arg = avoid using named labels in inline assembly
410411
.help = only local labels of the form `<number>:` should be used in inline asm

compiler/rustc_lint/src/builtin.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ use rustc_span::source_map::Spanned;
6666
use rustc_span::symbol::{kw, sym, Ident, Symbol};
6767
use rustc_span::{BytePos, InnerSpan, Span};
6868
use rustc_target::abi::Abi;
69+
use rustc_target::asm::InlineAsmArch;
6970
use rustc_trait_selection::infer::{InferCtxtExt, TyCtxtInferExt};
7071
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
7172
use rustc_trait_selection::traits::{self, misc::type_allowed_to_implement_copy};
@@ -2908,16 +2909,22 @@ impl<'tcx> LateLintPass<'tcx> for AsmLabels {
29082909
InvalidAsmLabel::FormatArg { missing_precise_span },
29092910
);
29102911
}
2911-
AsmLabelKind::Binary => {
2912-
// the binary asm issue only occurs when using intel syntax
2913-
if !options.contains(InlineAsmOptions::ATT_SYNTAX) {
2914-
cx.emit_span_lint(
2915-
BINARY_ASM_LABELS,
2916-
span,
2917-
InvalidAsmLabel::Binary { missing_precise_span, span },
2918-
)
2919-
}
2912+
// the binary asm issue only occurs when using intel syntax on x86 targets
2913+
AsmLabelKind::Binary
2914+
if !options.contains(InlineAsmOptions::ATT_SYNTAX)
2915+
&& matches!(
2916+
cx.tcx.sess.asm_arch,
2917+
Some(InlineAsmArch::X86 | InlineAsmArch::X86_64) | None
2918+
) =>
2919+
{
2920+
cx.emit_span_lint(
2921+
BINARY_ASM_LABELS,
2922+
span,
2923+
InvalidAsmLabel::Binary { missing_precise_span, span },
2924+
)
29202925
}
2926+
// No lint on anything other than x86
2927+
AsmLabelKind::Binary => (),
29212928
};
29222929
}
29232930
}

compiler/rustc_lint/src/lints.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -2074,7 +2074,9 @@ pub enum InvalidAsmLabel {
20742074
missing_precise_span: bool,
20752075
},
20762076
#[diag(lint_invalid_asm_label_binary)]
2077-
#[note]
2077+
#[help]
2078+
#[note(lint_note1)]
2079+
#[note(lint_note2)]
20782080
Binary {
20792081
#[note(lint_invalid_asm_label_no_span)]
20802082
missing_precise_span: bool,

library/std/Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ hermit-abi = { version = "0.4.0", features = ['rustc-dep-of-std'], public = true
5656
wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
5757

5858
[target.'cfg(target_os = "uefi")'.dependencies]
59-
r-efi = { version = "4.2.0", features = ['rustc-dep-of-std'] }
59+
r-efi = { version = "4.5.0", features = ['rustc-dep-of-std'] }
6060
r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std'] }
6161

6262
[features]

library/std/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -293,6 +293,7 @@
293293
#![feature(doc_masked)]
294294
#![feature(doc_notable_trait)]
295295
#![feature(dropck_eyepatch)]
296+
#![feature(extended_varargs_abi_support)]
296297
#![feature(f128)]
297298
#![feature(f16)]
298299
#![feature(if_let_guard)]

library/std/src/sys/pal/uefi/helpers.rs

+197-2
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,21 @@
1212
use r_efi::efi::{self, Guid};
1313
use r_efi::protocols::{device_path, device_path_to_text};
1414

15-
use crate::ffi::OsString;
15+
use crate::ffi::{OsStr, OsString};
1616
use crate::io::{self, const_io_error};
1717
use crate::mem::{size_of, MaybeUninit};
18-
use crate::os::uefi::{self, env::boot_services, ffi::OsStringExt};
18+
use crate::os::uefi::{self, env::boot_services, ffi::OsStrExt, ffi::OsStringExt};
1919
use crate::ptr::NonNull;
2020
use crate::slice;
2121
use crate::sync::atomic::{AtomicPtr, Ordering};
2222
use crate::sys_common::wstr::WStrUnits;
2323

24+
type BootInstallMultipleProtocolInterfaces =
25+
unsafe extern "efiapi" fn(_: *mut r_efi::efi::Handle, _: ...) -> r_efi::efi::Status;
26+
27+
type BootUninstallMultipleProtocolInterfaces =
28+
unsafe extern "efiapi" fn(_: r_efi::efi::Handle, _: ...) -> r_efi::efi::Status;
29+
2430
const BOOT_SERVICES_UNAVAILABLE: io::Error =
2531
const_io_error!(io::ErrorKind::Other, "Boot Services are no longer available");
2632

@@ -221,3 +227,192 @@ pub(crate) fn runtime_services() -> Option<NonNull<r_efi::efi::RuntimeServices>>
221227
let runtime_services = unsafe { (*system_table.as_ptr()).runtime_services };
222228
NonNull::new(runtime_services)
223229
}
230+
231+
pub(crate) struct DevicePath(NonNull<r_efi::protocols::device_path::Protocol>);
232+
233+
impl DevicePath {
234+
pub(crate) fn from_text(p: &OsStr) -> io::Result<Self> {
235+
fn inner(
236+
p: &OsStr,
237+
protocol: NonNull<r_efi::protocols::device_path_from_text::Protocol>,
238+
) -> io::Result<DevicePath> {
239+
let path_vec = p.encode_wide().chain(Some(0)).collect::<Vec<u16>>();
240+
if path_vec[..path_vec.len() - 1].contains(&0) {
241+
return Err(const_io_error!(
242+
io::ErrorKind::InvalidInput,
243+
"strings passed to UEFI cannot contain NULs",
244+
));
245+
}
246+
247+
let path =
248+
unsafe { ((*protocol.as_ptr()).convert_text_to_device_path)(path_vec.as_ptr()) };
249+
250+
NonNull::new(path).map(DevicePath).ok_or_else(|| {
251+
const_io_error!(io::ErrorKind::InvalidFilename, "Invalid Device Path")
252+
})
253+
}
254+
255+
static LAST_VALID_HANDLE: AtomicPtr<crate::ffi::c_void> =
256+
AtomicPtr::new(crate::ptr::null_mut());
257+
258+
if let Some(handle) = NonNull::new(LAST_VALID_HANDLE.load(Ordering::Acquire)) {
259+
if let Ok(protocol) = open_protocol::<r_efi::protocols::device_path_from_text::Protocol>(
260+
handle,
261+
r_efi::protocols::device_path_from_text::PROTOCOL_GUID,
262+
) {
263+
return inner(p, protocol);
264+
}
265+
}
266+
267+
let handles = locate_handles(r_efi::protocols::device_path_from_text::PROTOCOL_GUID)?;
268+
for handle in handles {
269+
if let Ok(protocol) = open_protocol::<r_efi::protocols::device_path_from_text::Protocol>(
270+
handle,
271+
r_efi::protocols::device_path_from_text::PROTOCOL_GUID,
272+
) {
273+
LAST_VALID_HANDLE.store(handle.as_ptr(), Ordering::Release);
274+
return inner(p, protocol);
275+
}
276+
}
277+
278+
io::Result::Err(const_io_error!(
279+
io::ErrorKind::NotFound,
280+
"DevicePathFromText Protocol not found"
281+
))
282+
}
283+
284+
pub(crate) fn as_ptr(&self) -> *mut r_efi::protocols::device_path::Protocol {
285+
self.0.as_ptr()
286+
}
287+
}
288+
289+
impl Drop for DevicePath {
290+
fn drop(&mut self) {
291+
if let Some(bt) = boot_services() {
292+
let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
293+
unsafe {
294+
((*bt.as_ptr()).free_pool)(self.0.as_ptr() as *mut crate::ffi::c_void);
295+
}
296+
}
297+
}
298+
}
299+
300+
pub(crate) struct OwnedProtocol<T> {
301+
guid: r_efi::efi::Guid,
302+
handle: NonNull<crate::ffi::c_void>,
303+
protocol: *mut T,
304+
}
305+
306+
impl<T> OwnedProtocol<T> {
307+
// FIXME: Consider using unsafe trait for matching protocol with guid
308+
pub(crate) unsafe fn create(protocol: T, mut guid: r_efi::efi::Guid) -> io::Result<Self> {
309+
let bt: NonNull<r_efi::efi::BootServices> =
310+
boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
311+
let protocol: *mut T = Box::into_raw(Box::new(protocol));
312+
let mut handle: r_efi::efi::Handle = crate::ptr::null_mut();
313+
314+
// FIXME: Move into r-efi once extended_varargs_abi_support is stablized
315+
let func: BootInstallMultipleProtocolInterfaces =
316+
unsafe { crate::mem::transmute((*bt.as_ptr()).install_multiple_protocol_interfaces) };
317+
318+
let r = unsafe {
319+
func(
320+
&mut handle,
321+
&mut guid as *mut _ as *mut crate::ffi::c_void,
322+
protocol as *mut crate::ffi::c_void,
323+
crate::ptr::null_mut() as *mut crate::ffi::c_void,
324+
)
325+
};
326+
327+
if r.is_error() {
328+
drop(Box::from_raw(protocol));
329+
return Err(crate::io::Error::from_raw_os_error(r.as_usize()));
330+
};
331+
332+
let handle = NonNull::new(handle)
333+
.ok_or(io::const_io_error!(io::ErrorKind::Uncategorized, "found null handle"))?;
334+
335+
Ok(Self { guid, handle, protocol })
336+
}
337+
338+
pub(crate) fn handle(&self) -> NonNull<crate::ffi::c_void> {
339+
self.handle
340+
}
341+
}
342+
343+
impl<T> Drop for OwnedProtocol<T> {
344+
fn drop(&mut self) {
345+
// Do not deallocate a runtime protocol
346+
if let Some(bt) = boot_services() {
347+
let bt: NonNull<r_efi::efi::BootServices> = bt.cast();
348+
// FIXME: Move into r-efi once extended_varargs_abi_support is stablized
349+
let func: BootUninstallMultipleProtocolInterfaces = unsafe {
350+
crate::mem::transmute((*bt.as_ptr()).uninstall_multiple_protocol_interfaces)
351+
};
352+
let status = unsafe {
353+
func(
354+
self.handle.as_ptr(),
355+
&mut self.guid as *mut _ as *mut crate::ffi::c_void,
356+
self.protocol as *mut crate::ffi::c_void,
357+
crate::ptr::null_mut() as *mut crate::ffi::c_void,
358+
)
359+
};
360+
361+
// Leak the protocol in case uninstall fails
362+
if status == r_efi::efi::Status::SUCCESS {
363+
let _ = unsafe { Box::from_raw(self.protocol) };
364+
}
365+
}
366+
}
367+
}
368+
369+
impl<T> AsRef<T> for OwnedProtocol<T> {
370+
fn as_ref(&self) -> &T {
371+
unsafe { self.protocol.as_ref().unwrap() }
372+
}
373+
}
374+
375+
pub(crate) struct OwnedTable<T> {
376+
layout: crate::alloc::Layout,
377+
ptr: *mut T,
378+
}
379+
380+
impl<T> OwnedTable<T> {
381+
pub(crate) fn from_table_header(hdr: &r_efi::efi::TableHeader) -> Self {
382+
let header_size = hdr.header_size as usize;
383+
let layout = crate::alloc::Layout::from_size_align(header_size, 8).unwrap();
384+
let ptr = unsafe { crate::alloc::alloc(layout) as *mut T };
385+
Self { layout, ptr }
386+
}
387+
388+
pub(crate) const fn as_ptr(&self) -> *const T {
389+
self.ptr
390+
}
391+
392+
pub(crate) const fn as_mut_ptr(&self) -> *mut T {
393+
self.ptr
394+
}
395+
}
396+
397+
impl OwnedTable<r_efi::efi::SystemTable> {
398+
pub(crate) fn from_table(tbl: *const r_efi::efi::SystemTable) -> Self {
399+
let hdr = unsafe { (*tbl).hdr };
400+
401+
let owned_tbl = Self::from_table_header(&hdr);
402+
unsafe {
403+
crate::ptr::copy_nonoverlapping(
404+
tbl as *const u8,
405+
owned_tbl.as_mut_ptr() as *mut u8,
406+
hdr.header_size as usize,
407+
)
408+
};
409+
410+
owned_tbl
411+
}
412+
}
413+
414+
impl<T> Drop for OwnedTable<T> {
415+
fn drop(&mut self) {
416+
unsafe { crate::alloc::dealloc(self.ptr as *mut u8, self.layout) };
417+
}
418+
}

library/std/src/sys/pal/uefi/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ pub mod net;
2525
pub mod os;
2626
#[path = "../unsupported/pipe.rs"]
2727
pub mod pipe;
28-
#[path = "../unsupported/process.rs"]
2928
pub mod process;
3029
pub mod stdio;
3130
pub mod thread;

0 commit comments

Comments
 (0)