Instantly share code, notes, and snippets.

@glasswings /main.rs Secret
Created Jan 17, 2019

Embed
What would you like to do?
////
// Yes, yes, manual override *all* the things!
#![no_std]
#![no_main]
#![feature(lang_items)]
#![feature(asm)]
#![feature(core_panic_info)]
#![cfg(target_arch = "x86_64")]
#![feature(link_args)]
#![link_args = "-nostartfiles"]
use core::{ptr, panic};
////
// Constants which other languages would put in a header file.
// System call numbers
const SYS_EXIT: u64 = 60;
const SYS_WRITE: u64 = 1;
const SYS_READ: u64 = 0;
// Error numbers.
const EAGAIN: i64 = 4;
const EINTR: i64 = 11;
// Standard file descriptors.
const STDIN: i64 = 0;
const STDOUT: i64 = 1;
////
// Error handling: live dangerously and die explosivly
fn trigger_segfault() -> ! { unsafe {
let nowhere = 16usize as *mut u32;
ptr::write_volatile(nowhere, 0xdeadbeef);
loop {}
} }
#[panic_handler]
fn panic(_: &panic::PanicInfo) -> ! { trigger_segfault(); }
#[lang = "eh_personality"]
fn meh_personality() -> ! { trigger_segfault(); }
////
// Exit process
fn exit(error_code: i32) -> ! { unsafe {
let error_code = error_code as i64;
asm!("syscall"
:
: "{rax}"(SYS_EXIT), "{rdi}"(error_code)
: "rax"
: "volatile" );
// Unreachable
trigger_segfault();
} }
////
// Write to stdout.
fn say(mut x: &[u8]) { unsafe {
while x.len() != 0 {
let base_addr: *const u8 = x.as_ptr();
let count: usize = x.len();
let result: i64;
asm!("syscall"
: "={rax}"(result)
: "{rax}"(SYS_WRITE), "{rdi}"(STDOUT), "{rsi}"(base_addr), "{rdx}"(count)
:
: "volatile" );
if result > 0 {
x = &x[result as usize..]
} else if result == -EAGAIN || result == -EINTR {
continue
} else {
trigger_segfault()
}
}
} }
////
// Tastefully buffered getch. NOT THREAD SAFE.
fn getch() -> Option<u8> { unsafe {
const BUFFER_SIZE: usize = 128;
static mut BUFFER: [u8; BUFFER_SIZE] = [0; BUFFER_SIZE];
static mut FILLED: usize = 0;
static mut READ: usize = 0;
while READ == FILLED {
let base_addr = BUFFER.as_ptr();
let result: i64;
asm!("syscall"
: "={rax}"(result)
: "{rax}"(SYS_READ), "{rdi}"(STDIN), "{rsi}"(base_addr), "{rdx}"(BUFFER_SIZE)
: "memory"
: "volatile" );
if result > 0 {
READ = 0;
FILLED = result as usize;
} else if result == -EINTR || result == -EAGAIN {
continue
} else if result == 0 {
return None
} else {
trigger_segfault();
}
}
let ch = BUFFER[READ];
READ += 1;
return Some(ch)
} }
////
// Entry point.
#[no_mangle]
fn _start() -> ! {
let mut total: i64 = 0;
let mut current_number: i64 = 0;
while let Some(ch) = getch() {
match ch {
b'0' ... b'9' => {
current_number *= 10;
current_number += (ch - b'0') as i64;
},
_ => {
total += current_number;
current_number = 0;
}
}
}
total += current_number;
let mut output_buffer = [b' '; 30];
const MESSAGE_TOTAL: &str = "Total:";
let mut output_n = 28;
output_buffer[0..MESSAGE_TOTAL.len()].copy_from_slice(MESSAGE_TOTAL.as_bytes());
output_buffer[29] = b'\n';
if total == 0 { output_buffer[28] = b'0' }
while total != 0 {
let d = (total % 10) as u8;
output_buffer[output_n] = b'0' + d;
total /= 10;
output_n -= 1;
}
say(&output_buffer);
exit(0)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment