Skip to content

Instantly share code, notes, and snippets.

@XeCycle
Last active August 26, 2022 04:00
Show Gist options
  • Save XeCycle/93733bd917bd682d8d7315d00db39ca8 to your computer and use it in GitHub Desktop.
Save XeCycle/93733bd917bd682d8d7315d00db39ca8 to your computer and use it in GitHub Desktop.
dump command line and environment

Part of an attempt to rewrite my mini-tools in rust.

TODO:

  • do I need to take *mut InitFrame instead of &mut self to avoid UB?
  • is it possible to do this in cargo, or make it multi-file in other ways, with LTO?
  • why an extraneous ud2 is generated for unreachable_unchecked? (look at objdump -d initf.o)
rule rustc
command = rustc -o $out -C opt-level=s --crate-type staticlib --emit obj $in
rule ld
command = ld.lld --nmagic --lto-O1 --no-rosegment -z nognustack -o $out $in && llvm-strip --strip-sections $out
build initf.o: rustc initf.rs
build initf: ld initf.o
extern crate core;
use core::arch::{asm, global_asm};
use core::slice;
global_asm!(
r"
.global _start
_start:
xor %ebp, %ebp
mov %rsp, %rdi
call main_noret
",
options(att_syntax)
);
#[repr(C)]
struct InitFrame {
argc: i64,
}
impl InitFrame {
unsafe fn argv_base(f: *mut InitFrame) -> *mut *mut u8 {
(f as *mut _ as u64 + 8) as *mut *mut u8
}
unsafe fn argv(f: *mut InitFrame) -> &'static [*mut u8] {
slice::from_raw_parts_mut(InitFrame::argv_base(f), (*f).argc as _)
}
unsafe fn environ_base(f: *mut InitFrame) -> *mut *mut u8 {
InitFrame::argv_base(f).offset(((*f).argc + 1) as _)
}
}
unsafe fn syscall1(mut nr: i64, arg1: i64) -> i64 {
asm!(
"syscall",
inout("eax") nr,
in("rdi") arg1,
out("rcx") _,
out("r11") _
);
nr
}
unsafe fn syscall3(mut nr: i64, arg1: i64, arg2: i64, arg3: i64) -> i64 {
asm!(
"syscall",
inout("eax") nr,
in("rdi") arg1,
in("rsi") arg2,
in("rdx") arg3,
out("rcx") _,
out("r11") _
);
nr
}
unsafe fn strlen(s: *const u8) -> usize {
for len in 0.. {
if s.offset(len).read() == 0 {
return len as _
}
}
usize::MAX
}
unsafe fn from_cstr<'a>(s: *const u8) -> &'a [u8] {
slice::from_raw_parts(s, strlen(s))
}
fn sysret(ret: i64) -> Result<i64, i32> {
if ret as u64 > ((-4096i64) as u64) {
Err(-ret as _)
} else {
Ok(ret)
}
}
fn write(fd: i32, buf: &[u8]) -> Result<i64, i32> {
let ret = unsafe {
syscall3(1, fd as _, buf.as_ptr() as _, buf.len() as _)
};
sysret(ret)
}
fn main(initf: *mut InitFrame) -> Result<(), i32> {
let eol = [b'\n'];
for arg in unsafe { InitFrame::argv(initf) } {
write(1, unsafe {from_cstr(*arg)})?;
write(1, &eol)?;
}
unsafe {
let mut env = InitFrame::environ_base(initf);
loop {
let e1 = env.read();
if e1.is_null() {
break;
} else {
write(1, from_cstr(e1))?;
write(1, &eol)?;
}
env = env.offset(1);
}
}
Ok(())
}
#[no_mangle]
unsafe extern "C" fn main_noret(initf: *mut InitFrame) -> ! {
let exit_code = match main(initf) {
Ok(()) => 0,
Err(n) => n,
};
syscall1(231, exit_code as _);
core::hint::unreachable_unchecked();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment