os_abstraction_syscall.rs (1580B)
1 //! This is the next level of abstraction: instead of calling assembly directly, 2 //! we use the operating system's API. Instead of `asm` module we use `io`. 3 4 use std::io; 5 6 // This is specific to the Linux operating system and macOS. 7 // Every Linux (and maxOS) installation comes with a version `libc`, which is 8 // C library for communicating with the operating system. 9 // 10 // Having `libc`, with a consistent API, allows us to program the same way 11 // without worrying about the underlying platform architecture. 12 // 13 // Kernel developers can also make changes to the underlying ABI without 14 // breaking everyone's program. 15 #[cfg(target_family = "unix")] 16 // This flag tells the compiler to link to the "c" library on the system: 17 #[link(name = "c")] 18 // This defines what functions in the linked library we want to call: 19 unsafe extern "C" { 20 /// This uses Rusts FFI to call external functions 21 /// 22 /// The write function takes: 23 /// - The file descriptor `fd`, which in this case is a handle to `stdout`. 24 /// - A pointer to an array of u8, `buf` values. 25 /// - The length of that buffer, `count`. 26 fn write(fd: u32, buf: *const u8, count: usize) -> i32; 27 } 28 29 #[cfg(target_family = "unix")] 30 pub fn syscall(message: String) -> io::Result<()> { 31 let msg_ptr = message.as_ptr(); 32 let len = message.len(); 33 // This needs to be wrapped in unsafe block, since Rust can't guarantee 34 // safety when calling external functions: 35 let res = unsafe { write(1, msg_ptr, len) }; 36 37 if res == -1 { 38 return Err(io::Error::last_os_error()); 39 } 40 Ok(()) 41 }