libc: libc++ works
This commit is contained in:
parent
bc6a5b115c
commit
465fc53e02
13
test.cpp
Normal file
13
test.cpp
Normal file
@ -0,0 +1,13 @@
|
||||
#include <iostream>
|
||||
|
||||
int main() {
|
||||
std::vector<int> items;
|
||||
items.push_back(1);
|
||||
items.push_back(2);
|
||||
items.push_back(3);
|
||||
|
||||
for (const auto &item: items) {
|
||||
std::cout << "Item: " << item << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -54,10 +54,16 @@ fn run(binary: &str, args: &[String]) -> Result<!, Error> {
|
||||
}
|
||||
|
||||
// Call global constructors before handing off control to the program
|
||||
// .preinit_array, .preinit, ...
|
||||
for (_, lib) in libraries.iter_mut() {
|
||||
lib.call_constructors();
|
||||
unsafe { lib.call_early_constructors() };
|
||||
}
|
||||
root.call_constructors();
|
||||
unsafe { root.call_early_constructors() };
|
||||
// .init_array, .init, ...
|
||||
for (_, lib) in libraries.iter_mut() {
|
||||
unsafe { lib.call_constructors() };
|
||||
}
|
||||
unsafe { root.call_constructors() };
|
||||
|
||||
let entry = root.entry().ok_or(Error::NoEntrypoint)?;
|
||||
debug_trace!("entry = {:p}", entry);
|
||||
|
@ -1,14 +1,19 @@
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufReader, Read, Seek, SeekFrom},
|
||||
mem,
|
||||
ops::Range,
|
||||
path::{Path, PathBuf},
|
||||
ptr,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use elf::{
|
||||
abi::{
|
||||
DF_1_PIE, DT_FINI, DT_FINI_ARRAY, DT_FINI_ARRAYSZ, DT_FLAGS_1, DT_INIT, DT_INIT_ARRAY, 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, SHN_UNDEF, SHT_REL, SHT_RELA, STB_GLOBAL, STB_LOCAL, STB_WEAK
|
||||
DF_1_PIE, DT_FINI, DT_FINI_ARRAY, DT_FINI_ARRAYSZ, DT_FLAGS_1, DT_INIT, DT_INIT_ARRAY,
|
||||
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, SHN_UNDEF, SHT_REL, SHT_RELA, STB_GLOBAL, STB_LOCAL, STB_WEAK,
|
||||
},
|
||||
endian::AnyEndian,
|
||||
symbol::Symbol,
|
||||
@ -56,6 +61,7 @@ pub struct Object {
|
||||
dynamic_symbol_array: Vec<DynamicSymbol>,
|
||||
|
||||
init_array: Option<Range<usize>>,
|
||||
pre_init_array: Option<Range<usize>>,
|
||||
}
|
||||
|
||||
impl ResolvedSymbol<'_> {
|
||||
@ -144,7 +150,8 @@ impl Object {
|
||||
mapping: None,
|
||||
dynamic_symbol_array,
|
||||
|
||||
init_array: None
|
||||
init_array: None,
|
||||
pre_init_array: None,
|
||||
})
|
||||
}
|
||||
|
||||
@ -177,6 +184,8 @@ impl Object {
|
||||
if let Some(dynamic) = self.elf.dynamic()? {
|
||||
let mut dt_init_array = None;
|
||||
let mut dt_init_array_sz = None;
|
||||
let mut dt_preinit_array = None;
|
||||
let mut dt_preinit_array_sz = None;
|
||||
|
||||
for dynamic in dynamic {
|
||||
match dynamic.d_tag {
|
||||
@ -186,12 +195,18 @@ impl Object {
|
||||
DT_FINI_ARRAYSZ => todo!(),
|
||||
DT_INIT => todo!(),
|
||||
DT_FINI => todo!(),
|
||||
DT_PREINIT_ARRAY => todo!(),
|
||||
DT_PREINIT_ARRAYSZ => todo!(),
|
||||
_ => ()
|
||||
DT_PREINIT_ARRAY => dt_preinit_array = Some(dynamic.d_ptr()),
|
||||
DT_PREINIT_ARRAYSZ => dt_preinit_array_sz = Some(dynamic.d_val()),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
if let (Some(ptr), Some(size)) = (dt_preinit_array, dt_preinit_array_sz) {
|
||||
debug_trace!("{:?}: DT_PREINIT_ARRAY: {:#x?}", self.path, ptr..ptr + size);
|
||||
let ptr = ptr as i64 + mapping.base() as i64 - self.vma_start as i64;
|
||||
let ptr = ptr as usize;
|
||||
self.pre_init_array = Some(ptr..ptr + size as usize);
|
||||
}
|
||||
if let (Some(ptr), Some(size)) = (dt_init_array, dt_init_array_sz) {
|
||||
// This address is subject to relocation
|
||||
debug_trace!("{:?}: DT_INIT_ARRAY: {:#x?}", self.path, ptr..ptr + size);
|
||||
@ -253,21 +268,32 @@ impl Object {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn call_constructors(&mut self) {
|
||||
unsafe fn call_constructor_list(range: Range<usize>) {
|
||||
type Constructor = extern "C" fn();
|
||||
|
||||
if let Some(init_array) = self.init_array.as_ref() {
|
||||
for slot in init_array.clone().step_by(size_of::<usize>()) {
|
||||
let func = unsafe { core::ptr::with_exposed_provenance::<usize>(slot).read_unaligned() };
|
||||
for slot in range.step_by(size_of::<usize>()) {
|
||||
let func = ptr::with_exposed_provenance::<usize>(slot).read_unaligned();
|
||||
|
||||
if func == 0 || func == usize::MAX {
|
||||
continue;
|
||||
}
|
||||
|
||||
let func = unsafe { core::mem::transmute::<_, Constructor>(func) };
|
||||
|
||||
func();
|
||||
if func == 0 || func == usize::MAX {
|
||||
continue;
|
||||
}
|
||||
|
||||
let func = mem::transmute::<_, Constructor>(func);
|
||||
debug_trace!("ld: call constructor {func:p}");
|
||||
|
||||
func();
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn call_early_constructors(&mut self) {
|
||||
if let Some(pre_init_array) = self.pre_init_array.as_ref() {
|
||||
Self::call_constructor_list(pre_init_array.clone());
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn call_constructors(&mut self) {
|
||||
if let Some(init_array) = self.init_array.as_ref() {
|
||||
Self::call_constructor_list(init_array.clone());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
use std::{
|
||||
env,
|
||||
fs::{self, DirEntry},
|
||||
fs::{self, DirEntry, File},
|
||||
io::Write,
|
||||
path::{Path, PathBuf},
|
||||
process::Command,
|
||||
};
|
||||
@ -66,6 +67,7 @@ fn compile_crt0(arch: &str, output_dir: impl AsRef<Path>) {
|
||||
command
|
||||
.arg(format!("--target={}-unknown-none", arch))
|
||||
.arg("-nostdlib")
|
||||
.arg("-fPIC")
|
||||
.arg("-c")
|
||||
.arg("-o")
|
||||
.arg(output_dir.join("crt0.o"))
|
||||
@ -76,14 +78,88 @@ fn compile_crt0(arch: &str, output_dir: impl AsRef<Path>) {
|
||||
}
|
||||
}
|
||||
|
||||
fn ctype_item(ch: u8) -> String {
|
||||
let mut traits = vec![];
|
||||
// TODO include vertical tab here
|
||||
if ch.is_ascii_whitespace() {
|
||||
traits.push("_ISspace");
|
||||
}
|
||||
if ch.is_ascii_graphic() || ch == b' ' {
|
||||
traits.push("_ISprint");
|
||||
}
|
||||
if ch.is_ascii_control() {
|
||||
traits.push("_IScntrl");
|
||||
}
|
||||
if ch.is_ascii_uppercase() {
|
||||
traits.push("_ISupper");
|
||||
}
|
||||
if ch.is_ascii_lowercase() {
|
||||
traits.push("_ISlower");
|
||||
}
|
||||
if ch.is_ascii_alphabetic() {
|
||||
traits.push("_ISalpha");
|
||||
}
|
||||
if ch.is_ascii_digit() {
|
||||
traits.push("_ISdigit");
|
||||
}
|
||||
if ch.is_ascii_punctuation() {
|
||||
traits.push("_ISpunct");
|
||||
}
|
||||
if ch.is_ascii_hexdigit() {
|
||||
traits.push("_ISxdigit");
|
||||
}
|
||||
if ch == b' ' || ch == b'\t' {
|
||||
traits.push("_ISblank");
|
||||
}
|
||||
|
||||
if traits.is_empty() {
|
||||
"0,".to_owned()
|
||||
} else {
|
||||
let mut str = String::new();
|
||||
for (i, t) in traits.iter().enumerate() {
|
||||
if i != 0 {
|
||||
str.push('|');
|
||||
}
|
||||
str.push_str(t);
|
||||
}
|
||||
str.push(',');
|
||||
str
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_ctype_table(output_dir: impl AsRef<Path>) {
|
||||
// Table size: 384, __ctype_b_loc points to 128th element to allow the table to be indexed
|
||||
// by a signed char or EOF (-1) as well as any unsigned char.
|
||||
|
||||
let mut output = File::create(output_dir.as_ref().join("ctype_b.rs")).unwrap();
|
||||
|
||||
output
|
||||
.write_all(b"pub(crate) static __ctype_b_table: [c_ushort; 384] = [")
|
||||
.unwrap();
|
||||
|
||||
for ch in 128..=255u8 {
|
||||
let traits_string = ctype_item(ch);
|
||||
output.write_all(traits_string.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
for ch in 0..=255u8 {
|
||||
let traits_string = ctype_item(ch);
|
||||
output.write_all(traits_string.as_bytes()).unwrap();
|
||||
}
|
||||
|
||||
output.write_all(b"];").unwrap();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").expect("$TARGET 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 compile_output_dir = env::var("OUT_DIR").expect("$OUT_DIR is not set");
|
||||
|
||||
let output_dir = PathBuf::from(format!("target/{target}/{profile}"));
|
||||
let header_output = output_dir.join("include");
|
||||
|
||||
generate_ctype_table(compile_output_dir);
|
||||
compile_crt0(&arch, output_dir);
|
||||
|
||||
fs::read_dir("src/headers")
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include <stddef.h>
|
||||
|
||||
extern __attribute__((noreturn)) void __ygglibc_entry(const void *);
|
||||
extern __attribute__((noreturn)) void __ygglibc_entry(const void *, const void *);
|
||||
extern int main(int, const char **, const char **);
|
||||
|
||||
// // rust's shlib export breaks memset symbol
|
||||
// void *memset(void *dst, int val, size_t len) __attribute__((weak)) {
|
||||
@ -11,5 +12,5 @@ extern __attribute__((noreturn)) void __ygglibc_entry(const void *);
|
||||
// }
|
||||
|
||||
[[noreturn]] void _start(const void *arg) {
|
||||
__ygglibc_entry(arg);
|
||||
__ygglibc_entry(main, arg);
|
||||
}
|
||||
|
3
userspace/lib/ygglibc/include/bits/limits.h
Normal file
3
userspace/lib/ygglibc/include/bits/limits.h
Normal file
@ -0,0 +1,3 @@
|
||||
#ifndef _YGGDRASIL_LIMITS_H
|
||||
#define _YGGDRASIL_LIMITS_H 1
|
||||
#endif
|
@ -7,6 +7,10 @@ extern "C" {
|
||||
|
||||
[[noreturn]] void abort(void);
|
||||
|
||||
// No long double implementation yet
|
||||
long double strtold(const char *s, char **endptr);
|
||||
long double strtold_l(const char *s, char **endptr, locale_t locale);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
@ -24,6 +24,9 @@
|
||||
#define PRIu8 "hhu"
|
||||
#define PRIx8 "hhx"
|
||||
|
||||
#define PRIdPTR "zd"
|
||||
#define PRIxPTR "zx"
|
||||
|
||||
#define SCNo64 PRIo64
|
||||
#define SCNd64 PRId64
|
||||
#define SCNu64 PRIu64
|
||||
|
16
userspace/lib/ygglibc/include/machine/endian.h
Normal file
16
userspace/lib/ygglibc/include/machine/endian.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef _MACHINE_ENDIAN_H
|
||||
#define _MACHINE_ENDIAN_H 1
|
||||
|
||||
#if !defined(LITTLE_ENDIAN)
|
||||
#define LITTLE_ENDIAN 1234
|
||||
#endif
|
||||
|
||||
#if !defined(BIG_ENDIAN)
|
||||
#define BIG_ENDIAN 4321
|
||||
#endif
|
||||
|
||||
#if !defined(BYTE_ORDER)
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
#endif
|
||||
|
||||
#endif
|
@ -1,6 +1,5 @@
|
||||
use core::{
|
||||
alloc::{GlobalAlloc, Layout},
|
||||
cmp::Ordering,
|
||||
ffi::c_void,
|
||||
ptr::{self, null_mut, NonNull},
|
||||
};
|
||||
@ -73,7 +72,7 @@ unsafe fn get_allocation(ptr: NonNull<u8>) -> (NonNull<u8>, Layout) {
|
||||
(real_ptr, layout)
|
||||
}
|
||||
|
||||
pub fn c_alloc(size: usize, mut align: usize, zero: bool) -> EResult<NonNull<c_void>> {
|
||||
pub fn c_alloc(size: usize, align: usize, zero: bool) -> EResult<NonNull<c_void>> {
|
||||
// allocation layout:
|
||||
// [ header ] [ ... ]
|
||||
// header: 16 bytes
|
||||
@ -85,6 +84,12 @@ pub fn c_alloc(size: usize, mut align: usize, zero: bool) -> EResult<NonNull<c_v
|
||||
let layout = Layout::from_size_align(size, align).expect("Couldn't setup malloc() layout");
|
||||
let ptr = YALLOC.lock().allocate(layout).e_ok_or(errno::ENOMEM)?;
|
||||
|
||||
if zero {
|
||||
unsafe {
|
||||
memset(ptr.cast().as_ptr(), 0, size);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
ptr.cast::<usize>().write(size);
|
||||
ptr.cast::<usize>().add(1).write(align);
|
||||
|
@ -1,87 +1,11 @@
|
||||
use core::ffi::{c_int, c_void};
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __cxa_begin_catch(_exception: *mut c_void) -> *mut c_void {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __cxa_end_catch() {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __cxa_pure_virtual() {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __cxa_guard_acquire(_guard: *mut u64) -> c_int {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __cxa_guard_release(_guard: *mut u64) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __cxa_atexit(
|
||||
_destructor: extern "C" fn(*mut c_void),
|
||||
_arg: *mut c_void,
|
||||
_dso_handle: *mut c_void,
|
||||
) -> c_int {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __gxx_personality_v0() {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn _Unwind_Resume(_exception: *mut c_void) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// void *operator new(size_t x)
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn _Znwm(_x: usize) -> *mut c_void {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// void *operator new(size_t x, std::align_val_t y)
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn _ZnwmSt11align_val_t(_x: usize, _y: usize) -> *mut c_void {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// void *operator new[](size_t x)
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn _Znam(_x: usize) -> *mut c_void {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// void operator delete(void *x)
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn _ZdlPv(_x: *mut c_void) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// void operator delete(void *x, size_t y)
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn _ZdlPvm(_x: *mut c_void, _y: usize) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// void operator delete(void *x, size_t y, std::align_val_t z)
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn _ZdlPvmSt11align_val_t(_x: *mut c_void, _y: usize) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// void operator delete[](void *x)
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn _ZdaPv(_x: *mut c_void) {
|
||||
unimplemented!()
|
||||
yggdrasil_rt::debug_trace!("TODO: __cxa_atexit()");
|
||||
0
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(non_upper_case_globals, static_mut_refs)]
|
||||
|
||||
use core::{
|
||||
ffi::{c_char, CStr},
|
||||
@ -14,10 +14,7 @@ use crate::{
|
||||
error::EResult,
|
||||
headers::{
|
||||
errno,
|
||||
string::{
|
||||
mem::memcpy,
|
||||
str::{strcpy, strlen},
|
||||
},
|
||||
string::{mem::memcpy, str::strlen},
|
||||
},
|
||||
util::PointerExt,
|
||||
};
|
||||
@ -62,7 +59,7 @@ unsafe fn reclaim_env() -> EResult<()> {
|
||||
}
|
||||
|
||||
unsafe fn push_env(str: NonNull<c_char>) -> EResult<()> {
|
||||
reclaim_env();
|
||||
reclaim_env()?;
|
||||
|
||||
if shadow.try_reserve(1).is_err() {
|
||||
return EResult::Err(errno::ENOMEM);
|
||||
@ -168,7 +165,8 @@ pub unsafe fn remove_env(name: &[u8]) -> EResult<bool> {
|
||||
return EResult::Err(errno::EINVAL);
|
||||
}
|
||||
|
||||
reclaim_env();
|
||||
reclaim_env()?;
|
||||
|
||||
for i in 0..shadow.len() {
|
||||
let Some(entry) = NonNull::new(shadow[i]) else {
|
||||
continue;
|
||||
|
@ -37,6 +37,8 @@ pub trait OptionExt<T> {
|
||||
|
||||
pub trait CResult {
|
||||
const ERROR: Self;
|
||||
type Inner;
|
||||
fn into_inner(self) -> Self::Inner;
|
||||
}
|
||||
|
||||
#[must_use = "EResult must be converted into its output type with proper errno set"]
|
||||
@ -202,6 +204,11 @@ impl<T> CPtrResult<T> {
|
||||
|
||||
impl<T> CResult for CPtrResult<T> {
|
||||
const ERROR: Self = Self(null_mut());
|
||||
type Inner = *mut T;
|
||||
|
||||
fn into_inner(self) -> Self::Inner {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromResidual<EResult<Infallible>> for CPtrResult<T> {
|
||||
@ -222,6 +229,11 @@ impl CIsizeResult {
|
||||
|
||||
impl CResult for CIsizeResult {
|
||||
const ERROR: Self = Self(-1);
|
||||
type Inner = isize;
|
||||
|
||||
fn into_inner(self) -> Self::Inner {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CIntZeroResult {
|
||||
@ -230,6 +242,11 @@ impl CIntZeroResult {
|
||||
|
||||
impl CResult for CIntZeroResult {
|
||||
const ERROR: Self = Self(-1);
|
||||
type Inner = c_int;
|
||||
|
||||
fn into_inner(self) -> Self::Inner {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CEofResult {
|
||||
@ -240,6 +257,11 @@ impl CEofResult {
|
||||
|
||||
impl CResult for CEofResult {
|
||||
const ERROR: Self = Self(-1);
|
||||
type Inner = c_int;
|
||||
|
||||
fn into_inner(self) -> Self::Inner {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CIntCountResult {
|
||||
@ -250,6 +272,11 @@ impl CIntCountResult {
|
||||
|
||||
impl CResult for CIntCountResult {
|
||||
const ERROR: Self = Self(-1);
|
||||
type Inner = c_int;
|
||||
|
||||
fn into_inner(self) -> Self::Inner {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CFdResult {
|
||||
@ -260,6 +287,11 @@ impl CFdResult {
|
||||
|
||||
impl CResult for CFdResult {
|
||||
const ERROR: Self = Self(-1);
|
||||
type Inner = c_int;
|
||||
|
||||
fn into_inner(self) -> Self::Inner {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl COffsetResult {
|
||||
@ -270,6 +302,11 @@ impl COffsetResult {
|
||||
|
||||
impl CResult for COffsetResult {
|
||||
const ERROR: Self = Self(-1);
|
||||
type Inner = off_t;
|
||||
|
||||
fn into_inner(self) -> Self::Inner {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl CUsizeResult {
|
||||
@ -280,6 +317,11 @@ impl CUsizeResult {
|
||||
|
||||
impl CResult for CUsizeResult {
|
||||
const ERROR: Self = Self(0);
|
||||
type Inner = usize;
|
||||
|
||||
fn into_inner(self) -> Self::Inner {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl_from_residual!(
|
||||
|
25
userspace/lib/ygglibc/src/headers/ctype/ctype_b.rs
Normal file
25
userspace/lib/ygglibc/src/headers/ctype/ctype_b.rs
Normal file
@ -0,0 +1,25 @@
|
||||
use core::ffi::c_ushort;
|
||||
|
||||
pub const _ISspace: c_ushort = 1 << 0;
|
||||
pub const _ISprint: c_ushort = 1 << 1;
|
||||
pub const _IScntrl: c_ushort = 1 << 2;
|
||||
pub const _ISupper: c_ushort = 1 << 3;
|
||||
pub const _ISlower: c_ushort = 1 << 4;
|
||||
pub const _ISalpha: c_ushort = 1 << 5;
|
||||
pub const _ISdigit: c_ushort = 1 << 6;
|
||||
// regex_word: 1 << 7
|
||||
pub const _ISpunct: c_ushort = 1 << 8;
|
||||
pub const _ISxdigit: c_ushort = 1 << 9;
|
||||
pub const _ISblank: c_ushort = 1 << 10;
|
||||
|
||||
include!(concat!(env!("OUT_DIR"), "/ctype_b.rs"));
|
||||
|
||||
// # define __isctype(c, type) \
|
||||
// ((*__ctype_b_loc ())[(int) (c)] & (unsigned short int) type)
|
||||
|
||||
static mut __ctype_b_ptr: *const c_ushort = unsafe { __ctype_b_table.as_ptr().add(128) };
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __ctype_b_loc() -> *mut *mut c_ushort {
|
||||
(&raw mut __ctype_b_ptr).cast()
|
||||
}
|
@ -1,7 +1,9 @@
|
||||
use core::ffi::{c_int, c_short};
|
||||
use core::ffi::c_int;
|
||||
|
||||
use super::locale::locale_t;
|
||||
|
||||
mod ctype_b;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn isalnum(ch: c_int) -> c_int {
|
||||
(ch < 0xFF && (ch as u8).is_ascii_alphanumeric()) as _
|
||||
@ -159,8 +161,3 @@ unsafe extern "C" fn tolower_l(_ch: c_int, _locale: locale_t) -> c_int {
|
||||
unsafe extern "C" fn toupper_l(_ch: c_int, _locale: locale_t) -> c_int {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __ctype_b_loc() -> *mut *mut c_short {
|
||||
todo!()
|
||||
}
|
||||
|
12
userspace/lib/ygglibc/src/headers/limits/cbindgen.toml
Normal file
12
userspace/lib/ygglibc/src/headers/limits/cbindgen.toml
Normal file
@ -0,0 +1,12 @@
|
||||
language = "C"
|
||||
style = "Type"
|
||||
|
||||
sys_includes = [
|
||||
"bits/limits.h"
|
||||
]
|
||||
no_includes = true
|
||||
|
||||
include_guard = "_LIMITS_H"
|
||||
|
||||
usize_type = "size_t"
|
||||
isize_type = "ssize_t"
|
1
userspace/lib/ygglibc/src/headers/limits/mod.rs
Normal file
1
userspace/lib/ygglibc/src/headers/limits/mod.rs
Normal file
@ -0,0 +1 @@
|
||||
pub const PATH_MAX: usize = 4096;
|
12
userspace/lib/ygglibc/src/headers/link/cbindgen.toml
Normal file
12
userspace/lib/ygglibc/src/headers/link/cbindgen.toml
Normal file
@ -0,0 +1,12 @@
|
||||
language = "C"
|
||||
style = "Type"
|
||||
|
||||
sys_includes = [
|
||||
"stddef.h",
|
||||
]
|
||||
no_includes = true
|
||||
|
||||
include_guard = "_LINK_H"
|
||||
|
||||
usize_type = "size_t"
|
||||
isize_type = "ssize_t"
|
0
userspace/lib/ygglibc/src/headers/link/mod.rs
Normal file
0
userspace/lib/ygglibc/src/headers/link/mod.rs
Normal file
@ -3,6 +3,8 @@ use core::{
|
||||
ptr::null_mut,
|
||||
};
|
||||
|
||||
use alloc::boxed::Box;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
#[repr(C)]
|
||||
pub struct lconv {
|
||||
@ -62,12 +64,12 @@ pub const LC_ALL: c_int = 6;
|
||||
pub const __LC_LAST: usize = 6;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn duplocale(locobj: locale_t) -> locale_t {
|
||||
unsafe extern "C" fn duplocale(_locobj: locale_t) -> locale_t {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn freelocale(locobj: locale_t) {
|
||||
unsafe extern "C" fn freelocale(_locobj: locale_t) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
@ -78,20 +80,24 @@ unsafe extern "C" fn localeconv() -> *mut lconv {
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn newlocale(
|
||||
category_mask: c_int,
|
||||
locale: *const c_char,
|
||||
base: locale_t,
|
||||
_category_mask: c_int,
|
||||
_locale: *const c_char,
|
||||
_base: locale_t,
|
||||
) -> locale_t {
|
||||
let locale = Box::new(__locale_struct {
|
||||
__locales: [null_mut(); __LC_LAST]
|
||||
});
|
||||
|
||||
Box::into_raw(locale)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn setlocale(_category: c_int, _locale: *const c_char) -> *mut c_char {
|
||||
// TODO
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn setlocale(category: c_int, locale: *const c_char) -> *mut c_char {
|
||||
// TODO
|
||||
unsafe extern "C" fn uselocale(_locobj: locale_t) -> locale_t {
|
||||
null_mut()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn uselocale(locobj: locale_t) -> locale_t {
|
||||
todo!()
|
||||
}
|
||||
|
@ -100,6 +100,7 @@ pub mod grp;
|
||||
pub mod iconv;
|
||||
pub mod langinfo;
|
||||
pub mod libgen;
|
||||
pub mod limits;
|
||||
pub mod locale;
|
||||
pub mod monetary;
|
||||
pub mod nl_types;
|
||||
@ -131,3 +132,6 @@ pub mod sys_times;
|
||||
pub mod sys_types;
|
||||
pub mod sys_utsname;
|
||||
pub mod sys_wait;
|
||||
|
||||
// TODO Generate those as part of dyn-loader (and make dyn-loader a shared library)
|
||||
pub mod link;
|
||||
|
@ -1,5 +1,3 @@
|
||||
use core::ffi::c_int;
|
||||
|
||||
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
|
||||
pub mod x86_64;
|
||||
|
||||
|
@ -1,10 +1,10 @@
|
||||
use core::{arch::global_asm, ffi::c_int};
|
||||
use core::ffi::c_int;
|
||||
|
||||
pub type __jmp_buf = [usize; 8];
|
||||
|
||||
#[no_mangle]
|
||||
#[naked]
|
||||
unsafe extern "C" fn setjmp(buf: __jmp_buf) -> c_int {
|
||||
unsafe extern "C" fn setjmp(buf: *mut __jmp_buf) -> c_int {
|
||||
// %rdi -- jmp_buf pointer
|
||||
core::arch::naked_asm!(
|
||||
r#"
|
||||
@ -30,16 +30,17 @@ unsafe extern "C" fn setjmp(buf: __jmp_buf) -> c_int {
|
||||
|
||||
#[no_mangle]
|
||||
#[naked]
|
||||
unsafe extern "C" fn _setjmp(buf: __jmp_buf) -> c_int {
|
||||
unsafe extern "C" fn _setjmp(buf: *mut __jmp_buf) -> c_int {
|
||||
core::arch::naked_asm!("jmp setjmp", options(att_syntax))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[naked]
|
||||
unsafe extern "C" fn longjmp(buf: __jmp_buf, val: c_int) -> c_int {
|
||||
unsafe extern "C" fn longjmp(buf: *mut __jmp_buf, val: c_int) -> c_int {
|
||||
// %rdi -- jmp_buf pointer
|
||||
// %rsi -- return value
|
||||
core::arch::naked_asm!(r#"
|
||||
core::arch::naked_asm!(
|
||||
r#"
|
||||
// Restore the registers
|
||||
movq 0(%rdi), %rbx
|
||||
movq 8(%rdi), %rbp
|
||||
@ -55,11 +56,13 @@ unsafe extern "C" fn longjmp(buf: __jmp_buf, val: c_int) -> c_int {
|
||||
movq %rsi, %rax
|
||||
|
||||
ret
|
||||
"#, options(att_syntax))
|
||||
"#,
|
||||
options(att_syntax)
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
#[naked]
|
||||
unsafe extern "C" fn _longjmp(buf: __jmp_buf, val: c_int) -> c_int {
|
||||
unsafe extern "C" fn _longjmp(buf: *mut __jmp_buf, val: c_int) -> c_int {
|
||||
core::arch::naked_asm!("jmp longjmp", options(att_syntax))
|
||||
}
|
||||
|
@ -141,7 +141,22 @@ unsafe extern "C" fn putchar_unlocked(ch: c_int) -> CEofResult {
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn puts(str: *const c_char) -> CEofResult {
|
||||
let str = str.ensure_cstr();
|
||||
let out = stdout.ensure_mut();
|
||||
let out = match stdout.as_mut() {
|
||||
Some(out) => out,
|
||||
None => {
|
||||
// TODO this hack is needed because currently global constructors are called
|
||||
// before ygglibc is entered and I/O streams are initialized.
|
||||
// this will be removed when I properly implement passing DT_INIT_*** ranges
|
||||
// from dyn-loader to ygglibc.
|
||||
use yggdrasil_rt::io::RawFd;
|
||||
unsafe {
|
||||
yggdrasil_rt::sys::write(RawFd::STDOUT, str.to_bytes()).ok();
|
||||
yggdrasil_rt::sys::write(RawFd::STDOUT, b"\n").ok();
|
||||
}
|
||||
|
||||
return CEofResult::success(0)
|
||||
},
|
||||
};
|
||||
out.write_all(str.to_bytes())?;
|
||||
out.write_all(b"\n")?;
|
||||
CEofResult::success(0)
|
||||
|
@ -1,9 +1,9 @@
|
||||
use core::{ffi::{c_char, c_int, c_void}, ptr::NonNull};
|
||||
use core::ffi::c_void;
|
||||
|
||||
use crate::{
|
||||
error::{CEofResult, CPtrResult, CResult, CUsizeResult},
|
||||
io::{managed::{stdin, stdout, FILE}, Read, Write},
|
||||
util::{PointerExt, PointerStrExt},
|
||||
error::CUsizeResult,
|
||||
io::{managed::FILE, Read, Write},
|
||||
util::PointerExt,
|
||||
};
|
||||
|
||||
#[no_mangle]
|
||||
@ -27,10 +27,12 @@ unsafe extern "C" fn fwrite(
|
||||
nmemb: usize,
|
||||
fp: *mut FILE,
|
||||
) -> CUsizeResult {
|
||||
if fp.is_null() {
|
||||
loop {}
|
||||
}
|
||||
let size = size.checked_mul(nmemb).expect("size * nmemb too large");
|
||||
let buf = buf.cast::<u8>().ensure_slice(size);
|
||||
let fp = fp.ensure_mut();
|
||||
let len = fp.write(buf)?;
|
||||
CUsizeResult::success(len)
|
||||
}
|
||||
|
||||
|
@ -191,7 +191,7 @@ unsafe extern "C" fn asprintf(dst: *mut *mut c_char, fmt: *const c_char, mut arg
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn vasprintf(_dst: *mut *mut c_char, _fmt: *const c_char, args: VaList) -> c_int {
|
||||
unsafe extern "C" fn vasprintf(_dst: *mut *mut c_char, _fmt: *const c_char, _args: VaList) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@ impl ScanCharSet {
|
||||
return Err(FormatError);
|
||||
}
|
||||
} else {
|
||||
if let Some(start) = start.replace(ch) {
|
||||
if let Some(_start) = start.replace(ch) {
|
||||
// "c" without range
|
||||
set.insert(ch);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ style = "Type"
|
||||
sys_includes = [
|
||||
"stddef.h",
|
||||
"locale.h",
|
||||
"limits.h",
|
||||
"bits/stdlib.h"
|
||||
]
|
||||
no_includes = true
|
||||
@ -14,4 +15,4 @@ usize_type = "size_t"
|
||||
isize_type = "ssize_t"
|
||||
|
||||
[export]
|
||||
exclude = ["abort"]
|
||||
exclude = ["abort", "strtold", "strtold_l"]
|
||||
|
@ -35,8 +35,8 @@ unsafe extern "C" fn strtof(s: *const c_char, endptr: *mut *mut c_char) -> c_flo
|
||||
}
|
||||
|
||||
#[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 _
|
||||
unsafe extern "C" fn strtold(_s: *const c_char, _endptr: *mut *mut c_char) -> c_double {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
// ints
|
||||
@ -130,7 +130,7 @@ unsafe extern "C" fn strtold_l(
|
||||
_endptr: *mut *mut c_char,
|
||||
_locale: locale_t,
|
||||
) -> c_double {
|
||||
todo!()
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
|
@ -30,6 +30,15 @@ unsafe extern "C" fn malloc(size: usize) -> CPtrResult<c_void> {
|
||||
CPtrResult::success(ptr)
|
||||
}
|
||||
|
||||
#[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)
|
||||
}
|
||||
|
||||
// Aligned allocations
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn posix_memalign(
|
||||
_memptr: *mut *mut c_void,
|
||||
@ -40,8 +49,6 @@ unsafe extern "C" fn posix_memalign(
|
||||
}
|
||||
|
||||
#[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)
|
||||
unsafe extern "C" fn aligned_alloc(_align: usize, _size: usize) -> *mut c_void {
|
||||
todo!()
|
||||
}
|
||||
|
@ -1,7 +1,14 @@
|
||||
use core::{ffi::{c_char, c_int}, ptr::NonNull};
|
||||
use core::{
|
||||
ffi::{c_char, c_int},
|
||||
ptr::NonNull,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
env, error::{CIntZeroResult, CPtrResult, CResult, OptionExt}, headers::errno, process, util::{PointerExt, PointerStrExt}
|
||||
env,
|
||||
error::{CIntZeroResult, CPtrResult, CResult, OptionExt},
|
||||
headers::errno,
|
||||
process,
|
||||
util::PointerStrExt,
|
||||
};
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::ffi::{c_char, c_int};
|
||||
|
||||
use crate::types::wchar_t;
|
||||
use crate::{error::CResult, headers::wchar::{mbstate_t, multibyte::mbrtowc}, types::wchar_t};
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn mblen(_s: *const c_char, _n: usize) -> c_int {
|
||||
@ -13,8 +13,9 @@ unsafe extern "C" fn mbstowcs(_dst: *mut wchar_t, _src: *const c_char, _n: usize
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn mbtowc(_dst: *mut wchar_t, _src: *const c_char, _n: usize) -> c_int {
|
||||
todo!()
|
||||
unsafe extern "C" fn mbtowc(dst: *mut wchar_t, src: *const c_char, n: usize) -> c_int {
|
||||
let mut state = mbstate_t { __dummy: 0 };
|
||||
mbrtowc(dst, src, n, &mut state).into_inner() as c_int
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
@ -1,4 +1,2 @@
|
||||
use core::ffi::{c_char, c_int, c_void};
|
||||
|
||||
pub mod mem;
|
||||
pub mod str;
|
||||
|
@ -1,4 +1,4 @@
|
||||
use core::ffi::{c_int, c_long, c_void};
|
||||
use core::ffi::{c_char, c_int, c_long, c_void};
|
||||
|
||||
use super::sys_types::{suseconds_t, time_t};
|
||||
|
||||
@ -44,3 +44,8 @@ unsafe extern "C" fn gettimeofday(_time: *mut timeval, _d: *mut c_void) -> c_int
|
||||
unsafe extern "C" fn setitimer(_timer: c_int, _new: *const itimerval, _old: *mut itimerval) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn utimes(_path: *const c_char, _times: *const timeval) -> c_int {
|
||||
todo!()
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ use crate::headers::{sys_types::time_t, time::tm};
|
||||
|
||||
use super::{get_timezone, CDateTime};
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn gmtime(tp: *const time_t) -> *mut tm {
|
||||
static mut BUFFER: MaybeUninit<tm> = MaybeUninit::uninit();
|
||||
@ -26,6 +27,7 @@ unsafe extern "C" fn gmtime_r(tp: *const time_t, timep: *mut tm) -> *mut tm {
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn localtime(tp: *const time_t) -> *mut tm {
|
||||
static mut BUFFER: MaybeUninit<tm> = MaybeUninit::uninit();
|
||||
|
@ -37,6 +37,7 @@ unsafe fn fmt_time<Tz: TimeZone, T: CDateTime>(
|
||||
writer.finish()
|
||||
}
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn asctime(timep: *const tm) -> *mut c_char {
|
||||
static mut BUFFER: [c_char; 32] = [0; 32];
|
||||
@ -54,6 +55,7 @@ unsafe extern "C" fn asctime_r(timep: *const tm, buffer: *mut c_char) -> *mut c_
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn ctime(tp: *const time_t) -> *mut c_char {
|
||||
static mut BUFFER: [c_char; 32] = [0; 32];
|
||||
|
@ -2,6 +2,7 @@ language = "C"
|
||||
style = "Type"
|
||||
|
||||
sys_includes = [
|
||||
"limits.h",
|
||||
"stddef.h",
|
||||
"sys/types.h"
|
||||
]
|
||||
|
@ -2,6 +2,8 @@ use core::ffi::{c_char, c_int, c_long};
|
||||
|
||||
use crate::headers::sys_types::{gid_t, off_t, uid_t};
|
||||
|
||||
pub const _PC_PATH_MAX: c_int = 0;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn access(path: *const c_char, mode: c_int) -> c_int {
|
||||
todo!()
|
||||
|
@ -1,5 +1,7 @@
|
||||
use core::ffi::{c_char, c_int, c_long, c_uint, c_void};
|
||||
|
||||
pub const _SC_PAGE_SIZE: c_int = 1;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn alarm(value: c_uint) -> c_uint {
|
||||
todo!()
|
||||
|
61
userspace/lib/ygglibc/src/headers/wchar/imp.rs
Normal file
61
userspace/lib/ygglibc/src/headers/wchar/imp.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use core::{ffi::c_char, ptr::NonNull, slice, str};
|
||||
|
||||
use crate::{error::EResult, headers::errno, types::wchar_t};
|
||||
|
||||
use super::mbstate_t;
|
||||
|
||||
// NOTE: stolen from relibc
|
||||
// https://tools.ietf.org/html/rfc3629
|
||||
static UTF8_CHAR_WIDTH: [u8; 256] = [
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, // 0x1F
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, // 0x3F
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, // 0x5F
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, // 0x7F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, // 0x9F
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, // 0xBF
|
||||
0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, // 0xDF
|
||||
3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF
|
||||
4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF
|
||||
];
|
||||
|
||||
// Given a first byte, determines how many bytes are in this UTF-8 character.
|
||||
#[inline]
|
||||
fn utf8_char_width(b: u8) -> usize {
|
||||
UTF8_CHAR_WIDTH[usize::from(b)].into()
|
||||
}
|
||||
|
||||
pub unsafe fn mbrtowc(
|
||||
dst: *mut wchar_t,
|
||||
src: NonNull<c_char>,
|
||||
n: usize,
|
||||
_state: &mut mbstate_t,
|
||||
) -> EResult<usize> {
|
||||
let size = utf8_char_width(src.cast::<u8>().read());
|
||||
// TODO EILSEQ
|
||||
if size > n || size == 0 {
|
||||
return EResult::Err(errno::EINVAL);
|
||||
}
|
||||
let slice = slice::from_raw_parts(src.cast::<u8>().as_ptr(), size);
|
||||
let Ok(decoded) = str::from_utf8(slice) else {
|
||||
return EResult::Err(errno::EINVAL);
|
||||
};
|
||||
|
||||
let result = decoded.chars().next().unwrap() as wchar_t;
|
||||
|
||||
if let Some(dst) = dst.as_mut() {
|
||||
*dst = result;
|
||||
}
|
||||
|
||||
if result != 0 {
|
||||
EResult::Ok(size)
|
||||
} else {
|
||||
EResult::Ok(0)
|
||||
}
|
||||
}
|
@ -1,6 +1,4 @@
|
||||
use core::ffi::{c_int, c_void};
|
||||
|
||||
use crate::types::wchar_t;
|
||||
use core::ffi::c_int;
|
||||
|
||||
use super::wctype::wint_t;
|
||||
|
||||
@ -8,9 +6,11 @@ pub mod io;
|
||||
pub mod multibyte;
|
||||
pub mod string;
|
||||
|
||||
pub const WEOF: wchar_t = -1;
|
||||
mod imp;
|
||||
|
||||
pub const WEOF: wint_t = (-1i32) as wint_t;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct mbstate_t {
|
||||
__dummy: c_int
|
||||
pub __dummy: c_int,
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use core::ffi::{c_char, c_int};
|
||||
use core::{ffi::{c_char, c_int}, ptr::NonNull};
|
||||
|
||||
use crate::types::wchar_t;
|
||||
use crate::{error::CUsizeResult, headers::wchar::imp, types::wchar_t};
|
||||
|
||||
use super::mbstate_t;
|
||||
|
||||
@ -14,14 +14,32 @@ unsafe extern "C" fn wcrtomb(_dst: *mut c_char, _wc: wchar_t, _state: *mut mbsta
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[allow(static_mut_refs)]
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn mbrtowc(
|
||||
_dst: *mut wchar_t,
|
||||
_src: *const c_char,
|
||||
_n: usize,
|
||||
_state: *mut mbstate_t,
|
||||
) -> usize {
|
||||
todo!()
|
||||
pub unsafe extern "C" fn mbrtowc(
|
||||
dst: *mut wchar_t,
|
||||
src: *const c_char,
|
||||
n: usize,
|
||||
state: *mut mbstate_t,
|
||||
) -> CUsizeResult {
|
||||
static mut GLOBAL: mbstate_t = mbstate_t { __dummy: 0 };
|
||||
|
||||
let state = match state.as_mut() {
|
||||
Some(state) => state,
|
||||
None => &mut GLOBAL
|
||||
};
|
||||
|
||||
let res = match NonNull::new(src.cast_mut()) {
|
||||
Some(src) => {
|
||||
imp::mbrtowc(dst, src, n, state)?
|
||||
}
|
||||
None => {
|
||||
let x: [c_char; 1] = [0];
|
||||
imp::mbrtowc(dst, NonNull::from_ref(&x[0]), 1, state)?
|
||||
}
|
||||
};
|
||||
|
||||
CUsizeResult::success(res)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
21
userspace/lib/ygglibc/src/init.rs
Normal file
21
userspace/lib/ygglibc/src/init.rs
Normal file
@ -0,0 +1,21 @@
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use crate::{io, ssp};
|
||||
|
||||
static INIT_COMPLETE: AtomicBool = AtomicBool::new(false);
|
||||
|
||||
// TODO implement topological sorting for proper .init_array calls in dyn-loader
|
||||
#[link_section = ".preinit_array"]
|
||||
#[used]
|
||||
static PREINIT_ARRAY: [extern "C" fn (); 1] = [init];
|
||||
|
||||
pub extern "C" fn init() {
|
||||
if INIT_COMPLETE.swap(true, Ordering::Acquire) {
|
||||
return;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
ssp::init();
|
||||
io::init();
|
||||
}
|
||||
}
|
@ -58,11 +58,6 @@ impl<'a> ReadBuffer<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.position = 0;
|
||||
self.len = 0;
|
||||
}
|
||||
|
||||
pub fn fill_from<R: Read + ?Sized>(&mut self, source: &mut R) -> EResult<&[u8]> {
|
||||
let buffer = unsafe { self.data.as_slice_mut() };
|
||||
if self.position == self.len {
|
||||
|
@ -9,11 +9,15 @@
|
||||
slice_internals,
|
||||
linkage,
|
||||
rustc_private,
|
||||
naked_functions
|
||||
naked_functions,
|
||||
non_null_from_ref
|
||||
)]
|
||||
#![allow(internal_features)]
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
|
||||
use core::{ffi::{c_char, c_int}, ptr::null};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use env::environ;
|
||||
|
||||
extern crate alloc;
|
||||
@ -24,8 +28,10 @@ extern crate compiler_builtins;
|
||||
extern crate std;
|
||||
|
||||
mod allocator;
|
||||
mod cxxabi;
|
||||
mod env;
|
||||
mod error;
|
||||
mod init;
|
||||
mod io;
|
||||
mod panic;
|
||||
mod process;
|
||||
@ -33,25 +39,15 @@ mod ssp;
|
||||
mod sync;
|
||||
mod types;
|
||||
mod util;
|
||||
mod cxxabi;
|
||||
|
||||
pub mod headers;
|
||||
|
||||
#[no_mangle]
|
||||
unsafe extern "C" fn __ygglibc_entry(arg: usize) {
|
||||
use core::{
|
||||
ffi::{c_char, c_int},
|
||||
ptr::null,
|
||||
};
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
extern "C" {
|
||||
fn main(argc: c_int, argv: *const *const c_char, envp: *const *const c_char) -> c_int;
|
||||
}
|
||||
|
||||
ssp::init();
|
||||
io::init();
|
||||
unsafe extern "C" fn __ygglibc_entry(
|
||||
main: extern "C" fn(c_int, *const *const c_char, *const *const c_char) -> c_int,
|
||||
arg: usize,
|
||||
) {
|
||||
init::init();
|
||||
|
||||
// Setup args
|
||||
let args = env::handle_kernel_argument(arg);
|
||||
|
@ -33,7 +33,7 @@ impl PanicPrinter {
|
||||
let text = &self.buffer[..self.pos];
|
||||
if !text.is_empty() {
|
||||
// Print to debug trace
|
||||
unsafe { yggdrasil_rt::debug::trace_raw(text) };
|
||||
yggdrasil_rt::debug::trace_raw(text);
|
||||
|
||||
// Print to stderr
|
||||
if let Some(print) = self.print.as_mut() {
|
||||
@ -74,11 +74,11 @@ fn panic_handler(pi: &core::panic::PanicInfo) -> ! {
|
||||
if let Some(location) = pi.location() {
|
||||
writeln!(printer, "{}:{}:", location.file(), location.line()).ok();
|
||||
}
|
||||
writeln!(printer, " {}", pi.message());
|
||||
writeln!(printer, " {}", pi.message()).ok();
|
||||
|
||||
printer.flush();
|
||||
}
|
||||
1 => unsafe {
|
||||
1 => {
|
||||
yggdrasil_rt::debug_trace!("!!! ygglibc panicked while panicking !!!");
|
||||
}
|
||||
_ => {}
|
||||
|
@ -1,8 +1,18 @@
|
||||
use core::{ffi::{c_char, c_int, CStr}, ptr::NonNull, time::Duration};
|
||||
use core::{
|
||||
ffi::{c_char, c_int, CStr},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use yggdrasil_rt::{process::{ExitCode, Signal}, 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},
|
||||
};
|
||||
|
||||
pub fn getpid() -> pid_t {
|
||||
let pid = unsafe { syscall::get_pid() };
|
||||
@ -48,12 +58,14 @@ unsafe extern "C" fn __assert_fail(file: *const c_char, line: c_int, message: *c
|
||||
let err = stderr.as_mut().unwrap();
|
||||
let file = match file.is_null() {
|
||||
false => CStr::from_ptr(file).to_str().ok(),
|
||||
true => None
|
||||
}.unwrap_or("???");
|
||||
true => None,
|
||||
}
|
||||
.unwrap_or("???");
|
||||
let expr = match message.is_null() {
|
||||
false => CStr::from_ptr(message).to_str().ok(),
|
||||
true => None
|
||||
}.unwrap_or("???");
|
||||
true => None,
|
||||
}
|
||||
.unwrap_or("???");
|
||||
|
||||
writeln!(err, "Assertion failed: '{}' at {}:{}", expr, file, line).ok();
|
||||
|
||||
|
@ -1,7 +1,5 @@
|
||||
use core::{
|
||||
ffi::{c_char, c_int, CStr},
|
||||
fmt,
|
||||
ptr::NonNull,
|
||||
ffi::{c_char, c_int, CStr}, fmt, panic::Location, ptr::NonNull
|
||||
};
|
||||
|
||||
use yggdrasil_rt::io::RawFd;
|
||||
@ -38,8 +36,13 @@ impl<T> PointerExt for T {
|
||||
unsafe { self.as_ref().expect("ensure() failed: NULL pointer") }
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
unsafe fn ensure_mut(self: *mut Self) -> &'static mut Self {
|
||||
unsafe { self.as_mut().expect("ensure_mut() failed: NULL pointer") }
|
||||
let caller = Location::caller();
|
||||
match self.as_mut() {
|
||||
Some(ptr) => ptr,
|
||||
None => panic!("{caller:?}: ensure_mut() failed: NULL pointer"),
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn ensure_slice(self: *const Self, len: usize) -> &'static [Self]
|
||||
@ -130,9 +133,9 @@ pub unsafe fn cstr_prefix<F: Fn(u8, u8) -> bool>(a: NonNull<u8>, b: &[u8], cmp:
|
||||
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(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| {
|
||||
|
@ -39,11 +39,52 @@ impl Llvm {
|
||||
command
|
||||
}
|
||||
|
||||
pub fn c_clangpp(&self, env: &BuildEnv) -> Command {
|
||||
let mut command = Command::new(self.root.join("bin/clang++"));
|
||||
command.arg(format!("--target={}-unknown-yggdrasil", env.arch.name()));
|
||||
command.arg(format!("--sysroot={}", env.llvm_sysroot.display()));
|
||||
// TODO: Not yet implemented features:
|
||||
command.arg("-fno-exceptions");
|
||||
command.arg("-fno-rtti");
|
||||
command
|
||||
}
|
||||
|
||||
pub fn clang(&self) -> PathBuf {
|
||||
self.root.join("bin/clang")
|
||||
}
|
||||
}
|
||||
|
||||
fn build_test_cpp_program(
|
||||
env: &BuildEnv,
|
||||
llvm: &Llvm,
|
||||
install: &mut Vec<(PathBuf, PathBuf)>,
|
||||
) -> Result<(), Error> {
|
||||
log::info!("Building a test C++ program [PIE]");
|
||||
let target_dir = &env.userspace_output_dir;
|
||||
|
||||
let mut command = llvm.c_clangpp(env);
|
||||
command
|
||||
.args([
|
||||
"-v",
|
||||
"-fpie",
|
||||
"-Bdynamic",
|
||||
"-O0",
|
||||
"-ggdb",
|
||||
"-fstack-protector-strong",
|
||||
])
|
||||
.arg("-o")
|
||||
.arg(target_dir.join("cpp-test"))
|
||||
.arg(env.workspace_root.join("test.cpp"));
|
||||
|
||||
if !command.status()?.success() {
|
||||
return Err(Error::ExternalCommandFailed);
|
||||
}
|
||||
|
||||
install.push((target_dir.join("cpp-test"), "cpp-test".into()));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn build_test_c_program(
|
||||
env: &BuildEnv,
|
||||
llvm: &Llvm,
|
||||
@ -184,7 +225,19 @@ fn install_openlibm(env: &BuildEnv, libm: &Openlibm) -> Result<(), Error> {
|
||||
fn build_llvm(env: &BuildEnv) -> Result<Llvm, Error> {
|
||||
// Configuration:
|
||||
/*
|
||||
cmake -DLLVM_ENABLE_PROJECTS="clang;lld;compiler-rt" -DLLVM_TARGETS_TO_BUILD=X86 -DCMAKE_SYSTEM_NAME=yggdrasil -DLLVM_USE_LINKER=lld -DBUILD_SHARED_LIBS=false -DLLVM_BUILD_TOOLS=false -DLLVM_CCACHE_BUILD=true -DCMAKE_BUILD_TYPE=Release -DCMAKE_HOST_TRIPLE=x86_64-unknown-linux-gnu -DUNIX=1 -GNinja -DCMAKE_INSTALL_PREFIX=/home/alnyan/build/ygg/toolchain-c/prefix/host ../llvm
|
||||
cmake
|
||||
-DLLVM_ENABLE_PROJECTS="clang;lld;compiler-rt"
|
||||
-DLLVM_TARGETS_TO_BUILD=X86
|
||||
-DCMAKE_SYSTEM_NAME=yggdrasil
|
||||
-DLLVM_USE_LINKER=lld
|
||||
-DBUILD_SHARED_LIBS=false
|
||||
-DLLVM_BUILD_TOOLS=false
|
||||
-DLLVM_CCACHE_BUILD=true
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
-DCMAKE_HOST_TRIPLE=x86_64-unknown-linux-gnu
|
||||
-DUNIX=1
|
||||
-GNinja
|
||||
-DCMAKE_INSTALL_PREFIX=/home/alnyan/build/ygg/toolchain-c/prefix/host ../llvm
|
||||
|
||||
Build:
|
||||
cmake --build . -j 16
|
||||
@ -207,7 +260,13 @@ pub fn build_c(env: &BuildEnv, install: &mut Vec<(PathBuf, PathBuf)>) -> Result<
|
||||
install_openlibm(env, &libm)?;
|
||||
|
||||
build_test_c_program(env, &llvm, install)?;
|
||||
build_test_cpp_program(env, &llvm, install)?;
|
||||
|
||||
// TODO
|
||||
install.push((
|
||||
env.llvm_sysroot.join("lib/libc++.so"),
|
||||
"lib/libc++.so".into(),
|
||||
));
|
||||
install.push((ygglibc.shared_lib_file, "lib/libygglibc.so".into()));
|
||||
install.push((libm.shared_lib_file, "lib/libopenlibm.so.4".into()));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user