i686: proper stack alignmnent for i686, working libc
This commit is contained in:
parent
961ff9ff6f
commit
d198571ac7
@ -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<K: KernelTableManager, PA: PhysicalMemoryAllocator<Address = PhysicalAddres
|
||||
unsafe { (*self.inner.get()).gs_base = tp };
|
||||
gdt::set_gs_base(tp);
|
||||
}
|
||||
|
||||
fn align_stack_for_entry(sp: usize) -> usize {
|
||||
(sp & !0xF) - 12
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_common_context(builder: &mut StackBuilder, entry: usize) {
|
||||
|
@ -141,6 +141,10 @@ pub trait TaskContext<K: KernelTableManager, PA: PhysicalMemoryAllocator>: Sized
|
||||
let ptr = Box::into_raw(closure) as usize;
|
||||
Self::kernel(closure_wrapper::<F>, ptr)
|
||||
}
|
||||
|
||||
fn align_stack_for_entry(sp: usize) -> usize {
|
||||
sp
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StackBuilder {
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
);
|
||||
|
@ -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(())
|
||||
}
|
||||
|
@ -97,8 +97,27 @@ fn run(binary: &str, args: &[String]) -> Result<!, Error> {
|
||||
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!()
|
||||
}
|
||||
|
||||
|
@ -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<i32> {
|
||||
unsafe { self.data.as_non_null_ptr().add(offset as usize).cast() }
|
||||
}
|
||||
|
||||
pub fn base(&self) -> usize {
|
||||
self.data.addr().into()
|
||||
}
|
||||
|
@ -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<AnyEndian, R>,
|
||||
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::<Vec<_>>();
|
||||
|
||||
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(())
|
||||
|
@ -28,6 +28,51 @@ impl Relocation for Rel {
|
||||
symbol: &ResolvedSymbol,
|
||||
load_base: usize,
|
||||
) -> Result<Option<Self::Value>, 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
@ -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<Option<Self::Value>, Error> {
|
||||
unimplemented!("rel-type relocations are not implemented for i686")
|
||||
}
|
||||
}
|
||||
|
||||
impl Relocation for Rela {
|
||||
type Value = RelaValue;
|
||||
@ -27,8 +41,7 @@ impl Relocation for Rela {
|
||||
load_base: usize,
|
||||
) -> Result<Option<Self::Value>, Error> {
|
||||
match symbol {
|
||||
ResolvedSymbol::Tls(tls) => {
|
||||
match self.r_type {
|
||||
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 _))),
|
||||
@ -41,13 +54,21 @@ impl Relocation for Rela {
|
||||
debug_trace!("{}@tpoff -> {}", name, offset_from_tp);
|
||||
|
||||
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),
|
||||
},
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
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<Option<Self::Value>, 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)
|
||||
// // }
|
||||
// }
|
||||
}
|
||||
|
@ -3,6 +3,11 @@ use std::path::{Path, PathBuf};
|
||||
use crate::error::Error;
|
||||
|
||||
pub fn find_library(name: &str) -> Result<PathBuf, Error> {
|
||||
// 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);
|
||||
|
@ -209,9 +209,9 @@ impl ObjectSet {
|
||||
|
||||
pub fn load_all(&mut self) -> Result<Option<TlsImage>, 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
|
||||
|
@ -64,14 +64,37 @@ fn generate_header(config_path: impl AsRef<Path>, header_output: impl AsRef<Path
|
||||
fn compile_crt0(arch: &str, output_dir: impl AsRef<Path>) {
|
||||
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");
|
||||
|
6
userspace/lib/ygglibc/crt/i686/crt0.c
Normal file
6
userspace/lib/ygglibc/crt/i686/crt0.c
Normal file
@ -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);
|
||||
}
|
34
userspace/lib/ygglibc/etc/i686-unknown-none.json
Normal file
34
userspace/lib/ygglibc/etc/i686-unknown-none.json
Normal file
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
15
userspace/lib/ygglibc/include/bits/sys_types.h
Normal file
15
userspace/lib/ygglibc/include/bits/sys_types.h
Normal file
@ -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
|
44
userspace/lib/ygglibc/src/headers/setjmp/i686.rs
Normal file
44
userspace/lib/ygglibc/src/headers/setjmp/i686.rs
Normal file
@ -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))
|
||||
}
|
@ -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;
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ impl From<FileAttr> 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;
|
||||
|
||||
|
4
userspace/lib/ygglibc/src/headers/sys_types/bits32.rs
Normal file
4
userspace/lib/ygglibc/src/headers/sys_types/bits32.rs
Normal file
@ -0,0 +1,4 @@
|
||||
pub type ssize_t = i32;
|
||||
|
||||
// TODO _FILE_OFFSET_BITS
|
||||
pub type off_t = ssize_t;
|
2
userspace/lib/ygglibc/src/headers/sys_types/bits64.rs
Normal file
2
userspace/lib/ygglibc/src/headers/sys_types/bits64.rs
Normal file
@ -0,0 +1,2 @@
|
||||
pub type ssize_t = i64;
|
||||
pub type off_t = ssize_t;
|
@ -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",
|
||||
|
@ -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 {
|
||||
|
@ -96,6 +96,7 @@ impl TryFromExt<c_int> for RawFd {
|
||||
|
||||
impl TryFromExt<(off_t, c_int)> for SeekFrom {
|
||||
fn e_try_from((offset, whence): (off_t, c_int)) -> EResult<Self> {
|
||||
let offset: i64 = offset.try_into().unwrap();
|
||||
match whence {
|
||||
SEEK_SET => {
|
||||
if offset < 0 {
|
||||
|
@ -2,3 +2,9 @@ use yggdrasil_rt::process::thread_local::TlsImage;
|
||||
|
||||
// TODO OnceLock
|
||||
pub(super) static mut TLS_IMAGE: Option<TlsImage> = None;
|
||||
|
||||
#[linkage = "weak"]
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn ___tls_get_addr() -> ! {
|
||||
loop {}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
env::BuildEnv,
|
||||
env::{Arch, BuildEnv},
|
||||
error::Error,
|
||||
util::{self, git_clone},
|
||||
};
|
||||
@ -111,6 +111,9 @@ fn build_test_c_program(
|
||||
return Err(Error::ExternalCommandFailed);
|
||||
}
|
||||
|
||||
install.push((target_dir.join("c-test"), "c-test".into()));
|
||||
|
||||
if env.arch == Arch::x86_64 {
|
||||
log::info!("Building a test C program [static]");
|
||||
let mut command = llvm.c_clang(env);
|
||||
command
|
||||
@ -130,8 +133,8 @@ fn build_test_c_program(
|
||||
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()));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -71,9 +71,9 @@ fn build_userspace(
|
||||
) -> Result<(), Error> {
|
||||
log::info!("Building userspace");
|
||||
CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace"))?;
|
||||
// TODO other architectures
|
||||
if env.arch == Arch::x86_64 {
|
||||
CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace/dynload-program"))?;
|
||||
// TODO other architectures
|
||||
if env.arch == Arch::x86_64 || env.arch == Arch::i686 {
|
||||
c::build_c(env, extra)?;
|
||||
}
|
||||
|
||||
@ -118,7 +118,6 @@ fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
|
||||
// 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",
|
||||
@ -132,7 +131,6 @@ fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
|
||||
"/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 {
|
||||
|
Loading…
x
Reference in New Issue
Block a user