i686: proper stack alignmnent for i686, working libc

This commit is contained in:
Mark Poliakov 2024-11-18 13:56:43 +02:00
parent 961ff9ff6f
commit d198571ac7
32 changed files with 485 additions and 162 deletions

View File

@ -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) {

View File

@ -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 {

View File

@ -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 {

View File

@ -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);
}

View File

@ -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());

View File

@ -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;

View File

@ -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)
);

View File

@ -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(())
}

View File

@ -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!()
}

View File

@ -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()
}

View File

@ -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(())

View File

@ -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)
}
}
}
}
}

View File

@ -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
}
}

View File

@ -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)
// // }
// }
}

View File

@ -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);

View File

@ -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

View File

@ -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");

View 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);
}

View 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"
]
}
}

View 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

View 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))
}

View File

@ -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;

View File

@ -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(),
}
}

View File

@ -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;

View File

@ -0,0 +1,4 @@
pub type ssize_t = i32;
// TODO _FILE_OFFSET_BITS
pub type off_t = ssize_t;

View File

@ -0,0 +1,2 @@
pub type ssize_t = i64;
pub type off_t = ssize_t;

View File

@ -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",

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {}
}

View File

@ -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(())
}

View File

@ -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 {