diff --git a/blog/content/second-edition/posts/01-freestanding-rust-binary/index.md b/blog/content/second-edition/posts/01-freestanding-rust-binary/index.md index f663a2c4..c434c5d3 100644 --- a/blog/content/second-edition/posts/01-freestanding-rust-binary/index.md +++ b/blog/content/second-edition/posts/01-freestanding-rust-binary/index.md @@ -132,7 +132,7 @@ fn main() {} #[lang = "panic_fmt"] #[no_mangle] -pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, +pub extern "C" fn rust_begin_panic(_msg: core::fmt::Arguments, _file: &'static str, _line: u32, _column: u32) -> ! { loop {} @@ -198,7 +198,7 @@ To tell the Rust compiler that we don't want to use the normal entry point chain #[lang = "panic_fmt"] #[no_mangle] -pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, +pub extern "C" fn rust_begin_panic(_msg: core::fmt::Arguments, _file: &'static str, _line: u32, _column: u32) -> ! { loop {} @@ -214,14 +214,15 @@ On Linux, the default entry point is called `_start`. The linker just looks for ```rust #[no_mangle] -pub extern fn _start() -> ! { +pub extern "C" fn _start() -> ! { loop {} } ``` -It's important that we disable the [name mangling] through the `no_mangle` attribute, otherwise the compiler would generate some cryptic `_ZN3blog_os4_start7hb173fedf945531caE` symbol that the linker wouldn't recognize. +It's important that we disable the [name mangling] through the `no_mangle` attribute, otherwise the compiler would generate some cryptic `_ZN3blog_os4_start7hb173fedf945531caE` symbol that the linker wouldn't recognize. We also have to mark the function as `extern "C"` to tell the compiler that it should use the [C calling convention] for this function (instead of the unspecified Rust calling convention). [name mangling]: https://en.wikipedia.org/wiki/Name_mangling +[C calling convention]: https://en.wikipedia.org/wiki/Calling_convention The `!` return type means that the function is diverging, i.e. not allowed to ever return. This is required because the entry point is not called by any function, but invoked directly by the operating system or bootloader. So instead of returning, the entry point should e.g. invoke the [`exit` system call] of the operating system. In our case, shutting down the machine could be a reasonable action, since there's nothing left to do if a freestanding binary returns. For now, we fulfill the requirement by looping endlessly. @@ -269,12 +270,12 @@ On Windows, the linker requires two entry points [depending on the used subsyste ```rust #[no_mangle] -pub extern fn mainCRTStartup() -> ! { +pub extern "C" fn mainCRTStartup() -> ! { main(); } #[no_mangle] -pub extern fn main() -> ! { +pub extern "C" fn main() -> ! { loop {} } ``` @@ -288,7 +289,7 @@ macOS [does not support statically linked binaries], so we have to link the `lib ```rust #[no_mangle] -pub extern fn main() -> ! { +pub extern "C" fn main() -> ! { loop {} } ``` @@ -313,7 +314,7 @@ A minimal freestanding Rust binary looks like this: #[lang = "panic_fmt"] // define a function that should be called on panic #[no_mangle] -pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, +pub extern "C" fn rust_begin_panic(_msg: core::fmt::Arguments, _file: &'static str, _line: u32, _column: u32) -> ! { loop {} @@ -321,7 +322,7 @@ pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, // On Linux: #[no_mangle] // don't mangle the name of this function -pub extern fn _start() -> ! { +pub extern "C" fn _start() -> ! { // this function is the entry point, since the linker looks for a function // named `_start` by default loop {} @@ -329,19 +330,19 @@ pub extern fn _start() -> ! { // On Windows: #[no_mangle] -pub extern fn WinMainCRTStartup() -> ! { +pub extern "C" fn WinMainCRTStartup() -> ! { WinMain(); } #[no_mangle] -pub extern fn WinMain() -> ! { +pub extern "C" fn WinMain() -> ! { loop {} } // On macOS: #[no_mangle] -pub extern fn main() -> ! { +pub extern "C" fn main() -> ! { loop {} } ``` diff --git a/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md b/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md index 2698a2a1..1b2db0fa 100644 --- a/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md +++ b/blog/content/second-edition/posts/02-minimal-rust-kernel/index.md @@ -203,14 +203,14 @@ Compiling for our new target will use Linux conventions (I'm not quite sure why, #[lang = "panic_fmt"] // define a function that should be called on panic #[no_mangle] -pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, +pub extern "C" fn rust_begin_panic(_msg: core::fmt::Arguments, _file: &'static str, _line: u32, _column: u32) -> ! { loop {} } #[no_mangle] // don't mangle the name of this function -pub extern fn _start() -> ! { +pub extern "C" fn _start() -> ! { // this function is the entry point, since the linker looks for a function // named `_start` by default loop {} @@ -277,7 +277,7 @@ The implementation looks like this: static HELLO: &[u8] = b"Hello World!"; #[no_mangle] -pub extern fn _start() -> ! { +pub extern "C" fn _start() -> ! { let vga_buffer = 0xb8000 as *const u8 as *mut u8; for (i, &byte) in HELLO.iter().enumerate() { diff --git a/blog/content/second-edition/posts/03-vga-text-buffer/index.md b/blog/content/second-edition/posts/03-vga-text-buffer/index.md index dea6a5eb..1eaafa20 100644 --- a/blog/content/second-edition/posts/03-vga-text-buffer/index.md +++ b/blog/content/second-edition/posts/03-vga-text-buffer/index.md @@ -507,7 +507,7 @@ Now we can delete the `print_something` function and print directly from our `_s ```rust // in src/main.rs #[no_mangle] -pub extern fn _start() -> ! { +pub extern "C" fn _start() -> ! { use core::fmt::Write; vga_buffer::WRITER.lock().write_str("Hello again").unwrap(); write!(vga_buffer::WRITER.lock(), ", some numbers: {} {}", 42, 1.337).unwrap(); @@ -586,7 +586,7 @@ To use `println` in `main.rs`, we need to import the macros of the VGA buffer mo mod vga_buffer; #[no_mangle] -pub extern fn _start() { +pub extern "C" fn _start() { println!("Hello World{}", "!"); loop {} diff --git a/src/main.rs b/src/main.rs index 9bf6bc6d..b1295e0a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -15,7 +15,7 @@ mod vga_buffer; /// This function is the entry point, since the linker looks for a function /// named `_start_` by default. #[no_mangle] // don't mangle the name of this function -pub extern fn _start() -> ! { +pub extern "C" fn _start() -> ! { println!("Hello World{}", "!"); loop {} @@ -24,7 +24,7 @@ pub extern fn _start() -> ! { /// This function is called on panic. #[lang = "panic_fmt"] #[no_mangle] -pub extern fn rust_begin_panic(_msg: core::fmt::Arguments, +pub extern "C" fn rust_begin_panic(_msg: core::fmt::Arguments, _file: &'static str, _line: u32, _column: u32) -> ! {