#[no_std] Question

Given a main function that is declared as so

fn main(_argc: i32, _argv: *const *const u8) -> i32

How do you actually convert the *const *const u8 value into something we can operate with in Rust?

My working code thus far is

#![feature(start)]
#![no_std]
#![no_main]

extern crate libc;
mod io;

use core::slice::from_raw_parts;
use core::mem::size_of_val;

#[no_mangle]
pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {
    unsafe {
        for argument in from_raw_parts(_argv, _argc as usize) {
            for character in from_raw_parts(argument, size_of_val(argument)) {
                io::print_char(*character as i8)
            }
        }
        io::print_char(b'\n' as i8);
        for character in "World, Hello".bytes() {
            io::print_char(character as i8);
        }
        io::print_char(b'\n' as i8);
    }

    0
}


However, running the application with World, Hello results in the arguments getting printed out mangled, whereas the byte slice created in memory prints fine.

���������t���t
World, Hello
1 Like

This code is missing the io module.

It's just a wrapper over putchar

extern crate libc;

extern {
    pub fn putchar(c: i8) -> i8;
}

pub fn print_char(input: i8) {
    unsafe { let _ = putchar(input); }
}

Try something like this:

#[no_mangle]
pub extern fn main(_argc: i32, _argv: *const *const libc::c_char) -> i32 {
    unsafe {
        for argument in from_raw_parts(_argv, _argc as usize) {
            for character in from_raw_parts(*argument, libc::strlen(*argument)) {
                io::print_char(*character)
            }
        }
    }
    0
}

Note that the outer for loop does not read memory; the type of "argument" is &*const libc::c_char, which is essentially the same type as argv.

2 Likes

How about this: Rust Playground?

for &arg in slice::from_raw_parts(_argv, _argc as usize) {
    let slice = slice::from_raw_parts(arg, strlen(arg));
    let s: &str = str::from_utf8_unchecked(slice);
    print_ln(s).unwrap();
}

So that works. I am able to properly read the arguments and print them with the following:

#![feature(start)]
#![no_std]
#![no_main]

extern crate libc;
mod io;

use core::slice::from_raw_parts;

#[no_mangle]
pub extern fn main(_argc: i32, _argv: *const *const i8) -> i32 {
    unsafe {
        for &argument in from_raw_parts(_argv, _argc as usize) {
            let capacity = libc::strlen(argument);
            for &character in from_raw_parts(argument, capacity) {
                io::print_char(character);
            }
            io::print_char(b' ' as i8);
        }
        io::print_char(b'\n' as i8);
    }

    0
}