Understanding OS-Backed Event Queues, System Calls, and Cross-Platform Abstractions 56 let message = "Hello world from syscall!\n"; let message = String::from(message); syscall(message). unwrap(); } The only difference is that instead of pulling in the asm module, we pull in the io module. Using the OS-provided API in Linux and mac OS Y ou can run this code directly in the Rust playground since it runs on Linux, or you can run it locally on a Linux machine using WSL or on mac OS: ch03/b-normal-syscall #[cfg(target_family = "unix")] #[link(name = "c")] extern "C" { fn write(fd: u32, buf: *const u8, count: usize)-> i32; } fn syscall(message: String)-> io::Result<()> { let msg_ptr = message. as_ptr(); let len = message. len(); let res = unsafe { write(1, msg_ptr, len) }; if res ==-1 { return Err(io::Error::last_os_error()); } Ok(()) } Let's go through the different steps one by one. Knowing how to do a proper syscall will be very useful for us later on in this book. #[link(name = "c")] Every Linux (and mac OS) installation comes with a version of libc, which is a C library for communicating with the operating system. Having libc, with a consistent API, allows us to program the same way without worrying about the underlying platform architecture. Kernel developers can also make changes to the underlying ABI without breaking everyone's program. This flag tells the compiler to link to the "c" library on the system. Next up is the definition of what functions in the linked library we want to call: extern "C" { fn write(fd: u32, buf: *const u8, count: usize); }