fix last commit. improve process code.

master
WangRunji 6 years ago
parent e3fb47a03e
commit 6923efd250

@ -1,3 +1,10 @@
# Commands:
# make build Build
# make run Build and run in QEMU
# make justrun Run the last build
# make doc Generate docs
# make asm Open the deassemble file of the last build
# make header Open 'objdump -h' of the last build
# make addr2line Use addr2line to recover line info in backtrace # make addr2line Use addr2line to recover line info in backtrace
# make clean Clean # make clean Clean
# #

@ -3,7 +3,7 @@ use core::fmt;
use log::*; use log::*;
use spin::{Mutex, RwLock}; use spin::{Mutex, RwLock};
use xmas_elf::{ElfFile, header, program::{Flags, Type}}; use xmas_elf::{ElfFile, header, program::{Flags, Type, SegmentData}};
use rcore_memory::PAGE_SIZE; use rcore_memory::PAGE_SIZE;
use rcore_thread::Tid; use rcore_thread::Tid;
use core::str; use core::str;
@ -183,51 +183,41 @@ impl Thread {
pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box<Thread> pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box<Thread>
where Iter: Iterator<Item=&'a str> where Iter: Iterator<Item=&'a str>
{ {
// Parse elf // Parse ELF
let elf = ElfFile::new(data).expect("failed to read elf"); let elf = ElfFile::new(data).expect("failed to read elf");
let is32 = match elf.header.pt2 { let is32 = match elf.header.pt2 {
header::HeaderPt2::Header32(_) => true, header::HeaderPt2::Header32(_) => true,
header::HeaderPt2::Header64(_) => false, header::HeaderPt2::Header64(_) => false,
}; };
// Check ELF type
match elf.header.pt2.type_().as_type() { match elf.header.pt2.type_().as_type() {
header::Type::Executable => { header::Type::Executable => {},
// panic!("ELF is not shared object");
},
header::Type::SharedObject => {}, header::Type::SharedObject => {},
_ => panic!("ELF is not executable or shared object"), _ => panic!("ELF is not executable or shared object"),
} }
if let Some(interp) = elf.program_iter().filter(|ph| ph.get_type() == Ok(Type::Interp)).next() { // Check interpreter
let offset = interp.offset() as usize; if let Ok(loader_path) = elf.get_interpreter() {
let size = interp.file_size() as usize - 1; // skip last '\0' // assuming absolute path
if offset + size < data.len() { if let Ok(inode) = crate::fs::ROOT_INODE.lookup_follow(&loader_path[1..], FOLLOW_MAX_DEPTH) {
if let Ok(loader_path) = str::from_utf8(&data[offset..(offset+size)]) { if let Ok(buf) = inode.read_as_vec() {
// assuming absolute path debug!("using loader {}", &loader_path);
if let Ok(inode) = crate::fs::ROOT_INODE.lookup_follow(&loader_path[1..], FOLLOW_MAX_DEPTH) { // Elf loader should not have INTERP
if let Ok(buf) = inode.read_as_vec() { // No infinite loop
debug!("using loader {}", &loader_path); let mut new_args: Vec<&str> = args.collect();
// Elf loader should not have INTERP new_args.insert(0, loader_path);
// No infinite loop return Thread::new_user(buf.as_slice(), new_args.into_iter());
let mut new_args: Vec<&str> = args.collect();
new_args.insert(0, loader_path);
return Thread::new_user(buf.as_slice(), new_args.into_iter());
} else {
warn!("loader specified as {} but failed to read", &loader_path);
}
} else {
warn!("loader specified as {} but not found", &loader_path);
}
} else { } else {
warn!("loader specified but not found"); warn!("loader specified as {} but failed to read", &loader_path);
} }
} else { } else {
warn!("loader specified but invalid"); warn!("loader specified as {} but not found", &loader_path);
} }
} }
// Make page table // Make page table
let (mut vm, entry_addr) = memory_set_from(&elf); let mut vm = elf.make_memory_set();
// User stack // User stack
use crate::consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER32_STACK_OFFSET}; use crate::consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER32_STACK_OFFSET};
@ -240,20 +230,14 @@ impl Thread {
ustack_top ustack_top
}; };
// Make init info
let init_info = ProcInitInfo { let init_info = ProcInitInfo {
args: args.map(|s| String::from(s)).collect(), args: args.map(|s| String::from(s)).collect(),
envs: BTreeMap::new(), envs: BTreeMap::new(),
auxv: { auxv: {
let mut map = BTreeMap::new(); let mut map = BTreeMap::new();
if let Some(phdr) = elf.program_iter() if let Some(phdr_vaddr) = elf.get_phdr_vaddr() {
.find(|ph| ph.get_type() == Ok(Type::Phdr)) { map.insert(abi::AT_PHDR, phdr_vaddr as usize);
// if phdr exists in program header, use it
map.insert(abi::AT_PHDR, phdr.virtual_addr() as usize);
} else if let Some(elf_addr) = elf.program_iter().find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0) {
// otherwise, check if elf is loaded from the beginning, then phdr can be inferred.
map.insert(abi::AT_PHDR, elf_addr.virtual_addr() as usize + elf.header.pt2.ph_offset() as usize);
} else {
warn!("new_user: no phdr found, tls might not work");
} }
map.insert(abi::AT_PHENT, elf.header.pt2.ph_entry_size() as usize); map.insert(abi::AT_PHENT, elf.header.pt2.ph_entry_size() as usize);
map.insert(abi::AT_PHNUM, elf.header.pt2.ph_count() as usize); map.insert(abi::AT_PHNUM, elf.header.pt2.ph_count() as usize);
@ -274,6 +258,8 @@ impl Thread {
files.insert(1, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false }))); files.insert(1, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false })));
files.insert(2, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false }))); files.insert(2, FileLike::File(FileHandle::new(crate::fs::STDOUT.clone(), OpenOptions { read: false, write: true, append: false })));
let entry_addr = elf.header.pt2.entry_point() as usize;
Box::new(Thread { Box::new(Thread {
context: unsafe { context: unsafe {
Context::new_user_thread( Context::new_user_thread(
@ -299,9 +285,11 @@ impl Thread {
/// Fork a new process from current one /// Fork a new process from current one
pub fn fork(&self, tf: &TrapFrame) -> Box<Thread> { pub fn fork(&self, tf: &TrapFrame) -> Box<Thread> {
// Clone memory set, make a new page table // Clone memory set, make a new page table
let vm = self.proc.lock().vm.clone(); let proc = self.proc.lock();
let files = self.proc.lock().files.clone(); let vm = proc.vm.clone();
let cwd = self.proc.lock().cwd.clone(); let files = proc.files.clone();
let cwd = proc.cwd.clone();
drop(proc);
let parent = Some(self.proc.clone()); let parent = Some(self.proc.clone());
debug!("fork: finish clone MemorySet"); debug!("fork: finish clone MemorySet");
@ -324,7 +312,6 @@ impl Thread {
} }
} }
Box::new(Thread { Box::new(Thread {
context: unsafe { Context::new_fork(tf, kstack.top(), vm.token()) }, context: unsafe { Context::new_fork(tf, kstack.top(), vm.token()) },
kstack, kstack,
@ -376,50 +363,6 @@ impl Process {
} }
} }
/// Generate a MemorySet according to the ELF file.
/// Also return the real entry point address.
fn memory_set_from(elf: &ElfFile<'_>) -> (MemorySet, usize) {
debug!("creating MemorySet from ELF");
let mut ms = MemorySet::new();
let entry = elf.header.pt2.entry_point() as usize;
// [NoMMU] Get total memory size and alloc space
let va_begin = elf.program_iter()
.filter(|ph| ph.get_type() == Ok(Type::Load))
.map(|ph| ph.virtual_addr()).min().unwrap() as usize;
let va_end = elf.program_iter()
.filter(|ph| ph.get_type() == Ok(Type::Load))
.map(|ph| ph.virtual_addr() + ph.mem_size()).max().unwrap() as usize;
let va_size = va_end - va_begin;
for ph in elf.program_iter() {
if ph.get_type() != Ok(Type::Load) {
continue;
}
let virt_addr = ph.virtual_addr() as usize;
let offset = ph.offset() as usize;
let file_size = ph.file_size() as usize;
let mem_size = ph.mem_size() as usize;
// Get target slice
let target = {
ms.push(virt_addr, virt_addr + mem_size, ph.flags().to_attr(), ByFrame::new(GlobalFrameAlloc), "");
unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) }
};
// Copy data
unsafe {
ms.with(|| {
if file_size != 0 {
target[..file_size].copy_from_slice(&elf.input[offset..offset + file_size]);
}
target[file_size..].iter_mut().for_each(|x| *x = 0);
});
}
}
(ms, entry)
}
trait ToMemoryAttr { trait ToMemoryAttr {
fn to_attr(&self) -> MemoryAttr; fn to_attr(&self) -> MemoryAttr;
} }
@ -432,3 +375,78 @@ impl ToMemoryAttr for Flags {
flags flags
} }
} }
/// Helper functions to process ELF file
trait ElfExt {
/// Generate a MemorySet according to the ELF file.
fn make_memory_set(&self) -> MemorySet;
/// Get interpreter string if it has.
fn get_interpreter(&self) -> Result<&str, &str>;
/// Get virtual address of PHDR section if it has.
fn get_phdr_vaddr(&self) -> Option<u64>;
}
impl ElfExt for ElfFile<'_> {
fn make_memory_set(&self) -> MemorySet {
debug!("creating MemorySet from ELF");
let mut ms = MemorySet::new();
for ph in self.program_iter() {
if ph.get_type() != Ok(Type::Load) {
continue;
}
let virt_addr = ph.virtual_addr() as usize;
let mem_size = ph.mem_size() as usize;
let data = match ph.get_data(self).unwrap() {
SegmentData::Undefined(data) => data,
_ => unreachable!(),
};
// Get target slice
let target = {
ms.push(virt_addr, virt_addr + mem_size, ph.flags().to_attr(), ByFrame::new(GlobalFrameAlloc), "");
unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) }
};
// Copy data
unsafe {
ms.with(|| {
if data.len() != 0 {
target[..data.len()].copy_from_slice(data);
}
target[data.len()..].iter_mut().for_each(|x| *x = 0);
});
}
}
ms
}
fn get_interpreter(&self) -> Result<&str, &str> {
let header = self.program_iter()
.filter(|ph| ph.get_type() == Ok(Type::Interp))
.next().ok_or("no interp header")?;
let data = match header.get_data(self)? {
SegmentData::Undefined(data) => data,
_ => unreachable!(),
};
let path = str::from_utf8(data)
.map_err(|_| "failed to convert to utf8")?;
Ok(path)
}
fn get_phdr_vaddr(&self) -> Option<u64> {
if let Some(phdr) = self.program_iter()
.find(|ph| ph.get_type() == Ok(Type::Phdr)) {
// if phdr exists in program header, use it
Some(phdr.virtual_addr())
} else if let Some(elf_addr) = self.program_iter()
.find(|ph| ph.get_type() == Ok(Type::Load) && ph.offset() == 0) {
// otherwise, check if elf is loaded from the beginning, then phdr can be inferred.
Some(elf_addr.virtual_addr() + self.header.pt2.ph_offset())
} else {
warn!("elf: no phdr found, tls might not work");
None
}
}
}

Loading…
Cancel
Save