mirror of
https://github.com/XunilGroup/XunilOS.git
synced 2026-04-25 11:49:03 +02:00
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
This commit is contained in:
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "user/apps/doomgeneric"]
|
||||
path = user/apps/doomgeneric
|
||||
url = git@github.com:xunilGroup/doomgeneric-xunil.git
|
||||
Binary file not shown.
@@ -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,
|
||||
|
||||
@@ -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(),
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
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<u64, ()> {
|
||||
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::<Elf64Rela>() {
|
||||
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::<Elf64Dyn>();
|
||||
|
||||
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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
4
user/apps/helloworld/compile.sh
Normal file
4
user/apps/helloworld/compile.sh
Normal file
@@ -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
|
||||
6
user/apps/helloworld/helloworld.c
Normal file
6
user/apps/helloworld/helloworld.c
Normal file
@@ -0,0 +1,6 @@
|
||||
#include "../src/stdio.h"
|
||||
|
||||
void _start() {
|
||||
write(0, "Hello, World!", 13);
|
||||
exit(0);
|
||||
}
|
||||
2
user/libxunil/include/inttypes.h
Normal file
2
user/libxunil/include/inttypes.h
Normal file
@@ -0,0 +1,2 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
32
user/libxunil/include/stdio.h
Normal file
32
user/libxunil/include/stdio.h
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
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);
|
||||
20
user/libxunil/include/stdlib.h
Normal file
20
user/libxunil/include/stdlib.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
|
||||
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);
|
||||
22
user/libxunil/include/string.h
Normal file
22
user/libxunil/include/string.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
|
||||
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);
|
||||
8
user/libxunil/include/strings.h
Normal file
8
user/libxunil/include/strings.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
|
||||
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);
|
||||
@@ -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 {}
|
||||
22
user/libxunil/to_implement.txt
Normal file
22
user/libxunil/to_implement.txt
Normal file
@@ -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
|
||||
Reference in New Issue
Block a user