Auto merge of #108262 - ChrisDenton:libntdll, r=Mark-Simulacrum
Distribute libntdll.a with windows-gnu toolchains This allows the OS loader to load essential functions (e.g. read/write file) at load time instead of lazily doing so at runtime. r? libs
This commit is contained in:
commit
3ff4d56650
@ -296,7 +296,6 @@ pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xc000000d_u32 as _;
|
|||||||
|
|
||||||
pub const STATUS_PENDING: NTSTATUS = 0x103 as _;
|
pub const STATUS_PENDING: NTSTATUS = 0x103 as _;
|
||||||
pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _;
|
pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _;
|
||||||
pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _;
|
|
||||||
|
|
||||||
// Equivalent to the `NT_SUCCESS` C preprocessor macro.
|
// Equivalent to the `NT_SUCCESS` C preprocessor macro.
|
||||||
// See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values
|
// See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values
|
||||||
@ -1282,6 +1281,46 @@ extern "system" {
|
|||||||
) -> NTSTATUS;
|
) -> NTSTATUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[link(name = "ntdll")]
|
||||||
|
extern "system" {
|
||||||
|
pub fn NtCreateFile(
|
||||||
|
FileHandle: *mut HANDLE,
|
||||||
|
DesiredAccess: ACCESS_MASK,
|
||||||
|
ObjectAttributes: *const OBJECT_ATTRIBUTES,
|
||||||
|
IoStatusBlock: *mut IO_STATUS_BLOCK,
|
||||||
|
AllocationSize: *mut i64,
|
||||||
|
FileAttributes: ULONG,
|
||||||
|
ShareAccess: ULONG,
|
||||||
|
CreateDisposition: ULONG,
|
||||||
|
CreateOptions: ULONG,
|
||||||
|
EaBuffer: *mut c_void,
|
||||||
|
EaLength: ULONG,
|
||||||
|
) -> NTSTATUS;
|
||||||
|
pub fn NtReadFile(
|
||||||
|
FileHandle: BorrowedHandle<'_>,
|
||||||
|
Event: HANDLE,
|
||||||
|
ApcRoutine: Option<IO_APC_ROUTINE>,
|
||||||
|
ApcContext: *mut c_void,
|
||||||
|
IoStatusBlock: &mut IO_STATUS_BLOCK,
|
||||||
|
Buffer: *mut crate::mem::MaybeUninit<u8>,
|
||||||
|
Length: ULONG,
|
||||||
|
ByteOffset: Option<&LARGE_INTEGER>,
|
||||||
|
Key: Option<&ULONG>,
|
||||||
|
) -> NTSTATUS;
|
||||||
|
pub fn NtWriteFile(
|
||||||
|
FileHandle: BorrowedHandle<'_>,
|
||||||
|
Event: HANDLE,
|
||||||
|
ApcRoutine: Option<IO_APC_ROUTINE>,
|
||||||
|
ApcContext: *mut c_void,
|
||||||
|
IoStatusBlock: &mut IO_STATUS_BLOCK,
|
||||||
|
Buffer: *const u8,
|
||||||
|
Length: ULONG,
|
||||||
|
ByteOffset: Option<&LARGE_INTEGER>,
|
||||||
|
Key: Option<&ULONG>,
|
||||||
|
) -> NTSTATUS;
|
||||||
|
pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> ULONG;
|
||||||
|
}
|
||||||
|
|
||||||
// Functions that aren't available on every version of Windows that we support,
|
// Functions that aren't available on every version of Windows that we support,
|
||||||
// but we still use them and just provide some form of a fallback implementation.
|
// but we still use them and just provide some form of a fallback implementation.
|
||||||
compat_fn_with_fallback! {
|
compat_fn_with_fallback! {
|
||||||
@ -1322,52 +1361,6 @@ compat_fn_optional! {
|
|||||||
compat_fn_with_fallback! {
|
compat_fn_with_fallback! {
|
||||||
pub static NTDLL: &CStr = ansi_str!("ntdll");
|
pub static NTDLL: &CStr = ansi_str!("ntdll");
|
||||||
|
|
||||||
pub fn NtCreateFile(
|
|
||||||
FileHandle: *mut HANDLE,
|
|
||||||
DesiredAccess: ACCESS_MASK,
|
|
||||||
ObjectAttributes: *const OBJECT_ATTRIBUTES,
|
|
||||||
IoStatusBlock: *mut IO_STATUS_BLOCK,
|
|
||||||
AllocationSize: *mut i64,
|
|
||||||
FileAttributes: ULONG,
|
|
||||||
ShareAccess: ULONG,
|
|
||||||
CreateDisposition: ULONG,
|
|
||||||
CreateOptions: ULONG,
|
|
||||||
EaBuffer: *mut c_void,
|
|
||||||
EaLength: ULONG
|
|
||||||
) -> NTSTATUS {
|
|
||||||
STATUS_NOT_IMPLEMENTED
|
|
||||||
}
|
|
||||||
pub fn NtReadFile(
|
|
||||||
FileHandle: BorrowedHandle<'_>,
|
|
||||||
Event: HANDLE,
|
|
||||||
ApcRoutine: Option<IO_APC_ROUTINE>,
|
|
||||||
ApcContext: *mut c_void,
|
|
||||||
IoStatusBlock: &mut IO_STATUS_BLOCK,
|
|
||||||
Buffer: *mut crate::mem::MaybeUninit<u8>,
|
|
||||||
Length: ULONG,
|
|
||||||
ByteOffset: Option<&LARGE_INTEGER>,
|
|
||||||
Key: Option<&ULONG>
|
|
||||||
) -> NTSTATUS {
|
|
||||||
STATUS_NOT_IMPLEMENTED
|
|
||||||
}
|
|
||||||
pub fn NtWriteFile(
|
|
||||||
FileHandle: BorrowedHandle<'_>,
|
|
||||||
Event: HANDLE,
|
|
||||||
ApcRoutine: Option<IO_APC_ROUTINE>,
|
|
||||||
ApcContext: *mut c_void,
|
|
||||||
IoStatusBlock: &mut IO_STATUS_BLOCK,
|
|
||||||
Buffer: *const u8,
|
|
||||||
Length: ULONG,
|
|
||||||
ByteOffset: Option<&LARGE_INTEGER>,
|
|
||||||
Key: Option<&ULONG>
|
|
||||||
) -> NTSTATUS {
|
|
||||||
STATUS_NOT_IMPLEMENTED
|
|
||||||
}
|
|
||||||
pub fn RtlNtStatusToDosError(
|
|
||||||
Status: NTSTATUS
|
|
||||||
) -> ULONG {
|
|
||||||
Status as ULONG
|
|
||||||
}
|
|
||||||
pub fn NtCreateKeyedEvent(
|
pub fn NtCreateKeyedEvent(
|
||||||
KeyedEventHandle: LPHANDLE,
|
KeyedEventHandle: LPHANDLE,
|
||||||
DesiredAccess: ACCESS_MASK,
|
DesiredAccess: ACCESS_MASK,
|
||||||
|
@ -210,6 +210,8 @@ fn make_win_dist(
|
|||||||
rustc_dlls.push("libgcc_s_seh-1.dll");
|
rustc_dlls.push("libgcc_s_seh-1.dll");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Libraries necessary to link the windows-gnu toolchains.
|
||||||
|
// System libraries will be preferred if they are available (see #67429).
|
||||||
let target_libs = [
|
let target_libs = [
|
||||||
//MinGW libs
|
//MinGW libs
|
||||||
"libgcc.a",
|
"libgcc.a",
|
||||||
@ -223,6 +225,7 @@ fn make_win_dist(
|
|||||||
"libmoldname.a",
|
"libmoldname.a",
|
||||||
"libpthread.a",
|
"libpthread.a",
|
||||||
//Windows import libs
|
//Windows import libs
|
||||||
|
//This should contain only the set of libraries necessary to link the standard library.
|
||||||
"libadvapi32.a",
|
"libadvapi32.a",
|
||||||
"libbcrypt.a",
|
"libbcrypt.a",
|
||||||
"libcomctl32.a",
|
"libcomctl32.a",
|
||||||
@ -236,6 +239,7 @@ fn make_win_dist(
|
|||||||
"libkernel32.a",
|
"libkernel32.a",
|
||||||
"libmsimg32.a",
|
"libmsimg32.a",
|
||||||
"libmsvcrt.a",
|
"libmsvcrt.a",
|
||||||
|
"libntdll.a",
|
||||||
"libodbc32.a",
|
"libodbc32.a",
|
||||||
"libole32.a",
|
"libole32.a",
|
||||||
"liboleaut32.a",
|
"liboleaut32.a",
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
use rustc_target::abi::Size;
|
|
||||||
use rustc_target::spec::abi::Abi;
|
use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
use log::trace;
|
use log::trace;
|
||||||
@ -11,7 +10,6 @@ use crate::*;
|
|||||||
|
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum Dlsym {
|
pub enum Dlsym {
|
||||||
NtWriteFile,
|
|
||||||
SetThreadDescription,
|
SetThreadDescription,
|
||||||
WaitOnAddress,
|
WaitOnAddress,
|
||||||
WakeByAddressSingle,
|
WakeByAddressSingle,
|
||||||
@ -23,7 +21,6 @@ impl Dlsym {
|
|||||||
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
|
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
|
||||||
Ok(match name {
|
Ok(match name {
|
||||||
"GetSystemTimePreciseAsFileTime" => None,
|
"GetSystemTimePreciseAsFileTime" => None,
|
||||||
"NtWriteFile" => Some(Dlsym::NtWriteFile),
|
|
||||||
"SetThreadDescription" => Some(Dlsym::SetThreadDescription),
|
"SetThreadDescription" => Some(Dlsym::SetThreadDescription),
|
||||||
"WaitOnAddress" => Some(Dlsym::WaitOnAddress),
|
"WaitOnAddress" => Some(Dlsym::WaitOnAddress),
|
||||||
"WakeByAddressSingle" => Some(Dlsym::WakeByAddressSingle),
|
"WakeByAddressSingle" => Some(Dlsym::WakeByAddressSingle),
|
||||||
@ -49,72 +46,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||||||
this.check_abi(abi, Abi::System { unwind: false })?;
|
this.check_abi(abi, Abi::System { unwind: false })?;
|
||||||
|
|
||||||
match dlsym {
|
match dlsym {
|
||||||
Dlsym::NtWriteFile => {
|
|
||||||
if !this.frame_in_std() {
|
|
||||||
throw_unsup_format!(
|
|
||||||
"`NtWriteFile` support is crude and just enough for stdout to work"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let [
|
|
||||||
handle,
|
|
||||||
_event,
|
|
||||||
_apc_routine,
|
|
||||||
_apc_context,
|
|
||||||
io_status_block,
|
|
||||||
buf,
|
|
||||||
n,
|
|
||||||
byte_offset,
|
|
||||||
_key,
|
|
||||||
] = check_arg_count(args)?;
|
|
||||||
let handle = this.read_target_isize(handle)?;
|
|
||||||
let buf = this.read_pointer(buf)?;
|
|
||||||
let n = this.read_scalar(n)?.to_u32()?;
|
|
||||||
let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer
|
|
||||||
let io_status_block = this.deref_operand(io_status_block)?;
|
|
||||||
|
|
||||||
if byte_offset != 0 {
|
|
||||||
throw_unsup_format!(
|
|
||||||
"`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let written = if handle == -11 || handle == -12 {
|
|
||||||
// stdout/stderr
|
|
||||||
use std::io::{self, Write};
|
|
||||||
|
|
||||||
let buf_cont =
|
|
||||||
this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?;
|
|
||||||
let res = if this.machine.mute_stdout_stderr {
|
|
||||||
Ok(buf_cont.len())
|
|
||||||
} else if handle == -11 {
|
|
||||||
io::stdout().write(buf_cont)
|
|
||||||
} else {
|
|
||||||
io::stderr().write(buf_cont)
|
|
||||||
};
|
|
||||||
// We write at most `n` bytes, which is a `u32`, so we cannot have written more than that.
|
|
||||||
res.ok().map(|n| u32::try_from(n).unwrap())
|
|
||||||
} else {
|
|
||||||
throw_unsup_format!(
|
|
||||||
"on Windows, writing to anything except stdout/stderr is not supported"
|
|
||||||
)
|
|
||||||
};
|
|
||||||
// We have to put the result into io_status_block.
|
|
||||||
if let Some(n) = written {
|
|
||||||
let io_status_information =
|
|
||||||
this.mplace_field_named(&io_status_block, "Information")?;
|
|
||||||
this.write_scalar(
|
|
||||||
Scalar::from_target_usize(n.into(), this),
|
|
||||||
&io_status_information.into(),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
// Return whether this was a success. >= 0 is success.
|
|
||||||
// For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
|
|
||||||
this.write_scalar(
|
|
||||||
Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }),
|
|
||||||
dest,
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
Dlsym::SetThreadDescription => {
|
Dlsym::SetThreadDescription => {
|
||||||
let [handle, name] = check_arg_count(args)?;
|
let [handle, name] = check_arg_count(args)?;
|
||||||
|
|
||||||
|
@ -69,6 +69,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||||||
this.write_scalar(result, dest)?;
|
this.write_scalar(result, dest)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// File related shims
|
||||||
|
"NtWriteFile" => {
|
||||||
|
if !this.frame_in_std() {
|
||||||
|
throw_unsup_format!(
|
||||||
|
"`NtWriteFile` support is crude and just enough for stdout to work"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let [
|
||||||
|
handle,
|
||||||
|
_event,
|
||||||
|
_apc_routine,
|
||||||
|
_apc_context,
|
||||||
|
io_status_block,
|
||||||
|
buf,
|
||||||
|
n,
|
||||||
|
byte_offset,
|
||||||
|
_key,
|
||||||
|
] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
|
||||||
|
let handle = this.read_target_isize(handle)?;
|
||||||
|
let buf = this.read_pointer(buf)?;
|
||||||
|
let n = this.read_scalar(n)?.to_u32()?;
|
||||||
|
let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer
|
||||||
|
let io_status_block = this.deref_operand(io_status_block)?;
|
||||||
|
|
||||||
|
if byte_offset != 0 {
|
||||||
|
throw_unsup_format!(
|
||||||
|
"`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let written = if handle == -11 || handle == -12 {
|
||||||
|
// stdout/stderr
|
||||||
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
let buf_cont =
|
||||||
|
this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?;
|
||||||
|
let res = if this.machine.mute_stdout_stderr {
|
||||||
|
Ok(buf_cont.len())
|
||||||
|
} else if handle == -11 {
|
||||||
|
io::stdout().write(buf_cont)
|
||||||
|
} else {
|
||||||
|
io::stderr().write(buf_cont)
|
||||||
|
};
|
||||||
|
// We write at most `n` bytes, which is a `u32`, so we cannot have written more than that.
|
||||||
|
res.ok().map(|n| u32::try_from(n).unwrap())
|
||||||
|
} else {
|
||||||
|
throw_unsup_format!(
|
||||||
|
"on Windows, writing to anything except stdout/stderr is not supported"
|
||||||
|
)
|
||||||
|
};
|
||||||
|
// We have to put the result into io_status_block.
|
||||||
|
if let Some(n) = written {
|
||||||
|
let io_status_information =
|
||||||
|
this.mplace_field_named(&io_status_block, "Information")?;
|
||||||
|
this.write_scalar(
|
||||||
|
Scalar::from_target_usize(n.into(), this),
|
||||||
|
&io_status_information.into(),
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
// Return whether this was a success. >= 0 is success.
|
||||||
|
// For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
|
||||||
|
this.write_scalar(
|
||||||
|
Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }),
|
||||||
|
dest,
|
||||||
|
)?;
|
||||||
|
}
|
||||||
|
|
||||||
// Allocation
|
// Allocation
|
||||||
"HeapAlloc" => {
|
"HeapAlloc" => {
|
||||||
let [handle, flags, size] =
|
let [handle, flags, size] =
|
||||||
|
@ -112,9 +112,9 @@ endif
|
|||||||
# Extra flags needed to compile a working executable with the standard library
|
# Extra flags needed to compile a working executable with the standard library
|
||||||
ifdef IS_WINDOWS
|
ifdef IS_WINDOWS
|
||||||
ifdef IS_MSVC
|
ifdef IS_MSVC
|
||||||
EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib
|
EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib
|
||||||
else
|
else
|
||||||
EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt
|
EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll
|
||||||
EXTRACXXFLAGS := -lstdc++
|
EXTRACXXFLAGS := -lstdc++
|
||||||
# So this is a bit hacky: we can't use the DLL version of libstdc++ because
|
# So this is a bit hacky: we can't use the DLL version of libstdc++ because
|
||||||
# it pulls in the DLL version of libgcc, which means that we end up with 2
|
# it pulls in the DLL version of libgcc, which means that we end up with 2
|
||||||
|
Loading…
x
Reference in New Issue
Block a user