diff --git a/kernel/arch/i686/src/context.rs b/kernel/arch/i686/src/context.rs index 3240b55f..0c6a785c 100644 --- a/kernel/arch/i686/src/context.rs +++ b/kernel/arch/i686/src/context.rs @@ -31,8 +31,8 @@ pub struct ExceptionFrame { pub eip: u32, pub cs: u32, pub eflags: u32, - esp: u32, - ss: u32, + pub esp: u32, + pub ss: u32, } #[allow(unused)] @@ -225,6 +225,10 @@ impl usize { + (sp & !0xF) - 12 + } } fn setup_common_context(builder: &mut StackBuilder, entry: usize) { diff --git a/kernel/arch/interface/src/task.rs b/kernel/arch/interface/src/task.rs index eabc0952..de147b19 100644 --- a/kernel/arch/interface/src/task.rs +++ b/kernel/arch/interface/src/task.rs @@ -141,6 +141,10 @@ pub trait TaskContext: Sized let ptr = Box::into_raw(closure) as usize; Self::kernel(closure_wrapper::, ptr) } + + fn align_stack_for_entry(sp: usize) -> usize { + sp + } } pub struct StackBuilder { diff --git a/kernel/libk/src/task/process.rs b/kernel/libk/src/task/process.rs index dca22ddc..2ea11ef9 100644 --- a/kernel/libk/src/task/process.rs +++ b/kernel/libk/src/task/process.rs @@ -137,7 +137,8 @@ impl Process { let space = inner.space.clone().unwrap(); - let sp = (options.stack_top - 8) as *mut usize; + // let sp = (options.stack_top - 4) as *mut usize; + let sp = TaskContextImpl::align_stack_for_entry(options.stack_top) as *mut usize; let sp = unsafe { Thread::setup_stack_header(&space, sp, options.argument)? }; let info = UserContextInfo { diff --git a/kernel/libk/src/task/thread.rs b/kernel/libk/src/task/thread.rs index d77daed0..784b5348 100644 --- a/kernel/libk/src/task/thread.rs +++ b/kernel/libk/src/task/thread.rs @@ -184,9 +184,10 @@ impl Thread { ) -> Result<*mut usize, Error> { #[cfg(any(target_arch = "x86", rust_analyzer))] { + // Argument sp = sp.sub(1); sp.write_foreign_volatile(space, argument); - + // Return address sp = sp.sub(1); sp.write_foreign_volatile(space, 0); } diff --git a/kernel/src/arch/i686/exception.rs b/kernel/src/arch/i686/exception.rs index 45c289ef..00b799c4 100644 --- a/kernel/src/arch/i686/exception.rs +++ b/kernel/src/arch/i686/exception.rs @@ -154,6 +154,7 @@ fn dump_user_exception(kind: ExceptionKind, frame: &ExceptionFrame) { let thread = Thread::current(); warnln!("{:?} in {} ({:?})", kind, thread.id, thread.name); warnln!("ip = {:02x}:{:08x}", frame.cs, frame.eip); + warnln!("sp = {:02x}:{:08x}", frame.ss, frame.esp); warnln!("cr3 = {:#010x}", CR3.get()); if kind == ExceptionKind::PageFault { warnln!("cr2 = {:#010x}", CR2.get()); diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index cbe3272c..66778e69 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -5,7 +5,7 @@ #![allow(nonstandard_style)] #![allow(unused)] -#[cfg(not(feature = "rustc-dep-of-std"))] +// #[cfg(not(feature = "rustc-dep-of-std"))] extern crate compiler_builtins; extern crate yggdrasil_abi as abi; diff --git a/lib/runtime/src/process/thread_local/i686.rs b/lib/runtime/src/process/thread_local/i686.rs index ac20cdf3..3497e564 100644 --- a/lib/runtime/src/process/thread_local/i686.rs +++ b/lib/runtime/src/process/thread_local/i686.rs @@ -13,3 +13,22 @@ pub fn get_thread_pointer() -> usize { pub unsafe fn set_thread_pointer(value: usize) -> Result<(), Error> { crate::sys::set_thread_option(&ThreadOption::ThreadPointer(value)) } + +// ___tls_get_addr, TLS_index structure address gets passed in the %eax register +#[cfg(any(feature = "__tls_get_addr", rust_analyzer))] +core::arch::global_asm!( + r#" +.pushsection .text +.global ___tls_get_addr +.type ___tls_get_addr, %function +___tls_get_addr: + sub $8, %esp + push %eax + call __tls_get_addr@plt + add $12, %esp + ret +.size ___tls_get_addr, . - ___tls_get_addr +.popsection +"#, + options(att_syntax) +); diff --git a/lib/runtime/src/process/thread_local/mod.rs b/lib/runtime/src/process/thread_local/mod.rs index adc972d6..f5627ad8 100644 --- a/lib/runtime/src/process/thread_local/mod.rs +++ b/lib/runtime/src/process/thread_local/mod.rs @@ -52,7 +52,10 @@ pub struct TlsImage { /// DTV table, containing dynamic TLS module mappings pub struct Dtv { + // DTV entries for TLS allocated by the dynamic linker/loader entries: Vec<*mut c_void>, + // Entries for pthread_setspecific()-like behavior + specific: Vec<*mut c_void>, } struct TcbHeader { @@ -120,9 +123,53 @@ impl Dtv { fn new() -> Self { Self { entries: Vec::new(), + specific: Vec::new(), } } + #[inline] + fn get_key(list: &Vec<*mut c_void>, key: usize) -> *mut c_void { + if key == 0 || key > list.len() { + panic!("Out-of-bounds TLS key: {key}"); + } + list[key - 1] + } + + #[inline] + fn set_key(list: &mut Vec<*mut c_void>, key: usize, value: *mut c_void) { + if key == 0 || key > list.len() { + panic!("Out-of-bounds TLS key: {key}") + } + list[key - 1] = value; + } + + /// Returns a value assocaited with a given thread-specific key. + /// + /// # Panics + /// + /// Will panic if key == 0. + /// Will panic if key is longer than the DTV itself. + pub fn get_specific(&self, key: usize) -> *mut c_void { + Self::get_key(&self.specific, key) + } + + /// Sets a DTV entry for a thread-specific key. + /// + /// # Panics + /// + /// Will panic if key == 0. + /// Will panic if key is longer than the DTV itself. + pub fn set_specific(&mut self, key: usize, value: *mut c_void) { + Self::set_key(&mut self.specific, key, value) + } + + /// Allocates a new thread-specific key in the DTV, filling it with a NULL value. + pub fn new_specific(&mut self) -> usize { + self.specific.push(null_mut()); + let key = self.specific.len(); + key + } + /// Returns a value associated with a given key. /// /// # Panics @@ -130,28 +177,19 @@ impl Dtv { /// Will panic if key == 0. /// Will panic if key is larger than the DTV itself. pub fn get(&self, key: usize) -> *mut c_void { - if key == 0 { - panic!("Zero key used when calling DTV::get()"); - } - let key = key - 1; - if key >= self.entries.len() { - panic!("Key not in DTV: {}", key + 1); - } - self.entries[key] + Self::get_key(&self.entries, key) } /// Sets a DTV entry, growing the DTV allocation if necessary - pub fn set(&mut self, key: usize, value: *mut c_void) -> Result<(), Error> { - if key == 0 { - return Err(Error::InvalidArgument); + /// + /// # Panics + /// + /// Will panic if key == 0. + pub fn set(&mut self, key: usize, value: *mut c_void) { + if key > self.entries.len() { + self.entries.resize(key, null_mut()); } - let key = key - 1; - if key >= self.entries.len() { - // TODO return an error if resize fails - self.entries.resize(key + 1, null_mut()); - } - self.entries[key] = value; - Ok(()) + Self::set_key(&mut self.entries, key, value) } } @@ -210,7 +248,7 @@ fn setup_dtv(image: &TlsImage, tls_base: usize) -> Result<(), Error> { dtv.set( module_id, core::ptr::with_exposed_provenance_mut(tls_base + module_offset), - )?; + ); } Ok(()) } diff --git a/userspace/dyn-loader/src/main.rs b/userspace/dyn-loader/src/main.rs index 8c73c081..02fa9aea 100644 --- a/userspace/dyn-loader/src/main.rs +++ b/userspace/dyn-loader/src/main.rs @@ -97,8 +97,27 @@ fn run(binary: &str, args: &[String]) -> Result { debug_trace!("entry = {:p}", entry); let argument = env::build_argument(args, &auxv)?; + unsafe { enter(entry, argument) }; +} - entry(argument); +unsafe fn enter(entry: extern "C" fn(usize), argument: usize) -> ! { + #[cfg(any(target_arch = "x86", rust_analyzer))] + { + core::arch::asm!( + r#" + xor %ebp, %ebp + and $~0xF, %esp + sub $8, %esp + pushl {0} + call *{1} + "#, + in(reg) argument, + in(reg) entry, + options(att_syntax) + ); + } + #[cfg(any(target_arch = "x86_64", rust_analyzer))] + {} unreachable!() } diff --git a/userspace/dyn-loader/src/mapping.rs b/userspace/dyn-loader/src/mapping.rs index 14f9bfcb..fc7345ab 100644 --- a/userspace/dyn-loader/src/mapping.rs +++ b/userspace/dyn-loader/src/mapping.rs @@ -32,6 +32,10 @@ impl Mapping { unsafe { self.data.as_non_null_ptr().add(offset as usize).cast() } } + pub fn dword(&mut self, offset: u64) -> NonNull { + unsafe { self.data.as_non_null_ptr().add(offset as usize).cast() } + } + pub fn base(&self) -> usize { self.data.addr().into() } diff --git a/userspace/dyn-loader/src/object.rs b/userspace/dyn-loader/src/object.rs index 03e2976f..219498c6 100644 --- a/userspace/dyn-loader/src/object.rs +++ b/userspace/dyn-loader/src/object.rs @@ -14,8 +14,10 @@ use elf::{ DT_INIT_ARRAYSZ, DT_NEEDED, DT_PREINIT_ARRAY, DT_PREINIT_ARRAYSZ, ET_DYN, ET_EXEC, PT_DYNAMIC, PT_GNU_EH_FRAME, PT_GNU_RELRO, PT_GNU_STACK, PT_INTERP, PT_LOAD, PT_NOTE, PT_NULL, PT_PHDR, PT_TLS, SHN_UNDEF, SHT_REL, SHT_RELA, STB_GLOBAL, STB_LOCAL, STB_WEAK, + STT_TLS, }, endian::AnyEndian, + parse::{ParseAt, ParsingIterator}, segment::ProgramHeader, symbol::Symbol, ElfStream, @@ -25,8 +27,8 @@ use yggdrasil_rt::mem::MappingFlags; use crate::{ error::Error, mapping::Mapping, - relocation::{Relocation, RelocationValue}, - state::{ExportedNormalSymbol, ExportedSymbol, ExportedTlsSymbol, State}, thread_local::TlsLayout, + relocation::{Relocation, RelocationValue, SymbolRelocation}, + state::{ExportedNormalSymbol, ExportedSymbol, ExportedTlsSymbol, State}, }; pub enum ElfType { @@ -40,7 +42,7 @@ pub enum ResolvedSymbol<'s> { Global(&'s ExportedNormalSymbol), Tls(&'s ExportedTlsSymbol), Local, - Null, + Null(u32), } pub struct DynamicSymbol { @@ -76,7 +78,7 @@ impl ResolvedSymbol<'_> { Self::Local => todo!(), Self::Global(sym) => sym.value as i64, Self::Tls(_) => 0, - Self::Null => 0, + Self::Null(_) => 0, } } } @@ -180,7 +182,7 @@ impl Object { self.id = id; } - pub fn load(&mut self, state: &mut State) -> Result<(), Error> { + pub fn load(&mut self) -> Result<(), Error> { // Already loaded if self.mapping.is_some() { return Ok(()); @@ -376,9 +378,39 @@ impl Object { } } + fn apply_relocations<'s, R: SymbolRelocation, F: Fn(usize) -> &'s DynamicSymbol>( + state: &mut State, + mapping: &mut Mapping, + object_id: u32, + rel_section: ParsingIterator, + get_dynsym: F, + ) -> Result<(), Error> { + for rel in rel_section { + let dynsym = get_dynsym(rel.symbol()); + let sym = match dynsym.raw.st_bind() { + STB_GLOBAL | STB_WEAK => match state.lookup(dynsym).unwrap() { + ExportedSymbol::Normal(export) => ResolvedSymbol::Global(export), + ExportedSymbol::Tls(export) => ResolvedSymbol::Tls(export), + }, + STB_LOCAL => { + if dynsym.name.is_empty() { + ResolvedSymbol::Null(object_id) + } else { + todo!("Relocation against local symbol: {:?}", dynsym.name) + } + } + _ => todo!("Unhandled relocation symbol binding"), + }; + + if let Some(value) = rel.resolve(state, &dynsym.name, &sym, mapping.base())? { + value.write(mapping, rel.offset()); + } + } + Ok(()) + } + pub fn relocate(&mut self, state: &mut State) -> Result<(), Error> { let mapping = self.mapping.as_mut().ok_or(Error::NotLoaded)?; - let image_offset = mapping.base() as isize - self.vma_start as isize; let rela_sections = self .elf @@ -390,28 +422,9 @@ impl Object { for rela_section in rela_sections { let rela_section = self.elf.section_data_as_relas(&rela_section)?; - - for rela in rela_section { - let dynsym = &self.dynamic_symbol_array[rela.r_sym as usize]; - let sym = match dynsym.raw.st_bind() { - STB_GLOBAL | STB_WEAK => match state.lookup(dynsym).unwrap() { - ExportedSymbol::Normal(export) => ResolvedSymbol::Global(export), - ExportedSymbol::Tls(export) => ResolvedSymbol::Tls(export), - } - STB_LOCAL => { - if dynsym.name.is_empty() { - ResolvedSymbol::Null - } else { - todo!("Relocation against local symbol: {:?}", dynsym.name) - } - } - _ => todo!(), - }; - - if let Some(value) = rela.resolve(&state, &dynsym.name, &sym, mapping.base())? { - value.write(mapping, rela.r_offset); - } - } + Self::apply_relocations(state, mapping, self.id, rela_section, |idx| { + &self.dynamic_symbol_array[idx] + })?; } let rel_sections = self @@ -422,8 +435,11 @@ impl Object { .cloned() .collect::>(); - if !rel_sections.is_empty() { - todo!("SHT_REL is not yet implemented") + for rel_section in rel_sections { + let rel_section = self.elf.section_data_as_rels(&rel_section)?; + Self::apply_relocations(state, mapping, self.id, rel_section, |idx| { + &self.dynamic_symbol_array[idx] + })?; } Ok(()) diff --git a/userspace/dyn-loader/src/relocation/i686.rs b/userspace/dyn-loader/src/relocation/i686.rs index a0547943..23c18529 100644 --- a/userspace/dyn-loader/src/relocation/i686.rs +++ b/userspace/dyn-loader/src/relocation/i686.rs @@ -28,6 +28,51 @@ impl Relocation for Rel { symbol: &ResolvedSymbol, load_base: usize, ) -> Result, Error> { - todo!() + match symbol { + ResolvedSymbol::Tls(tls) => match self.r_type { + // R_386_DTPMOD32: TLS module ID + 35 => Ok(Some(RelValue::DWordNoAddend(tls.module_id as _))), + // R_386_DTPOFF32: TLS offset within a module + 36 => Ok(Some(RelValue::DWordNoAddend(tls.offset as _))), + // R_386_TPOFF: tp-relative offset + 14 => { + // Need to extract fixed global offset + let tls_layout = state.tls_layout.as_ref().unwrap(); + // Offset from TLS start + let offset = tls_layout.offset(tls.module_id, tls.offset).unwrap(); + let offset_from_tp = -((tls_layout.tp_offset - offset) as i32); + debug_trace!("{}@tpoff -> {}", name, offset_from_tp); + + Ok(Some(RelValue::DWordNoAddend(offset_from_tp))) + } + // 14 => Ok(Some(RelValue::DWordNoAddend())) + + _ => todo!("Unsupported relocation against TLS symbol: {}", self.r_type) + }, + &ResolvedSymbol::Null(object_id) => match self.r_type { + // R_386_RELATIVE: B + A + 8 => Ok(Some(RelValue::DWord(load_base as _))), + + // R_386_DTPMOD32: TLS module ID + 35 => Ok(Some(RelValue::DWordNoAddend(object_id as _))), + + _ => todo!("Unsupported relocation against NULL symbol: {}", self.r_type), + } + _ => { + let s: i32 = symbol.value().try_into().unwrap(); + if s == 0 { + todo!("Relocation: r_type={}, name={name} is NULL", self.r_type) + } + match self.r_type { + // R_386_32: S + A + 1 => Ok(Some(RelValue::DWord(s))), + // R_386_GLOB_DAT: S + // R_386_JMP_SLOT: S + 6 | 7 => Ok(Some(RelValue::DWordNoAddend(s))), + + _ => todo!("Unsupported relocation type: {}", self.r_type) + } + } + } } } diff --git a/userspace/dyn-loader/src/relocation/mod.rs b/userspace/dyn-loader/src/relocation/mod.rs index ab456cef..3c0a06c7 100644 --- a/userspace/dyn-loader/src/relocation/mod.rs +++ b/userspace/dyn-loader/src/relocation/mod.rs @@ -1,3 +1,5 @@ +use elf::{parse::ParseAt, relocation::{Rel, Rela}}; + use crate::{error::Error, mapping::Mapping, object::ResolvedSymbol, state::State}; #[cfg(any(target_arch = "x86_64", rust_analyzer))] @@ -10,13 +12,19 @@ pub enum RelaValue { } pub enum RelValue { - + DWord(i32), + DWordNoAddend(i32), } pub trait RelocationValue { fn write(&self, mapping: &mut Mapping, offset: u64); } +pub trait SymbolRelocation: Relocation + ParseAt { + fn symbol(&self) -> usize; + fn offset(&self) -> u64; +} + pub trait Relocation { type Value: RelocationValue; @@ -39,6 +47,34 @@ impl RelocationValue for RelaValue { impl RelocationValue for RelValue { fn write(&self, mapping: &mut Mapping, offset: u64) { - match *self {} + match *self { + Self::DWord(value) => { + let a = unsafe { mapping.dword(offset).read() }; + unsafe { mapping.dword(offset).write(value + a) }; + }, + Self::DWordNoAddend(value) => { + unsafe { mapping.dword(offset).write(value) }; + } + } + } +} + +impl SymbolRelocation for Rel { + fn symbol(&self) -> usize { + self.r_sym as _ + } + + fn offset(&self) -> u64 { + self.r_offset + } +} + +impl SymbolRelocation for Rela { + fn symbol(&self) -> usize { + self.r_sym as _ + } + + fn offset(&self) -> u64 { + self.r_offset } } diff --git a/userspace/dyn-loader/src/relocation/x86_64.rs b/userspace/dyn-loader/src/relocation/x86_64.rs index 7b98c031..466f82a5 100644 --- a/userspace/dyn-loader/src/relocation/x86_64.rs +++ b/userspace/dyn-loader/src/relocation/x86_64.rs @@ -5,7 +5,7 @@ use elf::{ R_X86_64_64, R_X86_64_DTPMOD64, R_X86_64_DTPOFF64, R_X86_64_GLOB_DAT, R_X86_64_JUMP_SLOT, R_X86_64_RELATIVE, R_X86_64_TPOFF64, }, - relocation::Rela, + relocation::{Rel, Rela}, }; use crate::{ @@ -14,7 +14,21 @@ use crate::{ state::State, }; -use super::{RelaValue, Relocation}; +use super::{RelValue, RelaValue, Relocation}; + +impl Relocation for Rel { + type Value = RelValue; + + fn resolve( + &self, + _state: &State, + _name: &str, + _symbol: &ResolvedSymbol, + _load_base: usize, + ) -> Result, Error> { + unimplemented!("rel-type relocations are not implemented for i686") + } +} impl Relocation for Rela { type Value = RelaValue; @@ -27,27 +41,34 @@ impl Relocation for Rela { load_base: usize, ) -> Result, Error> { match symbol { - ResolvedSymbol::Tls(tls) => { - match self.r_type { - // Object ID (index into DTV) of the object containing this symbol - R_X86_64_DTPMOD64 => Ok(Some(RelaValue::QWord(tls.module_id as _))), - R_X86_64_DTPOFF64 => Ok(Some(RelaValue::QWord(tls.offset as _))), - R_X86_64_TPOFF64 => { - // Need to extract fixed global offset - let tls_layout = state.tls_layout.as_ref().unwrap(); - // Offset from TLS start - let offset = tls_layout.offset(tls.module_id, tls.offset).unwrap(); - let offset_from_tp = -((tls_layout.tp_offset - offset) as i64); - debug_trace!("{}@tpoff -> {}", name, offset_from_tp); + ResolvedSymbol::Tls(tls) => match self.r_type { + // Object ID (index into DTV) of the object containing this symbol + R_X86_64_DTPMOD64 => Ok(Some(RelaValue::QWord(tls.module_id as _))), + R_X86_64_DTPOFF64 => Ok(Some(RelaValue::QWord(tls.offset as _))), + R_X86_64_TPOFF64 => { + // Need to extract fixed global offset + let tls_layout = state.tls_layout.as_ref().unwrap(); + // Offset from TLS start + let offset = tls_layout.offset(tls.module_id, tls.offset).unwrap(); + let offset_from_tp = -((tls_layout.tp_offset - offset) as i64); + debug_trace!("{}@tpoff -> {}", name, offset_from_tp); - Ok(Some(RelaValue::QWord(offset_from_tp))) - }, - _ => todo!(), + Ok(Some(RelaValue::QWord(offset_from_tp))) } - } + + _ => todo!("Unsupported relocation against TLS symbol: {}", self.r_type) + }, + &ResolvedSymbol::Null(object_id) => match self.r_type { + // TLS module ID + R_X86_64_DTPMOD64 => Ok(Some(RelaValue::QWord(object_id as _))), + // B + A + R_X86_64_RELATIVE => Ok(Some(RelaValue::QWord(load_base as i64 + self.r_addend))), + + _ => todo!("Unsupported relocation against NULL symbol: {}", self.r_type), + }, _ => { let s = symbol.value() as i64; - if s == 0 && self.r_type != R_X86_64_RELATIVE { + if s == 0 { todo!() } match self.r_type { @@ -55,44 +76,9 @@ impl Relocation for Rela { R_X86_64_JUMP_SLOT | R_X86_64_GLOB_DAT => Ok(Some(RelaValue::QWord(s))), // S + A R_X86_64_64 => Ok(Some(RelaValue::QWord(s + self.r_addend))), - // B + A - R_X86_64_RELATIVE => { - Ok(Some(RelaValue::QWord(load_base as i64 + self.r_addend))) - } - _ => todo!(), + _ => todo!("Unsupported relocation type: {}", self.r_type), } } } } - // fn resolve<'a, F: Fn(u32) -> Result<&'a DynamicSymbol, Error>>( - // &'a self, - - // ) -> Result, Error> { - // todo!() - // // let image_offset = image_offset as i64; - // // let symbol = image_symbol(self.r_sym)?; - - // // let base_value = match self.r_type { - // // // image_offset already applied - // // R_X86_64_JUMP_SLOT => state.lookup(source, symbol), - // // // image_offset already applied - // // R_X86_64_GLOB_DAT => state.lookup(source, symbol), - // // R_X86_64_64 => todo!(), - // // R_X86_64_DTPMOD64 | R_X86_64_DTPOFF64 => todo!(), - // // _ => todo!(), - // // } as i64; - - // // match self.r_type { - // // // S - // // R_X86_64_GLOB_DAT | R_X86_64_JUMP_SLOT => Ok(Some(RelaValue::QWord(base_value))), - // // // S + A - // // R_X86_64_64 => todo!(), - // // // B + A - // // R_X86_64_RELATIVE => todo!(), - // // // TODO TLS relocations - // // R_X86_64_DTPMOD64 => todo!(), - // // R_X86_64_DTPOFF64 => todo!(), - // // _ => todo!("Unhandled relocation type: {:#x}", self.r_type) - // // } - // } } diff --git a/userspace/dyn-loader/src/search.rs b/userspace/dyn-loader/src/search.rs index f808921d..072e6c5c 100644 --- a/userspace/dyn-loader/src/search.rs +++ b/userspace/dyn-loader/src/search.rs @@ -3,6 +3,11 @@ use std::path::{Path, PathBuf}; use crate::error::Error; pub fn find_library(name: &str) -> Result { + // TODO this is a hack, because Rust puts a hash at the end of its libstd.so + if name.starts_with("libstd-") { + return find_library("libstd.so"); + } + let path = Path::new("/lib").join(name); if path.exists() { return Ok(path); diff --git a/userspace/dyn-loader/src/state.rs b/userspace/dyn-loader/src/state.rs index a551a74e..f0f806af 100644 --- a/userspace/dyn-loader/src/state.rs +++ b/userspace/dyn-loader/src/state.rs @@ -209,9 +209,9 @@ impl ObjectSet { pub fn load_all(&mut self) -> Result, Error> { // Load all objects somewhere, order doesn't matter - self.root.load(&mut self.state)?; + self.root.load()?; for (_, lib) in self.libraries.iter_mut() { - lib.load(&mut self.state)?; + lib.load()?; } // Build a TLS master copy somewhere diff --git a/userspace/lib/ygglibc/build.rs b/userspace/lib/ygglibc/build.rs index 7e611104..5617538c 100644 --- a/userspace/lib/ygglibc/build.rs +++ b/userspace/lib/ygglibc/build.rs @@ -64,14 +64,37 @@ fn generate_header(config_path: impl AsRef, header_output: impl AsRef) { let output_dir = output_dir.as_ref(); let mut command = Command::new("clang"); + let arch = if arch == "x86" { + "i686" + } else { + arch + }; + let input_dir = PathBuf::from("crt").join(arch); + let crt0_c = input_dir.join("crt0.c"); + let crt0_s = input_dir.join("crt0.S"); + + let input_file = if crt0_c.exists() { + crt0_c + } else if crt0_s.exists() { + crt0_s + } else { + panic!("No crt0.* file for {arch}"); + }; + command .arg(format!("--target={}-unknown-none", arch)) .arg("-nostdlib") .arg("-fPIC") - .arg("-c") + .arg("-c"); + + if arch == "i686" { + command.arg("-m32"); + } + + command .arg("-o") .arg(output_dir.join("crt0.o")) - .arg(format!("crt/{}/crt0.c", arch)); + .arg(input_file); if !command.status().unwrap().success() { panic!("Couldn't compile crt0.o"); diff --git a/userspace/lib/ygglibc/crt/i686/crt0.c b/userspace/lib/ygglibc/crt/i686/crt0.c new file mode 100644 index 00000000..13c56673 --- /dev/null +++ b/userspace/lib/ygglibc/crt/i686/crt0.c @@ -0,0 +1,6 @@ +extern void __ygglibc_entry(const void *, const void *); +extern int main(int, const char **, const char **); + +void _start(const void *arg) { + __ygglibc_entry(main, arg); +} diff --git a/userspace/lib/ygglibc/etc/i686-unknown-none.json b/userspace/lib/ygglibc/etc/i686-unknown-none.json new file mode 100644 index 00000000..d0221cf3 --- /dev/null +++ b/userspace/lib/ygglibc/etc/i686-unknown-none.json @@ -0,0 +1,34 @@ +{ + "is-builtin": false, + "arch": "x86", + "cpu": "pentium4", + "os": "none", + "llvm-target": "i686-unknown-linux-gnu", + "data-layout": "e-m:e-p:32:32-p270:32:32-p271:32:32-p272:64:64-i128:128-f64:32:64-f80:32-n8:16:32-S128", + "max-atomic-width": 64, + "target-pointer-width": "32", + "features": "+sse,-soft-float", + + "executables": true, + "dynamic-linking": true, + "panic-strategy": "abort", + "relocation-model": "pic", + "position-independent-executables": true, + "crt-static-allows-dylibs": true, + + "has-thread-local": true, + + "supported-split-debuginfo": [ + "packed", + "unpacked", + "off" + ], + + "linker": "rust-lld", + "linker-flavor": "ld.lld", + "pre-link-args": { + "ld.lld": [ + "--dynamic-linker=/libexec/dyn-loader" + ] + } +} diff --git a/userspace/lib/ygglibc/include/bits/sys_types.h b/userspace/lib/ygglibc/include/bits/sys_types.h new file mode 100644 index 00000000..415626d5 --- /dev/null +++ b/userspace/lib/ygglibc/include/bits/sys_types.h @@ -0,0 +1,15 @@ +#ifndef _YGGDRASIL_SYS_TYPES_H +#define _YGGDRASIL_SYS_TYPES_H 1 + +#if __SIZEOF_SIZE_T__ == 8 +typedef int64_t ssize_t; +#elif __SIZEOF_SIZE_T__ == 4 +typedef int32_t ssize_t; +#else +#error __SIZEOF_SIZE_T__ value not supported +#endif + +// TODO _FILE_OFFSET_BITS +typedef ssize_t off_t; + +#endif diff --git a/userspace/lib/ygglibc/src/headers/setjmp/i686.rs b/userspace/lib/ygglibc/src/headers/setjmp/i686.rs new file mode 100644 index 00000000..c93bcdbd --- /dev/null +++ b/userspace/lib/ygglibc/src/headers/setjmp/i686.rs @@ -0,0 +1,44 @@ +use core::ffi::c_int; + +pub type __jmp_buf = [usize; 8]; + +// TODO + +#[no_mangle] +#[naked] +unsafe extern "C" fn setjmp(buf: *mut __jmp_buf) -> c_int { + core::arch::naked_asm!( + r#" + jmp . + "#, + options(att_syntax) + ); +} + +#[no_mangle] +#[naked] +unsafe extern "C" fn _setjmp(buf: *mut __jmp_buf) -> c_int { + core::arch::naked_asm!( + r#" + jmp . + "#, + options(att_syntax) + ); +} + +#[no_mangle] +#[naked] +unsafe extern "C" fn longjmp(buf: *mut __jmp_buf, val: c_int) -> c_int { + core::arch::naked_asm!( + r#" + jmp . + "#, + options(att_syntax) + ) +} + +#[no_mangle] +#[naked] +unsafe extern "C" fn _longjmp(buf: *mut __jmp_buf, val: c_int) -> c_int { + core::arch::naked_asm!("jmp .", options(att_syntax)) +} diff --git a/userspace/lib/ygglibc/src/headers/setjmp/mod.rs b/userspace/lib/ygglibc/src/headers/setjmp/mod.rs index 749c1d02..2f87949f 100644 --- a/userspace/lib/ygglibc/src/headers/setjmp/mod.rs +++ b/userspace/lib/ygglibc/src/headers/setjmp/mod.rs @@ -1,7 +1,11 @@ #[cfg(any(target_arch = "x86_64", rust_analyzer))] pub mod x86_64; - #[cfg(any(target_arch = "x86_64", rust_analyzer))] pub use x86_64::__jmp_buf; +#[cfg(any(target_arch = "x86", rust_analyzer))] +pub mod i686; +#[cfg(any(target_arch = "x86", rust_analyzer))] +pub use i686::__jmp_buf; + pub type jmp_buf = __jmp_buf; diff --git a/userspace/lib/ygglibc/src/headers/stdio/file.rs b/userspace/lib/ygglibc/src/headers/stdio/file.rs index a231f454..07ad9432 100644 --- a/userspace/lib/ygglibc/src/headers/stdio/file.rs +++ b/userspace/lib/ygglibc/src/headers/stdio/file.rs @@ -172,7 +172,7 @@ unsafe extern "C" fn fsetpos(fp: *mut FILE, pos: *const fpos_t) -> CIntZeroResul unsafe extern "C" fn ftell(fp: *mut FILE) -> c_long { match ftello(fp) { COffsetResult::ERROR => -1, - COffsetResult(off) => off, + COffsetResult(off) => off.try_into().unwrap(), } } diff --git a/userspace/lib/ygglibc/src/headers/sys_stat/mod.rs b/userspace/lib/ygglibc/src/headers/sys_stat/mod.rs index dfe8e001..4d7bab64 100644 --- a/userspace/lib/ygglibc/src/headers/sys_stat/mod.rs +++ b/userspace/lib/ygglibc/src/headers/sys_stat/mod.rs @@ -77,7 +77,7 @@ impl From for stat { st.st_gid = u32::from(value.gid).try_into().unwrap(); // TODO st.st_blksize = 512; - st.st_blocks = (st.st_size + 511) / 512; + st.st_blocks = ((st.st_size + 511) / 512).try_into().unwrap(); // TODO st.st_nlink = 1; diff --git a/userspace/lib/ygglibc/src/headers/sys_types/bits32.rs b/userspace/lib/ygglibc/src/headers/sys_types/bits32.rs new file mode 100644 index 00000000..2d301c80 --- /dev/null +++ b/userspace/lib/ygglibc/src/headers/sys_types/bits32.rs @@ -0,0 +1,4 @@ +pub type ssize_t = i32; + +// TODO _FILE_OFFSET_BITS +pub type off_t = ssize_t; diff --git a/userspace/lib/ygglibc/src/headers/sys_types/bits64.rs b/userspace/lib/ygglibc/src/headers/sys_types/bits64.rs new file mode 100644 index 00000000..fdf15514 --- /dev/null +++ b/userspace/lib/ygglibc/src/headers/sys_types/bits64.rs @@ -0,0 +1,2 @@ +pub type ssize_t = i64; +pub type off_t = ssize_t; diff --git a/userspace/lib/ygglibc/src/headers/sys_types/cbindgen.toml b/userspace/lib/ygglibc/src/headers/sys_types/cbindgen.toml index 379b156b..8036b501 100644 --- a/userspace/lib/ygglibc/src/headers/sys_types/cbindgen.toml +++ b/userspace/lib/ygglibc/src/headers/sys_types/cbindgen.toml @@ -1,7 +1,7 @@ language = "C" style = "Type" -sys_includes = ["stdint.h", "stddef.h"] +sys_includes = ["stdint.h", "stddef.h", "bits/sys_types.h"] no_includes = true include_guard = "_SYS_TYPES_H" @@ -20,9 +20,7 @@ include = [ "ino_t", "mode_t", "nlink_t", - "off_t", "pid_t", - "ssize_t", "suseconds_t", "time_t", "timer_t", diff --git a/userspace/lib/ygglibc/src/headers/sys_types/mod.rs b/userspace/lib/ygglibc/src/headers/sys_types/mod.rs index c59f0af6..91981f4d 100644 --- a/userspace/lib/ygglibc/src/headers/sys_types/mod.rs +++ b/userspace/lib/ygglibc/src/headers/sys_types/mod.rs @@ -1,5 +1,16 @@ use core::ffi::{c_int, c_ulong, c_void}; +#[cfg(any(target_pointer_width = "64", rust_analyzer))] +mod bits64; +#[cfg(any(target_pointer_width = "64", rust_analyzer))] +pub use bits64::*; + +#[cfg(any(target_pointer_width = "32", rust_analyzer))] +mod bits32; +#[cfg(any(target_pointer_width = "32", rust_analyzer))] +pub use bits32::*; + + pub type pid_t = i32; pub type uid_t = i32; pub type gid_t = i32; @@ -12,9 +23,6 @@ pub type timer_t = i32; pub type mode_t = c_int; -#[cfg(any(target_pointer_width = "64", rust_analyzer))] -pub type ssize_t = i64; - pub type blkcnt_t = i64; pub type blksize_t = c_ulong; pub type nlink_t = u64; @@ -29,8 +37,6 @@ pub type clock_t = u64; #[repr(transparent)] pub struct time_t(pub i64); -pub type off_t = i64; - pub type suseconds_t = c_ulong; impl time_t { diff --git a/userspace/lib/ygglibc/src/io/mod.rs b/userspace/lib/ygglibc/src/io/mod.rs index caa62a90..01021c3c 100644 --- a/userspace/lib/ygglibc/src/io/mod.rs +++ b/userspace/lib/ygglibc/src/io/mod.rs @@ -96,6 +96,7 @@ impl TryFromExt for RawFd { impl TryFromExt<(off_t, c_int)> for SeekFrom { fn e_try_from((offset, whence): (off_t, c_int)) -> EResult { + let offset: i64 = offset.try_into().unwrap(); match whence { SEEK_SET => { if offset < 0 { diff --git a/userspace/lib/ygglibc/src/thread/tls.rs b/userspace/lib/ygglibc/src/thread/tls.rs index b7983d55..72514d7f 100644 --- a/userspace/lib/ygglibc/src/thread/tls.rs +++ b/userspace/lib/ygglibc/src/thread/tls.rs @@ -2,3 +2,9 @@ use yggdrasil_rt::process::thread_local::TlsImage; // TODO OnceLock pub(super) static mut TLS_IMAGE: Option = None; + +#[linkage = "weak"] +#[no_mangle] +unsafe extern "C" fn ___tls_get_addr() -> ! { + loop {} +} diff --git a/xtask/src/build/c.rs b/xtask/src/build/c.rs index dfd90bf8..f52812e0 100644 --- a/xtask/src/build/c.rs +++ b/xtask/src/build/c.rs @@ -5,7 +5,7 @@ use std::{ }; use crate::{ - env::BuildEnv, + env::{Arch, BuildEnv}, error::Error, util::{self, git_clone}, }; @@ -111,27 +111,30 @@ fn build_test_c_program( return Err(Error::ExternalCommandFailed); } - log::info!("Building a test C program [static]"); - let mut command = llvm.c_clang(env); - command - .args([ - "-v", - "-static", - "-O0", - "-ggdb", - "-fstack-protector-strong", - "-lm", - ]) - .arg("-o") - .arg(target_dir.join("c-test-static")) - .arg(env.workspace_root.join("test.c")); - - if !command.status()?.success() { - return Err(Error::ExternalCommandFailed); - } - install.push((target_dir.join("c-test"), "c-test".into())); - install.push((target_dir.join("c-test-static"), "c-test-static".into())); + + if env.arch == Arch::x86_64 { + log::info!("Building a test C program [static]"); + let mut command = llvm.c_clang(env); + command + .args([ + "-v", + "-static", + "-O0", + "-ggdb", + "-fstack-protector-strong", + "-lm", + ]) + .arg("-o") + .arg(target_dir.join("c-test-static")) + .arg(env.workspace_root.join("test.c")); + + if !command.status()?.success() { + return Err(Error::ExternalCommandFailed); + } + + install.push((target_dir.join("c-test-static"), "c-test-static".into())); + } Ok(()) } diff --git a/xtask/src/build/userspace.rs b/xtask/src/build/userspace.rs index 322fbd6a..79066013 100644 --- a/xtask/src/build/userspace.rs +++ b/xtask/src/build/userspace.rs @@ -71,9 +71,9 @@ fn build_userspace( ) -> Result<(), Error> { log::info!("Building userspace"); CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace"))?; + CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace/dynload-program"))?; // TODO other architectures - if env.arch == Arch::x86_64 { - CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace/dynload-program"))?; + if env.arch == Arch::x86_64 || env.arch == Arch::i686 { c::build_c(env, extra)?; } @@ -118,21 +118,19 @@ fn build_rootfs, D: AsRef>( // TODO this is a temporary hack fs::create_dir_all(rootfs_dir.join("lib"))?; // TODO other architectures - if env.arch == Arch::x86_64 { - util::copy_file( - env.workspace_root.join(format!( - "userspace/dynload-program/target/{}-unknown-yggdrasil/{}/dynload-program", - env.arch.name(), - env.profile.name() - )), - rootfs_dir.join("dynload-program"), - )?; + util::copy_file( + env.workspace_root.join(format!( + "userspace/dynload-program/target/{}-unknown-yggdrasil/{}/dynload-program", + env.arch.name(), + env.profile.name() + )), + rootfs_dir.join("dynload-program"), + )?; - util::copy_file(format!( + util::copy_file(format!( "/home/alnyan/build/ygg/toolchain/build/host/stage1-std/{}-unknown-yggdrasil/release/libstd.so", env.arch.name() ), rootfs_dir.join("lib/libstd.so"))?; - } log::info!("Installing extras"); for (src, dst) in install_extra {