liveBook · Manning

Extern "C"

As explained in Rust in Action: Systems programming concepts and techniques

extern "C" is Rust syntax that specifies C-compatible calling and linkage conventions for functions or foreign-function interfaces.

`extern "C"` tells Rust to use C calling conventions instead of Rust’s. A calling convention governs details such as how function arguments are laid out in memory. This matters when code outside ordinary Rust execution must call a function: if the caller and function disagree, the call may fail. section 11.2.3

A kernel entry point

`#[no_mangle] pub extern "C" fn _start() -> !` defines an entry point for a small operating-system kernel. `extern "C"` selects the calling convention; the separate `#[no_mangle]` attribute prevents Rust from changing the function’s symbol name. Both details matter to booting the kernel. section 11.2.3

Listing 11.4 Creating an OS kernel that paints a block of color
 1 #![no_std]                              #1
 2 #![no_main]                             #1
 3 #![feature(core_intrinsics)]            #2
 4   
 5 use core::intrinsics;                   #2
 6 use core::panic::PanicInfo;             #3
 7  
 8 #[panic_handler]
 9 #[no_mangle]
10 pub fn panic(_info: &PanicInfo) -> ! {
11   intrinsics::abort();                  #4
12 }
13  
14 #[no_mangle]
15 pub extern "C" fn _start() -> ! {
16   let framebuffer = 0xb8000 as *mut u8;
17  
18   unsafe {
19     framebuffer
20       .offset(1)                        #5
21       .write_volatile(0x30);            #6
22   }
23  
24   loop {}
25 }

See `_start` in a working kernel that writes to the display’s frame buffer. section 11.2.3

`extern "C"` can also surround declarations of functions supplied from elsewhere. In the LLVM intrinsic declarations, `#[link_name]` identifies each function for the linker. Rust knows their declared type signatures, but calls to them must occur in an `unsafe` block. section 12.9.2

Listing 12.15 Declaring the LLVM intrinsic functions within listing 12.17
extern "C" {
  #[link_name = "llvm.eh.sjlj.setjmp"]      #1
  pub fn setjmp(_: *mut i8) -> i32;         #2
 
  #[link_name = "llvm.eh.sjlj.longjmp"]     #1
  pub fn longjmp(_: *mut i8);
}

Compare the block form of `extern "C"` with the kernel’s single-function form. section 12.9.2

How Rust in Action: Systems programming concepts and techniques covers it

How deep it goes
Explains the calling-convention purpose and shows both function and block syntax, without detailing argument layout.
Examples
Shows a kernel `_start` function and declarations for LLVM setjmp and longjmp intrinsics.
What it assumes
Introduces calling conventions through a concrete boot example; assumes familiarity with basic Rust function declarations.
What you can do after
Apply it to a kernel entry point or external function declarations while distinguishing calling conventions from symbol names.
How it connects
Connects calling conventions to symbol mangling, linker names, unsafe calls, and operating-system booting.

Also explained in

Compare how 2 books explain extern "C" →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Rust in Action: Systems programming concepts and techniques. The section links point to the parts of the book it draws on.