Skip to content

Rust

Rust

OffensiveRust
200ThingsToRememberAboutRust
Embedded in Rust
Making a C++ Lib with Rust
Creating a statically linked Rust application
Automatically generates Rust FFI bindings to C (and some C++) libraries.
Rust GUI
Cross-platform Rust GUI
https://github.com/rust-embedded/rust-raspberrypi-OS-tutorials
https://fasterthanli.me/articles/a-half-hour-to-learn-rust
https://github.com/Dhghomon/easy_rust

Rust Memory

What Each memory option is for a rust variable

Cargo Settings

Make debug builds smaller:

export CARGO_PROFILE_RELEASE_LTO=thin

Change the Linker to another executable on linux:

[target.x86_64-unknown-linux-gnu]
rustflags = [
    "-C", "link-arg=-fuse-ld=lld",
]

Overwrite Linker options:

rustflags=(
  "-C link-arg=-fuse-ld=lld"
  "-C link-arg=-Wl,--compress-debug-sections=zlib"
  "-C force-frame-pointers=yes"
)
export RUSTFLAGS="${rustflags[*]}"

Example Cargo.toml

[package]
name = "ping"
version = "0.1.0"
edition = "2021"

[dependencies]
#delf = { path = "../delf" } #Used to specify a library in another directory


[profile.release]
strip = true  # Automatically strip symbols from the binary.
#opt-level = "z"  # Optimize for size.
opt-level = "s"  # Optimize for size.
lto = true # Used to remove deadcode and unused functions
panic = "abort" # Remove backtrace when crashes

Building

Build and Run the release version with command line arguments:

>>> cargo run --release -- arg1 arg2 

Install other versions of rust:

>>> rustup toolchain install nightly-2022-11-06

Run other version of rust:

>>> rustup run nightly cargo build
>>> cargo +nightly-2022-11-06 build --release

Cross Compiling:

>>> rustup run nightly rustc --print target-list
aarch64-apple-darwin
aarch64-apple-ios
aarch64-apple-ios-macabi
aarch64-apple-ios-sim
aarch64-apple-tvos
aarch64-apple-watchos-sim
aarch64-fuchsia
aarch64-kmc-solid_asp3
aarch64-linux-android
aarch64-nintendo-switch-freestanding
aarch64-pc-windows-gnullvm
aarch64-pc-windows-msvc
aarch64-unknown-freebsd
aarch64-unknown-hermit
aarch64-unknown-linux-gnu
aarch64-unknown-linux-gnu_ilp32
aarch64-unknown-linux-musl
aarch64-unknown-netbsd
aarch64-unknown-none
aarch64-unknown-none-softfloat
aarch64-unknown-nto-qnx710
aarch64-unknown-openbsd
aarch64-unknown-redox
aarch64-unknown-uefi
aarch64-uwp-windows-msvc
aarch64-wrs-vxworks
aarch64_be-unknown-linux-gnu
aarch64_be-unknown-linux-gnu_ilp32
arm-linux-androideabi
arm-unknown-linux-gnueabi
arm-unknown-linux-gnueabihf
arm-unknown-linux-musleabi
arm-unknown-linux-musleabihf
arm64_32-apple-watchos
armeb-unknown-linux-gnueabi
armebv7r-none-eabi
armebv7r-none-eabihf
armv4t-none-eabi
armv4t-unknown-linux-gnueabi
armv5te-none-eabi
armv5te-unknown-linux-gnueabi
armv5te-unknown-linux-musleabi
armv5te-unknown-linux-uclibceabi
armv6-unknown-freebsd
armv6-unknown-netbsd-eabihf
armv6k-nintendo-3ds
armv7-apple-ios
armv7-linux-androideabi
armv7-unknown-freebsd
armv7-unknown-linux-gnueabi
armv7-unknown-linux-gnueabihf
armv7-unknown-linux-musleabi
armv7-unknown-linux-musleabihf
armv7-unknown-linux-uclibceabi
armv7-unknown-linux-uclibceabihf
armv7-unknown-netbsd-eabihf
armv7-wrs-vxworks-eabihf
armv7a-kmc-solid_asp3-eabi
armv7a-kmc-solid_asp3-eabihf
armv7a-none-eabi
armv7a-none-eabihf
armv7k-apple-watchos
armv7r-none-eabi
armv7r-none-eabihf
armv7s-apple-ios
asmjs-unknown-emscripten
avr-unknown-gnu-atmega328
bpfeb-unknown-none
bpfel-unknown-none
hexagon-unknown-linux-musl
i386-apple-ios
i586-pc-windows-msvc
i586-unknown-linux-gnu
i586-unknown-linux-musl
i686-apple-darwin
i686-linux-android
i686-pc-windows-gnu
i686-pc-windows-msvc
i686-unknown-freebsd
i686-unknown-haiku
i686-unknown-linux-gnu
i686-unknown-linux-musl
i686-unknown-netbsd
i686-unknown-openbsd
i686-unknown-uefi
i686-uwp-windows-gnu
i686-uwp-windows-msvc
i686-wrs-vxworks
m68k-unknown-linux-gnu
mips-unknown-linux-gnu
mips-unknown-linux-musl
mips-unknown-linux-uclibc
mips64-openwrt-linux-musl
mips64-unknown-linux-gnuabi64
mips64-unknown-linux-muslabi64
mips64el-unknown-linux-gnuabi64
mips64el-unknown-linux-muslabi64
mipsel-sony-psp
mipsel-sony-psx
mipsel-unknown-linux-gnu
mipsel-unknown-linux-musl
mipsel-unknown-linux-uclibc
mipsel-unknown-none
mipsisa32r6-unknown-linux-gnu
mipsisa32r6el-unknown-linux-gnu
mipsisa64r6-unknown-linux-gnuabi64
mipsisa64r6el-unknown-linux-gnuabi64
msp430-none-elf
nvptx64-nvidia-cuda
powerpc-unknown-freebsd
powerpc-unknown-linux-gnu
powerpc-unknown-linux-gnuspe
powerpc-unknown-linux-musl
powerpc-unknown-netbsd
powerpc-unknown-openbsd
powerpc-wrs-vxworks
powerpc-wrs-vxworks-spe
powerpc64-ibm-aix
powerpc64-unknown-freebsd
powerpc64-unknown-linux-gnu
powerpc64-unknown-linux-musl
powerpc64-unknown-openbsd
powerpc64-wrs-vxworks
powerpc64le-unknown-freebsd
powerpc64le-unknown-linux-gnu
powerpc64le-unknown-linux-musl
riscv32gc-unknown-linux-gnu
riscv32gc-unknown-linux-musl
riscv32i-unknown-none-elf
riscv32im-unknown-none-elf
riscv32imac-unknown-none-elf
riscv32imac-unknown-xous-elf
riscv32imc-esp-espidf
riscv32imc-unknown-none-elf
riscv64gc-unknown-freebsd
riscv64gc-unknown-linux-gnu
riscv64gc-unknown-linux-musl
riscv64gc-unknown-none-elf
riscv64gc-unknown-openbsd
riscv64imac-unknown-none-elf
s390x-unknown-linux-gnu
s390x-unknown-linux-musl
sparc-unknown-linux-gnu
sparc64-unknown-linux-gnu
sparc64-unknown-netbsd
sparc64-unknown-openbsd
sparcv9-sun-solaris
thumbv4t-none-eabi
thumbv5te-none-eabi
thumbv6m-none-eabi
thumbv7a-pc-windows-msvc
thumbv7a-uwp-windows-msvc
thumbv7em-none-eabi
thumbv7em-none-eabihf
thumbv7m-none-eabi
thumbv7neon-linux-androideabi
thumbv7neon-unknown-linux-gnueabihf
thumbv7neon-unknown-linux-musleabihf
thumbv8m.base-none-eabi
thumbv8m.main-none-eabi
thumbv8m.main-none-eabihf
wasm32-unknown-emscripten
wasm32-unknown-unknown
wasm32-wasi
wasm64-unknown-unknown
x86_64-apple-darwin
x86_64-apple-ios
x86_64-apple-ios-macabi
x86_64-apple-tvos
x86_64-apple-watchos-sim
x86_64-fortanix-unknown-sgx
x86_64-fuchsia
x86_64-linux-android
x86_64-pc-nto-qnx710
x86_64-pc-solaris
x86_64-pc-windows-gnu
x86_64-pc-windows-gnullvm
x86_64-pc-windows-msvc
x86_64-sun-solaris
x86_64-unknown-dragonfly
x86_64-unknown-freebsd
x86_64-unknown-haiku
x86_64-unknown-hermit
x86_64-unknown-illumos
x86_64-unknown-l4re-uclibc
x86_64-unknown-linux-gnu
x86_64-unknown-linux-gnux32
x86_64-unknown-linux-musl
x86_64-unknown-netbsd
x86_64-unknown-none
x86_64-unknown-openbsd
x86_64-unknown-redox
x86_64-unknown-uefi
x86_64-uwp-windows-gnu
x86_64-uwp-windows-msvc
x86_64-wrs-vxworks
>>> rustup run nightly rustup toolchain install nightly-2022-11-06-i686-pc-windows-msvc
>>> rustup run nightly rustup target add i686-pc-windows-msvc
>>> rustup run nightly cargo build --target i686-pc-windows-msvc

Expanding Macros

cargo expand

Learning Rust

https://rustforjs.dev/
How I went about learning Rust
Roguelike Tutorial - In Rust
Writing an OS in Rust

Examples

https://medium.com/@ilegra/building-a-microservice-with-rust-ef9641cf2331

Concepts

https://doc.rust-lang.org/std/clone/trait.Clone.html
https://depth-first.com/articles/2020/01/27/rust-ownership-by-example/
https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html
https://doc.rust-lang.org/rust-by-example/scope/lifetime.html

Smart Pointers:
- Box\<T>: To store something on the heap.
- Used when you don't know the size at compile time.
- Used when the type is recursive
- Rc\<T>: If you need to have multiple functions referencing the underlined data structure
- Is only de allocated when all references are removed from scope
- Arc\<T>: Atomic Reference Counters
- Used when need multiple threads interacting with the same object

Async:
(async) Rust doesn't have to be hard

Macros

Simple Macro for a Function:

macro_rules! create_function {
    // This macro takes an argument of designator `ident` and
    // creates a function named `$func_name`.
    // The `ident` designator is used for variable/function names.
    ($func_name:ident) => {
        fn $func_name() {
            // The `stringify!` macro converts an `ident` into a string.
            println!("You called {:?}()",
                     stringify!($func_name));
        }
    };
}

// Create functions named `foo` and `bar` with the above macro.
create_function!(foo);
create_function!(bar);

fn main() {
    foo();
    bar();
}

Macro for many arguments:

// `find_min!` will calculate the minimum of any number of arguments.
macro_rules! find_min {
    // Base case:
    ($x:expr) => ($x);
    // `$x` followed by at least one `$y,`
    ($x:expr, $($y:expr),+) => (
        // Call `find_min!` on the tail `$y`
        std::cmp::min($x, find_min!($($y),+))
    )
}

fn main() {
    println!("{}", find_min!(1));
    println!("{}", find_min!(1 + 2, 2));
    println!("{}", find_min!(5, 2 * 3, 4));
}

Borrowing

Immutable Borrow:

fn main() {
    let mut s = String::from("hello world goodbye universe");

    // You can make as many imputable borrow that you want
    let r1 = &s[0..5];
    let r2 = &s[6..11];
    let r3 = &s[12..19];
    let r4 = &s[20..28];

    println!("{}, {}, and {} {}", r1, r2, r3, r4);

    //Only after r1, r2, and r3 are not used anymore in the scope can you use a mutable reference
    let r5 = &mut s; // no problem
    println!("{}", r5);
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

Mutable Borrowing:

fn main() {
    let mut s = String::from("hello");

    //Make a mutable string
    // If this is in a scope then it will be removed at the end of the 
    let r1 = &mut s;

    // Since you have a mutable borrow then you cant have a immutable  borrow. The following will fail
    // let r2 = &mut s;
    change(r1);
    
    // Since there is a mutable variables based on s you cant use s only r1 until it is removed
    println!("{}", r1);
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

No Dangling Return:

fn main() {
    let reference_to_nothing = no_dangle();
    println!("{}", reference_to_nothing);
}

fn no_dangle() -> String {
    let s = String::from("hello");

    //You cant return a reference to a string that was created in this function scope
    //&s
    s
}

String Slice Borrowing:

    let s = String::from("hello world");

    let hello = &s[0..5];
    let world = &s[6..11];

    println!("{}", reference_to_nothing);

Importing from other files

Source

In the main.rs file you need include mod filename;. This links the file to main function. Then in the actual file you can import the module with use crate::filename;

Operators

?: if the function returns a Result or Option this extracts the value or the error from the result

Loops

Breaking Named:

#![allow(unreachable_code)]

fn main() {
    'outer: loop {
        println!("Entered the outer loop");

        'inner: loop {
            println!("Entered the inner loop");

            // This would break only the inner loop
            //break;

            // This breaks the outer loop
            break 'outer;
        }

        println!("This point will never be reached");
    }

    println!("Exited the outer loop");
}

Loop over Mutable:

fn main() {
    let mut names = vec!["Bob", "Frank", "Ferris"];

    for name in names.iter_mut() {
        *name = match name {
            &mut "Ferris" => "There is a rustacean among us!",
            _ => "Hello",
        }
    }

    println!("names: {:?}", names);
}

Structures

Remove Padding in structures:

fn main() {
    struct Foo {
        a: u8,
        b: u32,
    }

    #[repr(packed)]
    struct FooPacked {
        a: u8,
        b: u32,
    }

    use std::mem::size_of;
    println!("Foo       = {}", size_of::<Foo>());
    println!("FooPacked = {}", size_of::<FooPacked>());
}

Remove Reorder:

fn main() {
    // first, let's declare both structs: with Rust repr
    struct IOI_Rust {
        ttl: u8,
        tos: u8,
        flags: u8,
        options_size: u8,
        options_data: u32,
    }

    // and C repr
    #[repr(C)]
    struct IOI_C {
        ttl: u8,
        tos: u8,
        flags: u8,
        options_size: u8,
        options_data: u32,
    }

    use memoffset::span_of;
    use std::mem::size_of;

    // let's make a quick macro, this will make this a lot easier
    macro_rules! print_offset {
        // the macro takes one identifier (the struct's name), then a tuple
        // of identifiers (the field names)
        ($type: ident, ($($field: ident),*)) => {
            // `$type` is an identifier, but we're going to
            // print it out, so we need it as a string instead.
            let t = stringify!($type);

            // this will repeat for each $field
            $(
                let f = stringify!($field);
                let span = span_of!($type, $field);
                println!("{:10} {:15} {:?}", t, f, span);
            )*

            // finally, print the total field size
            let ts = size_of::<$type>();
            println!("{:10} {:15} {}", t, "(total)", ts);
            println!();
        };
    }
    print_offset!(IOI_Rust, (ttl, tos, flags, options_size, options_data));
    print_offset!(IOI_C, (ttl, tos, flags, options_size, options_data));
}

/*
IOI_Rust   ttl             4..5
IOI_Rust   tos             5..6
IOI_Rust   flags           6..7
IOI_Rust   options_size    7..8
IOI_Rust   options_data    0..4
IOI_Rust   (total)         8

IOI_C      ttl             0..1
IOI_C      tos             1..2
IOI_C      flags           2..3
IOI_C      options_size    3..4
IOI_C      options_data    4..8
IOI_C      (total)         8
*/

Lifetimes

#[derive(Debug)]
struct Point(i32, i32);

//Used to keep the lifetime of the function to the parent function
fn left_most<'a>(p1: &'a Point, p2: &'a Point) -> &'a Point {
    if p1.0 < p2.0 {
        p1
    } else {
        p2
    }
}

fn main() {
    let p1: Point = Point(10, 10);
    let p2: Point = Point(20, 20);
    let p3 = left_most(&p1, &p2); // What is the lifetime of p3?
    println!("p3: {p3:?}");
}

Hacking

Linux Kernel Crate

Hooking Golang

https://github.com/metalbear-co/mirrord/blob/main/mirrord/layer/src/hooks.rs

Hypervisor

https://memn0ps.github.io/hypervisor-development-in-rust-part-1/?ref=upstract.com