mirror of
https://github.com/Noratrieb/portability.git
synced 2026-01-14 15:55:04 +01:00
fixes
This commit is contained in:
parent
091e833acf
commit
dc6ef2108d
17 changed files with 221 additions and 39 deletions
1
.envrc
Normal file
1
.envrc
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
use nix
|
||||||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -2,5 +2,7 @@
|
||||||
|
|
||||||
*.exe
|
*.exe
|
||||||
*.pdb
|
*.pdb
|
||||||
|
*.dll
|
||||||
|
*.dll.lib
|
||||||
|
|
||||||
!/test/*.exe
|
!/test/*.exe
|
||||||
|
|
|
||||||
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -52,6 +52,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
"libc",
|
||||||
"memmap2",
|
"memmap2",
|
||||||
"windows",
|
"windows",
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -10,3 +10,6 @@ memmap2 = "0.9.5"
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
windows = { version = "0.59.0", features = ["Win32_System_Memory", "Win32_Security", "Win32_System_SystemInformation"] }
|
windows = { version = "0.59.0", features = ["Win32_System_Memory", "Win32_Security", "Win32_System_SystemInformation"] }
|
||||||
|
|
||||||
|
[target.'cfg(unix)'.dependencies]
|
||||||
|
libc = "0.2.169"
|
||||||
|
|
|
||||||
3
shell.nix
Normal file
3
shell.nix
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
{ pkgs ? import <nixpkgs> { } }: pkgs.mkShell {
|
||||||
|
nativeBuildInputs = with pkgs; [ lld_18 rustup ];
|
||||||
|
}
|
||||||
74
src/lib.rs
74
src/lib.rs
|
|
@ -1,7 +1,11 @@
|
||||||
mod emulated;
|
mod emulated;
|
||||||
mod sys;
|
mod sys;
|
||||||
|
|
||||||
use std::{ffi::CStr, fmt::Debug, path::PathBuf};
|
use std::{
|
||||||
|
ffi::CStr,
|
||||||
|
fmt::Debug,
|
||||||
|
path::{Path, PathBuf},
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
|
#[derive(Clone, Copy, Debug, bytemuck::Zeroable, bytemuck::Pod)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
@ -197,7 +201,7 @@ struct ImportDirectoryTableEntry {
|
||||||
const IMAGE_FILE_MACHINE_AMD64: u16 = 0x8664;
|
const IMAGE_FILE_MACHINE_AMD64: u16 = 0x8664;
|
||||||
const IMAGE_FILE_MACHINE_ARM64: u16 = 0xaa64;
|
const IMAGE_FILE_MACHINE_ARM64: u16 = 0xaa64;
|
||||||
|
|
||||||
pub fn execute(pe: &[u8]) {
|
pub fn execute(pe: &[u8], executable_path: &Path) {
|
||||||
let (header, after_header) = parse_header(pe);
|
let (header, after_header) = parse_header(pe);
|
||||||
|
|
||||||
match (std::env::consts::ARCH, header.machine) {
|
match (std::env::consts::ARCH, header.machine) {
|
||||||
|
|
@ -258,14 +262,12 @@ pub fn execute(pe: &[u8]) {
|
||||||
|
|
||||||
assert_eq!(base & (allocation_granularity - 1), 0);
|
assert_eq!(base & (allocation_granularity - 1), 0);
|
||||||
|
|
||||||
let total_size = section_table.last().unwrap().virtual_address as usize;
|
let last_section = section_table.last().unwrap();
|
||||||
|
let total_size = (last_section.virtual_address as usize + last_section.virtual_size as usize)
|
||||||
|
.next_multiple_of(allocation_granularity);
|
||||||
|
|
||||||
let a = unsafe {
|
let a = unsafe {
|
||||||
crate::sys::anon_write_map(
|
crate::sys::anon_write_map(total_size, std::ptr::with_exposed_provenance(base)).unwrap()
|
||||||
total_size.next_multiple_of(allocation_granularity),
|
|
||||||
std::ptr::with_exposed_provenance(base),
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// allocate the sections.
|
// allocate the sections.
|
||||||
|
|
@ -273,11 +275,10 @@ pub fn execute(pe: &[u8]) {
|
||||||
if section.virtual_size > section.size_of_raw_data {
|
if section.virtual_size > section.size_of_raw_data {
|
||||||
todo!("zero padding")
|
todo!("zero padding")
|
||||||
}
|
}
|
||||||
|
eprintln!("mapping section {:?}", section.name);
|
||||||
|
|
||||||
let section_a = &mut a[section.virtual_address as usize..];
|
let section_a = &mut a[section.virtual_address as usize..];
|
||||||
|
|
||||||
dbg!(section);
|
|
||||||
|
|
||||||
section_a[..section.size_of_raw_data as usize].copy_from_slice(
|
section_a[..section.size_of_raw_data as usize].copy_from_slice(
|
||||||
&pe[section.pointer_to_raw_data as usize..][..section.size_of_raw_data as usize],
|
&pe[section.pointer_to_raw_data as usize..][..section.size_of_raw_data as usize],
|
||||||
);
|
);
|
||||||
|
|
@ -289,19 +290,21 @@ pub fn execute(pe: &[u8]) {
|
||||||
)
|
)
|
||||||
.to_vec();
|
.to_vec();
|
||||||
|
|
||||||
|
eprintln!("checking imports");
|
||||||
for import_directory in import_directory_table {
|
for import_directory in import_directory_table {
|
||||||
dbg!(import_directory);
|
dbg!(import_directory);
|
||||||
|
|
||||||
let dll_name = CStr::from_bytes_until_nul(&a[import_directory.name_rva as usize..])
|
let dll_name = CStr::from_bytes_until_nul(&a[import_directory.name_rva as usize..])
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
let dll_name = dll_name.to_str().unwrap();
|
||||||
if dll_name.is_empty() {
|
if dll_name.is_empty() {
|
||||||
// Trailing null import directory.
|
// Trailing null import directory.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
dbg!(&dll_name);
|
eprintln!("loading dll {dll_name}");
|
||||||
|
|
||||||
let dll = find_dll(&dll_name);
|
let dll = find_dll(&dll_name, executable_path);
|
||||||
match dll {
|
match dll {
|
||||||
Some(DllLocation::Emulated) => eprintln!(" emulating {dll_name:?}"),
|
Some(DllLocation::Emulated) => eprintln!(" emulating {dll_name:?}"),
|
||||||
Some(DllLocation::Found(path)) => todo!("unsupported, loading dll at {path:?}"),
|
Some(DllLocation::Found(path)) => todo!("unsupported, loading dll at {path:?}"),
|
||||||
|
|
@ -329,11 +332,10 @@ pub fn execute(pe: &[u8]) {
|
||||||
let func_name =
|
let func_name =
|
||||||
CStr::from_bytes_until_nul(&a[hint_name_table_rva as usize + 2..]).unwrap();
|
CStr::from_bytes_until_nul(&a[hint_name_table_rva as usize + 2..]).unwrap();
|
||||||
eprintln!(" import by name: hint={hint} name={func_name:?}");
|
eprintln!(" import by name: hint={hint} name={func_name:?}");
|
||||||
let resolved_va =
|
let resolved_va = emulated::emulate(dll_name, func_name.to_str().unwrap())
|
||||||
emulated::emulate(dll_name.to_str().unwrap(), func_name.to_str().unwrap())
|
.unwrap_or_else(|| {
|
||||||
.unwrap_or_else(|| {
|
panic!("could not find function {func_name:?} in dll {dll_name:?}")
|
||||||
panic!("could not find function {func_name:?} in dll {dll_name:?}")
|
});
|
||||||
});
|
|
||||||
|
|
||||||
assert_eq!(size_of::<usize>(), size_of::<u64>());
|
assert_eq!(size_of::<usize>(), size_of::<u64>());
|
||||||
a[import_directory.import_address_table_rva as usize..][i * size_of::<u64>()..]
|
a[import_directory.import_address_table_rva as usize..][i * size_of::<u64>()..]
|
||||||
|
|
@ -343,6 +345,7 @@ pub fn execute(pe: &[u8]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eprintln!("applying section protections");
|
||||||
for section in section_table {
|
for section in section_table {
|
||||||
let mode = if section
|
let mode = if section
|
||||||
.characteristics
|
.characteristics
|
||||||
|
|
@ -368,13 +371,13 @@ pub fn execute(pe: &[u8]) {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
eprintln!("YOLO");
|
let entrypoint =
|
||||||
|
optional_header.image_base as usize + optional_header.address_of_entry_point as usize;
|
||||||
|
eprintln!("YOLO to {:#x}", entrypoint);
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let entrypoint = std::mem::transmute::<usize, unsafe fn() -> !>(
|
let result = sys::call_entrypoint_via_stdcall(entrypoint);
|
||||||
optional_header.address_of_entry_point as usize,
|
eprintln!("result: {result}");
|
||||||
);
|
|
||||||
entrypoint();
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -406,18 +409,39 @@ enum DllLocation {
|
||||||
Found(PathBuf),
|
Found(PathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_dll(name: &CStr) -> Option<DllLocation> {
|
fn find_dll(name: &str, executable_path: &Path) -> Option<DllLocation> {
|
||||||
// https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order
|
// https://learn.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-search-order
|
||||||
let name = name.to_str().unwrap();
|
|
||||||
if name.starts_with("api-") && emulated::supports_dll(name) {
|
if name.starts_with("api-") && emulated::supports_dll(name) {
|
||||||
// This is an API set, essentially a virtual alias
|
// This is an API set, essentially a virtual alias
|
||||||
// https://learn.microsoft.com/en-us/windows/win32/apiindex/windows-apisets
|
// https://learn.microsoft.com/en-us/windows/win32/apiindex/windows-apisets
|
||||||
return Some(DllLocation::Emulated);
|
return Some(DllLocation::Emulated);
|
||||||
}
|
}
|
||||||
|
|
||||||
if emulated::supports_dll(name) {
|
if emulated::supports_dll(name) {
|
||||||
return Some(DllLocation::Emulated);
|
return Some(DllLocation::Emulated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let name_lowercase = name.to_lowercase();
|
||||||
|
|
||||||
|
let probe_path = |path: &Path| -> Option<PathBuf> {
|
||||||
|
std::fs::read_dir(path)
|
||||||
|
.ok()?
|
||||||
|
.find(|entry| {
|
||||||
|
entry
|
||||||
|
.as_ref()
|
||||||
|
.map(|entry| {
|
||||||
|
entry
|
||||||
|
.file_name()
|
||||||
|
.to_str()
|
||||||
|
.is_some_and(|name| name.to_lowercase() == name_lowercase)
|
||||||
|
})
|
||||||
|
.unwrap_or(false)
|
||||||
|
})
|
||||||
|
.map(|entry| entry.unwrap().path())
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(path) = probe_path(executable_path.parent().unwrap()) {
|
||||||
|
return Some(DllLocation::Found(path));
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
src/main.rs
14
src/main.rs
|
|
@ -1,5 +1,6 @@
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::os::windows::fs::OpenOptionsExt;
|
use std::os::windows::fs::OpenOptionsExt;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut opts = std::fs::OpenOptions::new();
|
let mut opts = std::fs::OpenOptions::new();
|
||||||
|
|
@ -10,14 +11,11 @@ fn main() {
|
||||||
windows::Win32::Foundation::GENERIC_EXECUTE.0 | windows::Win32::Foundation::GENERIC_READ.0,
|
windows::Win32::Foundation::GENERIC_EXECUTE.0 | windows::Win32::Foundation::GENERIC_READ.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
let file = opts
|
let path = std::env::args()
|
||||||
.open(
|
.nth(1)
|
||||||
std::env::args()
|
.unwrap_or_else(|| "test/example_exe.exe".into());
|
||||||
.nth(1)
|
let file = opts.open(&path).unwrap();
|
||||||
.unwrap_or_else(|| "test/example_exe.exe".into()),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let map = unsafe { memmap2::Mmap::map(&file).unwrap() };
|
let map = unsafe { memmap2::Mmap::map(&file).unwrap() };
|
||||||
|
|
||||||
portability::execute(&map);
|
portability::execute(&map, Path::new(&path));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
79
src/sys.rs
79
src/sys.rs
|
|
@ -14,7 +14,8 @@ mod imp {
|
||||||
Foundation::INVALID_HANDLE_VALUE,
|
Foundation::INVALID_HANDLE_VALUE,
|
||||||
System::{
|
System::{
|
||||||
Memory::{
|
Memory::{
|
||||||
FILE_MAP_EXECUTE, FILE_MAP_WRITE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE, PAGE_PROTECTION_FLAGS, PAGE_READONLY, PAGE_READWRITE
|
FILE_MAP_EXECUTE, FILE_MAP_WRITE, PAGE_EXECUTE_READ, PAGE_EXECUTE_READWRITE,
|
||||||
|
PAGE_PROTECTION_FLAGS, PAGE_READONLY, PAGE_READWRITE,
|
||||||
},
|
},
|
||||||
SystemInformation::SYSTEM_INFO,
|
SystemInformation::SYSTEM_INFO,
|
||||||
},
|
},
|
||||||
|
|
@ -51,8 +52,6 @@ mod imp {
|
||||||
None,
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
eprintln!("created {address:p} {size:x}");
|
|
||||||
|
|
||||||
debug_assert_eq!(address.addr() & (allocation_granularity() - 1), 0);
|
debug_assert_eq!(address.addr() & (allocation_granularity() - 1), 0);
|
||||||
debug_assert_eq!(size & (allocation_granularity() - 1), 0);
|
debug_assert_eq!(size & (allocation_granularity() - 1), 0);
|
||||||
|
|
||||||
|
|
@ -78,7 +77,7 @@ mod imp {
|
||||||
|
|
||||||
pub(crate) fn protect(address: *const (), size: usize, mode: Mode) -> io::Result<()> {
|
pub(crate) fn protect(address: *const (), size: usize, mode: Mode) -> io::Result<()> {
|
||||||
debug_assert_eq!(address.addr() & (page_size() - 1), 0);
|
debug_assert_eq!(address.addr() & (page_size() - 1), 0);
|
||||||
let mut old= PAGE_PROTECTION_FLAGS::default();
|
let mut old = PAGE_PROTECTION_FLAGS::default();
|
||||||
unsafe {
|
unsafe {
|
||||||
windows::Win32::System::Memory::VirtualProtect(
|
windows::Win32::System::Memory::VirtualProtect(
|
||||||
address.cast::<c_void>(),
|
address.cast::<c_void>(),
|
||||||
|
|
@ -93,11 +92,81 @@ mod imp {
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn call_entrypoint_via_stdcall(fnptr: *const ()) -> u32 {
|
||||||
|
let fnptr = unsafe { std::mem::transmute::<_, unsafe extern "stdcall" fn() -> u32>(fnptr) };
|
||||||
|
unsafe { fnptr() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
mod imp {
|
mod imp {
|
||||||
compile_error!("no unix yet lol skill issue");
|
use std::io;
|
||||||
|
|
||||||
|
use super::Mode;
|
||||||
|
|
||||||
|
pub(crate) fn allocation_granularity() -> usize {
|
||||||
|
unsafe { libc::sysconf(libc::_SC_PAGESIZE) as usize }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn page_size() -> usize {
|
||||||
|
allocation_granularity()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn anon_write_map<'a>(
|
||||||
|
size: usize,
|
||||||
|
address: *const (),
|
||||||
|
) -> io::Result<&'a mut [u8]> {
|
||||||
|
debug_assert_eq!(address.addr() & (allocation_granularity() - 1), 0);
|
||||||
|
debug_assert_eq!(size & (allocation_granularity() - 1), 0);
|
||||||
|
|
||||||
|
let ret = libc::mmap(
|
||||||
|
address as _,
|
||||||
|
size,
|
||||||
|
libc::PROT_READ | libc::PROT_WRITE,
|
||||||
|
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS,
|
||||||
|
-1,
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
if ret == libc::MAP_FAILED {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
} else if ret.addr() != address.addr() {
|
||||||
|
Err(io::Error::new(
|
||||||
|
io::ErrorKind::AlreadyExists,
|
||||||
|
"address already taken".to_owned(),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(std::slice::from_raw_parts_mut(
|
||||||
|
address.cast_mut().cast(),
|
||||||
|
size,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn protect(address: *const (), size: usize, mode: super::Mode) -> io::Result<()> {
|
||||||
|
debug_assert_eq!(address.addr() & (page_size() - 1), 0);
|
||||||
|
let prot = match mode {
|
||||||
|
Mode::Read => libc::PROT_READ,
|
||||||
|
Mode::Write => libc::PROT_READ | libc::PROT_WRITE,
|
||||||
|
Mode::Execute => libc::PROT_READ | libc::PROT_EXEC,
|
||||||
|
};
|
||||||
|
let ret = unsafe { libc::mprotect(address as _, size, prot) };
|
||||||
|
if ret == 0 {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) unsafe fn call_entrypoint_via_stdcall(fnptr: usize) -> u32 {
|
||||||
|
// todo this might be correct or not idk??? is it close enough in this case maybe?? use asm probably.
|
||||||
|
let fnptr = unsafe {
|
||||||
|
std::mem::transmute::<*const (), unsafe extern "C" fn() -> u32>(
|
||||||
|
std::ptr::with_exposed_provenance(fnptr),
|
||||||
|
)
|
||||||
|
};
|
||||||
|
unsafe { fnptr() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) use imp::*;
|
pub(crate) use imp::*;
|
||||||
|
|
|
||||||
3
test/build.sh
Executable file
3
test/build.sh
Executable file
|
|
@ -0,0 +1,3 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
rustc example_exe.rs --target x86_64-pc-windows-msvc -Cpanic=abort -Clinker=lld-link -Clink-arg=/entry:my_main -Clink-arg=/NODEFAULTLIB -Cdebuginfo=0
|
||||||
BIN
test/example_exe.exe
Normal file → Executable file
BIN
test/example_exe.exe
Normal file → Executable file
Binary file not shown.
|
|
@ -1,5 +1,6 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
#![windows_subsystem = "console"]
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn handle_panic(_: &core::panic::PanicInfo<'_>) -> ! {
|
fn handle_panic(_: &core::panic::PanicInfo<'_>) -> ! {
|
||||||
|
|
@ -7,4 +8,6 @@ fn handle_panic(_: &core::panic::PanicInfo<'_>) -> ! {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub fn main() {}
|
pub extern "stdcall" fn my_main() -> u32 {
|
||||||
|
42
|
||||||
|
}
|
||||||
|
|
|
||||||
BIN
test/example_exe_crt.exe
Normal file
BIN
test/example_exe_crt.exe
Normal file
Binary file not shown.
10
test/example_exe_crt.rs
Normal file
10
test/example_exe_crt.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn handle_panic(_: &core::panic::PanicInfo<'_>) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "stdcall" fn my_main() {}
|
||||||
16
test2/Makefile
Normal file
16
test2/Makefile
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
RUSTC = rustc --target x86_64-pc-windows-msvc -Cpanic=abort -Clinker=lld-link -Clink-arg=/NODEFAULTLIB -Clink-arg=/debug:none -Cdebuginfo=0
|
||||||
|
|
||||||
|
build: empty_exe.exe one_dll.exe
|
||||||
|
|
||||||
|
empty_exe.exe: empty_exe.rs
|
||||||
|
$(RUSTC) empty_exe.rs
|
||||||
|
|
||||||
|
one_dll.exe: one_dll.rs small_dll.dll
|
||||||
|
$(RUSTC) one_dll.rs
|
||||||
|
|
||||||
|
small_dll.dll: small_dll.rs
|
||||||
|
$(RUSTC) small_dll.rs
|
||||||
|
|
||||||
|
.PHONY: clean
|
||||||
|
clean:
|
||||||
|
rm *.exe *.pdb *.dll
|
||||||
13
test2/empty_exe.rs
Normal file
13
test2/empty_exe.rs
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![windows_subsystem = "console"]
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn handle_panic(_: &core::panic::PanicInfo<'_>) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "stdcall" fn mainCRTStartup() -> u32 {
|
||||||
|
42
|
||||||
|
}
|
||||||
18
test2/one_dll.rs
Normal file
18
test2/one_dll.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#![no_std]
|
||||||
|
#![no_main]
|
||||||
|
#![windows_subsystem = "console"]
|
||||||
|
|
||||||
|
#[link(name = "small_dll", kind = "raw-dylib")]
|
||||||
|
unsafe extern "C" {
|
||||||
|
safe fn my_export() -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn handle_panic(_: &core::panic::PanicInfo<'_>) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "stdcall" fn mainCRTStartup() -> u32 {
|
||||||
|
my_export()
|
||||||
|
}
|
||||||
18
test2/small_dll.rs
Normal file
18
test2/small_dll.rs
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
#![no_std]
|
||||||
|
#![crate_type = "cdylib"]
|
||||||
|
#![windows_subsystem = "console"]
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn handle_panic(_: &core::panic::PanicInfo<'_>) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn my_export() -> u32 {
|
||||||
|
42
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "stdcall" fn _DllMainCRTStartup() -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue