extern crate alloc;
use alloc::{string::String, vec::Vec};
use memory_addr::VirtAddr;
use crate::auxv::{AuxvEntry, AuxvType};
struct UserStack {
sp: usize,
}
impl UserStack {
pub fn new(sp: usize) -> Self {
Self { sp }
}
fn push(&mut self, src: &[u8], stack_data: &mut Vec<u8>) {
self.sp -= src.len();
stack_data.splice(0..0, src.iter().cloned());
}
pub fn push_usize_slice(&mut self, src: &[usize], stack_data: &mut Vec<u8>) {
for val in src.iter().rev() {
let bytes = val.to_le_bytes();
self.push(&bytes, stack_data);
}
}
pub fn push_str(&mut self, str: &str, stack_data: &mut Vec<u8>) -> usize {
self.push(b"\0", stack_data);
self.push(str.as_bytes(), stack_data);
self.sp
}
pub fn get_sp(&self) -> usize {
self.sp
}
}
fn init_stack(args: &[String], envs: &[String], auxv: &mut [AuxvEntry], sp: usize) -> Vec<u8> {
let mut data = Vec::new();
let mut stack = UserStack::new(sp);
stack.push("0123456789abcdef".as_bytes(), &mut data);
let random_str_pos = stack.get_sp();
let envs_slice: Vec<_> = envs
.iter()
.map(|env| stack.push_str(env, &mut data))
.collect();
let argv_slice: Vec<_> = args
.iter()
.map(|arg| stack.push_str(arg, &mut data))
.collect();
let padding_null = "\0".repeat(8);
stack.push(padding_null.as_bytes(), &mut data);
stack.push("\0".repeat(stack.get_sp() % 16).as_bytes(), &mut data);
assert!(stack.get_sp() % 16 == 0);
for auxv_entry in auxv.iter_mut() {
if auxv_entry.get_type() == AuxvType::RANDOM {
*auxv_entry.value_mut_ref() = random_str_pos;
}
if auxv_entry.get_type() == AuxvType::EXECFN {
*auxv_entry.value_mut_ref() = argv_slice[0];
}
}
stack.push_usize_slice(
unsafe {
core::slice::from_raw_parts(
auxv.as_ptr() as *const usize,
core::mem::size_of_val(auxv) / core::mem::size_of::<usize>(),
)
},
&mut data,
);
stack.push(padding_null.as_bytes(), &mut data);
stack.push_usize_slice(envs_slice.as_slice(), &mut data);
stack.push(padding_null.as_bytes(), &mut data);
stack.push_usize_slice(argv_slice.as_slice(), &mut data);
stack.push_usize_slice(&[args.len()], &mut data);
data
}
pub fn app_stack_region(
args: &[String],
envs: &[String],
auxv: &mut [AuxvEntry],
stack_base: VirtAddr,
stack_size: usize,
) -> Vec<u8> {
let ustack_bottom = stack_base;
let ustack_top = ustack_bottom + stack_size;
init_stack(args, envs, auxv, ustack_top.into())
}