Rollup merge of #84758 - ChrisDenton:dllimport, r=dtolnay

MSVC: Avoid using jmp stubs for dll function imports

Windows import libraries contain two symbols for every function: `__imp_FunctionName` and `FunctionName` (where `FunctionName` is the name of the function to be imported).

`__imp_FunctionName` contains the address of the imported function. This will be filled in by the Windows executable loader at runtime. `FunctionName` contains a jmp stub that simply jumps to the address given by `__imp_FunctionName`. E.g. it's a function that solely contains a single jmp instruction:

```asm
jmp __imp_FunctionName
```

When using an external DLL function in Rust, by default the linker will link to FunctionName, causing a bit of indirection at runtime. In Microsoft's C++ it's possible to instead tell it to insert calls to the address in `__imp_FunctionName` by using the  `__declspec(dllimport)` attribute. In Rust it's possible to get effectively the same behaviour using the `#[link]` attribute on `extern` blocks.

----

The second commit also merges multiple `extern` blocks into one block. This is because otherwise Rust will currently create duplicate linker arguments for each block. In this case having duplicates shouldn't matter much other than the noise when displaying the linker command.
This commit is contained in:
Dylan DPC 2021-05-23 03:23:34 +02:00 committed by GitHub
commit d5fa533ab0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 170 additions and 168 deletions

View file

@ -631,7 +631,7 @@ pub struct timeval {
pub tv_usec: c_long, pub tv_usec: c_long,
} }
// Functions forbidden when targeting UWP // Desktop specific functions & types
cfg_if::cfg_if! { cfg_if::cfg_if! {
if #[cfg(not(target_vendor = "uwp"))] { if #[cfg(not(target_vendor = "uwp"))] {
pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
@ -645,7 +645,7 @@ if #[cfg(not(target_vendor = "uwp"))] {
pub ExceptionRecord: *mut EXCEPTION_RECORD, pub ExceptionRecord: *mut EXCEPTION_RECORD,
pub ExceptionAddress: LPVOID, pub ExceptionAddress: LPVOID,
pub NumberParameters: DWORD, pub NumberParameters: DWORD,
pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS] pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS],
} }
pub enum CONTEXT {} pub enum CONTEXT {}
@ -656,8 +656,8 @@ if #[cfg(not(target_vendor = "uwp"))] {
pub ContextRecord: *mut CONTEXT, pub ContextRecord: *mut CONTEXT,
} }
pub type PVECTORED_EXCEPTION_HANDLER = extern "system" pub type PVECTORED_EXCEPTION_HANDLER =
fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG; extern "system" fn(ExceptionInfo: *mut EXCEPTION_POINTERS) -> LONG;
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
@ -691,44 +691,66 @@ if #[cfg(not(target_vendor = "uwp"))] {
pub const TOKEN_READ: DWORD = 0x20008; pub const TOKEN_READ: DWORD = 0x20008;
#[link(name = "advapi32")]
extern "system" { extern "system" {
// Forbidden when targeting UWP
#[link_name = "SystemFunction036"] #[link_name = "SystemFunction036"]
pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN; pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN;
pub fn ReadConsoleW(hConsoleInput: HANDLE,
lpBuffer: LPVOID,
nNumberOfCharsToRead: DWORD,
lpNumberOfCharsRead: LPDWORD,
pInputControl: PCONSOLE_READCONSOLE_CONTROL) -> BOOL;
pub fn WriteConsoleW(hConsoleOutput: HANDLE,
lpBuffer: LPCVOID,
nNumberOfCharsToWrite: DWORD,
lpNumberOfCharsWritten: LPDWORD,
lpReserved: LPVOID) -> BOOL;
pub fn GetConsoleMode(hConsoleHandle: HANDLE,
lpMode: LPDWORD) -> BOOL;
// Allowed but unused by UWP // Allowed but unused by UWP
pub fn OpenProcessToken(ProcessHandle: HANDLE, pub fn OpenProcessToken(
DesiredAccess: DWORD, ProcessHandle: HANDLE,
TokenHandle: *mut HANDLE) -> BOOL; DesiredAccess: DWORD,
pub fn GetUserProfileDirectoryW(hToken: HANDLE, TokenHandle: *mut HANDLE,
lpProfileDir: LPWSTR, ) -> BOOL;
lpcchSize: *mut DWORD) -> BOOL; }
pub fn GetFileInformationByHandle(hFile: HANDLE,
lpFileInformation: LPBY_HANDLE_FILE_INFORMATION) #[link(name = "userenv")]
-> BOOL; extern "system" {
pub fn SetHandleInformation(hObject: HANDLE, // Allowed but unused by UWP
dwMask: DWORD, pub fn GetUserProfileDirectoryW(
dwFlags: DWORD) -> BOOL; hToken: HANDLE,
pub fn AddVectoredExceptionHandler(FirstHandler: ULONG, lpProfileDir: LPWSTR,
VectoredHandler: PVECTORED_EXCEPTION_HANDLER) lpcchSize: *mut DWORD,
-> LPVOID; ) -> BOOL;
pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR, }
lpTargetFileName: LPCWSTR,
lpSecurityAttributes: LPSECURITY_ATTRIBUTES) #[link(name = "kernel32")]
-> BOOL; extern "system" {
// Functions forbidden when targeting UWP
pub fn ReadConsoleW(
hConsoleInput: HANDLE,
lpBuffer: LPVOID,
nNumberOfCharsToRead: DWORD,
lpNumberOfCharsRead: LPDWORD,
pInputControl: PCONSOLE_READCONSOLE_CONTROL,
) -> BOOL;
pub fn WriteConsoleW(
hConsoleOutput: HANDLE,
lpBuffer: LPCVOID,
nNumberOfCharsToWrite: DWORD,
lpNumberOfCharsWritten: LPDWORD,
lpReserved: LPVOID,
) -> BOOL;
pub fn GetConsoleMode(hConsoleHandle: HANDLE, lpMode: LPDWORD) -> BOOL;
// Allowed but unused by UWP
pub fn GetFileInformationByHandle(
hFile: HANDLE,
lpFileInformation: LPBY_HANDLE_FILE_INFORMATION,
) -> BOOL;
pub fn SetHandleInformation(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD) -> BOOL;
pub fn AddVectoredExceptionHandler(
FirstHandler: ULONG,
VectoredHandler: PVECTORED_EXCEPTION_HANDLER,
) -> LPVOID;
pub fn CreateHardLinkW(
lpSymlinkFileName: LPCWSTR,
lpTargetFileName: LPCWSTR,
lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
) -> BOOL;
pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL;
} }
} }
} }
@ -747,55 +769,32 @@ if #[cfg(target_vendor = "uwp")] {
pub Directory: BOOLEAN, pub Directory: BOOLEAN,
} }
#[link(name = "bcrypt")]
extern "system" { extern "system" {
pub fn GetFileInformationByHandleEx(hFile: HANDLE, pub fn BCryptGenRandom(
fileInfoClass: FILE_INFO_BY_HANDLE_CLASS, hAlgorithm: LPVOID,
lpFileInformation: LPVOID, pBuffer: *mut u8,
dwBufferSize: DWORD) -> BOOL; cbBuffer: ULONG,
pub fn BCryptGenRandom(hAlgorithm: LPVOID, pBuffer: *mut u8, dwFlags: ULONG,
cbBuffer: ULONG, dwFlags: ULONG) -> LONG; ) -> LONG;
}
#[link(name = "kernel32")]
extern "system" {
pub fn GetFileInformationByHandleEx(
hFile: HANDLE,
fileInfoClass: FILE_INFO_BY_HANDLE_CLASS,
lpFileInformation: LPVOID,
dwBufferSize: DWORD,
) -> BOOL;
} }
} }
} }
// Shared between Desktop & UWP // Shared between Desktop & UWP
#[link(name = "kernel32")]
extern "system" { extern "system" {
pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int;
pub fn WSACleanup() -> c_int;
pub fn WSAGetLastError() -> c_int;
pub fn WSADuplicateSocketW(
s: SOCKET,
dwProcessId: DWORD,
lpProtocolInfo: LPWSAPROTOCOL_INFO,
) -> c_int;
pub fn WSASend(
s: SOCKET,
lpBuffers: LPWSABUF,
dwBufferCount: DWORD,
lpNumberOfBytesSent: LPDWORD,
dwFlags: DWORD,
lpOverlapped: LPWSAOVERLAPPED,
lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
) -> c_int;
pub fn WSARecv(
s: SOCKET,
lpBuffers: LPWSABUF,
dwBufferCount: DWORD,
lpNumberOfBytesRecvd: LPDWORD,
lpFlags: LPDWORD,
lpOverlapped: LPWSAOVERLAPPED,
lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
) -> c_int;
pub fn GetCurrentProcessId() -> DWORD; pub fn GetCurrentProcessId() -> DWORD;
pub fn WSASocketW(
af: c_int,
kind: c_int,
protocol: c_int,
lpProtocolInfo: LPWSAPROTOCOL_INFO,
g: GROUP,
dwFlags: DWORD,
) -> SOCKET;
pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int;
pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION); pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION); pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION);
pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOL; pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOL;
@ -882,28 +881,6 @@ extern "system" {
pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL; pub fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD; pub fn GetCurrentDirectoryW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD;
pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL; pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
pub fn closesocket(socket: SOCKET) -> c_int;
pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int;
pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int;
pub fn recvfrom(
socket: SOCKET,
buf: *mut c_void,
len: c_int,
flags: c_int,
addr: *mut SOCKADDR,
addrlen: *mut c_int,
) -> c_int;
pub fn sendto(
socket: SOCKET,
buf: *const c_void,
len: c_int,
flags: c_int,
addr: *const SOCKADDR,
addrlen: c_int,
) -> c_int;
pub fn shutdown(socket: SOCKET, how: c_int) -> c_int;
pub fn accept(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET;
pub fn DuplicateHandle( pub fn DuplicateHandle(
hSourceProcessHandle: HANDLE, hSourceProcessHandle: HANDLE,
hSourceHandle: HANDLE, hSourceHandle: HANDLE,
@ -950,32 +927,6 @@ extern "system" {
pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE; pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW) -> HANDLE;
pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL; pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL;
pub fn FindClose(findFile: HANDLE) -> BOOL; pub fn FindClose(findFile: HANDLE) -> BOOL;
pub fn getsockopt(
s: SOCKET,
level: c_int,
optname: c_int,
optval: *mut c_char,
optlen: *mut c_int,
) -> c_int;
pub fn setsockopt(
s: SOCKET,
level: c_int,
optname: c_int,
optval: *const c_void,
optlen: c_int,
) -> c_int;
pub fn getsockname(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int;
pub fn getpeername(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int;
pub fn bind(socket: SOCKET, address: *const SOCKADDR, address_len: socklen_t) -> c_int;
pub fn listen(socket: SOCKET, backlog: c_int) -> c_int;
pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int;
pub fn getaddrinfo(
node: *const c_char,
service: *const c_char,
hints: *const ADDRINFOA,
res: *mut *mut ADDRINFOA,
) -> c_int;
pub fn freeaddrinfo(res: *mut ADDRINFOA);
pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void; pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void;
pub fn GetModuleHandleA(lpModuleName: LPCSTR) -> HMODULE; pub fn GetModuleHandleA(lpModuleName: LPCSTR) -> HMODULE;
@ -1012,47 +963,23 @@ extern "system" {
lpNumberOfBytesTransferred: LPDWORD, lpNumberOfBytesTransferred: LPDWORD,
bWait: BOOL, bWait: BOOL,
) -> BOOL; ) -> BOOL;
pub fn select(
nfds: c_int,
readfds: *mut fd_set,
writefds: *mut fd_set,
exceptfds: *mut fd_set,
timeout: *const timeval,
) -> c_int;
// >= Vista / Server 2008
// https://docs.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-createsymboliclinkw
pub fn CreateSymbolicLinkW( pub fn CreateSymbolicLinkW(
lpSymlinkFileName: LPCWSTR, lpSymlinkFileName: LPCWSTR,
lpTargetFileName: LPCWSTR, lpTargetFileName: LPCWSTR,
dwFlags: DWORD, dwFlags: DWORD,
) -> BOOLEAN; ) -> BOOLEAN;
// >= Vista / Server 2008
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfinalpathnamebyhandlew
pub fn GetFinalPathNameByHandleW( pub fn GetFinalPathNameByHandleW(
hFile: HANDLE, hFile: HANDLE,
lpszFilePath: LPCWSTR, lpszFilePath: LPCWSTR,
cchFilePath: DWORD, cchFilePath: DWORD,
dwFlags: DWORD, dwFlags: DWORD,
) -> DWORD; ) -> DWORD;
// >= Vista / Server 2003
// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-setthreadstackguarantee
#[cfg(not(target_vendor = "uwp"))]
pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL;
// >= Vista / Server 2008
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-setfileinformationbyhandle
pub fn SetFileInformationByHandle( pub fn SetFileInformationByHandle(
hFile: HANDLE, hFile: HANDLE,
FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
lpFileInformation: LPVOID, lpFileInformation: LPVOID,
dwBufferSize: DWORD, dwBufferSize: DWORD,
) -> BOOL; ) -> BOOL;
// >= Vista / Server 2008
// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-sleepconditionvariablesrw
pub fn SleepConditionVariableSRW( pub fn SleepConditionVariableSRW(
ConditionVariable: PCONDITION_VARIABLE, ConditionVariable: PCONDITION_VARIABLE,
SRWLock: PSRWLOCK, SRWLock: PSRWLOCK,
@ -1060,13 +987,9 @@ extern "system" {
Flags: ULONG, Flags: ULONG,
) -> BOOL; ) -> BOOL;
// >= Vista / Server 2008
// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-wakeconditionvariable
pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE); pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE);
pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE); pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE);
// >= Vista / Server 2008
// https://docs.microsoft.com/en-us/windows/win32/api/synchapi/nf-synchapi-acquiresrwlockexclusive
pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK); pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK);
pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK); pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK);
pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK); pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK);
@ -1075,6 +998,99 @@ extern "system" {
pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN; pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN;
} }
#[link(name = "ws2_32")]
extern "system" {
pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int;
pub fn WSACleanup() -> c_int;
pub fn WSAGetLastError() -> c_int;
pub fn WSADuplicateSocketW(
s: SOCKET,
dwProcessId: DWORD,
lpProtocolInfo: LPWSAPROTOCOL_INFO,
) -> c_int;
pub fn WSASend(
s: SOCKET,
lpBuffers: LPWSABUF,
dwBufferCount: DWORD,
lpNumberOfBytesSent: LPDWORD,
dwFlags: DWORD,
lpOverlapped: LPWSAOVERLAPPED,
lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
) -> c_int;
pub fn WSARecv(
s: SOCKET,
lpBuffers: LPWSABUF,
dwBufferCount: DWORD,
lpNumberOfBytesRecvd: LPDWORD,
lpFlags: LPDWORD,
lpOverlapped: LPWSAOVERLAPPED,
lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE,
) -> c_int;
pub fn WSASocketW(
af: c_int,
kind: c_int,
protocol: c_int,
lpProtocolInfo: LPWSAPROTOCOL_INFO,
g: GROUP,
dwFlags: DWORD,
) -> SOCKET;
pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int;
pub fn closesocket(socket: SOCKET) -> c_int;
pub fn recv(socket: SOCKET, buf: *mut c_void, len: c_int, flags: c_int) -> c_int;
pub fn send(socket: SOCKET, buf: *const c_void, len: c_int, flags: c_int) -> c_int;
pub fn recvfrom(
socket: SOCKET,
buf: *mut c_void,
len: c_int,
flags: c_int,
addr: *mut SOCKADDR,
addrlen: *mut c_int,
) -> c_int;
pub fn sendto(
socket: SOCKET,
buf: *const c_void,
len: c_int,
flags: c_int,
addr: *const SOCKADDR,
addrlen: c_int,
) -> c_int;
pub fn shutdown(socket: SOCKET, how: c_int) -> c_int;
pub fn accept(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> SOCKET;
pub fn getsockopt(
s: SOCKET,
level: c_int,
optname: c_int,
optval: *mut c_char,
optlen: *mut c_int,
) -> c_int;
pub fn setsockopt(
s: SOCKET,
level: c_int,
optname: c_int,
optval: *const c_void,
optlen: c_int,
) -> c_int;
pub fn getsockname(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int;
pub fn getpeername(socket: SOCKET, address: *mut SOCKADDR, address_len: *mut c_int) -> c_int;
pub fn bind(socket: SOCKET, address: *const SOCKADDR, address_len: socklen_t) -> c_int;
pub fn listen(socket: SOCKET, backlog: c_int) -> c_int;
pub fn connect(socket: SOCKET, address: *const SOCKADDR, len: c_int) -> c_int;
pub fn getaddrinfo(
node: *const c_char,
service: *const c_char,
hints: *const ADDRINFOA,
res: *mut *mut ADDRINFOA,
) -> c_int;
pub fn freeaddrinfo(res: *mut ADDRINFOA);
pub fn select(
nfds: c_int,
readfds: *mut fd_set,
writefds: *mut fd_set,
exceptfds: *mut fd_set,
timeout: *const timeval,
) -> c_int;
}
// 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! { compat_fn! {

View file

@ -281,17 +281,3 @@ pub fn abort_internal() -> ! {
} }
crate::intrinsics::abort(); crate::intrinsics::abort();
} }
cfg_if::cfg_if! {
if #[cfg(target_vendor = "uwp")] {
#[link(name = "ws2_32")]
// For BCryptGenRandom
#[link(name = "bcrypt")]
extern "C" {}
} else {
#[link(name = "advapi32")]
#[link(name = "ws2_32")]
#[link(name = "userenv")]
extern "C" {}
}
}