From 6ac13a876f33bb726ade75995aac3b5f87a90c4a Mon Sep 17 00:00:00 2001 From: csd4ni3l Date: Wed, 1 Apr 2026 21:25:34 +0200 Subject: [PATCH] Add ET_DYN support for the ELF loader, which required adding relocations, add some more functions to libxunil, use include inside of tests instead of manually defining types and add basic libc header files. Move libxunil to the user folder, and add helloworld and doomgeneric as apps --- .gitmodules | 3 + assets/helloworld.elf | Bin 13656 -> 14176 bytes kernel/src/driver/elf/header.rs | 40 ++++ kernel/src/driver/elf/loader.rs | 4 +- kernel/src/driver/elf/program.rs | 231 ++++++++++++++++++++- kernel/src/driver/elf/section.rs | 32 +-- kernel/src/driver/syscall.rs | 8 +- kernel/src/main.rs | 3 +- libxunil/tests/compile.sh | 4 - libxunil/tests/helloworld.c | 7 - user/apps/helloworld/compile.sh | 4 + user/apps/helloworld/helloworld.c | 6 + {libxunil => user/libxunil}/.gitignore | 0 {libxunil => user/libxunil}/Cargo.lock | 0 {libxunil => user/libxunil}/Cargo.toml | 0 user/libxunil/include/inttypes.h | 2 + user/libxunil/include/stdio.h | 32 +++ user/libxunil/include/stdlib.h | 20 ++ user/libxunil/include/string.h | 22 ++ user/libxunil/include/strings.h | 8 + {libxunil => user/libxunil}/src/lib.rs | 26 +++ {libxunil => user/libxunil}/src/syscall.rs | 0 user/libxunil/to_implement.txt | 22 ++ 23 files changed, 437 insertions(+), 37 deletions(-) create mode 100644 .gitmodules delete mode 100644 libxunil/tests/compile.sh delete mode 100644 libxunil/tests/helloworld.c create mode 100644 user/apps/helloworld/compile.sh create mode 100644 user/apps/helloworld/helloworld.c rename {libxunil => user/libxunil}/.gitignore (100%) rename {libxunil => user/libxunil}/Cargo.lock (100%) rename {libxunil => user/libxunil}/Cargo.toml (100%) create mode 100644 user/libxunil/include/inttypes.h create mode 100644 user/libxunil/include/stdio.h create mode 100644 user/libxunil/include/stdlib.h create mode 100644 user/libxunil/include/string.h create mode 100644 user/libxunil/include/strings.h rename {libxunil => user/libxunil}/src/lib.rs (59%) rename {libxunil => user/libxunil}/src/syscall.rs (100%) create mode 100644 user/libxunil/to_implement.txt diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..8de9921 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "user/apps/doomgeneric"] + path = user/apps/doomgeneric + url = git@github.com:xunilGroup/doomgeneric-xunil.git diff --git a/assets/helloworld.elf b/assets/helloworld.elf index 61a550d9e4827202b2648018f909429aaac25e2a..12f43350b2b3a6a4c324fa4b934b5ffd2014cb60 100755 GIT binary patch literal 14176 zcmeHO-D@0G6u+A^O_^$1 zZMGt~S_}j%_Cc@@6$1JozWCxp&_as=tq%e550JbB0)4Q8tx9RebMBmzOvgl86d&{+ znEN~T+;i@^_cxmx=H8jN`Ud+OLLtG@C=Lp&g~OgDK@D05DF6x4CALDjON6EGrnRO& zX>$#pi4j7iV2&o#s2;?c^b&%R+c8e&)5sx!zmS>HAGaCW7In{I@!*}P5e1AKhr|D? zI7t9@Me$p_ZsizpoLw~kAU;BVjB-w38(wlO)We$R5X5IavtZ=7V-Sbqyjx+~la%jn zd7){_`R#^ejc^SNjf%Y|c8@j)*GspTe;XNl>FT2&;aJe0FRb6IEI#K&Ft4xh z!0)vq<*yh}3@8Q^1BwB~fMP%~pcqgLCX=A4xi7WH={o+)UU0K8Z%4Axu&I^ zLVURc?8eMDmyx371Qee3o$I>iudR$2Gq>D57oS3(ujlZ2^fGp2%>1}ek6w9o-uU(k zIJ)&Wn?u4lmk3pF%wsZiT&T}OsYEfL7*Gr-1{4E|0mXn~Krx^gPz)#r6a$KZe~AIZ z&gV-{Y9~tNy!9~T47D~sgOBKVmVEsu*L@Giaou%K0<;0*dHmymvw$xEUIH8g{2mYm z&xBDzZzM&i77n#;Z{Bhq_5~gS8(y=}=VR#5(-NL;=-t6*)_AOoc|V1AIx?3>@WWtx z4QzbuyBF#fT= zs1}RFo{q#K-J)ErI2rA5ScN+Y=MkM0;kksz-!*_~oIV zBhU8=(}eqO_8De>vgb&jX&g=pb71i3p`JnWXn+4m-*NMJ&!NFSQ=FYA!60(*}RkA|2&J-ciL#HhC zvYk(%QRt3cbD&<533WSbPLxvx+ssVL_znhJ|1K~vcJqOqEbCsL0MsWN%DU7(MhJxQ=pz!+R)!_RRQ1G|R@pV!dd0oQ1 z__xaOY)^m<`{sCFHyMNLRd7WXzJxjj?^TW^kj`(5C^Je_S9}GJ4&t{w-&Yk(;^^d>T zk)1<3=jC`>uEg8WhT~t2r}c0V-rGW9f3LPyXZtiX_~Us!U8Z=xPaDO*Pw^3UU?c;s z(|*BRD1KbMcV3e$4T`Um<4&;R-x-ga$A$lYdG0chimOpi`O0quo%6DJ7bxq+pN)AQ K7ub<782<-4FjKk! delta 1018 zcmaiy&ubGw6vy9eY;_Y%22=Y3+hkK(3RTmXZIf0+w}?Tol!BhbQqyE(m88LtU{o;X zBwobydB{Of!T+GS^dtz4xp?sA!9$KY2#PmBsBd;>Y!SqPw{PC(edo>W%pw1@UnG_z#n`meII^1$7+zI=MtNk?T&Nwl2FIdh*dBeq^yxK+_O;|@Bqr)tUMC|$rCjywj z9kvqrZ*iQ~LIWRuPX72(NmZ`4f3+U5*Q2}NPmOQa`G9|mkLrFZc=>7j9owGd-GFZ7 zO2vY4G2+E#W1MyIt`TNEY#71gFTd^W$-97IT9hSwk2}VRkv3(5@?1jkf^3(Vk2Wy_ zp6lGgPi$-}R%Ibf$A<8EEL7`(GkRf)!6!_Mc6_ll)_Hkv_y{Ow@bu9hKMDrVE=G(_!+gW9|C+cmMzZ diff --git a/kernel/src/driver/elf/header.rs b/kernel/src/driver/elf/header.rs index 1355965..5d1ed80 100644 --- a/kernel/src/driver/elf/header.rs +++ b/kernel/src/driver/elf/header.rs @@ -101,6 +101,39 @@ pub const AT_UID: u64 = 11; pub const AT_GID: u64 = 13; pub const AT_NULL: u64 = 0; +// Dynamic structure types +pub const DT_NULL: i64 = 0; +pub const DT_NEEDED: i64 = 1; +pub const DT_PLTRELSZ: i64 = 2; +pub const DT_PLTGOT: i64 = 3; +pub const DT_HASH: i64 = 4; +pub const DT_STRTAB: i64 = 5; +pub const DT_SYMTAB: i64 = 6; +pub const DT_RELA: i64 = 7; +pub const DT_RELASZ: i64 = 8; +pub const DT_RELAENT: i64 = 9; +pub const DT_STRSZ: i64 = 10; +pub const DT_SYMENT: i64 = 11; +pub const DT_INIT: i64 = 12; +pub const DT_FINI: i64 = 13; +pub const DT_SONAME: i64 = 14; +pub const DT_RPATH: i64 = 15; +pub const DT_SYMBOLIC: i64 = 16; +pub const DT_REL: i64 = 17; +pub const DT_RELSZ: i64 = 18; +pub const DT_RELENT: i64 = 19; +pub const DT_PLTREL: i64 = 20; +pub const DT_DEBUG: i64 = 21; +pub const DT_TEXTREL: i64 = 22; +pub const DT_JMPREL: i64 = 23; +pub const DT_BIND_NOW: i64 = 24; +pub const DT_RUNPATH: i64 = 29; +pub const DT_FLAGS: i64 = 30; +pub const DT_GNU_HASH: i64 = 0x6ffffef5; +pub const DT_VERSYM: i64 = 0x6ffffff0; +pub const DT_VERNEED: i64 = 0x6ffffffe; +pub const DT_VERNEEDNUM: i64 = 0x6fffffff; + #[repr(C)] pub struct Elf64Ehdr { pub e_ident: [u8; 16], @@ -155,6 +188,13 @@ pub struct Elf64Sym { pub st_size: u64, } +#[repr(C)] +#[derive(Copy, Clone, Debug)] +pub struct Elf64Dyn { + pub d_tag: i64, + pub d_val: u64, +} + #[repr(C)] pub struct Elf64Rela { pub r_offset: u64, diff --git a/kernel/src/driver/elf/loader.rs b/kernel/src/driver/elf/loader.rs index 4149613..2022004 100644 --- a/kernel/src/driver/elf/loader.rs +++ b/kernel/src/driver/elf/loader.rs @@ -36,8 +36,8 @@ pub fn load_file( } return match elf_header.e_type { - ET_EXEC => unsafe { load_program(frame_allocator, mapper, elf_header, elf_bytes) }, - ET_DYN => return null(), // TODO + ET_EXEC => unsafe { load_program(frame_allocator, mapper, elf_header, elf_bytes, false) }, + ET_DYN => unsafe { load_program(frame_allocator, mapper, elf_header, elf_bytes, true) }, // TODO ET_REL => return null(), _ => return null(), }; diff --git a/kernel/src/driver/elf/program.rs b/kernel/src/driver/elf/program.rs index c27a7e5..0fa7d69 100644 --- a/kernel/src/driver/elf/program.rs +++ b/kernel/src/driver/elf/program.rs @@ -1,3 +1,9 @@ +use core::{ + ffi::CStr, + ptr::{null, null_mut}, +}; + +use alloc::vec::Vec; use x86_64::{ VirtAddr, structures::paging::{ @@ -8,7 +14,16 @@ use x86_64::{ use crate::{ arch::x86_64::paging::XunilFrameAllocator, driver::{ - elf::header::{Elf64Ehdr, Elf64Phdr, PF_X, PT_LOAD}, + elf::{ + header::{ + DT_JMPREL, DT_NEEDED, DT_NULL, DT_PLTREL, DT_PLTRELSZ, DT_RELA, DT_RELAENT, + DT_RELASZ, DT_STRSZ, DT_STRTAB, DT_SYMENT, DT_SYMTAB, Elf64Dyn, Elf64Ehdr, + Elf64Phdr, Elf64Rela, Elf64Sym, PF_X, PT_DYNAMIC, PT_LOAD, R_X86_64_64, + R_X86_64_GLOB_DAT, R_X86_64_JUMP_SLOT, R_X86_64_NONE, R_X86_64_RELATIVE, SHN_UNDEF, + STB_WEAK, + }, + reloc::elf_do_reloc, + }, syscall::memset, }, util::{align_down, align_up}, @@ -20,24 +35,229 @@ pub unsafe fn elf_pheader(hdr: *const Elf64Ehdr) -> *const Elf64Phdr { unsafe { (hdr as *const u8).add((*hdr).e_phoff as usize) as *const Elf64Phdr } } +pub fn get_vaddr(phdr: *const Elf64Phdr, load_bias: u64) -> *mut u8 { + unsafe { ((*phdr).p_vaddr + load_bias) as *mut u8 } +} + pub unsafe fn load_program( frame_allocator: &mut XunilFrameAllocator, mapper: &mut OffsetPageTable, hdr: *const Elf64Ehdr, elf_bytes: &[u8], + pie: bool, ) -> *const u8 { let phdr = unsafe { elf_pheader(hdr) }; let phnum = unsafe { (*hdr).e_phnum }; + let mut program_headers: Vec<*const Elf64Phdr> = Vec::new(); + let mut pt_dynamic_header: *const Elf64Phdr = core::ptr::null(); for i in 0..phnum { let program_header = unsafe { phdr.add(i as usize) }; + let p_type = unsafe { (*program_header).p_type }; - if unsafe { (*program_header).p_type } == PT_LOAD { - load_segment_to_memory(frame_allocator, mapper, program_header, elf_bytes); + if p_type == PT_LOAD { + program_headers.push(program_header); + } else if p_type == PT_DYNAMIC { + pt_dynamic_header = program_header as *const Elf64Phdr; } } - return unsafe { (*hdr).e_entry as *const u8 }; + if !pie { + for program_header in program_headers { + load_segment_to_memory(frame_allocator, mapper, program_header, elf_bytes, 0); + } + return unsafe { (*hdr).e_entry as *const u8 }; + } else { + let base_address = 0x0000_0100_0000; // TODO: add per-process memory + let min_vaddr = align_down( + program_headers + .iter() + .map(|&phdr| get_vaddr(phdr, 0) as u64) + .min() + .unwrap(), + 4096, + ); + + let load_bias = base_address - min_vaddr; + + for program_header in program_headers { + load_segment_to_memory( + frame_allocator, + mapper, + program_header, + elf_bytes, + load_bias, + ); + } + + if pt_dynamic_header.is_null() { + return null(); + } + + parse_dyn( + hdr, + pt_dynamic_header, + unsafe { elf_bytes.as_ptr().add((*phdr).p_offset as usize) as *const Elf64Dyn }, + load_bias, + ); + + return unsafe { ((*hdr).e_entry + load_bias) as *const u8 }; + } +} + +fn cstr_from_strtab( + strtab_ptr: *const u8, + strtab_size: u64, + off: u32, +) -> Option<&'static core::ffi::CStr> { + let off = off as u64; + if strtab_ptr.is_null() || off >= strtab_size { + return None; + } + + let mut i = off; + + while i < strtab_size { + let b = unsafe { *strtab_ptr.add(i as usize) }; + if b == 0 { + let start = unsafe { strtab_ptr.add(off as usize) } as *const core::ffi::c_char; + return Some(unsafe { CStr::from_ptr(start as *const i8) }); + } + i += 1; + } + + None +} + +pub fn dyn_get_symaddr( + strtab_ptr: *const u8, + strtab_size: u64, + symtab_ptr: *const Elf64Sym, + idx: u64, + load_bias: u64, +) -> Result { + let sym = unsafe { &*symtab_ptr.add(idx as usize) }; + if sym.st_shndx != SHN_UNDEF { + return Ok(load_bias + sym.st_value); + } + + let name = cstr_from_strtab(strtab_ptr, strtab_size, idx as u32); + + let bind = sym.st_info >> 4; + if bind == STB_WEAK { Ok(0) } else { Err(()) } +} + +fn apply_relocations( + hdr: *const Elf64Ehdr, + rela_ptr: *mut Elf64Rela, + rela_table_size: u64, + symtab_ptr: *const Elf64Sym, + strtab_ptr: *const u8, + strtab_size: u64, + load_bias: u64, +) { + for i in 0..rela_table_size as usize / size_of::() { + let rela_ptr = unsafe { rela_ptr.add(i) }; + let ptr = unsafe { (load_bias + (*rela_ptr).r_offset) as *mut u64 }; + let mut value: u64 = 0; + match unsafe { ((*rela_ptr).r_info & 0xffff_ffff) as u32 } { + x if x == R_X86_64_RELATIVE as u32 => unsafe { + value = (load_bias as i64 + (*rela_ptr).r_addend) as u64; + }, + x if x == R_X86_64_64 as u32 => unsafe { + value = (dyn_get_symaddr( + strtab_ptr, + strtab_size, + symtab_ptr, + (*rela_ptr).r_info >> 32, + load_bias, + ) + .unwrap() as i64 + + (*rela_ptr).r_addend) as u64; + }, + x if [R_X86_64_GLOB_DAT, R_X86_64_JUMP_SLOT].contains(&x) => unsafe { + value = dyn_get_symaddr( + strtab_ptr, + strtab_size, + symtab_ptr, + (*rela_ptr).r_info >> 32, + load_bias, + ) + .unwrap() as u64; + }, + x if x == R_X86_64_NONE as u32 => { + continue; // explicitly do nothing + } + _ => { + continue; + } + } + unsafe { *ptr = value }; + } +} + +fn parse_dyn( + hdr: *const Elf64Ehdr, + phdr: *const Elf64Phdr, + dyn_hdr_original: *const Elf64Dyn, + load_bias: u64, +) { + let mut i: usize = 0; + let file_size: u64 = unsafe { (*phdr).p_filesz }; + + let mut rela_ptr: *mut Elf64Rela = null_mut(); + let mut rela_table_size: u64 = 0; + + let mut symtab_ptr: *const Elf64Sym = null(); + + let mut strtab_ptr: *const u8 = null(); + let mut strtab_size: u64 = 0; + + let max = file_size as usize / size_of::(); + + while unsafe { (*dyn_hdr_original.add(i)).d_tag != DT_NULL } && i < max { + let dyn_hdr = unsafe { *(dyn_hdr_original.add(i)) }; + match dyn_hdr.d_tag { + DT_RELA => rela_ptr = (dyn_hdr.d_val + load_bias) as *mut Elf64Rela, + DT_RELASZ => { + rela_table_size = dyn_hdr.d_val; + } + DT_JMPREL => { + // TODO: plt relocations + } + DT_PLTREL => { + // TODO: plt relocations + } + DT_PLTRELSZ => { + // TODO: plt relocations + } + DT_NEEDED => { + // TODO: do dynamic loading + } + DT_SYMTAB => symtab_ptr = (dyn_hdr.d_val + load_bias) as *const Elf64Sym, + DT_STRTAB => strtab_ptr = (dyn_hdr.d_val + load_bias) as *const u8, + DT_STRSZ => { + strtab_size = dyn_hdr.d_val; + } + _ => (), + } + + i += 1; + } + + if rela_ptr.is_null() || symtab_ptr.is_null() || strtab_ptr.is_null() { + return; + } + + apply_relocations( + hdr, + rela_ptr, + rela_table_size, + symtab_ptr, + strtab_ptr, + strtab_size, + load_bias, + ); } pub fn load_segment_to_memory( @@ -45,12 +265,13 @@ pub fn load_segment_to_memory( mapper: &mut OffsetPageTable, phdr: *const Elf64Phdr, elf_bytes: &[u8], + load_bias: u64, ) { let mem_size: u64 = unsafe { (*phdr).p_memsz }; let p_offset: u64 = unsafe { (*phdr).p_offset }; let file_size: u64 = unsafe { (*phdr).p_filesz }; - let vaddr: *mut u8 = unsafe { (*phdr).p_vaddr as *mut u8 }; + let vaddr: *mut u8 = get_vaddr(phdr, load_bias); if p_offset > elf_bytes.len() as u64 || file_size > elf_bytes.len() as u64 diff --git a/kernel/src/driver/elf/section.rs b/kernel/src/driver/elf/section.rs index 1900782..64aa46a 100644 --- a/kernel/src/driver/elf/section.rs +++ b/kernel/src/driver/elf/section.rs @@ -11,25 +11,29 @@ pub unsafe fn elf_section(hdr: *const Elf64Ehdr, idx: usize) -> *const Elf64Shdr unsafe { elf_sheader(hdr).add(idx) } } -// pub unsafe fn elf_str_table(hdr: *const Elf64Ehdr) -> *const u8 { -// if unsafe { (*hdr).e_shstrndx == SHN_UNDEF } { -// return core::ptr::null(); -// } +pub unsafe fn elf_str_table(hdr: *const Elf64Ehdr) -> *const u8 { + if unsafe { (*hdr).e_shstrndx == SHN_UNDEF } { + return core::ptr::null(); + } -// let shdr = unsafe { elf_section(hdr, (*hdr).e_shstrndx as usize) }; + let shdr = unsafe { elf_section(hdr, (*hdr).e_shstrndx as usize) }; -// unsafe { (hdr as *const u8).add((*shdr).sh_offset as usize) } -// } + unsafe { (hdr as *const u8).add((*shdr).sh_offset as usize) } +} -// pub unsafe fn elf_lookup_string(hdr: *const Elf64Ehdr, offset: usize) -> *const u8 { -// let str_tab: *const u8 = unsafe { elf_str_table(hdr) }; +fn elf_lookup_string<'a>(hdr: *const Elf64Ehdr, offset: usize) -> &'a str { + let strtab: *const u8 = unsafe { elf_str_table(hdr) }; + let mut len = 0; -// if str_tab.is_null() { -// return core::ptr::null(); -// } + let start = unsafe { strtab.add(offset) }; -// return unsafe { str_tab.add(offset) }; -// } + unsafe { + while *start.add(len) != 0 { + len += 1; + } + core::str::from_raw_parts(start, len) + } +} pub fn elf_lookup_symbol(name: &CStr) -> *const u8 { return core::ptr::null(); diff --git a/kernel/src/driver/syscall.rs b/kernel/src/driver/syscall.rs index 9e268a0..62fafc4 100644 --- a/kernel/src/driver/syscall.rs +++ b/kernel/src/driver/syscall.rs @@ -39,6 +39,10 @@ pub unsafe fn free(ptr: *mut u8, size: usize, align: usize) { } } +pub unsafe fn memset(ptr: *mut u8, val: u8, count: usize) { + unsafe { core::ptr::write_bytes(ptr, val, count) }; +} + #[unsafe(no_mangle)] pub unsafe extern "C" fn syscall_dispatch( num: usize, @@ -65,9 +69,5 @@ pub unsafe extern "C" fn syscall_dispatch( } } -pub unsafe fn memset(ptr: *mut u8, val: u8, count: usize) { - unsafe { core::ptr::write_bytes(ptr, val, count) }; -} - pub type Fd = i32; pub type Off = i64; diff --git a/kernel/src/main.rs b/kernel/src/main.rs index b7d1297..98c395a 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -1,7 +1,8 @@ #![no_std] #![no_main] #![feature(abi_x86_interrupt)] - +#![feature(str_from_raw_parts)] +#![allow(warnings)] extern crate alloc; use core::fmt::Write; diff --git a/libxunil/tests/compile.sh b/libxunil/tests/compile.sh deleted file mode 100644 index 6f67051..0000000 --- a/libxunil/tests/compile.sh +++ /dev/null @@ -1,4 +0,0 @@ -gcc -nostdlib -nostdinc -static -no-pie \ - -o $1 $1.c \ - -L../target/release -l:libxunil.a -mv $1 ../../assets/$1.elf diff --git a/libxunil/tests/helloworld.c b/libxunil/tests/helloworld.c deleted file mode 100644 index 9f4caf3..0000000 --- a/libxunil/tests/helloworld.c +++ /dev/null @@ -1,7 +0,0 @@ -void write(int fd, const char* buf, unsigned long count); -void exit(int code); - -void _start() { - write(1, "Hello from C!\n", 14); - exit(0); -} diff --git a/user/apps/helloworld/compile.sh b/user/apps/helloworld/compile.sh new file mode 100644 index 0000000..9dd4556 --- /dev/null +++ b/user/apps/helloworld/compile.sh @@ -0,0 +1,4 @@ +gcc -nostdlib -nostdinc -static -static-pie \ + -o $1 $1.c \ + -L../../libxunil/target/release -l:libxunil.a +mv $1 ../../../assets/$1.elf diff --git a/user/apps/helloworld/helloworld.c b/user/apps/helloworld/helloworld.c new file mode 100644 index 0000000..ac017d3 --- /dev/null +++ b/user/apps/helloworld/helloworld.c @@ -0,0 +1,6 @@ +#include "../src/stdio.h" + +void _start() { + write(0, "Hello, World!", 13); + exit(0); +} diff --git a/libxunil/.gitignore b/user/libxunil/.gitignore similarity index 100% rename from libxunil/.gitignore rename to user/libxunil/.gitignore diff --git a/libxunil/Cargo.lock b/user/libxunil/Cargo.lock similarity index 100% rename from libxunil/Cargo.lock rename to user/libxunil/Cargo.lock diff --git a/libxunil/Cargo.toml b/user/libxunil/Cargo.toml similarity index 100% rename from libxunil/Cargo.toml rename to user/libxunil/Cargo.toml diff --git a/user/libxunil/include/inttypes.h b/user/libxunil/include/inttypes.h new file mode 100644 index 0000000..c2d4f4b --- /dev/null +++ b/user/libxunil/include/inttypes.h @@ -0,0 +1,2 @@ +#include +#include diff --git a/user/libxunil/include/stdio.h b/user/libxunil/include/stdio.h new file mode 100644 index 0000000..1749750 --- /dev/null +++ b/user/libxunil/include/stdio.h @@ -0,0 +1,32 @@ +#pragma once +#include +#include + +typedef struct FILE FILE; + +extern FILE *stdin; +extern FILE *stdout; +extern FILE *stderr; + +#define EOF (-1) + +FILE *fopen(const char *path, const char *mode); +int fclose(FILE *fp); +size_t fread(void *ptr, size_t size, size_t nmemb, FILE *fp); +size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *fp); +int fseek(FILE *fp, long offset, int whence); +long ftell(FILE *fp); +int fflush(FILE *fp); +char *fgets(char *s, int size, FILE *fp); +int fputs(const char *s, FILE *fp); +int feof(FILE *fp); +int ferror(FILE *fp); + +int printf(const char *fmt, ...); +int fprintf(FILE *fp, const char *fmt, ...); +int sprintf(char *buf, const char *fmt, ...); +int snprintf(char *buf, size_t size, const char *fmt, ...); +int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap); +int vfprintf(FILE *fp, const char *fmt, va_list ap); +void write(int fd, const char* buf, unsigned long count); +void exit(int code); diff --git a/user/libxunil/include/stdlib.h b/user/libxunil/include/stdlib.h new file mode 100644 index 0000000..c9fbb5f --- /dev/null +++ b/user/libxunil/include/stdlib.h @@ -0,0 +1,20 @@ +#pragma once +#include + +void *malloc(size_t size); +void *calloc(size_t nmemb, size_t size); +void *realloc(void *ptr, size_t size); +void free(void *ptr); + +void exit(int status); +void abort(void); + +int atoi(const char *s); +long atol(const char *s); +double atof(const char *s); +long strtol(const char *s, char **endptr, int base); +double strtod(const char *s, char **endptr); + +char *getenv(const char *name); +void qsort(void *base, size_t nmemb, size_t size, int (*cmp)(const void *, const void *)); +int abs(int x); diff --git a/user/libxunil/include/string.h b/user/libxunil/include/string.h new file mode 100644 index 0000000..c4209c4 --- /dev/null +++ b/user/libxunil/include/string.h @@ -0,0 +1,22 @@ +#pragma once +#include + +void *memset(void *s, int c, size_t n); +void *memcpy(void *dst, const void *src, size_t n); +void *memmove(void *dst, const void *src, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); +void *memchr(const void *s, int c, size_t n); + +size_t strlen(const char *s); +char *strcpy(char *dst, const char *src); +char *strncpy(char *dst, const char *src, size_t n); +char *strcat(char *dst, const char *src); +char *strncat(char *dst, const char *src, size_t n); +int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); +char *strchr(const char *s, int c); +char *strrchr(const char *s, int c); +char *strstr(const char *haystack, const char *needle); +char *strtok(char *str, const char *delim); +char *strdup(const char *s); +char *strerror(int errnum); diff --git a/user/libxunil/include/strings.h b/user/libxunil/include/strings.h new file mode 100644 index 0000000..5abbdee --- /dev/null +++ b/user/libxunil/include/strings.h @@ -0,0 +1,8 @@ +#pragma once +#include + +int strcasecmp(const char *s1, const char *s2); +int strncasecmp(const char *s1, const char *s2, size_t n); +void bzero(void *s, size_t n); +void bcopy(const void *src, void *dest, size_t n); +int bcmp(const void *s1, const void *s2, size_t n); diff --git a/libxunil/src/lib.rs b/user/libxunil/src/lib.rs similarity index 59% rename from libxunil/src/lib.rs rename to user/libxunil/src/lib.rs index 4f27d7e..94043a6 100644 --- a/libxunil/src/lib.rs +++ b/user/libxunil/src/lib.rs @@ -35,6 +35,32 @@ extern "C" fn puts(s: *const u8) -> isize { 0 } +#[unsafe(no_mangle)] +extern "C" fn abs(n: i32) -> i32 { + n.abs() +} + +#[unsafe(no_mangle)] +extern "C" fn atoi(mut c: *const u8) -> i32 { + let mut value: i32 = 0; + let mut sign: i32 = 1; + unsafe { + if (*c) == b'+' || (*c) == b'-' { + if *c == b'-' { + sign = -1; + } + c = c.add(1); + } + while (*c).is_ascii_digit() { + value *= 10; + value += ((*c) - b'0') as i32; + c = c.add(1); + } + } + + value * sign +} + #[panic_handler] fn panic(_: &core::panic::PanicInfo) -> ! { loop {} diff --git a/libxunil/src/syscall.rs b/user/libxunil/src/syscall.rs similarity index 100% rename from libxunil/src/syscall.rs rename to user/libxunil/src/syscall.rs diff --git a/user/libxunil/to_implement.txt b/user/libxunil/to_implement.txt new file mode 100644 index 0000000..d335a2a --- /dev/null +++ b/user/libxunil/to_implement.txt @@ -0,0 +1,22 @@ +abs +atoi +calloc +__ctype_toupper_loc +fprintf +free +malloc +memcpy +memset +printf +realloc +__stack_chk_fail +stderr +strcasecmp +strcmp +strdup +strlen +strncasecmp +strncmp +strncpy +strrchr +toupper