libc: dynamic libc

This commit is contained in:
Mark Poliakov 2024-11-12 17:07:06 +02:00
parent 457e82d2e3
commit 312deb8a56
43 changed files with 1790 additions and 71 deletions

View File

@ -289,13 +289,14 @@ pub fn clone_tls(space: &ProcessAddressSpace, image: &ProcessImage) -> Result<us
fn is_dynamic<F: Read + Seek>( fn is_dynamic<F: Read + Seek>(
elf: &mut ElfStream<AnyEndian, FileReader<F>>, elf: &mut ElfStream<AnyEndian, FileReader<F>>,
) -> Result<bool, Error> { ) -> Result<bool, Error> {
if elf.ehdr.e_type != elf::abi::ET_DYN { if elf.ehdr.e_type != elf::abi::ET_DYN && elf.ehdr.e_type != elf::abi::ET_EXEC {
return Ok(false); return Ok(false);
} }
let dynamic = elf.dynamic().map_err(from_parse_error)?; let dynamic = elf.dynamic().map_err(from_parse_error)?;
let Some(dynamic) = dynamic else { let Some(dynamic) = dynamic else {
// No .dynamic section -> not dynamic // No .dynamic section -> not dynamic
log::debug!("No .dynamic -> not dynamic");
return Ok(false); return Ok(false);
}; };

View File

@ -248,6 +248,7 @@ fn xxx_load_program<P: AsRef<Path>>(
file.seek(SeekFrom::Start(0))?; file.seek(SeekFrom::Start(0))?;
log::debug!("open_elf_file({:?})", path);
if head.starts_with(b"\x7FELF") { if head.starts_with(b"\x7FELF") {
match elf::open_elf_file(file)? { match elf::open_elf_file(file)? {
ElfKind::Static(elf, file) => { ElfKind::Static(elf, file) => {

8
test.c
View File

@ -2,8 +2,12 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <assert.h> #include <assert.h>
#include <stdlib.h>
#include <fcntl.h>
int main(int argc, const char **argv) {
int x = 1234;
printf("Hello %d!!!\n", x);
int main() {
printf("Hello!\n");
return 0; return 0;
} }

View File

@ -94,6 +94,8 @@ fn run<P: AsRef<Path>>(path: P, args: &[String]) -> Result<(), Error> {
// Then relocate the main object // Then relocate the main object
main_object.relocate(&mut state)?; main_object.relocate(&mut state)?;
debug_trace!("Load finished");
if !state.undefined_references.is_empty() { if !state.undefined_references.is_empty() {
for item in state.undefined_references.iter() { for item in state.undefined_references.iter() {
eprintln!("Undefined reference to {:?}", item); eprintln!("Undefined reference to {:?}", item);

View File

@ -56,6 +56,7 @@ impl ObjectTls {
impl Object { impl Object {
pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, Error> { pub fn open<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
let path = path.as_ref().to_owned(); let path = path.as_ref().to_owned();
debug_trace!("Object::open({:?})", path);
let file = BufReader::new(File::open(&path)?); let file = BufReader::new(File::open(&path)?);
let mut elf = ElfStream::open_stream(file)?; let mut elf = ElfStream::open_stream(file)?;
let file = BufReader::new(File::open(&path)?); let file = BufReader::new(File::open(&path)?);
@ -123,6 +124,7 @@ impl Object {
return Ok(None); return Ok(None);
} }
let vma = self.elf.ehdr.e_entry as usize; let vma = self.elf.ehdr.e_entry as usize;
debug_trace!("entry = {:#x}", mapping.base + vma - self.vma_start);
Ok(Some(unsafe { Ok(Some(unsafe {
std::mem::transmute(mapping.base + vma - self.vma_start) std::mem::transmute(mapping.base + vma - self.vma_start)
@ -138,6 +140,7 @@ impl Object {
let size = self.vma_end - self.vma_start; let size = self.vma_end - self.vma_start;
let mut mapping = ObjectMapping::new(size)?; let mut mapping = ObjectMapping::new(size)?;
let base = mapping.base;
let object_data = mapping.as_slice_mut(); let object_data = mapping.as_slice_mut();
for segment in self.elf.segments() { for segment in self.elf.segments() {
@ -154,6 +157,13 @@ impl Object {
elf::abi::PT_LOAD => { elf::abi::PT_LOAD => {
let rel_offset = segment.p_vaddr as usize - self.vma_start; let rel_offset = segment.p_vaddr as usize - self.vma_start;
debug_trace!(
"{:?} {:#x?} -> {:#x?}",
self.path,
segment.p_vaddr..segment.p_vaddr + mem_size as u64,
base + rel_offset..base + rel_offset + mem_size
);
let segment_data = &mut object_data[rel_offset..rel_offset + mem_size]; let segment_data = &mut object_data[rel_offset..rel_offset + mem_size];
if file_size > 0 { if file_size > 0 {
@ -189,7 +199,7 @@ impl Object {
continue; continue;
} }
state.export_symbol(dynsym, mapping.base, &self.path, self.tls_module_id); state.export_symbol(dynsym, mapping.base, &self.path, self.tls_module_id, self.vma_start);
} }
self.mapping = Some(mapping); self.mapping = Some(mapping);
@ -201,6 +211,7 @@ impl Object {
for dynsym in self.dynamic_symbol_array.iter_mut() { for dynsym in self.dynamic_symbol_array.iter_mut() {
if dynsym.value.is_none() { if dynsym.value.is_none() {
debug_trace!("Resolve {:?}", dynsym.name);
state.resolve_symbol(dynsym); state.resolve_symbol(dynsym);
} else if dynsym.raw.st_shndx == elf::abi::SHN_UNDEF { } else if dynsym.raw.st_shndx == elf::abi::SHN_UNDEF {
state.undefined_references.push(dynsym.name.clone()); state.undefined_references.push(dynsym.name.clone());
@ -227,8 +238,9 @@ impl Object {
self.tls_module_id, self.tls_module_id,
|idx| Ok(&self.dynamic_symbol_array[idx as usize]), |idx| Ok(&self.dynamic_symbol_array[idx as usize]),
mapping.base, mapping.base,
self.vma_start
)? { )? {
value.write(mapping, entry.r_offset); value.write(mapping, entry.r_offset - self.vma_start as u64);
} }
} }
} }

View File

@ -35,6 +35,7 @@ pub trait RelocationExt {
tls_module_id: Option<usize>, tls_module_id: Option<usize>,
image_symbol: F, image_symbol: F,
image_base: usize, image_base: usize,
vma_start: usize,
) -> Result<Option<RelValue>, Error>; ) -> Result<Option<RelValue>, Error>;
} }
@ -46,6 +47,7 @@ impl RelocationExt for Rela {
tls_module_id: Option<usize>, tls_module_id: Option<usize>,
image_symbol: F, image_symbol: F,
image_base: usize, image_base: usize,
vma_start: usize,
) -> Result<Option<RelValue>, Error> { ) -> Result<Option<RelValue>, Error> {
let image_base = image_base as i64; let image_base = image_base as i64;
let symbol = image_symbol(self.r_sym)?; let symbol = image_symbol(self.r_sym)?;
@ -114,6 +116,7 @@ impl RelocationExt for Rela {
tls_module_id: Option<usize>, tls_module_id: Option<usize>,
image_symbol: F, image_symbol: F,
image_base: usize, image_base: usize,
vma_start: usize,
) -> Result<Option<RelValue>, Error> { ) -> Result<Option<RelValue>, Error> {
let image_base = image_base as i64; let image_base = image_base as i64;
let symbol = image_symbol(self.r_sym)?; let symbol = image_symbol(self.r_sym)?;

View File

@ -51,6 +51,7 @@ impl State {
load_base: usize, load_base: usize,
source: P, source: P,
tls_index: Option<usize>, tls_index: Option<usize>,
vma_start: usize,
) { ) {
if sym.raw.st_symtype() == elf::abi::STT_TLS { if sym.raw.st_symtype() == elf::abi::STT_TLS {
// If it exports TLS symbols, it has TLS, I guess // If it exports TLS symbols, it has TLS, I guess
@ -72,7 +73,7 @@ impl State {
sym.value = Some(value); sym.value = Some(value);
sym.tls_index = Some(module_id); sym.tls_index = Some(module_id);
} else { } else {
let sym_value = sym.raw.st_value as usize + load_base; let sym_value = sym.raw.st_value as usize + load_base - vma_start;
let value = if let Some((value, _)) = self.symbol_table.get(&sym.name) { let value = if let Some((value, _)) = self.symbol_table.get(&sym.name) {
*value *value
} else { } else {

View File

@ -65,6 +65,12 @@ dependencies = [
"windows-sys 0.59.0", "windows-sys 0.59.0",
] ]
[[package]]
name = "autocfg"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.6.0" version = "2.6.0"
@ -124,6 +130,15 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
version = "0.4.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
dependencies = [
"num-traits",
]
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.5.20" version = "4.5.20"
@ -245,6 +260,15 @@ version = "2.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
[[package]]
name = "num-traits"
version = "0.2.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [
"autocfg",
]
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.20.2" version = "1.20.2"
@ -570,6 +594,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cbindgen", "cbindgen",
"chrono",
"libyalloc", "libyalloc",
"yggdrasil-abi", "yggdrasil-abi",
"yggdrasil-rt", "yggdrasil-rt",

View File

@ -4,13 +4,15 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[lib] [lib]
crate-type = ["staticlib"] crate-type = ["cdylib", "staticlib"]
[dependencies] [dependencies]
yggdrasil-rt = { path = "../../../lib/runtime" } yggdrasil-rt = { path = "../../../lib/runtime" }
yggdrasil-abi = { path = "../../../lib/abi", features = ["alloc", "bytemuck"] } yggdrasil-abi = { path = "../../../lib/abi", features = ["alloc", "bytemuck"] }
libyalloc = { path = "../../../lib/libyalloc" } libyalloc = { path = "../../../lib/libyalloc" }
bitflags = "2.6.0" bitflags = "2.6.0"
chrono = { version = "0.4.31", default-features = false }
[build-dependencies] [build-dependencies]
cbindgen = { git = "https://git.alnyan.me/yggdrasil/cbindgen.git", branch = "master" } cbindgen = { git = "https://git.alnyan.me/yggdrasil/cbindgen.git", branch = "master" }

View File

@ -1,5 +1,8 @@
use std::{ use std::{
env, fs::{self, DirEntry}, path::Path env,
fs::{self, DirEntry},
path::{Path, PathBuf},
process::Command,
}; };
const RENAMES: &[(&str, &str)] = &[ const RENAMES: &[(&str, &str)] = &[
@ -32,9 +35,7 @@ fn generate_header(config_path: impl AsRef<Path>, header_output: impl AsRef<Path
.unwrap() .unwrap()
.replace("_", "/"); .replace("_", "/");
// TODO use outer workspace's target directory? // TODO use outer workspace's target directory?
let header_path = header_output let header_path = header_output.join(&relative_path).with_extension("h");
.join(&relative_path)
.with_extension("h");
let mod_path = config_path.with_file_name("mod.rs"); let mod_path = config_path.with_file_name("mod.rs");
let mut config = cbindgen::Config::from_file(config_path).unwrap(); let mut config = cbindgen::Config::from_file(config_path).unwrap();
@ -52,11 +53,32 @@ fn generate_header(config_path: impl AsRef<Path>, header_output: impl AsRef<Path
.write_to_file(header_path); .write_to_file(header_path);
} }
fn compile_crt0(arch: &str, output_dir: impl AsRef<Path>) {
let output_dir = output_dir.as_ref();
let mut command = Command::new("clang");
command
.arg(format!("--target={}-unknown-none", arch))
.arg("-nostdlib")
.arg("-nostdinc")
.arg("-c")
.arg("-o")
.arg(output_dir.join("crt0.o"))
.arg(format!("crt/{}/crt0.S", arch));
if !command.status().unwrap().success() {
panic!("Couldn't compile crt0.S");
}
}
fn main() { fn main() {
let target = env::var("TARGET").expect("$TARGET is not set"); let target = env::var("TARGET").expect("$TARGET is not set");
let profile = env::var("PROFILE").expect("$PROFILE is not set"); let profile = env::var("PROFILE").expect("$PROFILE is not set");
let arch = env::var("CARGO_CFG_TARGET_ARCH").expect("$CARGO_CFG_TARGET_ARCH is not set");
let header_output = format!("target/{target}/{profile}/include"); let output_dir = PathBuf::from(format!("target/{target}/{profile}"));
let header_output = output_dir.join("include");
compile_crt0(&arch, output_dir);
fs::read_dir("src/headers") fs::read_dir("src/headers")
.unwrap() .unwrap()
@ -72,4 +94,3 @@ fn main() {
generate_header(&p, &header_output); generate_header(&p, &header_output);
}); });
} }

View File

@ -0,0 +1,11 @@
.section .text
.global _start
.extern __ygglibc_entry
.type _start, %function
_start:
// %rdi -- kernel argument
leaq __ygglibc_entry(%rip), %rax
jmp *%rax
.size _start, . - _start

View File

@ -13,11 +13,18 @@
"executables": true, "executables": true,
"panic-strategy": "abort", "panic-strategy": "abort",
"dynamic-linking": true, "dynamic-linking": true,
"relocation-model": "static", "relocation-model": "pic",
"position-independent-executables": false, "position-independent-executables": true,
"crt-static-allows-dylibs": true,
"has-thread-local": false, "has-thread-local": false,
"linker": "rust-lld", "linker": "rust-lld",
"linker-flavor": "ld.lld" "linker-flavor": "ld.lld",
"late-link-args-dynamic": {
"ld.lld": [
"--dynamic-linker=/libexec/dyn-loader"
]
}
} }

View File

@ -0,0 +1,16 @@
#ifndef _YGGDRASIL_SYS_STAT_H
#define _YGGDRASIL_SYS_STAT_H 1
#define st_atime st_atim.tv_sec
#define st_mtime st_mtim.tv_sec
#define st_ctime st_ctim.tv_sec
#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
#endif

View File

@ -0,0 +1,6 @@
#ifndef _YGGDRASIL_TIME_H
#define _YGGDRASIL_TIME_H 1
typedef struct timespec __ygg_timespec_t;
#endif

View File

@ -31,6 +31,10 @@ pub trait ResultExt<T, E> {
fn e_map_err<F: FnOnce(E) -> Errno>(self, map: F) -> EResult<T>; fn e_map_err<F: FnOnce(E) -> Errno>(self, map: F) -> EResult<T>;
} }
pub trait OptionExt<T> {
fn e_ok_or(self, err: Errno) -> EResult<T>;
}
pub trait CResult { pub trait CResult {
const ERROR: Self; const ERROR: Self;
} }
@ -144,6 +148,15 @@ impl<T, E> ResultExt<T, E> for Result<T, E> {
} }
} }
impl<T> OptionExt<T> for Option<T> {
fn e_ok_or(self, err: Errno) -> EResult<T> {
match self {
Some(value) => EResult::Ok(value),
None => EResult::Err(err)
}
}
}
impl<T> Try for EResult<T> { impl<T> Try for EResult<T> {
type Output = T; type Output = T;
type Residual = EResult<Infallible>; type Residual = EResult<Infallible>;

View File

@ -1,4 +1,4 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types, non_upper_case_globals)]
// <aio.h> - // <aio.h> -
// <arpa/inet.h> - // <arpa/inet.h> -
@ -60,11 +60,11 @@
// <sys/sem.h> - // <sys/sem.h> -
// <sys/shm.h> - // <sys/shm.h> -
// <sys/socket.h> - // <sys/socket.h> -
// <sys/stat.h> - // <sys/stat.h> =
// <sys/statvfs.h> - // <sys/statvfs.h> -
// <sys/time.h> - // <sys/time.h> =
// <sys/times.h> - // <sys/times.h> -
// <sys/types.h> - // <sys/types.h> +
// <sys/uio.h> - // <sys/uio.h> -
// <sys/un.h> - // <sys/un.h> -
// <sys/utsname.h> - // <sys/utsname.h> -
@ -73,7 +73,7 @@
// <tar.h> - // <tar.h> -
// <termios.h> - // <termios.h> -
// <tgmath.h> - // <tgmath.h> -
// <time.h> - // <time.h> =
// <trace.h> - // <trace.h> -
// <ulimit.h> - // <ulimit.h> -
// <unistd.h> ~ // <unistd.h> ~
@ -96,5 +96,8 @@ pub mod string;
pub mod strings; pub mod strings;
pub mod unistd; pub mod unistd;
pub mod signal; pub mod signal;
pub mod time;
pub mod sys_types; pub mod sys_types;
pub mod sys_stat;
pub mod sys_time;

View File

@ -0,0 +1,416 @@
use core::{
ffi::{c_char, c_double, c_float, c_int, c_long, c_longlong, c_ulong, c_ulonglong},
ptr::{null_mut, NonNull},
};
use crate::util::cstr_matches_insensitive;
// base64
#[no_mangle]
unsafe extern "C" fn a64l(_s: *const c_char) -> c_long {
todo!()
}
#[no_mangle]
unsafe extern "C" fn l64a(_v: c_long) -> *mut c_char {
todo!()
}
// floats
#[no_mangle]
unsafe extern "C" fn atof(s: *const c_char) -> c_double {
strtod(s, null_mut())
}
#[no_mangle]
unsafe extern "C" fn strtod(s: *const c_char, endptr: *mut *mut c_char) -> c_double {
str_to_float_ext(s, endptr) as _
}
#[no_mangle]
unsafe extern "C" fn strtof(s: *const c_char, endptr: *mut *mut c_char) -> c_float {
str_to_float_ext(s, endptr) as _
}
#[no_mangle]
unsafe extern "C" fn strtold(s: *const c_char, endptr: *mut *mut c_char) -> c_double {
str_to_float_ext(s, endptr) as _
}
// ints
#[no_mangle]
unsafe extern "C" fn atoi(s: *const c_char) -> c_int {
str_to_int_ext(s, null_mut(), 10)
}
#[no_mangle]
unsafe extern "C" fn atol(s: *const c_char) -> c_long {
str_to_int_ext(s, null_mut(), 10)
}
#[no_mangle]
unsafe extern "C" fn atoll(s: *const c_char) -> c_longlong {
str_to_int_ext(s, null_mut(), 10)
}
#[no_mangle]
unsafe extern "C" fn strtol(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_long {
str_to_int_ext(s, endptr, base)
}
#[no_mangle]
unsafe extern "C" fn strtoll(
s: *const c_char,
endptr: *mut *mut c_char,
base: c_int,
) -> c_longlong {
str_to_int_ext(s, endptr, base)
}
#[no_mangle]
unsafe extern "C" fn strtoul(s: *const c_char, endptr: *mut *mut c_char, base: c_int) -> c_ulong {
str_to_uint_ext(s, endptr, base)
}
#[no_mangle]
unsafe extern "C" fn strtoull(
s: *const c_char,
endptr: *mut *mut c_char,
base: c_int,
) -> c_ulonglong {
str_to_uint_ext(s, endptr, base)
}
#[derive(Clone, Copy, PartialEq)]
enum Radix {
Oct,
Dec,
Hex,
}
trait StrToInt {
type Unsigned: StrToUint;
const ZERO: Self;
fn from_unsigned(value: Self::Unsigned, sign: bool) -> Self;
}
trait StrToUint {
const ZERO: Self;
fn append_digit(self, digit: u8, radix: Radix) -> Self;
}
impl Radix {
pub fn from_c(c: c_int) -> Option<Self> {
match c {
8 => Some(Self::Oct),
10 => Some(Self::Dec),
16 => Some(Self::Hex),
_ => None,
}
}
pub const fn multiplier(&self) -> u8 {
match self {
Self::Oct => 8,
Self::Dec => 10,
Self::Hex => 16,
}
}
}
impl StrToInt for i32 {
type Unsigned = u32;
const ZERO: Self = 0;
fn from_unsigned(value: Self::Unsigned, sign: bool) -> Self {
match sign {
true => value as Self,
false => -(value as Self),
}
}
}
impl StrToInt for i64 {
type Unsigned = u64;
const ZERO: Self = 0;
fn from_unsigned(value: Self::Unsigned, sign: bool) -> Self {
match sign {
true => value as Self,
false => -(value as Self),
}
}
}
impl StrToUint for u32 {
const ZERO: Self = 0;
fn append_digit(self, digit: u8, radix: Radix) -> Self {
let mul = radix.multiplier();
self * (mul as Self) + (digit as Self)
}
}
impl StrToUint for u64 {
const ZERO: Self = 0;
fn append_digit(self, digit: u8, radix: Radix) -> Self {
let mul = radix.multiplier();
self * (mul as Self) + (digit as Self)
}
}
unsafe fn str_to_int_ext<I: StrToInt>(
src: *const c_char,
endptr: *mut *mut c_char,
base: c_int,
) -> I {
let src = NonNull::new(src.cast_mut()).expect("str_to_int: NULL string");
let radix = Radix::from_c(base);
let (value, end) = str_to_int(src.cast(), radix);
if !endptr.is_null() {
endptr.write(end.as_ptr().cast());
}
value
}
unsafe fn str_to_uint_ext<U: StrToUint>(
src: *const c_char,
endptr: *mut *mut c_char,
base: c_int,
) -> U {
let src = NonNull::new(src.cast_mut()).expect("str_to_uint: NULL string");
let radix = Radix::from_c(base);
let (value, end) = str_to_uint(src.cast(), radix, true);
if !endptr.is_null() {
endptr.write(end.as_ptr().cast());
}
value
}
unsafe fn str_to_float_ext(src: *const c_char, endptr: *mut *mut c_char) -> f64 {
let src = NonNull::new(src.cast_mut()).expect("str_to_float: NULL string");
let (value, end) = str_to_float(src.cast());
if !endptr.is_null() {
endptr.write(end.as_ptr().cast());
}
value
}
unsafe fn str_to_int<I: StrToInt>(mut src: NonNull<u8>, radix: Option<Radix>) -> (I, NonNull<u8>) {
// Skip whitespace
while src.read().is_ascii_whitespace() {
src = src.add(1);
}
// Get sign
let sign = match src.read() {
b'+' => {
src = src.add(1);
true
}
b'-' => {
src = src.add(1);
false
}
_ => true,
};
let (unsigned, endptr) = str_to_uint::<I::Unsigned>(src, radix, false);
(I::from_unsigned(unsigned, sign), endptr)
}
unsafe fn str_to_uint<U: StrToUint>(
mut src: NonNull<u8>,
radix: Option<Radix>,
skip_whitespace: bool,
) -> (U, NonNull<u8>) {
if skip_whitespace {
// Skip whitespace
while src.read().is_ascii_whitespace() {
src = src.add(1);
}
}
// Guess radix if None
let ch = src.read();
let radix = match (ch, radix) {
(b'0', None) => {
let ch = src.add(1).read();
if ch == b'x' || ch == b'X' {
src = src.add(2);
Radix::Hex
} else {
Radix::Oct
}
}
(_, None) => {
// Not 0, 0x or 0X
Radix::Dec
}
(b'0', Some(Radix::Hex)) => {
let ch = src.add(1).read();
if ch == b'x' || ch == b'X' {
src = src.add(2);
}
Radix::Hex
}
(_, Some(radix)) => radix,
};
let mut value = U::ZERO;
loop {
let ch = src.read();
if ch == 0 {
break;
}
let digit = match (ch, radix) {
(b'0'..=b'9', Radix::Dec | Radix::Hex) => ch - b'0',
(b'0'..=b'7', Radix::Oct) => ch - b'0',
(b'a'..=b'f', Radix::Hex) => ch - b'a' + 10,
(b'A'..=b'F', Radix::Hex) => ch - b'A' + 10,
(_, _) => return (value, src),
};
value = value.append_digit(digit, radix);
src = src.add(1);
}
(value, src)
}
unsafe fn str_to_float(mut src: NonNull<u8>) -> (f64, NonNull<u8>) {
// Skip leading whitespace
while src.read().is_ascii_whitespace() {
src = src.add(1);
}
// Get sign
let sign = match src.read() {
b'+' => {
src = src.add(1);
true
}
b'-' => {
src = src.add(1);
false
}
_ => true,
};
// Either:
// * decimal float
// * hex float
// * INF/INFINITY, disregarding case
// * NAN, disregarding case
if is_nan(src) {
return (f64::NAN, src.add(3));
}
if let Some(len) = is_inf(src) {
return match sign {
false => (f64::NEG_INFINITY, src.add(len)),
true => (f64::INFINITY, src.add(len)),
};
}
match is_hex(src) {
true => unimplemented!(),
false => str_to_float_dec(src, sign),
}
}
unsafe fn str_to_float_dec(mut src: NonNull<u8>, sign: bool) -> (f64, NonNull<u8>) {
// 123.456e123
let mut int_part = 0u64;
let mut frac_part = 0u64;
let mut frac_digits = 0;
// Read integer part
loop {
let ch = src.read();
let digit = match ch {
b'0'..=b'9' => ch - b'0',
b'.' | b'E' | b'e' => break,
_ => return (assemble_float(sign, int_part, 0, 0), src),
};
int_part = int_part * 10 + digit as u64;
src = src.add(1);
}
// maybe .
let ch = src.read();
if ch == b'.' {
src = src.add(1);
// Parse fractional part
loop {
let ch = src.read();
let digit = match ch {
b'0'..=b'9' => ch - b'0',
b'e' | b'E' => break,
_ => return (assemble_float(sign, int_part, frac_part, frac_digits), src),
};
frac_part = frac_part * 10 + digit as u64;
frac_digits += 1;
src = src.add(1);
}
}
// maybe exponent
let ch = src.read();
if ch == b'e' || ch == b'E' {
todo!()
}
todo!()
}
unsafe fn is_nan(s: NonNull<u8>) -> bool {
cstr_matches_insensitive(s, b"nan")
}
unsafe fn is_inf(s: NonNull<u8>) -> Option<usize> {
const INFINITY: &[u8] = b"infinity";
const INF: &[u8] = b"inf";
if cstr_matches_insensitive(s, INFINITY) {
Some(INFINITY.len())
} else if cstr_matches_insensitive(s, INF) {
Some(INF.len())
} else {
None
}
}
unsafe fn is_hex(s: NonNull<u8>) -> bool {
cstr_matches_insensitive(s, b"0x")
}
fn powi(f: f64, i: i32) -> f64 {
let mut v = 1.0;
for _ in 0..i {
v *= f;
}
v
}
fn assemble_float(sign: bool, i: u64, f: u64, n: i32) -> f64 {
let i = i as f64;
let f = f as f64 / powi(10.0, n);
let v = i + f;
match sign {
false => -v,
true => v,
}
}

View File

@ -0,0 +1,8 @@
// int grantpt(int);
// char *mkdtemp(char *);
// int mkstemp(char *);
// int posix_openpt(int);
// char *ptsname(int);
// char *realpath(const char *restrict, char *restrict);
// int unlockpt(int);

View File

@ -0,0 +1,47 @@
use core::{
ffi::{c_int, c_void},
ptr::NonNull,
};
use crate::{
allocator,
error::{CPtrResult, OptionExt},
headers::errno,
};
#[no_mangle]
unsafe extern "C" fn calloc(size: usize, nmemb: usize) -> CPtrResult<c_void> {
let size = size.checked_mul(nmemb).e_ok_or(errno::ENOMEM)?;
let ptr = allocator::c_alloc(size, 16, true)?;
CPtrResult::success(ptr)
}
#[no_mangle]
unsafe extern "C" fn free(ptr: *mut c_void) {
match NonNull::new(ptr) {
Some(ptr) => allocator::c_free(ptr),
None => (),
}
}
#[no_mangle]
unsafe extern "C" fn malloc(size: usize) -> CPtrResult<c_void> {
let ptr = allocator::c_alloc(size, 16, false)?;
CPtrResult::success(ptr)
}
#[no_mangle]
unsafe extern "C" fn posix_memalign(
_memptr: *mut *mut c_void,
_alignment: usize,
_size: usize,
) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn realloc(ptr: *mut c_void, size: usize) -> CPtrResult<c_void> {
let old_ptr = NonNull::new(ptr);
let new_ptr = allocator::c_realloc(old_ptr, size)?;
CPtrResult::success(new_ptr)
}

View File

@ -0,0 +1,61 @@
use core::ffi::{c_int, c_long, c_longlong};
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(C)]
pub struct div_t {
pub quot: c_int,
pub rem: c_int
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(C)]
pub struct ldiv_t {
pub quot: c_long,
pub rem: c_long
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
#[repr(C)]
pub struct lldiv_t {
pub quot: c_longlong,
pub rem: c_longlong
}
#[no_mangle]
unsafe extern "C" fn abs(v: c_int) -> c_int {
v.abs()
}
#[no_mangle]
unsafe extern "C" fn labs(v: c_long) -> c_long {
v.abs()
}
#[no_mangle]
unsafe extern "C" fn llabs(v: c_longlong) -> c_longlong {
v.abs()
}
#[no_mangle]
unsafe extern "C" fn div(x: c_int, y: c_int) -> div_t {
div_t {
quot: x / y,
rem: x % y
}
}
#[no_mangle]
unsafe extern "C" fn ldiv(x: c_long, y: c_long) -> ldiv_t {
ldiv_t {
quot: x / y,
rem: x % y
}
}
#[no_mangle]
unsafe extern "C" fn lldiv(x: c_longlong, y: c_longlong) -> lldiv_t {
lldiv_t {
quot: x / y,
rem: x % y
}
}

View File

@ -1,8 +1,28 @@
use core::ffi::c_void; use core::ffi::c_int;
use crate::error::CPtrResult; mod conv;
mod io;
mod malloc;
mod math;
mod process;
mod random;
mod util;
mod wide;
#[no_mangle] pub const EXIT_SUCCESS: c_int = 0;
pub unsafe extern "C" fn malloc(size: usize) -> CPtrResult<c_void> { pub const EXIT_FAILURE: c_int = 1;
todo!()
} pub const MB_CUR_MAX: c_int = 4;
// TODO
// {RAND_MAX}
// Maximum value returned by rand(); at least 32767.
//
// WEXITSTATUS
// WIFEXITED
// WIFSIGNALED
// WIFSTOPPED
// WNOHANG
// WSTOPSIG
// WTERMSIG
// WUNTRACED

View File

@ -0,0 +1,61 @@
use core::ffi::{c_char, c_int};
use crate::{
error::{CIntZeroResult, CPtrResult},
process,
};
#[no_mangle]
unsafe extern "C" fn _Exit(status: c_int) -> ! {
process::c_exit_immediately(status)
}
#[no_mangle]
unsafe extern "C" fn abort() -> ! {
process::abort()
}
#[no_mangle]
unsafe extern "C" fn atexit(_f: extern "C" fn()) -> CIntZeroResult {
todo!()
}
#[no_mangle]
unsafe extern "C" fn exit(status: c_int) -> ! {
process::c_exit(status)
}
#[no_mangle]
unsafe extern "C" fn getenv(_name: *const c_char) -> CPtrResult<c_char> {
todo!()
}
#[no_mangle]
unsafe extern "C" fn putenv(_value: *const c_char) -> CPtrResult<c_char> {
todo!()
}
#[no_mangle]
unsafe extern "C" fn setenv(
_name: *const c_char,
_value: *const c_char,
_overwrite: c_int,
) -> CIntZeroResult {
todo!()
}
// Deprecated
#[no_mangle]
unsafe extern "C" fn setkey(_key: *const c_char) {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn system(_command: *const c_char) -> CIntZeroResult {
todo!()
}
#[no_mangle]
unsafe extern "C" fn unsetenv(_name: *const c_char) -> c_int {
todo!()
}

View File

@ -0,0 +1,17 @@
// double drand48(void);
// double erand48(unsigned short [3]);
// char *initstate(unsigned, char *, size_t);
// long jrand48(unsigned short [3]);
// void lcong48(unsigned short [7]);
// long lrand48(void);
// long mrand48(void);
// long nrand48(unsigned short [3]);
// int rand(void);
// int rand_r(unsigned *);
// long random(void);
// unsigned short *seed48(unsigned short [3]);
// char *setstate(char *);
// void srand(unsigned);
// void srand48(long);
// void srandom(unsigned);

View File

@ -0,0 +1,134 @@
use core::{
cmp::Ordering,
ffi::{c_int, c_void},
};
struct Array {
base: *mut c_void,
size: usize,
nmemb: usize,
}
impl Array {
unsafe fn new(base: *mut c_void, nmemb: usize, size: usize) -> Option<Self> {
if nmemb == 0 || size == 0 || base.is_null() {
return None;
}
Some(Self { base, nmemb, size })
}
fn element(&mut self, i: usize) -> *mut c_void {
if i >= self.nmemb {
panic!("i = {}, nmemb = {}", i, self.nmemb);
}
unsafe { self.base.add(i * self.size) }
}
fn partition<F: Fn(*mut c_void, *mut c_void) -> Ordering>(
&mut self,
lower: usize,
upper: usize,
cmp: &F,
) -> usize {
if lower >= upper {
panic!()
}
let pivot_ptr = self.element(lower);
let mut i = lower;
let mut j = upper;
while i < j {
while i <= upper - 1 && cmp(self.element(i), pivot_ptr).is_le() {
i += 1;
}
while j >= lower + 1 && cmp(self.element(j), pivot_ptr).is_gt() {
j -= 1;
}
if i < j {
self.swap(i, j);
}
}
self.swap(lower, j);
j
}
fn swap(&mut self, i: usize, j: usize) {
let el_i = self.element(i) as *mut u8;
let el_j = self.element(j) as *mut u8;
unsafe {
for i in 0..self.size {
core::ptr::swap(el_i.add(i), el_j.add(i));
}
}
}
fn sort_inner<F: Fn(*mut c_void, *mut c_void) -> Ordering>(
&mut self,
lower: usize,
upper: usize,
cmp: &F,
) {
if lower < upper {
let partition = self.partition(lower, upper, cmp);
if partition != 0 {
self.sort_inner(lower, partition - 1, cmp);
}
self.sort_inner(partition + 1, upper, cmp);
}
}
fn sort<F: Fn(*mut c_void, *mut c_void) -> Ordering>(&mut self, cmp: &F) {
if self.nmemb != 0 {
self.sort_inner(0, self.nmemb - 1, cmp);
}
}
}
pub type qsort_compar_fn_t = extern "C" fn(*const c_void, *const c_void) -> c_int;
pub type qsort_compar_r_fn_t = extern "C" fn(*const c_void, *const c_void, *mut c_void) -> c_int;
pub type bsearch_compar_fn_t = extern "C" fn(*const c_void, *const c_void) -> c_int;
#[no_mangle]
unsafe extern "C" fn bsearch(
_key: *const c_void,
_base: *const c_void,
_nmemb: usize,
_size: usize,
_compar: bsearch_compar_fn_t,
) -> *mut c_void {
todo!()
}
#[no_mangle]
unsafe extern "C" fn qsort(
base: *mut c_void,
nmemb: usize,
size: usize,
compar: qsort_compar_fn_t,
) {
let Some(mut array) = Array::new(base, nmemb, size) else {
return;
};
array.sort(&|a, b| compar(a, b).cmp(&0));
}
#[no_mangle]
unsafe extern "C" fn qsort_r(
base: *mut c_void,
nmemb: usize,
size: usize,
compar: qsort_compar_r_fn_t,
arg: *mut c_void,
) {
let Some(mut array) = Array::new(base, nmemb, size) else {
return;
};
array.sort(&|a, b| compar(a, b, arg).cmp(&0));
}
// int getsubopt(char **, char *const *, char **);

View File

@ -0,0 +1,6 @@
// int mblen(const char *, size_t);
// size_t mbstowcs(wchar_t *restrict, const char *restrict, size_t);
// int mbtowc(wchar_t *restrict, const char *restrict, size_t);
// size_t wcstombs(char *restrict, const wchar_t *restrict, size_t);
// int wctomb(char *, wchar_t);

View File

@ -0,0 +1,19 @@
language = "C"
style = "Tag"
sys_includes = [
"stddef.h",
"stdint.h",
"sys/types.h",
"time.h",
"bits/sys/stat.h"
]
no_includes = true
include_guard = "_SYS_STAT_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = ["stat"]

View File

@ -0,0 +1,221 @@
use core::ffi::{c_char, c_int};
use yggdrasil_rt::io::{FileAttr, FileMode, FileType};
use crate::{
error::CIntZeroResult,
util::{self, PointerStrExt},
};
use super::{
fcntl::{AT_FDCWD, AT_SYMLINK_NOFOLLOW},
sys_time::__ygg_timespec_t,
sys_types::{blkcnt_t, blksize_t, dev_t, gid_t, ino_t, mode_t, nlink_t, off_t, uid_t},
};
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[repr(C)]
pub struct stat {
pub st_dev: dev_t,
pub st_ino: ino_t,
pub st_mode: mode_t,
pub st_nlink: nlink_t,
pub st_uid: uid_t,
pub st_gid: gid_t,
pub st_rdev: dev_t,
pub st_size: off_t,
pub st_atim: __ygg_timespec_t,
pub st_mtim: __ygg_timespec_t,
pub st_ctim: __ygg_timespec_t,
pub st_blksize: blksize_t,
pub st_blocks: blkcnt_t,
}
pub const S_IFMT: c_int = 0xF << 16;
pub const S_IFBLK: c_int = 1 << 16;
pub const S_IFCHR: c_int = 2 << 16;
pub const S_IFIFO: c_int = 3 << 16;
pub const S_IFREG: c_int = 4 << 16;
pub const S_IFDIR: c_int = 5 << 16;
pub const S_IFLNK: c_int = 6 << 16;
pub const S_IFSOCK: c_int = 7 << 16;
pub const S_IRWXU: c_int = 0x7 << 6;
pub const S_IRUSR: c_int = 0x4 << 6;
pub const S_IWUSR: c_int = 0x2 << 6;
pub const S_IXUSR: c_int = 0x1 << 6;
pub const S_IRWXG: c_int = 0x7 << 3;
pub const S_IRGRP: c_int = 0x4 << 3;
pub const S_IWGRP: c_int = 0x2 << 3;
pub const S_IXGRP: c_int = 0x1 << 3;
pub const S_IRWXO: c_int = 0x7 << 0;
pub const S_IROTH: c_int = 0x4 << 0;
pub const S_IWOTH: c_int = 0x2 << 0;
pub const S_IXOTH: c_int = 0x1 << 0;
pub const S_ISUID: c_int = 1 << 11;
pub const S_ISGID: c_int = 1 << 10;
pub const S_ISVTX: c_int = 1 << 9;
impl From<FileAttr> for stat {
fn from(value: FileAttr) -> Self {
// TODO no translation for st_dev/st_rdev/st_ino/etc
let mut st = Self::default();
st.st_mode = (value.mode.bits() & 0o777) as _;
match value.ty {
FileType::Block => st.st_mode |= S_IFBLK,
FileType::Char => st.st_mode |= S_IFCHR,
FileType::File => st.st_mode |= S_IFREG,
FileType::Directory => st.st_mode |= S_IFDIR,
FileType::Symlink => st.st_mode |= S_IFLNK,
}
st.st_size = value.size.try_into().unwrap();
// TODO
st.st_uid = u32::from(value.uid).try_into().unwrap();
st.st_gid = u32::from(value.gid).try_into().unwrap();
// TODO
st.st_blksize = 512;
st.st_blocks = (st.st_size + 511) / 512;
// TODO
st.st_nlink = 1;
st
}
}
#[no_mangle]
unsafe extern "C" fn chmod(_pathname: *const c_char, _mode: mode_t) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn fchmod(_fd: c_int, _mode: mode_t) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn fchmodat(
_fd: c_int,
_pathname: *const c_char,
_mode: mode_t,
_opt: c_int,
) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn umask(_mode: mode_t) -> mode_t {
todo!()
// let new = FileMode::new((mode as u32) & 0o777);
// let old = process::update_umask(new);
// old.bits() as mode_t
}
// Create stuff
#[no_mangle]
unsafe extern "C" fn mkdir(pathname: *const c_char, mode: mode_t) -> CIntZeroResult {
mkdirat(AT_FDCWD, pathname, mode)
}
#[no_mangle]
unsafe extern "C" fn mkdirat(atfd: c_int, pathname: *const c_char, mode: mode_t) -> CIntZeroResult {
let _pathname = pathname.ensure_str();
let _atfd = util::at_fd(atfd)?;
let _mode = FileMode::new((mode & 0o777) as u32);
todo!()
// io::create_directory(atfd, pathname, mode)?;
// CIntZeroResult::OK
}
#[no_mangle]
unsafe extern "C" fn mkfifo(_pathname: *const c_char, _mode: mode_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn mkfifoat(_atfd: c_int, _pathname: *const c_char, _mode: mode_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn mknod(_pathname: *const c_char, _mode: mode_t, _dev: dev_t) -> c_int {
unimplemented!()
}
#[no_mangle]
unsafe extern "C" fn mknodat(
_atfd: c_int,
_pathname: *const c_char,
_mode: mode_t,
_dev: dev_t,
) -> c_int {
unimplemented!()
}
// File status
#[no_mangle]
unsafe extern "C" fn fstat(_fd: c_int, _statbuf: *mut stat) -> CIntZeroResult {
todo!()
// let fd = RawFd::e_try_from(fd)?;
// let attr = io::get_metadata(Some(fd), "", false)?;
// if let Some(statbuf) = statbuf.as_mut() {
// *statbuf = attr.into();
// }
// CIntZeroResult::OK
}
#[no_mangle]
unsafe extern "C" fn fstatat(
atfd: c_int,
pathname: *const c_char,
_statbuf: *mut stat,
opt: c_int,
) -> CIntZeroResult {
let _pathname = pathname.ensure_str();
let _atfd = util::at_fd(atfd)?;
let _follow = opt & AT_SYMLINK_NOFOLLOW == 0;
todo!()
// let attr = io::get_metadata(atfd, pathname, follow)?;
// if let Some(statbuf) = statbuf.as_mut() {
// *statbuf = attr.into();
// }
// CIntZeroResult::OK
}
#[no_mangle]
unsafe extern "C" fn lstat(pathname: *const c_char, statbuf: *mut stat) -> CIntZeroResult {
fstatat(AT_FDCWD, pathname, statbuf, AT_SYMLINK_NOFOLLOW)
}
#[no_mangle]
unsafe extern "C" fn stat(pathname: *const c_char, statbuf: *mut stat) -> CIntZeroResult {
fstatat(AT_FDCWD, pathname, statbuf, 0)
}
// File time updates
#[no_mangle]
unsafe extern "C" fn futimens(_fd: c_int, _times: *const __ygg_timespec_t) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn utimensat(
_atfd: c_int,
_pathname: *const c_char,
_times: *const __ygg_timespec_t,
_opt: c_int,
) -> c_int {
todo!()
}

View File

@ -0,0 +1,14 @@
language = "C"
style = "Tag"
sys_includes = ["stdarg.h", "stddef.h", "stdint.h", "sys/types.h"]
no_includes = true
include_guard = "_SYS_TIME_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = ["timeval", "timespec", "__ygg_timeval_t", "__ygg_timespec_t"]
exclude = []

View File

@ -0,0 +1,20 @@
use core::ffi::c_long;
use super::sys_types::{suseconds_t, time_t};
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[repr(C)]
pub struct timeval {
pub tv_sec: time_t,
pub tv_usec: suseconds_t,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[repr(C)]
pub struct timespec {
pub tv_sec: time_t,
pub tv_nsec: c_long,
}
pub type __ygg_timeval_t = timeval;
pub type __ygg_timespec_t = timespec;

View File

@ -32,3 +32,7 @@ pub struct time_t(pub i64);
pub type off_t = i64; pub type off_t = i64;
pub type suseconds_t = c_ulong; pub type suseconds_t = c_ulong;
impl time_t {
pub const INVALID: Self = Self(i64::MAX);
}

View File

@ -0,0 +1,20 @@
language = "C"
style = "Tag"
sys_includes = [
"stddef.h",
"stdint.h",
"locale.h",
"sys/types.h",
"sys/time.h",
"bits/time.h",
]
no_includes = true
include_guard = "_TIME_H"
usize_type = "size_t"
isize_type = "ssize_t"
[export]
include = ["tm", "itimerspec"]

View File

@ -0,0 +1,64 @@
use core::{cmp::Ordering, mem::MaybeUninit, ptr::null_mut};
use chrono::Utc;
use crate::headers::{sys_types::time_t, time::tm};
use super::{get_timezone, CDateTime};
#[no_mangle]
unsafe extern "C" fn gmtime(tp: *const time_t) -> *mut tm {
static mut BUFFER: MaybeUninit<tm> = MaybeUninit::uninit();
gmtime_r(tp, BUFFER.as_mut_ptr())
}
#[no_mangle]
unsafe extern "C" fn gmtime_r(tp: *const time_t, timep: *mut tm) -> *mut tm {
let tp = tp.as_ref().unwrap();
let timep = timep.as_mut().unwrap();
match tp.to_datetime(Utc) {
Some(t) => {
*timep = t.into();
timep
}
None => null_mut(),
}
}
#[no_mangle]
unsafe extern "C" fn localtime(tp: *const time_t) -> *mut tm {
static mut BUFFER: MaybeUninit<tm> = MaybeUninit::uninit();
localtime_r(tp, BUFFER.as_mut_ptr())
}
#[no_mangle]
unsafe extern "C" fn localtime_r(tp: *const time_t, timep: *mut tm) -> *mut tm {
let tp = tp.as_ref().unwrap();
let timep = timep.as_mut().unwrap();
let tz = get_timezone();
match tp.to_datetime(tz) {
Some(t) => {
*timep = t.into();
timep
}
None => null_mut(),
}
}
#[no_mangle]
unsafe extern "C" fn mktime(timep: *const tm) -> time_t {
let timep = timep.as_ref().unwrap();
let _is_dst = match timep.tm_isdst.cmp(&0) {
Ordering::Less => todo!(),
Ordering::Equal => false,
Ordering::Greater => true,
};
let tz = get_timezone();
match timep.to_datetime(tz) {
Some(t) => time_t(t.timestamp() as _),
None => time_t::INVALID,
}
}

View File

@ -0,0 +1,113 @@
use core::{
ffi::{c_char, c_int, c_long},
ptr::null_mut,
time::Duration,
};
use chrono::{DateTime, Datelike, NaiveDate, NaiveDateTime, NaiveTime, TimeZone, Timelike, Utc};
use super::{sys_time::__ygg_timespec_t, sys_types::time_t};
mod convert;
mod string;
mod timer;
mod util;
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[repr(C)]
pub struct itimerspec {
pub it_interval: __ygg_timespec_t,
pub it_value: __ygg_timespec_t,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Default)]
#[repr(C)]
pub struct tm {
pub tm_sec: c_int,
pub tm_min: c_int,
pub tm_hour: c_int,
pub tm_mday: c_int,
pub tm_mon: c_int,
pub tm_year: c_int,
pub tm_wday: c_int,
pub tm_yday: c_int,
pub tm_isdst: c_int,
}
#[no_mangle]
pub static mut daylight: c_int = 0;
#[no_mangle]
pub static mut timezone: c_long = 0;
#[no_mangle]
pub static mut tzname: *mut *mut c_char = null_mut();
pub trait CDateTime {
fn to_naive_datetime(&self) -> Option<NaiveDateTime>;
fn to_datetime<Tz: TimeZone>(&self, tz: Tz) -> Option<DateTime<Tz>> {
self.to_naive_datetime()?.and_local_timezone(tz).latest()
}
}
impl tm {
pub fn naive_date(&self) -> Option<NaiveDate> {
NaiveDate::from_ymd_opt(
self.tm_year + 1900,
u32::try_from(self.tm_mon).ok()? + 1,
u32::try_from(self.tm_mday).ok()?,
)
}
pub fn naive_time(&self) -> Option<NaiveTime> {
NaiveTime::from_hms_opt(
u32::try_from(self.tm_hour).ok()?,
u32::try_from(self.tm_min).ok()?,
u32::try_from(self.tm_sec).ok()?,
)
}
}
impl CDateTime for tm {
fn to_naive_datetime(&self) -> Option<NaiveDateTime> {
let date = self.naive_date()?;
let time = self.naive_time()?;
Some(NaiveDateTime::new(date, time))
}
}
impl CDateTime for time_t {
fn to_naive_datetime(&self) -> Option<NaiveDateTime> {
NaiveDateTime::from_timestamp_opt(self.0, 0)
}
}
impl<T: Datelike + Timelike> From<T> for tm {
fn from(value: T) -> Self {
Self {
tm_sec: value.second() as _,
tm_min: value.minute() as _,
tm_hour: value.hour() as _,
tm_mday: value.day() as _,
tm_mon: value.month0() as _,
tm_year: value.year() - 1900,
tm_wday: value.weekday().num_days_from_sunday() as _,
tm_yday: value.ordinal0() as _,
tm_isdst: 0,
}
}
}
impl From<__ygg_timespec_t> for Duration {
fn from(value: __ygg_timespec_t) -> Self {
Self::new(
value.tv_sec.0.try_into().unwrap(),
value.tv_nsec.try_into().unwrap(),
)
}
}
pub unsafe fn get_timezone() -> impl TimeZone {
// TODO get it from C
Utc
}

View File

@ -0,0 +1,112 @@
use core::{ffi::c_char, ptr::{null_mut, NonNull}};
use chrono::{Datelike, TimeZone, Timelike, Utc};
use crate::{headers::{locale::locale_t, sys_types::time_t}, util::CStringWriter};
use super::{get_timezone, tm, CDateTime};
unsafe fn fmt_time<Tz: TimeZone, T: CDateTime>(
t: &T,
tz: Tz,
buffer: *mut c_char,
) -> Option<NonNull<c_char>> {
const MONTHS: &[&str] = &[
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
];
const WDAYS: &[&str] = &["Sun", "Mon", "Wed", "Thu", "Fri", "Sat"];
use core::fmt::Write;
let dt = t.to_datetime(tz)?;
let mut writer = CStringWriter::from_ptr(buffer, usize::MAX)?;
writeln!(
writer,
"{} {} {:02} {:02}:{:02}:{:02} {:04}",
WDAYS[dt.weekday().num_days_from_sunday() as usize],
MONTHS[dt.month0() as usize],
dt.day(),
dt.hour(),
dt.minute(),
dt.second(),
dt.year()
)
.ok()?;
writer.finish()
}
#[no_mangle]
unsafe extern "C" fn asctime(timep: *const tm) -> *mut c_char {
static mut BUFFER: [c_char; 32] = [0; 32];
asctime_r(timep, BUFFER.as_mut_ptr())
}
#[no_mangle]
unsafe extern "C" fn asctime_r(timep: *const tm, buffer: *mut c_char) -> *mut c_char {
let timep = timep.as_ref().unwrap();
// Utc, already accounts for timezone
match fmt_time(timep, Utc, buffer) {
Some(ptr) => ptr.as_ptr(),
None => null_mut()
}
}
#[no_mangle]
unsafe extern "C" fn ctime(tp: *const time_t) -> *mut c_char {
static mut BUFFER: [c_char; 32] = [0; 32];
ctime_r(tp, BUFFER.as_mut_ptr())
}
#[no_mangle]
unsafe extern "C" fn ctime_r(tp: *const time_t, buffer: *mut c_char) -> *mut c_char {
let tp = tp.as_ref().unwrap();
let tz = get_timezone();
match fmt_time(tp, tz, buffer) {
Some(ptr) => ptr.as_ptr(),
None => null_mut()
}
}
#[no_mangle]
unsafe extern "C" fn getdate(_string: *const c_char) -> *mut tm {
todo!()
}
#[no_mangle]
unsafe extern "C" fn getdate_r(_string: *const c_char, _timep: *mut tm) -> *mut tm {
todo!()
}
#[no_mangle]
unsafe extern "C" fn strftime(
_dst: *mut c_char,
_len: usize,
_format: *const c_char,
_timep: *const tm,
) -> usize {
todo!()
}
#[no_mangle]
unsafe extern "C" fn strftime_l(
_dst: *mut c_char,
_len: usize,
_format: *const c_char,
_timep: *const tm,
_locale: locale_t,
) -> usize {
todo!()
}
#[no_mangle]
unsafe extern "C" fn strptime(
_src: *const c_char,
_format: *const c_char,
_timep: *mut tm,
) -> *mut c_char {
todo!()
}

View File

@ -0,0 +1,55 @@
use core::ffi::c_int;
use crate::headers::{
sys_time::__ygg_timespec_t,
sys_types::{clock_t, clockid_t, pid_t},
};
/*
TODO
int timer_create(clockid_t, struct sigevent *restrict,
timer_t *restrict);
int timer_delete(timer_t);
int timer_getoverrun(timer_t);
int timer_gettime(timer_t, struct itimerspec *);
int timer_settime(timer_t, int, const struct itimerspec *restrict,
struct itimerspec *restrict);
*/
#[no_mangle]
unsafe extern "C" fn clock() -> clock_t {
// TODO
0
}
#[no_mangle]
unsafe extern "C" fn clock_getcpuclockid(_pid: pid_t, _clock_id_ptr: *mut clockid_t) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn clock_getres(_clock_id: clockid_t, _ts: *mut __ygg_timespec_t) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn clock_gettime(_clock_id: clockid_t, _ts: *mut __ygg_timespec_t) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn clock_settime(_clock_id: clockid_t, _ts: *const __ygg_timespec_t) -> c_int {
todo!()
}
#[no_mangle]
unsafe extern "C" fn clock_nanosleep(
_clock_id: clockid_t,
_flags: c_int,
_rqtp: *const __ygg_timespec_t,
_rmtp: *mut __ygg_timespec_t,
) -> c_int {
todo!()
}
// TODO Timer something

View File

@ -0,0 +1,39 @@
use core::{ffi::c_double, time::Duration};
use crate::{
error::CIntZeroResult,
headers::{sys_time::__ygg_timespec_t, sys_types::time_t},
process,
};
#[no_mangle]
unsafe extern "C" fn nanosleep(
rqtp: *const __ygg_timespec_t,
rmtp: *mut __ygg_timespec_t,
) -> CIntZeroResult {
let rqtp = rqtp.as_ref().unwrap();
if let Some(_rmtp) = rmtp.as_mut() {
todo!();
}
let amount = Duration::from(*rqtp);
process::sleep(amount)?;
CIntZeroResult::SUCCESS
}
#[no_mangle]
unsafe extern "C" fn time(_tp: *mut time_t) -> time_t {
todo!()
}
#[no_mangle]
unsafe extern "C" fn tzset() {
todo!()
}
#[no_mangle]
unsafe extern "C" fn difftime(_a: time_t, _b: time_t) -> c_double {
todo!()
}

View File

@ -9,36 +9,40 @@
slice_internals slice_internals
)] )]
#![allow(internal_features)] #![allow(internal_features)]
#![no_std] #![cfg_attr(not(test), no_std)]
extern crate alloc; extern crate alloc;
use core::{ #[cfg(test)]
ffi::{c_char, c_int}, extern crate std;
panic::PanicInfo,
ptr::null,
};
use alloc::vec::Vec;
use yggdrasil_rt::{debug_trace, process::Signal};
mod allocator; mod allocator;
mod args; mod args;
mod error; mod error;
mod io; mod io;
mod panic;
mod process; mod process;
mod sync; mod sync;
mod types; mod types;
mod util; mod util;
mod ssp;
pub mod headers; pub mod headers;
#[no_mangle] #[no_mangle]
unsafe extern "C" fn _start(arg: usize) { unsafe extern "C" fn __ygglibc_entry(arg: usize) {
use core::{
ffi::{c_char, c_int},
ptr::null,
};
use alloc::vec::Vec;
extern "C" { extern "C" {
fn main(argc: c_int, argv: *const *const c_char, envp: *const *const c_char) -> c_int; fn main(argc: c_int, argv: *const *const c_char, envp: *const *const c_char) -> c_int;
} }
ssp::init();
io::init(); io::init();
// Setup args // Setup args
@ -63,15 +67,3 @@ unsafe extern "C" fn _start(arg: usize) {
process::c_exit(status) process::c_exit(status)
} }
#[panic_handler]
fn panic_handler(pi: &PanicInfo) -> ! {
debug_trace!("PANIC {:?}", &pi);
// Kill myself
unsafe {
let pid = yggdrasil_rt::sys::get_pid();
yggdrasil_rt::sys::send_signal(pid, Signal::Aborted).ok();
unreachable!()
}
}

View File

@ -0,0 +1,8 @@
#[cfg(any(not(test), rust_analyzer))]
#[panic_handler]
fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
yggdrasil_rt::debug_trace!("PANIC {:?}", &pi);
// Kill myself
super::process::abort();
}

View File

@ -1,6 +1,6 @@
use core::{ffi::{c_char, c_int, CStr}, ptr::NonNull, time::Duration}; use core::{ffi::{c_char, c_int, CStr}, ptr::NonNull, time::Duration};
use yggdrasil_rt::{process::ExitCode, sys as syscall}; use yggdrasil_rt::{process::{ExitCode, Signal}, sys as syscall};
use crate::{error::EResult, headers::sys_types::pid_t, io::{self, managed::stderr}}; use crate::{error::EResult, headers::sys_types::pid_t, io::{self, managed::stderr}};
@ -20,7 +20,9 @@ pub fn sleep(duration: Duration) -> EResult<()> {
} }
pub fn abort() -> ! { pub fn abort() -> ! {
todo!() let pid = unsafe { syscall::get_pid() };
unsafe { syscall::send_signal(pid, Signal::Aborted).ok() };
unreachable!()
} }
pub fn c_exit_immediately(status: c_int) -> ! { pub fn c_exit_immediately(status: c_int) -> ! {

View File

@ -0,0 +1,15 @@
#![allow(non_upper_case_globals)]
#[no_mangle]
static mut __stack_chk_guard: usize = 0;
#[no_mangle]
unsafe extern "C" fn __stack_chk_fail() -> ! {
panic!("!!! Stack smashing detected !!!")
}
#[allow(static_mut_refs)]
pub unsafe fn init() {
// TODO generate random
__stack_chk_guard = 1234;
}

View File

@ -1,14 +1,25 @@
use core::ffi::{c_char, c_int, CStr}; use core::{
ffi::{c_char, c_int, CStr},
fmt,
ptr::NonNull,
};
use yggdrasil_rt::io::RawFd; use yggdrasil_rt::io::RawFd;
use crate::{error::{EResult, TryFromExt}, headers::{errno, fcntl::AT_FDCWD}}; use crate::{
error::{EResult, TryFromExt},
headers::{errno, fcntl::AT_FDCWD},
};
pub trait PointerExt { pub trait PointerExt {
unsafe fn ensure(self: *const Self) -> &'static Self; unsafe fn ensure(self: *const Self) -> &'static Self;
unsafe fn ensure_mut(self: *mut Self) -> &'static mut Self; unsafe fn ensure_mut(self: *mut Self) -> &'static mut Self;
unsafe fn ensure_slice(self: *const Self, len: usize) -> &'static [Self] where Self: Sized; unsafe fn ensure_slice(self: *const Self, len: usize) -> &'static [Self]
unsafe fn ensure_slice_mut(self: *mut Self, len: usize) -> &'static mut [Self] where Self: Sized; where
Self: Sized;
unsafe fn ensure_slice_mut(self: *mut Self, len: usize) -> &'static mut [Self]
where
Self: Sized;
} }
pub trait PointerStrExt { pub trait PointerStrExt {
@ -16,6 +27,12 @@ pub trait PointerStrExt {
unsafe fn ensure_cstr(self: *const Self) -> &'static CStr; unsafe fn ensure_cstr(self: *const Self) -> &'static CStr;
} }
pub struct CStringWriter {
ptr: NonNull<c_char>,
pos: usize,
limit: usize,
}
impl<T> PointerExt for T { impl<T> PointerExt for T {
unsafe fn ensure(self: *const Self) -> &'static Self { unsafe fn ensure(self: *const Self) -> &'static Self {
unsafe { self.as_ref().expect("ensure() failed: NULL pointer") } unsafe { self.as_ref().expect("ensure() failed: NULL pointer") }
@ -25,14 +42,20 @@ impl<T> PointerExt for T {
unsafe { self.as_mut().expect("ensure_mut() failed: NULL pointer") } unsafe { self.as_mut().expect("ensure_mut() failed: NULL pointer") }
} }
unsafe fn ensure_slice(self: *const Self, len: usize) -> &'static [Self] where Self: Sized { unsafe fn ensure_slice(self: *const Self, len: usize) -> &'static [Self]
where
Self: Sized,
{
if self.is_null() { if self.is_null() {
panic!("ensure_slice() failed: NULL pointer"); panic!("ensure_slice() failed: NULL pointer");
} }
unsafe { core::slice::from_raw_parts(self, len) } unsafe { core::slice::from_raw_parts(self, len) }
} }
unsafe fn ensure_slice_mut(self: *mut Self, len: usize) -> &'static mut [Self] where Self: Sized { unsafe fn ensure_slice_mut(self: *mut Self, len: usize) -> &'static mut [Self]
where
Self: Sized,
{
if self.is_null() { if self.is_null() {
panic!("ensure_slice_mut() failed: NULL pointer"); panic!("ensure_slice_mut() failed: NULL pointer");
} }
@ -42,7 +65,9 @@ impl<T> PointerExt for T {
impl PointerStrExt for c_char { impl PointerStrExt for c_char {
unsafe fn ensure_str(self: *const Self) -> &'static str { unsafe fn ensure_str(self: *const Self) -> &'static str {
self.ensure_cstr().to_str().expect("ensure_str() failed: not a valid string") self.ensure_cstr()
.to_str()
.expect("ensure_str() failed: not a valid string")
} }
unsafe fn ensure_cstr(self: *const Self) -> &'static CStr { unsafe fn ensure_cstr(self: *const Self) -> &'static CStr {
@ -53,6 +78,40 @@ impl PointerStrExt for c_char {
} }
} }
impl CStringWriter {
pub unsafe fn from_ptr(ptr: *mut c_char, limit: usize) -> Option<Self> {
let ptr = NonNull::new(ptr)?;
Some(Self { ptr, limit, pos: 0 })
}
pub fn finish(self) -> Option<NonNull<c_char>> {
if self.pos != self.limit {
unsafe {
self.ptr.add(self.pos).write(0);
}
Some(self.ptr)
} else {
None
}
}
}
impl fmt::Write for CStringWriter {
fn write_str(&mut self, s: &str) -> fmt::Result {
if self.pos + s.len() < self.limit {
let dst = unsafe {
core::slice::from_raw_parts_mut(self.ptr.add(self.pos).cast().as_ptr(), s.len())
};
dst.copy_from_slice(s.as_bytes());
self.pos += s.len();
Ok(())
} else {
Err(fmt::Error)
}
}
}
pub fn at_fd(fd: c_int) -> EResult<Option<RawFd>> { pub fn at_fd(fd: c_int) -> EResult<Option<RawFd>> {
match fd { match fd {
AT_FDCWD => EResult::Ok(None), AT_FDCWD => EResult::Ok(None),
@ -60,3 +119,23 @@ pub fn at_fd(fd: c_int) -> EResult<Option<RawFd>> {
_ => EResult::Err(errno::EBADF), _ => EResult::Err(errno::EBADF),
} }
} }
pub unsafe fn cstr_prefix<F: Fn(u8, u8) -> bool>(a: NonNull<u8>, b: &[u8], cmp: F) -> bool {
for (i, &bch) in b.iter().enumerate() {
let ach = a.add(i).read();
if ach == 0 || !cmp(ach, bch) {
return false;
}
}
true
}
pub unsafe fn cstr_matches(a: NonNull<u8>, b: &[u8]) -> bool {
cstr_prefix(a, b, |a, b| a == b)
}
pub unsafe fn cstr_matches_insensitive(a: NonNull<u8>, b: &[u8]) -> bool {
cstr_prefix(a, b, |a, b| {
a.to_ascii_lowercase() == b.to_ascii_lowercase()
})
}

View File

@ -80,7 +80,13 @@ impl<'e> CargoBuilder<'e> {
} }
} }
Self::Ygglibc(env) => { Self::Ygglibc(env) => {
let target = format!("{:?}-unknown-none", env.arch); let target = format!(
"{}/{:?}-unknown-none.json",
env.workspace_root
.join("userspace/lib/ygglibc/etc")
.display(),
env.arch
);
command command
.arg(arg) .arg(arg)

View File

@ -17,7 +17,9 @@ use crate::{
use super::{llvm::Llvm, InitrdGenerated}; use super::{llvm::Llvm, InitrdGenerated};
pub struct Ygglibc { pub struct Ygglibc {
lib_file: PathBuf, static_lib_file: PathBuf,
shared_lib_file: PathBuf,
crt0_file: PathBuf,
include_paths: Vec<PathBuf>, include_paths: Vec<PathBuf>,
} }
@ -68,14 +70,23 @@ const PROGRAMS: &[(&str, &str)] = &[
("dyn-loader", "libexec/dyn-loader"), ("dyn-loader", "libexec/dyn-loader"),
// TODO: proper process for C program builds // TODO: proper process for C program builds
("c-test", "c-test"), ("c-test", "c-test"),
("c-test-static", "c-test-static"),
]; ];
fn build_test_c_program(env: &BuildEnv, llvm: &Llvm) -> Result<(), Error> { fn build_test_c_program(env: &BuildEnv, llvm: &Llvm) -> Result<(), Error> {
log::info!("Building a test C program"); log::info!("Building a test C program");
let target_dir = &env.userspace_output_dir; let target_dir = &env.userspace_output_dir;
let mut command = llvm.c_clang(env); let mut command = llvm.c_clang(env);
command command
.args(["-static", "-Og", "-ggdb"]) .args([
"-v",
"-Bdynamic",
"-fpie",
"-O0",
"-ggdb",
"-fstack-protector-strong",
])
.arg("-o") .arg("-o")
.arg(target_dir.join("c-test")) .arg(target_dir.join("c-test"))
.arg(env.workspace_root.join("test.c")); .arg(env.workspace_root.join("test.c"));
@ -84,10 +95,21 @@ fn build_test_c_program(env: &BuildEnv, llvm: &Llvm) -> Result<(), Error> {
return Err(Error::ExternalCommandFailed); return Err(Error::ExternalCommandFailed);
} }
let mut command = llvm.c_clang(env);
command
.args(["-v", "-static", "-O0", "-ggdb", "-fstack-protector-strong"])
.arg("-o")
.arg(target_dir.join("c-test-static"))
.arg(env.workspace_root.join("test.c"));
if !command.status()?.success() {
return Err(Error::ExternalCommandFailed);
}
Ok(()) Ok(())
} }
fn install_ygglibc(env: &BuildEnv, ygglibc: Ygglibc) -> Result<(), Error> { fn install_ygglibc(env: &BuildEnv, ygglibc: &Ygglibc) -> Result<(), Error> {
log::info!("Installing ygglibc into LLVM sysroot"); log::info!("Installing ygglibc into LLVM sysroot");
let dst_lib_dir = env.llvm_sysroot.join("lib"); let dst_lib_dir = env.llvm_sysroot.join("lib");
@ -96,10 +118,12 @@ fn install_ygglibc(env: &BuildEnv, ygglibc: Ygglibc) -> Result<(), Error> {
fs::create_dir_all(&dst_lib_dir)?; fs::create_dir_all(&dst_lib_dir)?;
fs::create_dir_all(&dst_include_dir)?; fs::create_dir_all(&dst_include_dir)?;
fs::copy(ygglibc.lib_file, dst_lib_dir.join("libygglibc.a"))?; fs::copy(&ygglibc.static_lib_file, dst_lib_dir.join("libygglibc.a"))?;
fs::copy(&ygglibc.shared_lib_file, dst_lib_dir.join("libygglibc.so"))?;
fs::copy(&ygglibc.crt0_file, dst_lib_dir.join("crt0.o"))?;
for path in ygglibc.include_paths { for path in ygglibc.include_paths.iter() {
util::copy_dir_recursive(&path, &dst_include_dir)?; util::copy_dir_recursive(path, &dst_include_dir)?;
} }
Ok(()) Ok(())
@ -113,32 +137,38 @@ fn build_ygglibc(env: &BuildEnv) -> Result<Ygglibc, Error> {
env.profile.dir() env.profile.dir()
)); ));
CargoBuilder::Ygglibc(env).build(&ygglibc_dir)?; CargoBuilder::Ygglibc(env).build(&ygglibc_dir)?;
let lib_file = target_dir.join("libygglibc.a");
let static_lib_file = target_dir.join("libygglibc.a");
let shared_lib_file = target_dir.join("libygglibc.so");
let crt0_file = target_dir.join("crt0.o");
let generated_includes = target_dir.join("include"); let generated_includes = target_dir.join("include");
let static_includes = ygglibc_dir.join("include"); let static_includes = ygglibc_dir.join("include");
Ok(Ygglibc { Ok(Ygglibc {
lib_file, static_lib_file,
shared_lib_file,
crt0_file,
include_paths: vec![generated_includes, static_includes], include_paths: vec![generated_includes, static_includes],
}) })
} }
fn build_userspace(env: &BuildEnv, _: AllOk) -> Result<(), Error> { fn build_userspace(env: &BuildEnv, _: AllOk) -> Result<Ygglibc, Error> {
log::info!("Building userspace"); log::info!("Building userspace");
CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace"))?; CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace"))?;
CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace/dynload-program"))?; CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace/dynload-program"))?;
let ygglibc = build_ygglibc(env)?; let ygglibc = build_ygglibc(env)?;
let llvm = llvm::build_llvm(env)?; let llvm = llvm::build_llvm(env)?;
install_ygglibc(env, ygglibc)?; install_ygglibc(env, &ygglibc)?;
build_test_c_program(env, &llvm)?; build_test_c_program(env, &llvm)?;
Ok(()) Ok(ygglibc)
} }
fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>( fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
env: &BuildEnv, env: &BuildEnv,
install_extra: Vec<(PathBuf, PathBuf)>, install_extra: Vec<(PathBuf, PathBuf)>,
ygglibc: &Ygglibc,
build_dir: S, build_dir: S,
rootfs_dir: D, rootfs_dir: D,
_: AllOk, _: AllOk,
@ -186,6 +216,13 @@ fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
env.arch.name() env.arch.name()
), rootfs_dir.join("lib/libstd.so"))?; ), rootfs_dir.join("lib/libstd.so"))?;
log::info!("Installing ygglibc");
util::copy_file(
&ygglibc.shared_lib_file,
rootfs_dir.join("lib/libygglibc.so"),
)?;
log::info!("Installing extras"); log::info!("Installing extras");
for (src, dst) in install_extra { for (src, dst) in install_extra {
util::copy_file(src, rootfs_dir.join(dst))?; util::copy_file(src, rootfs_dir.join(dst))?;
@ -249,10 +286,11 @@ pub fn build_initrd(
) -> Result<InitrdGenerated, Error> { ) -> Result<InitrdGenerated, Error> {
let rootfs_dir = env.userspace_output_dir.join("rootfs"); let rootfs_dir = env.userspace_output_dir.join("rootfs");
build_userspace(env, check)?; let ygglibc = build_userspace(env, check)?;
build_rootfs( build_rootfs(
env, env,
install_extra, install_extra,
&ygglibc,
&env.userspace_output_dir, &env.userspace_output_dir,
&rootfs_dir, &rootfs_dir,
check, check,