Skip to content

Commit 3ff4d56

Browse files
committed
Auto merge of rust-lang#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
2 parents 822c10f + 154f5d7 commit 3ff4d56

File tree

5 files changed

+114
-118
lines changed

5 files changed

+114
-118
lines changed

library/std/src/sys/windows/c.rs

+40-47
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,6 @@ pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xc000000d_u32 as _;
296296

297297
pub const STATUS_PENDING: NTSTATUS = 0x103 as _;
298298
pub const STATUS_END_OF_FILE: NTSTATUS = 0xC0000011_u32 as _;
299-
pub const STATUS_NOT_IMPLEMENTED: NTSTATUS = 0xC0000002_u32 as _;
300299

301300
// Equivalent to the `NT_SUCCESS` C preprocessor macro.
302301
// See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values
@@ -1282,6 +1281,46 @@ extern "system" {
12821281
) -> NTSTATUS;
12831282
}
12841283

1284+
#[link(name = "ntdll")]
1285+
extern "system" {
1286+
pub fn NtCreateFile(
1287+
FileHandle: *mut HANDLE,
1288+
DesiredAccess: ACCESS_MASK,
1289+
ObjectAttributes: *const OBJECT_ATTRIBUTES,
1290+
IoStatusBlock: *mut IO_STATUS_BLOCK,
1291+
AllocationSize: *mut i64,
1292+
FileAttributes: ULONG,
1293+
ShareAccess: ULONG,
1294+
CreateDisposition: ULONG,
1295+
CreateOptions: ULONG,
1296+
EaBuffer: *mut c_void,
1297+
EaLength: ULONG,
1298+
) -> NTSTATUS;
1299+
pub fn NtReadFile(
1300+
FileHandle: BorrowedHandle<'_>,
1301+
Event: HANDLE,
1302+
ApcRoutine: Option<IO_APC_ROUTINE>,
1303+
ApcContext: *mut c_void,
1304+
IoStatusBlock: &mut IO_STATUS_BLOCK,
1305+
Buffer: *mut crate::mem::MaybeUninit<u8>,
1306+
Length: ULONG,
1307+
ByteOffset: Option<&LARGE_INTEGER>,
1308+
Key: Option<&ULONG>,
1309+
) -> NTSTATUS;
1310+
pub fn NtWriteFile(
1311+
FileHandle: BorrowedHandle<'_>,
1312+
Event: HANDLE,
1313+
ApcRoutine: Option<IO_APC_ROUTINE>,
1314+
ApcContext: *mut c_void,
1315+
IoStatusBlock: &mut IO_STATUS_BLOCK,
1316+
Buffer: *const u8,
1317+
Length: ULONG,
1318+
ByteOffset: Option<&LARGE_INTEGER>,
1319+
Key: Option<&ULONG>,
1320+
) -> NTSTATUS;
1321+
pub fn RtlNtStatusToDosError(Status: NTSTATUS) -> ULONG;
1322+
}
1323+
12851324
// Functions that aren't available on every version of Windows that we support,
12861325
// but we still use them and just provide some form of a fallback implementation.
12871326
compat_fn_with_fallback! {
@@ -1322,52 +1361,6 @@ compat_fn_optional! {
13221361
compat_fn_with_fallback! {
13231362
pub static NTDLL: &CStr = ansi_str!("ntdll");
13241363

1325-
pub fn NtCreateFile(
1326-
FileHandle: *mut HANDLE,
1327-
DesiredAccess: ACCESS_MASK,
1328-
ObjectAttributes: *const OBJECT_ATTRIBUTES,
1329-
IoStatusBlock: *mut IO_STATUS_BLOCK,
1330-
AllocationSize: *mut i64,
1331-
FileAttributes: ULONG,
1332-
ShareAccess: ULONG,
1333-
CreateDisposition: ULONG,
1334-
CreateOptions: ULONG,
1335-
EaBuffer: *mut c_void,
1336-
EaLength: ULONG
1337-
) -> NTSTATUS {
1338-
STATUS_NOT_IMPLEMENTED
1339-
}
1340-
pub fn NtReadFile(
1341-
FileHandle: BorrowedHandle<'_>,
1342-
Event: HANDLE,
1343-
ApcRoutine: Option<IO_APC_ROUTINE>,
1344-
ApcContext: *mut c_void,
1345-
IoStatusBlock: &mut IO_STATUS_BLOCK,
1346-
Buffer: *mut crate::mem::MaybeUninit<u8>,
1347-
Length: ULONG,
1348-
ByteOffset: Option<&LARGE_INTEGER>,
1349-
Key: Option<&ULONG>
1350-
) -> NTSTATUS {
1351-
STATUS_NOT_IMPLEMENTED
1352-
}
1353-
pub fn NtWriteFile(
1354-
FileHandle: BorrowedHandle<'_>,
1355-
Event: HANDLE,
1356-
ApcRoutine: Option<IO_APC_ROUTINE>,
1357-
ApcContext: *mut c_void,
1358-
IoStatusBlock: &mut IO_STATUS_BLOCK,
1359-
Buffer: *const u8,
1360-
Length: ULONG,
1361-
ByteOffset: Option<&LARGE_INTEGER>,
1362-
Key: Option<&ULONG>
1363-
) -> NTSTATUS {
1364-
STATUS_NOT_IMPLEMENTED
1365-
}
1366-
pub fn RtlNtStatusToDosError(
1367-
Status: NTSTATUS
1368-
) -> ULONG {
1369-
Status as ULONG
1370-
}
13711364
pub fn NtCreateKeyedEvent(
13721365
KeyedEventHandle: LPHANDLE,
13731366
DesiredAccess: ACCESS_MASK,

src/bootstrap/dist.rs

+4
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,8 @@ fn make_win_dist(
210210
rustc_dlls.push("libgcc_s_seh-1.dll");
211211
}
212212

213+
// Libraries necessary to link the windows-gnu toolchains.
214+
// System libraries will be preferred if they are available (see #67429).
213215
let target_libs = [
214216
//MinGW libs
215217
"libgcc.a",
@@ -223,6 +225,7 @@ fn make_win_dist(
223225
"libmoldname.a",
224226
"libpthread.a",
225227
//Windows import libs
228+
//This should contain only the set of libraries necessary to link the standard library.
226229
"libadvapi32.a",
227230
"libbcrypt.a",
228231
"libcomctl32.a",
@@ -236,6 +239,7 @@ fn make_win_dist(
236239
"libkernel32.a",
237240
"libmsimg32.a",
238241
"libmsvcrt.a",
242+
"libntdll.a",
239243
"libodbc32.a",
240244
"libole32.a",
241245
"liboleaut32.a",

src/tools/miri/src/shims/windows/dlsym.rs

-69
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use rustc_middle::mir;
2-
use rustc_target::abi::Size;
32
use rustc_target::spec::abi::Abi;
43

54
use log::trace;
@@ -11,7 +10,6 @@ use crate::*;
1110

1211
#[derive(Debug, Copy, Clone)]
1312
pub enum Dlsym {
14-
NtWriteFile,
1513
SetThreadDescription,
1614
WaitOnAddress,
1715
WakeByAddressSingle,
@@ -23,7 +21,6 @@ impl Dlsym {
2321
pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option<Dlsym>> {
2422
Ok(match name {
2523
"GetSystemTimePreciseAsFileTime" => None,
26-
"NtWriteFile" => Some(Dlsym::NtWriteFile),
2724
"SetThreadDescription" => Some(Dlsym::SetThreadDescription),
2825
"WaitOnAddress" => Some(Dlsym::WaitOnAddress),
2926
"WakeByAddressSingle" => Some(Dlsym::WakeByAddressSingle),
@@ -49,72 +46,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
4946
this.check_abi(abi, Abi::System { unwind: false })?;
5047

5148
match dlsym {
52-
Dlsym::NtWriteFile => {
53-
if !this.frame_in_std() {
54-
throw_unsup_format!(
55-
"`NtWriteFile` support is crude and just enough for stdout to work"
56-
);
57-
}
58-
59-
let [
60-
handle,
61-
_event,
62-
_apc_routine,
63-
_apc_context,
64-
io_status_block,
65-
buf,
66-
n,
67-
byte_offset,
68-
_key,
69-
] = check_arg_count(args)?;
70-
let handle = this.read_target_isize(handle)?;
71-
let buf = this.read_pointer(buf)?;
72-
let n = this.read_scalar(n)?.to_u32()?;
73-
let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer
74-
let io_status_block = this.deref_operand(io_status_block)?;
75-
76-
if byte_offset != 0 {
77-
throw_unsup_format!(
78-
"`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported"
79-
);
80-
}
81-
82-
let written = if handle == -11 || handle == -12 {
83-
// stdout/stderr
84-
use std::io::{self, Write};
85-
86-
let buf_cont =
87-
this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?;
88-
let res = if this.machine.mute_stdout_stderr {
89-
Ok(buf_cont.len())
90-
} else if handle == -11 {
91-
io::stdout().write(buf_cont)
92-
} else {
93-
io::stderr().write(buf_cont)
94-
};
95-
// We write at most `n` bytes, which is a `u32`, so we cannot have written more than that.
96-
res.ok().map(|n| u32::try_from(n).unwrap())
97-
} else {
98-
throw_unsup_format!(
99-
"on Windows, writing to anything except stdout/stderr is not supported"
100-
)
101-
};
102-
// We have to put the result into io_status_block.
103-
if let Some(n) = written {
104-
let io_status_information =
105-
this.mplace_field_named(&io_status_block, "Information")?;
106-
this.write_scalar(
107-
Scalar::from_target_usize(n.into(), this),
108-
&io_status_information.into(),
109-
)?;
110-
}
111-
// Return whether this was a success. >= 0 is success.
112-
// For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
113-
this.write_scalar(
114-
Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }),
115-
dest,
116-
)?;
117-
}
11849
Dlsym::SetThreadDescription => {
11950
let [handle, name] = check_arg_count(args)?;
12051

src/tools/miri/src/shims/windows/foreign_items.rs

+68
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
6969
this.write_scalar(result, dest)?;
7070
}
7171

72+
// File related shims
73+
"NtWriteFile" => {
74+
if !this.frame_in_std() {
75+
throw_unsup_format!(
76+
"`NtWriteFile` support is crude and just enough for stdout to work"
77+
);
78+
}
79+
80+
let [
81+
handle,
82+
_event,
83+
_apc_routine,
84+
_apc_context,
85+
io_status_block,
86+
buf,
87+
n,
88+
byte_offset,
89+
_key,
90+
] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?;
91+
let handle = this.read_target_isize(handle)?;
92+
let buf = this.read_pointer(buf)?;
93+
let n = this.read_scalar(n)?.to_u32()?;
94+
let byte_offset = this.read_target_usize(byte_offset)?; // is actually a pointer
95+
let io_status_block = this.deref_operand(io_status_block)?;
96+
97+
if byte_offset != 0 {
98+
throw_unsup_format!(
99+
"`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported"
100+
);
101+
}
102+
103+
let written = if handle == -11 || handle == -12 {
104+
// stdout/stderr
105+
use std::io::{self, Write};
106+
107+
let buf_cont =
108+
this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?;
109+
let res = if this.machine.mute_stdout_stderr {
110+
Ok(buf_cont.len())
111+
} else if handle == -11 {
112+
io::stdout().write(buf_cont)
113+
} else {
114+
io::stderr().write(buf_cont)
115+
};
116+
// We write at most `n` bytes, which is a `u32`, so we cannot have written more than that.
117+
res.ok().map(|n| u32::try_from(n).unwrap())
118+
} else {
119+
throw_unsup_format!(
120+
"on Windows, writing to anything except stdout/stderr is not supported"
121+
)
122+
};
123+
// We have to put the result into io_status_block.
124+
if let Some(n) = written {
125+
let io_status_information =
126+
this.mplace_field_named(&io_status_block, "Information")?;
127+
this.write_scalar(
128+
Scalar::from_target_usize(n.into(), this),
129+
&io_status_information.into(),
130+
)?;
131+
}
132+
// Return whether this was a success. >= 0 is success.
133+
// For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR.
134+
this.write_scalar(
135+
Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }),
136+
dest,
137+
)?;
138+
}
139+
72140
// Allocation
73141
"HeapAlloc" => {
74142
let [handle, flags, size] =

tests/run-make-fulldeps/tools.mk

+2-2
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ endif
112112
# Extra flags needed to compile a working executable with the standard library
113113
ifdef IS_WINDOWS
114114
ifdef IS_MSVC
115-
EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib
115+
EXTRACFLAGS := ws2_32.lib userenv.lib advapi32.lib bcrypt.lib ntdll.lib
116116
else
117-
EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt
117+
EXTRACFLAGS := -lws2_32 -luserenv -lbcrypt -lntdll
118118
EXTRACXXFLAGS := -lstdc++
119119
# So this is a bit hacky: we can't use the DLL version of libstdc++ because
120120
# it pulls in the DLL version of libgcc, which means that we end up with 2

0 commit comments

Comments
 (0)