Added libc code
This commit is contained in:
@@ -2,16 +2,14 @@
|
|||||||
|
|
||||||
SecureLang Library for C
|
SecureLang Library for C
|
||||||
|
|
||||||
THIS IS A TEST EDIT.
|
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* A subset of traditional libc features (e.g. `printf`)
|
* A subset of traditional libc features (e.g. provides `printf`)
|
||||||
* Some support for high level language features like garbage collection
|
* Some support for high level language features like garbage collection
|
||||||
* Simple licensing, with only small exceptions the code was written by me
|
* Simple copyright, with only small exceptions the code was written by me
|
||||||
|
|
||||||
## Limitations
|
## Limitations
|
||||||
|
|
||||||
* Doesn't support all legacy functions
|
* Doesn't support all legacy functions (e.g. doesn't provide `scanf`)
|
||||||
* Incomplete support for error handling, multithreading, signals etc.
|
* Incomplete support for error handling, multithreading, signals etc.
|
||||||
* Currently used for testing in-house systems so not readily buildable/testable on commodity platforms
|
* Currently used for testing in-house systems so not readily buildable/testable on commodity platforms
|
||||||
|
113
ctype.c
Normal file
113
ctype.c
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
int isspace(int ch) {
|
||||||
|
return (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
int isdigit(int ch) {
|
||||||
|
return (ch >= '0') && (ch <= '9');
|
||||||
|
}
|
||||||
|
|
||||||
|
int isxdigit(int ch) {
|
||||||
|
return isdigit(ch) || ((ch >= 'a') && (ch <= 'f')) || ((ch >= 'A') && (ch <= 'F'));
|
||||||
|
}
|
||||||
|
|
||||||
|
int isalpha(int ch) {
|
||||||
|
return ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'));
|
||||||
|
}
|
||||||
|
|
||||||
|
int isalnum(int ch) {
|
||||||
|
return isalpha(ch) || isdigit(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
int isprint(int ch) {
|
||||||
|
return isalnum(ch) || isspace(ch) || ispunct(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ispunct(int ch) {
|
||||||
|
switch (ch) {
|
||||||
|
case ',':
|
||||||
|
case '<':
|
||||||
|
case '.':
|
||||||
|
case '>':
|
||||||
|
case '/':
|
||||||
|
case '?':
|
||||||
|
case ';':
|
||||||
|
case ':':
|
||||||
|
case '\'':
|
||||||
|
case '\"':
|
||||||
|
case '[':
|
||||||
|
case ']':
|
||||||
|
case '{':
|
||||||
|
case '}':
|
||||||
|
case '`':
|
||||||
|
case '~':
|
||||||
|
case '@':
|
||||||
|
case '#':
|
||||||
|
case '$':
|
||||||
|
case '%':
|
||||||
|
case '^':
|
||||||
|
case '&':
|
||||||
|
case '*':
|
||||||
|
case '(':
|
||||||
|
case ')':
|
||||||
|
case '-':
|
||||||
|
case '_':
|
||||||
|
case '=':
|
||||||
|
case '+':
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int isupper(int ch) {
|
||||||
|
if (ch >= 'A' && ch <= 'Z') {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int islower(int ch) {
|
||||||
|
if (ch >= 'a' && ch <= 'a') {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int toupper(int ch) {
|
||||||
|
if (ch >= 'a' && ch <= 'z') {
|
||||||
|
return ((int)'A') + (ch - ((int)'a'));
|
||||||
|
} else {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int tolower(int ch) {
|
||||||
|
if (ch >= 'A' && ch <= 'Z') {
|
||||||
|
return ((int)'a') + (ch - ((int)'A'));
|
||||||
|
} else {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int isascii(int ch) {
|
||||||
|
int ascii = ch & 0x7F;
|
||||||
|
if (ch == ascii) {
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
370
elf.h
Normal file
370
elf.h
Normal file
@@ -0,0 +1,370 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
#ifndef _LIBC_ELF
|
||||||
|
#define _LIBC_ELF
|
||||||
|
|
||||||
|
// For the purposes of the audit program this is NEW CODE (but was written by me a while ago)
|
||||||
|
|
||||||
|
/* NOTE: The specification used as a reference is the draft at https://refspecs.linuxfoundation.org/elf/gabi4+/contents.html
|
||||||
|
* This header includes both 32-bit and 64-bit types.
|
||||||
|
* For x86-64 specific information I used as a reference https://refspecs.linuxfoundation.org/elf/x86_64-abi-0.95.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef uint32_t Elf32_Addr;
|
||||||
|
typedef uint32_t Elf32_Off;
|
||||||
|
typedef uint32_t Elf32_Word;
|
||||||
|
typedef int32_t Elf32_Sword;
|
||||||
|
typedef uint16_t Elf32_Half;
|
||||||
|
|
||||||
|
typedef uint64_t Elf64_Addr;
|
||||||
|
typedef uint64_t Elf64_Off;
|
||||||
|
typedef uint32_t Elf64_Word;
|
||||||
|
typedef int32_t Elf64_Sword;
|
||||||
|
typedef uint64_t Elf64_Xword;
|
||||||
|
typedef int64_t Elf64_Sxword;
|
||||||
|
typedef uint16_t Elf64_Half;
|
||||||
|
*/
|
||||||
|
typedef unsigned int Elf32_Addr;
|
||||||
|
typedef unsigned int Elf32_Off;
|
||||||
|
typedef unsigned int Elf32_Word;
|
||||||
|
typedef int Elf32_Sword;
|
||||||
|
typedef unsigned short Elf32_Half;
|
||||||
|
|
||||||
|
typedef unsigned long long Elf64_Addr;
|
||||||
|
typedef unsigned long long Elf64_Off;
|
||||||
|
typedef unsigned int Elf64_Word;
|
||||||
|
typedef int Elf64_Sword;
|
||||||
|
typedef unsigned long long Elf64_Xword;
|
||||||
|
typedef long long Elf64_Sxword;
|
||||||
|
typedef unsigned short Elf64_Half;
|
||||||
|
|
||||||
|
#define EV_NONE 0
|
||||||
|
#define EV_CURRENT 1
|
||||||
|
|
||||||
|
#define EI_MAG0 0
|
||||||
|
#define EI_MAG1 1
|
||||||
|
#define EI_MAG2 2
|
||||||
|
#define EI_MAG3 3
|
||||||
|
#define EI_CLASS 4
|
||||||
|
#define EI_DATA 5
|
||||||
|
#define EI_VERSION 6
|
||||||
|
#define EI_OSABI 7
|
||||||
|
#define EI_ABIVERSION 8
|
||||||
|
#define EI_PAD 9
|
||||||
|
#define EI_NIDENT 16
|
||||||
|
|
||||||
|
#define ELFMAG0 0x7F
|
||||||
|
#define ELFMAG1 'E'
|
||||||
|
#define ELFMAG2 'L'
|
||||||
|
#define ELFMAG3 'F'
|
||||||
|
|
||||||
|
#define ELFCLASSNONE 0
|
||||||
|
#define ELFCLASS32 1
|
||||||
|
#define ELFCLASS64 2
|
||||||
|
|
||||||
|
#define ELFDATANONE 0
|
||||||
|
#define ELFDATA2LSB 1
|
||||||
|
#define ELFDATA2MSB 2
|
||||||
|
|
||||||
|
|
||||||
|
#define ET_NONE 0
|
||||||
|
#define ET_REL 1
|
||||||
|
#define ET_EXEC 2
|
||||||
|
#define ET_DYN 3
|
||||||
|
#define ET_CORE 4
|
||||||
|
#define ET_LOOS 0xFE00
|
||||||
|
#define ET_HIOS 0xFEFF
|
||||||
|
#define ET_LOPROC 0xFF00
|
||||||
|
#define ET_HIPROC 0xFFFF
|
||||||
|
|
||||||
|
#define EM_X86_64 62
|
||||||
|
|
||||||
|
#define ELFOSABI_NONE 0
|
||||||
|
/* NOTE: SYSV is apparently the same as "NONE". */
|
||||||
|
#define ELFOSABI_SYSV 0
|
||||||
|
#define ELFOSABI_NETBSD 2
|
||||||
|
#define ELFOSABI_LINUX 3
|
||||||
|
#define ELFOSABI_SOLARIS 6
|
||||||
|
#define ELFOSABI_FREEBSD 9
|
||||||
|
#define ELFOSABI_OPENBSD 12
|
||||||
|
|
||||||
|
#define SHT_NULL 0
|
||||||
|
#define SHT_PROGBITS 1
|
||||||
|
#define SHT_SYMTAB 2
|
||||||
|
#define SHT_STRTAB 3
|
||||||
|
#define SHT_RELA 4
|
||||||
|
#define SHT_HASH 5
|
||||||
|
#define SHT_DYNAMIC 6
|
||||||
|
#define SHT_NOTE 7
|
||||||
|
#define SHT_NOBITS 8
|
||||||
|
#define SHT_REL 9
|
||||||
|
#define SHT_SHLIB 10
|
||||||
|
#define SHT_DYNSYM 11
|
||||||
|
#define SHT_INIT_ARRAY 14
|
||||||
|
#define SHT_FINI_ARRAY 15
|
||||||
|
#define SHT_PREINIT_ARRAY 16
|
||||||
|
#define SHT_GROUP 17
|
||||||
|
#define SHT_SYMTAB_SHNDX 18
|
||||||
|
#define SHT_LOOS 0x60000000
|
||||||
|
#define SHT_HIOS 0x6fffffff
|
||||||
|
#define SHT_LOPROC 0x70000000
|
||||||
|
#define SHT_HIPROC 0x7fffffff
|
||||||
|
#define SHT_LOUSER 0x80000000
|
||||||
|
#define SHT_HIUSER 0xffffffff
|
||||||
|
|
||||||
|
#define SHN_UNDEF 0
|
||||||
|
#define SHN_LORESERVE 0xff00
|
||||||
|
#define SHN_LOPROC 0xff00
|
||||||
|
#define SHN_HIPROC 0xff1f
|
||||||
|
#define SHN_LOOS 0xff20
|
||||||
|
#define SHN_HIOS 0xff3f
|
||||||
|
#define SHN_ABS 0xfff1
|
||||||
|
#define SHN_COMMON 0xfff2
|
||||||
|
#define SHN_XINDEX 0xffff
|
||||||
|
#define SHN_HIRESERVE 0xffff
|
||||||
|
|
||||||
|
#define SHF_WRITE 0x1
|
||||||
|
#define SHF_ALLOC 0x2
|
||||||
|
#define SHF_EXECINSTR 0x4
|
||||||
|
#define SHF_MERGE 0x10
|
||||||
|
#define SHF_STRINGS 0x20
|
||||||
|
#define SHF_INFO_LINK 0x40
|
||||||
|
#define SHF_LINK_ORDER 0x80
|
||||||
|
#define SHF_OS_NONCONFORMING 0x100
|
||||||
|
#define SHF_GROUP 0x200
|
||||||
|
#define SHF_TLS 0x400
|
||||||
|
#define SHF_MASKOS 0x0ff00000
|
||||||
|
#define SHF_MASKPROC 0xf0000000
|
||||||
|
|
||||||
|
|
||||||
|
#define STN_UNDEF 0
|
||||||
|
|
||||||
|
#define PT_NULL 0
|
||||||
|
#define PT_LOAD 1
|
||||||
|
#define PT_DYNAMIC 2
|
||||||
|
#define PT_INTERP 3
|
||||||
|
#define PT_NOTE 4
|
||||||
|
#define PT_SHLIB 5
|
||||||
|
#define PT_PHDR 6
|
||||||
|
#define PT_TLS 7
|
||||||
|
#define PT_LOOS 0x60000000
|
||||||
|
#define PT_HIOS 0x6fffffff
|
||||||
|
#define PT_LOPROC 0x70000000
|
||||||
|
#define PT_HIPROC 0x7fffffff
|
||||||
|
|
||||||
|
#define STT_NOTYPE 0
|
||||||
|
#define STT_OBJECT 1
|
||||||
|
#define STT_FUNC 2
|
||||||
|
#define STT_SECTION 3
|
||||||
|
#define STT_FILE 4
|
||||||
|
#define STT_COMMON 5
|
||||||
|
#define STT_TLS 6
|
||||||
|
#define STT_LOOS 10
|
||||||
|
#define STT_HIOS 12
|
||||||
|
#define STT_LOPROC 13
|
||||||
|
#define STT_HIPROC 15
|
||||||
|
|
||||||
|
#define PF_X 0x1
|
||||||
|
#define PF_W 0x2
|
||||||
|
#define PF_R 0x4
|
||||||
|
#define PF_MASKOS 0x0ff00000
|
||||||
|
#define PF_MASKPROC 0xf0000000
|
||||||
|
|
||||||
|
|
||||||
|
/* These macros are defined in the draft specification: */
|
||||||
|
/* NOTE: I think at least my _INFO is broken here. */
|
||||||
|
#define ELF32_R_SYM(i) ((i)>>8)
|
||||||
|
#define ELF32_R_TYPE(i) ((unsigned char)(i))
|
||||||
|
#define ELF32_R_INFO(s,t) (((s)<<8)+(unsigned char)(t))
|
||||||
|
|
||||||
|
#define ELF64_R_SYM(i) ((i)>>32)
|
||||||
|
#define ELF64_R_TYPE(i) ((i)&0xffffffffL)
|
||||||
|
#define ELF64_R_INFO(s,t) (((s)<<32)+((t)&0xffffffffL))
|
||||||
|
|
||||||
|
#define ELF32_ST_BIND(i) ((i)>>4)
|
||||||
|
#define ELF32_ST_TYPE(i) ((i)&0xf)
|
||||||
|
#define ELF32_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
|
||||||
|
|
||||||
|
#define ELF64_ST_BIND(i) ((i)>>4)
|
||||||
|
#define ELF64_ST_TYPE(i) ((i)&0xf)
|
||||||
|
#define ELF64_ST_INFO(b,t) (((b)<<4)+((t)&0xf))
|
||||||
|
|
||||||
|
#define ELF32_ST_VISIBILITY(o) ((o)&0x3)
|
||||||
|
#define ELF64_ST_VISIBILITY(o) ((o)&0x3)
|
||||||
|
|
||||||
|
/* These (relocation types?) are specific to x86-64. I still find it weird that ELF works that way (why not just encode the expressions so it'd be portable?) */
|
||||||
|
#define R_X86_64_NONE 0 //none none
|
||||||
|
#define R_X86_64_64 1 //word64 S + A
|
||||||
|
#define R_X86_64_PC32 2 //word32 S + A - P
|
||||||
|
#define R_X86_64_GOT32 3 //word32 G + A
|
||||||
|
#define R_X86_64_PLT32 4 //word32 L + A - P
|
||||||
|
#define R_X86_64_COPY 5 //none none
|
||||||
|
#define R_X86_64_GLOB_DAT 6 //word64 S
|
||||||
|
#define R_X86_64_JUMP_SLOT 7 //word64 S
|
||||||
|
#define R_X86_64_RELATIVE 8 //word64 B + A
|
||||||
|
#define R_X86_64_GOTPCREL 9 //word32 G + GOT + A - P
|
||||||
|
#define R_X86_64_32 10 //word32 S + A
|
||||||
|
#define R_X86_64_32S 11 //word32 S + A
|
||||||
|
#define R_X86_64_16 12 //word16 S + A
|
||||||
|
#define R_X86_64_PC16 13 //word16 S + A - P
|
||||||
|
#define R_X86_64_8 14 //word8 S + A
|
||||||
|
#define R_X86_64_PC8 15 //word8 S + A - P
|
||||||
|
#define R_X86_64_DPTMOD64 16 //word64
|
||||||
|
#define R_X86_64_DTPOFF64 17 //word64
|
||||||
|
#define R_X86_64_TPOFF64 18 //word64
|
||||||
|
#define R_X86_64_TLSGD 19 //word32
|
||||||
|
#define R_X86_64_TLSLD 20 //word32
|
||||||
|
#define R_X86_64_DTPOFF32 21 //word32
|
||||||
|
#define R_X86_64_GOTTPOFF 22 //word32
|
||||||
|
#define R_X86_64_TPOFF32 23 //word32
|
||||||
|
#define R_X86_64_PC64 24 //word64 S + A - P
|
||||||
|
#define R_X86_64_GOTOFF64 25 //word64 S + A - GOT
|
||||||
|
#define R_X86_64_GOTPC32 26 //word32 GOT + A - P
|
||||||
|
|
||||||
|
typedef struct Elf32_Ehdr_struct Elf32_Ehdr;
|
||||||
|
typedef struct Elf64_Ehdr_struct Elf64_Ehdr;
|
||||||
|
typedef struct Elf32_Shdr_struct Elf32_Shdr;
|
||||||
|
typedef struct Elf64_Shdr_struct Elf64_Shdr;
|
||||||
|
typedef struct Elf32_Sym_struct Elf32_Sym;
|
||||||
|
typedef struct Elf64_Sym_struct Elf64_Sym;
|
||||||
|
typedef struct Elf32_Rel_struct Elf32_Rel;
|
||||||
|
typedef struct Elf64_Rel_struct Elf64_Rel;
|
||||||
|
typedef struct Elf32_Rela_struct Elf32_Rela;
|
||||||
|
typedef struct Elf64_Rela_struct Elf64_Rela;
|
||||||
|
typedef struct Elf32_Phdr_struct Elf32_Phdr;
|
||||||
|
typedef struct Elf64_Phdr_struct Elf64_Phdr;
|
||||||
|
|
||||||
|
struct Elf32_Ehdr_struct {
|
||||||
|
unsigned char e_ident[EI_NIDENT];
|
||||||
|
Elf32_Half e_type;
|
||||||
|
Elf32_Half e_machine;
|
||||||
|
Elf32_Word e_version;
|
||||||
|
Elf32_Addr e_entry;
|
||||||
|
Elf32_Off e_phoff;
|
||||||
|
Elf32_Off e_shoff;
|
||||||
|
Elf32_Word e_flags;
|
||||||
|
Elf32_Half e_ehsize;
|
||||||
|
Elf32_Half e_phentsize;
|
||||||
|
Elf32_Half e_phnum;
|
||||||
|
Elf32_Half e_shentsize;
|
||||||
|
Elf32_Half e_shnum;
|
||||||
|
Elf32_Half e_shstrndx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Elf64_Ehdr_struct {
|
||||||
|
unsigned char e_ident[EI_NIDENT];
|
||||||
|
Elf64_Half e_type;
|
||||||
|
Elf64_Half e_machine;
|
||||||
|
Elf64_Word e_version;
|
||||||
|
Elf64_Addr e_entry;
|
||||||
|
Elf64_Off e_phoff;
|
||||||
|
Elf64_Off e_shoff;
|
||||||
|
Elf64_Word e_flags;
|
||||||
|
Elf64_Half e_ehsize;
|
||||||
|
Elf64_Half e_phentsize;
|
||||||
|
Elf64_Half e_phnum;
|
||||||
|
Elf64_Half e_shentsize;
|
||||||
|
Elf64_Half e_shnum;
|
||||||
|
Elf64_Half e_shstrndx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Elf32_Shdr_struct {
|
||||||
|
Elf32_Word sh_name;
|
||||||
|
Elf32_Word sh_type;
|
||||||
|
Elf32_Word sh_flags;
|
||||||
|
Elf32_Addr sh_addr;
|
||||||
|
Elf32_Off sh_offset;
|
||||||
|
Elf32_Word sh_size;
|
||||||
|
Elf32_Word sh_link;
|
||||||
|
Elf32_Word sh_info;
|
||||||
|
Elf32_Word sh_addralign;
|
||||||
|
Elf32_Word sh_entsize;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Elf64_Shdr_struct {
|
||||||
|
Elf64_Word sh_name;
|
||||||
|
Elf64_Word sh_type;
|
||||||
|
Elf64_Xword sh_flags;
|
||||||
|
Elf64_Addr sh_addr;
|
||||||
|
Elf64_Off sh_offset;
|
||||||
|
Elf64_Xword sh_size;
|
||||||
|
Elf64_Word sh_link;
|
||||||
|
Elf64_Word sh_info;
|
||||||
|
Elf64_Xword sh_addralign;
|
||||||
|
Elf64_Xword sh_entsize;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Elf32_Sym_struct {
|
||||||
|
Elf32_Word st_name;
|
||||||
|
Elf32_Addr st_value;
|
||||||
|
Elf32_Word st_size;
|
||||||
|
unsigned char st_info;
|
||||||
|
unsigned char st_other;
|
||||||
|
Elf32_Half st_shndx;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Elf64_Sym_struct {
|
||||||
|
Elf64_Word st_name;
|
||||||
|
unsigned char st_info;
|
||||||
|
unsigned char st_other;
|
||||||
|
Elf64_Half st_shndx;
|
||||||
|
Elf64_Addr st_value;
|
||||||
|
Elf64_Xword st_size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Elf32_Rel_struct {
|
||||||
|
Elf32_Addr r_offset;
|
||||||
|
Elf32_Word r_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Elf32_Rela_struct {
|
||||||
|
Elf32_Addr r_offset;
|
||||||
|
Elf32_Word r_info;
|
||||||
|
Elf32_Sword r_addend;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Elf64_Rel_struct {
|
||||||
|
Elf64_Addr r_offset;
|
||||||
|
Elf64_Xword r_info;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Elf64_Rela_struct {
|
||||||
|
Elf64_Addr r_offset;
|
||||||
|
Elf64_Xword r_info;
|
||||||
|
Elf64_Sxword r_addend;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Elf32_Phdr_struct {
|
||||||
|
Elf32_Word p_type;
|
||||||
|
Elf32_Off p_offset;
|
||||||
|
Elf32_Addr p_vaddr;
|
||||||
|
Elf32_Addr p_paddr;
|
||||||
|
Elf32_Word p_filesz;
|
||||||
|
Elf32_Word p_memsz;
|
||||||
|
Elf32_Word p_flags;
|
||||||
|
Elf32_Word p_align;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Elf64_Phdr_struct {
|
||||||
|
Elf64_Word p_type;
|
||||||
|
Elf64_Word p_flags;
|
||||||
|
Elf64_Off p_offset;
|
||||||
|
Elf64_Addr p_vaddr;
|
||||||
|
Elf64_Addr p_paddr;
|
||||||
|
Elf64_Xword p_filesz;
|
||||||
|
Elf64_Xword p_memsz;
|
||||||
|
Elf64_Xword p_align;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
1001
elmalloc.h
Normal file
1001
elmalloc.h
Normal file
File diff suppressed because it is too large
Load Diff
13
include.mk
Normal file
13
include.mk
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
L=libc
|
||||||
|
LIBC = $L/_libc_internal.o $L/_libc_stdio.o $L/_libc_memory.o $L/_libc_string.o $L/_libc_stdlib.o $L/_libc_ctype.o $L/_libc_misc.o $L/_libc_math.o $U/usys.o
|
||||||
|
LIBCH = $L/include/
|
||||||
|
|
||||||
|
# Note: Add -DLIBC_OOP for object-oriented FILE
|
||||||
|
|
||||||
|
_libc_%.o: %.c $(LIBCH)
|
||||||
|
$(CC) $(CFLAGS_MANDATORY) -I$L/include -c -o $@ $<
|
||||||
|
|
||||||
|
_libc_%: _libc_%.o $(LIBC)
|
||||||
|
$(LD) $(LDFLAGS) -T $L/link.ld -o $@ $^
|
||||||
|
$(OBJDUMP) -S $@ > $*.asm
|
||||||
|
$(OBJDUMP) -t $@ | sed '1,/SYMBOL TABLE/d; s/ .* / /; /^$$/d' > $*.sym
|
17
include/assert.h
Normal file
17
include/assert.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_ASSERT_H
|
||||||
|
#define _LIBC_ASSERT_H
|
||||||
|
|
||||||
|
#define assert(...) do {} while(0)
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
27
include/ctype.h
Normal file
27
include/ctype.h
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_CTYPE_H
|
||||||
|
#define _LIBC_CTYPE_H
|
||||||
|
|
||||||
|
int isspace(int ch);
|
||||||
|
int isdigit(int ch);
|
||||||
|
int isxdigit(int ch);
|
||||||
|
int isalpha(int ch);
|
||||||
|
int isalnum(int ch);
|
||||||
|
int isprint(int ch);
|
||||||
|
int ispunct(int ch);
|
||||||
|
int isupper(int ch);
|
||||||
|
int islower(int ch);
|
||||||
|
int toupper(int ch);
|
||||||
|
int tolower(int ch);
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
9
include/dirent.h
Normal file
9
include/dirent.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
30
include/errno.h
Normal file
30
include/errno.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_ERRNO_H
|
||||||
|
#define _LIBC_ERRNO_H
|
||||||
|
|
||||||
|
//extern int errno;
|
||||||
|
|
||||||
|
/* On modern Linux platforms the errno is simulated. This is presumably so that each
|
||||||
|
* thread can have it's own errno without the ABI becoming a huge mess.
|
||||||
|
*/
|
||||||
|
#ifdef __MAC
|
||||||
|
int errno;
|
||||||
|
#else
|
||||||
|
int* __errno_location();
|
||||||
|
|
||||||
|
#define errno __errno_location()[0]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ENOENT 2
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
9
include/fcntl.h
Normal file
9
include/fcntl.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
17
include/float.h
Normal file
17
include/float.h
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_FLOAT_H
|
||||||
|
#define _LIBC_FLOAT_H
|
||||||
|
|
||||||
|
#define DBL_MAX_EXP 1024
|
||||||
|
#define DBL_MANT_DIG 53
|
||||||
|
|
||||||
|
#endif
|
18
include/limits.h
Normal file
18
include/limits.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_LIMITS_H
|
||||||
|
#define _LIBC_LIMITS_H
|
||||||
|
|
||||||
|
#define CHAR_BIT 8
|
||||||
|
#define UINT_MAX 0xFFFFFFFFU
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
21
include/math.h
Normal file
21
include/math.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_MATH_H
|
||||||
|
#define _LIBC_MATH_H
|
||||||
|
|
||||||
|
double fabs(double n);
|
||||||
|
double pow(double x, double p);
|
||||||
|
double exp(double x);
|
||||||
|
|
||||||
|
double ldexp(double x, int exp);
|
||||||
|
|
||||||
|
// From ifndef at top of file:
|
||||||
|
#endif
|
15
include/memory.h
Normal file
15
include/memory.h
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_MEMORY_H
|
||||||
|
#define _LIBC_MEMORY_H
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
9
include/pwd.h
Normal file
9
include/pwd.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
28
include/setjmp.h
Normal file
28
include/setjmp.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_SETJMP_H
|
||||||
|
#define _LIBC_SETJMP_H
|
||||||
|
|
||||||
|
/*struct jmp_buf_struct {
|
||||||
|
int todo;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct jmp_buf_struct jmp_buf;*/
|
||||||
|
typedef int jmp_buf;
|
||||||
|
|
||||||
|
#define setjmp(x) \
|
||||||
|
0
|
||||||
|
// (printf("WARNING: Unimplemented: setjmp\n") && 0)
|
||||||
|
#define longjmp(x,y) \
|
||||||
|
printf("WARNING: Unimplemented: longjmp\n")
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
9
include/signal.h
Normal file
9
include/signal.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
45
include/stdarg.h
Normal file
45
include/stdarg.h
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_STDARG_H
|
||||||
|
#define _LIBC_STDARG_H
|
||||||
|
|
||||||
|
#ifdef _ZCC
|
||||||
|
|
||||||
|
typedef long long** va_list;
|
||||||
|
|
||||||
|
#define _VA_CHECK() \
|
||||||
|
if (__builtin_func_callconv != 101) {\
|
||||||
|
printf("ERROR: Unpacking varargs currently only works with __classic_call (#101). Function %s uses convention %d instead.\n", __func__, __builtin_func_callconv);\
|
||||||
|
}
|
||||||
|
|
||||||
|
#define va_start(list,lastarg) \
|
||||||
|
do {\
|
||||||
|
_VA_CHECK();\
|
||||||
|
list = &lastarg;\
|
||||||
|
list++;\
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#define va_arg(list,T) \
|
||||||
|
(*((T*)(list++)))
|
||||||
|
|
||||||
|
#define va_end(list) \
|
||||||
|
do {list = (void*)0;} while(0)
|
||||||
|
|
||||||
|
/* Not new C compiler, use GCC ABI */
|
||||||
|
#else
|
||||||
|
#define va_list __builtin_va_list
|
||||||
|
#define va_start __builtin_va_start
|
||||||
|
#define va_end __builtin_va_end
|
||||||
|
#define va_arg __builtin_va_arg
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
20
include/stdbool.h
Normal file
20
include/stdbool.h
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_STDBOOL_H
|
||||||
|
#define _LIBC_STDBOOL_H
|
||||||
|
|
||||||
|
typedef int bool;
|
||||||
|
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
23
include/stddef.h
Normal file
23
include/stddef.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_STDDEF_H
|
||||||
|
#define _LIBC_STDDEF_H
|
||||||
|
|
||||||
|
//#ifndef _LIBC_STDLIB_H
|
||||||
|
typedef long size_t;
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
#ifndef NULL
|
||||||
|
#define NULL ((void*) 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
36
include/stdint.h
Normal file
36
include/stdint.h
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_STDINT_H
|
||||||
|
#define _LIBC_STDINT_H
|
||||||
|
|
||||||
|
typedef char int8_t;
|
||||||
|
typedef short int16_t;
|
||||||
|
typedef int int32_t;
|
||||||
|
typedef long long int64_t;
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
typedef unsigned long long uint64_t;
|
||||||
|
|
||||||
|
typedef int64_t intptr_t;
|
||||||
|
typedef uint64_t uintptr_t;
|
||||||
|
|
||||||
|
typedef uint32_t uint_fast8_t;
|
||||||
|
typedef int32_t int_fast8_t;
|
||||||
|
typedef uint32_t uint_fast16_t;
|
||||||
|
typedef int32_t int_fast16_t;
|
||||||
|
typedef uint32_t uint_fast32_t;
|
||||||
|
typedef int32_t int_fast32_t;
|
||||||
|
typedef uint64_t uint_fast64_t;
|
||||||
|
typedef int64_t int_fast64_t;
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
120
include/stdio.h
Normal file
120
include/stdio.h
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_STDIO_H
|
||||||
|
#define _LIBC_STDIO_H
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#ifdef LIBC_OOP
|
||||||
|
// Theoretical OOP version of FILE, this would be ideal for C+OOP apps
|
||||||
|
// This is split into FILE (base class for interoperable stream objects)
|
||||||
|
// and _libc_FILE (the default FILE implementation using system file
|
||||||
|
// descriptors)
|
||||||
|
|
||||||
|
// Class hierarchy doesn't exist yet...
|
||||||
|
//#import <Resource.h>
|
||||||
|
@interface Resource {
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
/* The extensible FILE base type. */
|
||||||
|
@interface FILE : Resource {
|
||||||
|
FILE* backend;
|
||||||
|
}
|
||||||
|
-(id) init;
|
||||||
|
@end
|
||||||
|
|
||||||
|
/* The subclass of FILE which works over an OS file descriptor. */
|
||||||
|
@interface _libc_FILE : FILE {
|
||||||
|
int fd;
|
||||||
|
int ungot; // Character pushed back or -1
|
||||||
|
int eof;
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
|
#else
|
||||||
|
// Simplified data structure, only intended for bootstrapping (does not
|
||||||
|
// provide complex buffering or overloading)
|
||||||
|
|
||||||
|
struct _libc_FILE_internals {
|
||||||
|
int fd;
|
||||||
|
int ungot; // Character pushed back or -1
|
||||||
|
int eof;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct _libc_FILE_internals FILE;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define EXIT_FAILURE 1
|
||||||
|
#define EXIT_SUCCESS 0
|
||||||
|
|
||||||
|
extern FILE* stderr;
|
||||||
|
extern FILE* stdin;
|
||||||
|
extern FILE* stdout;
|
||||||
|
|
||||||
|
#define EOF ((int)-1)
|
||||||
|
|
||||||
|
#ifdef _ZCC
|
||||||
|
#define _LIBC_PRINTF_CALLCONV __classic_call
|
||||||
|
#else
|
||||||
|
#define _LIBC_PRINTF_CALLCONV
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int _LIBC_PRINTF_CALLCONV printf(const char* fmt, ...);
|
||||||
|
int _LIBC_PRINTF_CALLCONV sprintf(char *buf, const char* fmt, ...);
|
||||||
|
int _LIBC_PRINTF_CALLCONV snprintf(char *buf, size_t n, const char* fmt, ...);
|
||||||
|
int _LIBC_PRINTF_CALLCONV dprintf(int fd, const char* fmt, ...);
|
||||||
|
int _LIBC_PRINTF_CALLCONV fprintf(FILE* f, const char* fmt, ...);
|
||||||
|
|
||||||
|
int _LIBC_PRINTF_CALLCONV vfprintf(FILE* f, const char* fmt, va_list list);
|
||||||
|
int _LIBC_PRINTF_CALLCONV vsnprintf(char* str, size_t n, const char* fmt, va_list list);
|
||||||
|
|
||||||
|
// These are non-standard, but the other *printf functions need to be implemented somehow,
|
||||||
|
// so fnprintf/vfnprintf just use a callback function for output of n bytes of string output.
|
||||||
|
typedef int(*_libc_fnprintf_fn_t)(const char* str, int n, void* udata);
|
||||||
|
int _LIBC_PRINTF_CALLCONV _libc_fnprintf(_libc_fnprintf_fn_t fn, void* udata, const char* fmt, ...);
|
||||||
|
int _LIBC_PRINTF_CALLCONV _libc_vfnprintf(_libc_fnprintf_fn_t fn, void* udata, const char* fmt, va_list list);
|
||||||
|
|
||||||
|
FILE* fopen(const char* name, const char* mode);
|
||||||
|
FILE* freopen(const char* name, const char* mode, FILE* f);
|
||||||
|
int fclose(FILE* f);
|
||||||
|
int fflush(FILE* f);
|
||||||
|
|
||||||
|
long fread(void* buffer, long size, long count, FILE* f);
|
||||||
|
long fwrite(void* buffer, long size, long count, FILE* f);
|
||||||
|
|
||||||
|
char* fgets(char*, int, FILE*);
|
||||||
|
|
||||||
|
int fputs(const char*, FILE*);
|
||||||
|
int fputc(int, FILE*);
|
||||||
|
|
||||||
|
int feof(FILE* f);
|
||||||
|
|
||||||
|
void perror(const char*);
|
||||||
|
|
||||||
|
int putc(int c, FILE* f);
|
||||||
|
|
||||||
|
int putchar(int c);
|
||||||
|
|
||||||
|
int getc(FILE* f);
|
||||||
|
int ungetc(int c, FILE* f);
|
||||||
|
|
||||||
|
int fseek(FILE* f, long offset, int wh);
|
||||||
|
#define SEEK_SET 0
|
||||||
|
#define SEEK_CUR 1
|
||||||
|
#define SEEK_END 2
|
||||||
|
|
||||||
|
long ftell(FILE* f);
|
||||||
|
|
||||||
|
long getline(char** linevar, long *nvar, FILE* f);
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
50
include/stdlib.h
Normal file
50
include/stdlib.h
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_STDLIB_H
|
||||||
|
#define _LIBC_STDLIB_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
// By default, this libc includes both traditional and garbage collected
|
||||||
|
// memory managers. _libc_gcalloc is therefore preconfigured as a malloc
|
||||||
|
// alternative with garbage collection, but internally
|
||||||
|
// malloc/calloc/realloc/free are also just wrappers over a flexible
|
||||||
|
// memory manager.
|
||||||
|
|
||||||
|
void* malloc(size_t sz);
|
||||||
|
void* calloc(size_t n, size_t sz);
|
||||||
|
void* realloc(void* mem, size_t sz);
|
||||||
|
void free(void* mem);
|
||||||
|
void* _libc_gcalloc(size_t sz);
|
||||||
|
char* getenv(const char* key);
|
||||||
|
int setenv(const char* key, const char* value, int overwrite);
|
||||||
|
int unsetenv(const char* key);
|
||||||
|
void exit(int x);
|
||||||
|
void abort();
|
||||||
|
|
||||||
|
long strtol(const char* str, char**endvar, int base);
|
||||||
|
long long strtoll(const char* str, char**endvar, int base);
|
||||||
|
unsigned long strtoul(const char* str, char**endvar, int base);
|
||||||
|
unsigned long long strtoull(const char* str, char**endvar, int base);
|
||||||
|
|
||||||
|
float strtof(const char* str, char**endvar);
|
||||||
|
double strtod(const char* str, char**endvar);
|
||||||
|
long double strtold(const char* str, char**endvar);
|
||||||
|
|
||||||
|
double atof(const char* str);
|
||||||
|
int atoi(const char* str);
|
||||||
|
|
||||||
|
int rand();
|
||||||
|
void srand(unsigned int r);
|
||||||
|
#define RAND_MAX 999999999
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
33
include/string.h
Normal file
33
include/string.h
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_STRING_H
|
||||||
|
#define _LIBC_STRING_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
size_t strlen(const char* foo);
|
||||||
|
|
||||||
|
char *strchr(const char* str, int chr);
|
||||||
|
char *strrchr(const char* str, int chr);
|
||||||
|
char* strcat(char* str, const char* cat);
|
||||||
|
char* strcpy(char* buffer, const char* str);
|
||||||
|
char* strncpy(char* buffer, const char* str, size_t n);
|
||||||
|
const char* strpbrk(const char* str, const char* search);
|
||||||
|
int strcmp(const char* a, const char* b);
|
||||||
|
char* strdup(const char* str);
|
||||||
|
char* strndup(const char* str, size_t n);
|
||||||
|
|
||||||
|
void* memcpy(void* dst, const void* src, size_t nbytes);
|
||||||
|
|
||||||
|
void* memset(void* mem, int byt, size_t nbytes);
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
48
include/sys/event.h
Normal file
48
include/sys/event.h
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
// Zak's kqueue implementation
|
||||||
|
#ifndef SYS_EVENT_H
|
||||||
|
#define SYS_EVENT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// The kevent structure is used for waiting/receiving notifications.
|
||||||
|
struct kevent {
|
||||||
|
uintptr_t ident;
|
||||||
|
int16_t filter;
|
||||||
|
uint16_t flags;
|
||||||
|
uint32_t fflags;
|
||||||
|
int64_t data;
|
||||||
|
void* udata;
|
||||||
|
uint64_t ext[4];
|
||||||
|
};
|
||||||
|
|
||||||
|
// kqueue1 is the kqueue system call with a flags argument,
|
||||||
|
// as defined on NetBSD & OpenBSD.
|
||||||
|
int kqueue1(int flags);
|
||||||
|
|
||||||
|
// kqueue() without flags is equivalent to kqueue1(0)
|
||||||
|
#define kqueue() kqueue1(0)
|
||||||
|
|
||||||
|
// On FreeBSD, kqueue1 is also known as kqueuex
|
||||||
|
#define kqueuex(flags) kqueue1(flags)
|
||||||
|
|
||||||
|
// After creating a kqueue, kevent is the main syscall used.
|
||||||
|
// This accepts a list of changes and can receive multiple events.
|
||||||
|
int kevent(int queue, const struct kevent* changes, int nch, struct kevent* events, int nev, void* todo_timeout);
|
||||||
|
|
||||||
|
// The EV_SET() macro is for initialising a struct kevent*
|
||||||
|
#define EV_SET(ev,idn,flt,flg,ffl,dat,udt) \
|
||||||
|
do { \
|
||||||
|
(ev)->ident = idn; \
|
||||||
|
(ev)->filter = flt; \
|
||||||
|
(ev)->flags = flg; \
|
||||||
|
(ev)->fflags = ffl; \
|
||||||
|
(ev)->data = dat; \
|
||||||
|
(ev)->udata = udt; \
|
||||||
|
(ev)->ext[0] = 0; \
|
||||||
|
(ev)->ext[1] = 0; \
|
||||||
|
(ev)->ext[2] = 0; \
|
||||||
|
(ev)->ext[3] = 0; \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
// From ifndef at top of file:
|
||||||
|
#endif
|
23
include/syscalls.h
Normal file
23
include/syscalls.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
#ifndef _LIBC_SYSCALLS_H
|
||||||
|
#define _LIBC_SYSCALLS_H
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// NOTE: This is NOT the definitive list of system calls, this is just any
|
||||||
|
// syscall definitions which didn't fit anywhere else!
|
||||||
|
|
||||||
|
// TODO: Add some platform-checking here
|
||||||
|
|
||||||
|
void* sbrk(int incr);
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
||||||
|
|
40
include/time.h
Normal file
40
include/time.h
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#ifndef _LIBC_TIME_H
|
||||||
|
#define _LIBC_TIME_H
|
||||||
|
|
||||||
|
typedef long time_t;
|
||||||
|
|
||||||
|
char* ctime(const time_t* timevar);
|
||||||
|
time_t time(time_t* timevar);
|
||||||
|
|
||||||
|
/* TODO: This is not implemented on the current OS. */
|
||||||
|
struct tm {
|
||||||
|
int tm_sec;
|
||||||
|
int tm_min;
|
||||||
|
int tm_hour;
|
||||||
|
int tm_mday;
|
||||||
|
int tm_mon;
|
||||||
|
int tm_year;
|
||||||
|
int tm_wday;
|
||||||
|
int tm_yday;
|
||||||
|
int tm_isdst;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct timespec {
|
||||||
|
int tv_sec;
|
||||||
|
long tv_nsec;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tm* localtime(const time_t* timep);
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
18
include/unistd.h
Normal file
18
include/unistd.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
#ifndef _LIBC_UNISTD_H
|
||||||
|
#define _LIBC_UNISTD_H
|
||||||
|
|
||||||
|
void exit(int status);
|
||||||
|
typedef int pid_t;
|
||||||
|
pid_t getpid();
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
9
include/utime.h
Normal file
9
include/utime.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
65
internal.c
Normal file
65
internal.c
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#include "internal.h"
|
||||||
|
#include "simgc.h"
|
||||||
|
|
||||||
|
int main(int argc, char** argv, char** envv); // Note, the third argument is usually not implemented by the main function.
|
||||||
|
|
||||||
|
void _libc_malloc_init(void* stackptr);
|
||||||
|
void _libc_env_init(const char** envv);
|
||||||
|
void _libc_malloc_finish();
|
||||||
|
void _libc_stdio_init();
|
||||||
|
|
||||||
|
void _libc_start(int argc, char** argv, char** envv) {
|
||||||
|
_libc_env_init(envv);
|
||||||
|
_libc_malloc_init(&argc);
|
||||||
|
_libc_stdio_init();
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
write(1, "ARG: ", 5);
|
||||||
|
write(1, argv[i], strlen(argv[i]));
|
||||||
|
write(1, "\n", 1);
|
||||||
|
}
|
||||||
|
for (int i = 0; envv[i]; i++) {
|
||||||
|
write(1, "ENV: ", 5);
|
||||||
|
write(1, envv[i], strlen(envv[i]));
|
||||||
|
write(1, "\n", 1);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
int result = main(argc, argv, envv);
|
||||||
|
_libc_malloc_finish();
|
||||||
|
exit(result);
|
||||||
|
FATAL("Faulty 'exit' syscall");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is used to report missing functions or other critical errors, so
|
||||||
|
* it shouldn't use any additional library functions it should just
|
||||||
|
* print the error and exit using the simplest possible code path.
|
||||||
|
*/
|
||||||
|
void _libc_fatal(const char* msg, const char* fnc) {
|
||||||
|
const char* l1 = "FATAL ERROR:\n";
|
||||||
|
const char* l3 = "FUNCTION:\n";
|
||||||
|
write(2, l1, strlen(l1));
|
||||||
|
write(2, "\t", 1);
|
||||||
|
write(2, msg, strlen(msg));
|
||||||
|
write(2, "\n", 1);
|
||||||
|
write(2, l3, strlen(l3));
|
||||||
|
write(2, "\t", 1);
|
||||||
|
write(2, fnc, strlen(fnc));
|
||||||
|
write(2, "\n", 1);
|
||||||
|
// TODO: Trigger debugger here?
|
||||||
|
exit(-1);
|
||||||
|
l1 = "FAULTY EXIT? HOT LOOP FOREVER";
|
||||||
|
write(2, l1, strlen(l1));
|
||||||
|
while(1) {
|
||||||
|
// Hot loop forever
|
||||||
|
}
|
||||||
|
}
|
34
internal.h
Normal file
34
internal.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
#ifndef _LIBC_INTERNAL_H
|
||||||
|
#define _LIBC_INTERNAL_H
|
||||||
|
|
||||||
|
/* This should be called when a function isn't yet implemented or some similar
|
||||||
|
* irreconcilable error exists.
|
||||||
|
*/
|
||||||
|
void _libc_fatal(const char* errorstr, const char* function);
|
||||||
|
/* The _libc_fatalf function is like _libc_fatal except prints a formatted
|
||||||
|
* string ("printf style").
|
||||||
|
*/
|
||||||
|
/*void
|
||||||
|
#ifdef _ZCC
|
||||||
|
__classic_call
|
||||||
|
#endif
|
||||||
|
_libc_fatalf(const char* fmt, ...);*/
|
||||||
|
|
||||||
|
#define FATAL(msg) \
|
||||||
|
_libc_fatal(msg, __func__);
|
||||||
|
|
||||||
|
#define UNIMPLEMENTED() \
|
||||||
|
_libc_fatal("Unimplemented libc function", __func__)
|
||||||
|
|
||||||
|
/* From ifndef at top of file: */
|
||||||
|
#endif
|
||||||
|
|
25
link.ld
Normal file
25
link.ld
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
OUTPUT_ARCH("riscv")
|
||||||
|
ENTRY(_libc_start)
|
||||||
|
|
||||||
|
SECTIONS {
|
||||||
|
. = 0;
|
||||||
|
.text : {
|
||||||
|
. = ALIGN(4);
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
.rodata : {
|
||||||
|
. = ALIGN(16);
|
||||||
|
*(.rodata)
|
||||||
|
}
|
||||||
|
. = ALIGN(4096);
|
||||||
|
.data : {
|
||||||
|
. = ALIGN(16);
|
||||||
|
*(.data)
|
||||||
|
}
|
||||||
|
.bss : {
|
||||||
|
. = ALIGN(16);
|
||||||
|
*(.bss)
|
||||||
|
}
|
||||||
|
|
||||||
|
PROVIDE(_libc_programend = .);
|
||||||
|
}
|
216
math.c
Normal file
216
math.c
Normal file
@@ -0,0 +1,216 @@
|
|||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
unsigned int _libc_rand_seed = 12345;
|
||||||
|
|
||||||
|
int rand() {
|
||||||
|
_libc_rand_seed ^= _libc_rand_seed << 13;
|
||||||
|
_libc_rand_seed ^= _libc_rand_seed >> 17;
|
||||||
|
_libc_rand_seed ^= _libc_rand_seed << 5;
|
||||||
|
return _libc_rand_seed % (RAND_MAX+1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void srand(unsigned int r) {
|
||||||
|
if (r == 0) {
|
||||||
|
_libc_rand_seed = 1;
|
||||||
|
} else {
|
||||||
|
_libc_rand_seed = r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double fabs(double n) {
|
||||||
|
if (n < 0) {
|
||||||
|
return 0.0 - n;
|
||||||
|
} else {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
double ldexp(double x, int exp) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
double frexp(double x, int* expptr) {
|
||||||
|
// TODO: Check special cases?
|
||||||
|
uint64_t bits = *((uint64_t*)((void*)&x));
|
||||||
|
uint64_t exp = (bits>>52)&0x7FF;
|
||||||
|
*expptr = (int) exp - 1023;
|
||||||
|
bits &= 0x800FFFFFFFFFFFFFULL;
|
||||||
|
bits |= 1023ULL << 52;
|
||||||
|
return *((double*)((void*)&bits));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
double _libc_factorial(int n) {
|
||||||
|
double x = 1.0;
|
||||||
|
for (int i = 1; i <= n; i++) {
|
||||||
|
x *= i;
|
||||||
|
}
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This implementation is very very dumb.
|
||||||
|
double pow(double x, double p) {
|
||||||
|
double result = x;
|
||||||
|
for (int i = 2; i < p; i++) {
|
||||||
|
result *= x;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define EXP_EPSILON 0.0000000001
|
||||||
|
|
||||||
|
// NOTE: This function was written with the help of Qwen AI
|
||||||
|
double exp(double x) {
|
||||||
|
double r = 1.0;
|
||||||
|
double t = 1.0;
|
||||||
|
int n = 1;
|
||||||
|
|
||||||
|
while (fabs(t) < EXP_EPSILON) {
|
||||||
|
t = pow(x, n) / _libc_factorial(n);
|
||||||
|
r += t;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// NOTE: OLD CODE taken from PDPC400's math.c ("public domain")
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define HUGE_VAL 9.999999999999999999999E72
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Some constants to make life easier elsewhere
|
||||||
|
(These should I guess be in math.h)
|
||||||
|
|
||||||
|
*/
|
||||||
|
double _libc_pi = 3.1415926535897932384626433832795;
|
||||||
|
double _libc_ln10 = 2.3025850929940456840179914546844;
|
||||||
|
double _libc_ln2 = 0.69314718055994530941723212145818;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
exp(x) = 1 + x + x2/2 + x3/6 + x4/24 + x5/120 + ... + xn/n! + ...
|
||||||
|
|
||||||
|
*/
|
||||||
|
double exp (double x)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
double term,answer,work;
|
||||||
|
|
||||||
|
i=2;
|
||||||
|
term=x;
|
||||||
|
answer=x;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
work = i;
|
||||||
|
term = (term * x)/work;
|
||||||
|
if ( answer == (answer + term) )break;
|
||||||
|
answer = answer + (term);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
answer=answer+1.0;
|
||||||
|
return(answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
Calculate LOG using Taylor series.
|
||||||
|
|
||||||
|
log(1+ x) = x - x**2 + x**3 - x**4 + x**5
|
||||||
|
==== ==== ==== ==== .........
|
||||||
|
2 3 4 8
|
||||||
|
|
||||||
|
Note this only works for small x so we scale....
|
||||||
|
|
||||||
|
*/
|
||||||
|
double log (double x)
|
||||||
|
{
|
||||||
|
int i,scale;
|
||||||
|
double term,answer,work,xs;
|
||||||
|
|
||||||
|
if (x <= 0 )
|
||||||
|
{
|
||||||
|
/* need to set signal */
|
||||||
|
// TODO: Proper errno errno=EDOM;
|
||||||
|
return (HUGE_VAL);
|
||||||
|
}
|
||||||
|
if( x == 1.0)return(0.0);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Scale arguments to be in range 1 < x <= 10
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
scale = 0;
|
||||||
|
xs = x;
|
||||||
|
while ( xs > 10.0 ) { scale ++; xs=xs/10.0;}
|
||||||
|
while ( xs < 1.0 ) { scale --; xs=xs*10.0;}
|
||||||
|
*/
|
||||||
|
xs = frexp(x,&scale);
|
||||||
|
xs = (1.0 * xs) - 1.0;
|
||||||
|
scale = scale - 0;
|
||||||
|
|
||||||
|
i=2;
|
||||||
|
term=answer=xs;
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
work = i;
|
||||||
|
term = - (term * xs);
|
||||||
|
if ( answer == (answer + (term/work)) )break;
|
||||||
|
answer = answer + (term/work);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
answer = answer + (double)scale * _libc_ln2;
|
||||||
|
return(answer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
double log10(double x)
|
||||||
|
{
|
||||||
|
return ( log(x) / _libc_ln10 );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
This code uses log and exp to calculate x to the power y.
|
||||||
|
If
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
double pow(double x,double y)
|
||||||
|
{
|
||||||
|
int j,neg;
|
||||||
|
double yy,xx;
|
||||||
|
neg=0;
|
||||||
|
j=y;
|
||||||
|
yy=j;
|
||||||
|
if( yy == y) {
|
||||||
|
xx = x;
|
||||||
|
if ( y < 0 ){neg = 1; j = -j;}
|
||||||
|
if ( y == 0) return (1.0);
|
||||||
|
--j;
|
||||||
|
while(j>0){ xx=xx * x; j--;}
|
||||||
|
if(neg)xx=1.0/xx;
|
||||||
|
return (xx);
|
||||||
|
}
|
||||||
|
if (x < 0.0)
|
||||||
|
{
|
||||||
|
// TODO: Proper errno errno=EDOM;
|
||||||
|
return(0.0);
|
||||||
|
}
|
||||||
|
if (y == 0.0) return (1.0);
|
||||||
|
|
||||||
|
return (exp(y*log(x)));
|
||||||
|
}
|
86
memory.c
Normal file
86
memory.c
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#include <memory.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <syscalls.h>
|
||||||
|
#include "elmalloc.h"
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
elmm_t _libc_mm;
|
||||||
|
elmm_sbrk_data_t _libc_sbrkdata;
|
||||||
|
|
||||||
|
#define SIMGC_SYSMALLOC(x) elmm_malloc(&_libc_mm, x)
|
||||||
|
#define SIMGC_FREE(x) elmm_free(&_libc_mm, x)
|
||||||
|
#define SIMGC_IMPLEMENTATION
|
||||||
|
#include "simgc.h"
|
||||||
|
|
||||||
|
simgc_t _libc_gc;
|
||||||
|
simgc_thread_t* _libc_gcmainthread;
|
||||||
|
|
||||||
|
void _libc_malloc_init(void* stackptr) {
|
||||||
|
// Initialising the memory manager is currently a bit of work, but in
|
||||||
|
// theory should pay off as the memory manager code is easy to fine
|
||||||
|
// tune and adapt for more specialised allocators.
|
||||||
|
_libc_sbrkdata.func = (void*)(&sbrk); // Hooking it straight to the syscall should work, the userdata argument will be ignored
|
||||||
|
_libc_sbrkdata.max = 1024 * 1024 * 8;
|
||||||
|
_libc_sbrkdata.onlyChunk = NULL;
|
||||||
|
_libc_sbrkdata.udata = NULL;
|
||||||
|
_libc_mm.bigchunkMinimum = 1024 * 1024;
|
||||||
|
_libc_mm.bigchunkGranularity = 1024;
|
||||||
|
_libc_mm.initialised = false;
|
||||||
|
_libc_mm.lockFunction = NULL;
|
||||||
|
_libc_mm.bigchunkData = &_libc_sbrkdata;
|
||||||
|
_libc_mm.bigchunkFunction = &elmm_bigchunk_sbrk;
|
||||||
|
if (!elmm_init(&_libc_mm)) {
|
||||||
|
const char* err = "ERROR: Failed to initialise memory manager!\n";
|
||||||
|
write(2, err, strlen(err));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if (!elmm_growheap(&_libc_mm, 1024*1024*4)) {
|
||||||
|
printf("Growheap failed.\n");
|
||||||
|
} else {
|
||||||
|
printf("Growheap success!\n");
|
||||||
|
}
|
||||||
|
simgc_init(&_libc_gc);
|
||||||
|
_libc_gcmainthread = simgc_begin_inner(&_libc_gc, stackptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void _libc_malloc_finish() {
|
||||||
|
simgc_end_inner(_libc_gcmainthread);
|
||||||
|
simgc_reclaim(&_libc_gc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* _libc_gcalloc(size_t sz) {
|
||||||
|
return simgc_alloc(&_libc_gc, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* malloc(size_t sz) {
|
||||||
|
return elmm_malloc(&_libc_mm, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void* mem) {
|
||||||
|
return elmm_free(&_libc_mm, mem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* calloc(size_t n, size_t sz) {
|
||||||
|
/* TODO: check for overflow of n * sz? Probably not a problem IRL (may
|
||||||
|
* have been more of a thing back in the 16-bit era but I guess math
|
||||||
|
* overflow is not an important issue on 64-bit or even 32-bit memory
|
||||||
|
* allocator calls)
|
||||||
|
*/
|
||||||
|
return elmm_calloc(&_libc_mm, n, sz);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* realloc(void* mem, size_t sz) {
|
||||||
|
return elmm_realloc(&_libc_mm, mem, sz);
|
||||||
|
}
|
||||||
|
|
22
misc.c
Normal file
22
misc.c
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
char* ctime(const time_t* timevar) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t time(time_t* timevar) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
438
simgc.h
Normal file
438
simgc.h
Normal file
@@ -0,0 +1,438 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
// NOTE: This is entirely my code, except for the hashmap code being
|
||||||
|
// based on ChatGPT output. Don't worry, I'm using better AIs now, and
|
||||||
|
// will try to mark anywhere with AI generated code in case IP issues
|
||||||
|
// arise from them (or in case clients want pure AI-free code for policy
|
||||||
|
// reasons). Btw the AIs are pretty good at that kind of code
|
||||||
|
#ifndef SIMGC_H
|
||||||
|
#define SIMGC_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifndef SIMGC_SYSMALLOC
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define SIMGC_SYSMALLOC malloc
|
||||||
|
#endif
|
||||||
|
#ifndef SIMGC_SYSFREE
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define SIMGC_SYSFREE free
|
||||||
|
#endif
|
||||||
|
#ifndef SIMGC_LOCK_TYPE
|
||||||
|
#define SIMGC_LOCK_TYPE int
|
||||||
|
#define SIMGC_CREATELOCK(l) l = 1
|
||||||
|
#define SIMGC_DELETELOCK(l) l = 0
|
||||||
|
#define SIMGC_LOCK(l) l = 2
|
||||||
|
#define SIMGC_UNLOCK(l) l = 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SIMGC_GRANULARITY
|
||||||
|
#define SIMGC_GRANULARITY 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct simgc simgc_t;
|
||||||
|
typedef struct simgc_ptrset simgc_ptrset_t;
|
||||||
|
typedef struct simgc_ptrset_node simgc_ptrset_node_t;
|
||||||
|
typedef struct simgc_allocation simgc_allocation_t;
|
||||||
|
typedef struct simgc_thread simgc_thread_t;
|
||||||
|
|
||||||
|
struct simgc {
|
||||||
|
SIMGC_LOCK_TYPE alloclock; // Locking is not used properly yet but partly implemented as an example
|
||||||
|
void* sdata; // Any data which may be needed by any complex SIMGC_SYSMALLOC/SIMGC_SYSFREE macros
|
||||||
|
void* udata; // Any data which may be associated with the heap by program or libraries
|
||||||
|
simgc_ptrset_t* pointers;
|
||||||
|
simgc_allocation_t* allocations;
|
||||||
|
simgc_thread_t* threads;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct simgc_ptrset_node {
|
||||||
|
void* key;
|
||||||
|
simgc_ptrset_node_t* next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct simgc_ptrset {
|
||||||
|
simgc_t* gc;
|
||||||
|
simgc_ptrset_node_t** buckets;
|
||||||
|
size_t capacity;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct simgc_allocation {
|
||||||
|
simgc_allocation_t* next;
|
||||||
|
size_t sizeflg; // Size/flags
|
||||||
|
// NOTE: The data will start immediately after this struct
|
||||||
|
};
|
||||||
|
|
||||||
|
struct simgc_thread {
|
||||||
|
void* sdata; // The system thread pointer, if applicable
|
||||||
|
void* udata; // Userdata, pointer to info assigned by the program or libraries
|
||||||
|
void* stackbase; // Base of stack (NOTE: may be numerically higher or lower than "top")
|
||||||
|
void* stacktop; // Top of stack (NOTE: may be numerically higher or lower than "top")
|
||||||
|
simgc_thread_t* next; // Always NULL for now (until I add locking etc.)
|
||||||
|
simgc_t* gc;
|
||||||
|
int iomode;
|
||||||
|
};
|
||||||
|
|
||||||
|
int simgc_init(simgc_t* gc);
|
||||||
|
|
||||||
|
// simgc_beginio should be called before entering a blocking I/O or pause operation
|
||||||
|
void simgc_beginio(simgc_t* gc);
|
||||||
|
// simgc_endio should be called after exiting a blocking I/O or pause operation
|
||||||
|
void simgc_endio(simgc_t* gc);
|
||||||
|
|
||||||
|
simgc_thread_t* simgc_begin_inner(simgc_t* gc, void* stackbase);
|
||||||
|
void simgc_end_inner(simgc_thread_t* ctx);
|
||||||
|
#define SIMGC_RUN(c,f) \
|
||||||
|
do { \
|
||||||
|
intptr_t dummyval = 123; \
|
||||||
|
simgc_thread_t* ctx = simgc_begin_inner(c, &dummyval); \
|
||||||
|
f; \
|
||||||
|
simgc_end_inner(ctx); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
void* simgc_alloc(simgc_t* gc, size_t sz);
|
||||||
|
|
||||||
|
// From ifndef SIMGC_H
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SIMGC_IMPLEMENTATION
|
||||||
|
#ifndef SIMGC_IMPLEMENTATION_ALREADY
|
||||||
|
#define SIMGC_IMPLEMENTATION_ALREADY
|
||||||
|
|
||||||
|
// stdio is only used for debugging
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#define SIMGC_PTRSET_INITIAL_CAPACITY 16
|
||||||
|
|
||||||
|
|
||||||
|
static uint32_t simgc_ptrset_hash(void* ptr) {
|
||||||
|
//return (uint32_t)(uintptr_t)ptr;
|
||||||
|
uintptr_t val = (uintptr_t)ptr;
|
||||||
|
return ((uint32_t)(val ^ (val >> 32))) & 0x7FFFFFFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
simgc_ptrset_t* simgc_ptrset_create(simgc_t* gc) {
|
||||||
|
simgc_ptrset_t* set = (simgc_ptrset_t*)SIMGC_SYSMALLOC(sizeof(simgc_ptrset_t));
|
||||||
|
if (!set) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
set->gc = gc;
|
||||||
|
set->capacity = SIMGC_PTRSET_INITIAL_CAPACITY;
|
||||||
|
set->size = 0; // TODO: No calloc!
|
||||||
|
set->buckets = (simgc_ptrset_node_t**)calloc(set->capacity, sizeof(simgc_ptrset_node_t*));
|
||||||
|
if (!set->buckets) {
|
||||||
|
SIMGC_SYSFREE(set);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return set;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simgc_ptrset_free(simgc_ptrset_t* set) {
|
||||||
|
simgc_t* gc = set->gc;
|
||||||
|
for (size_t i = 0; i < set->capacity; ++i) {
|
||||||
|
simgc_ptrset_node_t* node = set->buckets[i];
|
||||||
|
while (node) {
|
||||||
|
simgc_ptrset_node_t* next = node->next;
|
||||||
|
SIMGC_SYSFREE(node);
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SIMGC_SYSFREE(set->buckets);
|
||||||
|
SIMGC_SYSFREE(set);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool simgc_ptrset_resize(simgc_ptrset_t* set, size_t new_capacity) {
|
||||||
|
simgc_ptrset_node_t** new_buckets = (simgc_ptrset_node_t**)calloc(new_capacity, sizeof(simgc_ptrset_node_t*));
|
||||||
|
if (!new_buckets) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < set->capacity; ++i) {
|
||||||
|
simgc_ptrset_node_t* node = set->buckets[i];
|
||||||
|
while (node) {
|
||||||
|
simgc_ptrset_node_t* next = node->next;
|
||||||
|
uint32_t hash = simgc_ptrset_hash(node->key);
|
||||||
|
size_t index = hash % new_capacity;
|
||||||
|
|
||||||
|
node->next = new_buckets[index];
|
||||||
|
new_buckets[index] = node;
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SIMGC_SYSFREE(set->buckets);
|
||||||
|
set->buckets = new_buckets;
|
||||||
|
set->capacity = new_capacity;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool simgc_ptrset_add(simgc_ptrset_t* set, void* ptr) {
|
||||||
|
if ((set->size + 1) * 2 > set->capacity) {
|
||||||
|
if (!simgc_ptrset_resize(set, set->capacity * 2)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t hash = simgc_ptrset_hash(ptr);
|
||||||
|
size_t index = ((uint64_t)hash) % ((uint64_t)(set->capacity));
|
||||||
|
simgc_ptrset_node_t* node = set->buckets[index];
|
||||||
|
|
||||||
|
while (node) {
|
||||||
|
if (node->key == ptr) {
|
||||||
|
return true; // Already in the set
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
simgc_ptrset_node_t* new_node = (simgc_ptrset_node_t*)SIMGC_SYSMALLOC(sizeof(simgc_ptrset_node_t));
|
||||||
|
if (!new_node) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
new_node->key = ptr;
|
||||||
|
new_node->next = set->buckets[index];
|
||||||
|
set->buckets[index] = new_node;
|
||||||
|
set->size++;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool simgc_ptrset_remove(simgc_ptrset_t* set, void* ptr) {
|
||||||
|
uint32_t hash = simgc_ptrset_hash(ptr);
|
||||||
|
size_t index = hash % set->capacity;
|
||||||
|
simgc_ptrset_node_t* node = set->buckets[index];
|
||||||
|
simgc_ptrset_node_t* prev = NULL;
|
||||||
|
|
||||||
|
while (node) {
|
||||||
|
if (node->key == ptr) {
|
||||||
|
if (prev) {
|
||||||
|
prev->next = node->next;
|
||||||
|
} else {
|
||||||
|
set->buckets[index] = node->next;
|
||||||
|
}
|
||||||
|
SIMGC_SYSFREE(node);
|
||||||
|
set->size--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
prev = node;
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool simgc_ptrset_has(simgc_ptrset_t* set, void* ptr) {
|
||||||
|
//fprintf(stderr, "LOOKING FOR %p\n", ptr);fflush(stderr);
|
||||||
|
uint32_t hash = simgc_ptrset_hash(ptr);
|
||||||
|
//fprintf(stderr, "HASH %x CAPACITY %llu\n", hash, set->capacity);fflush(stderr);
|
||||||
|
size_t index = hash % set->capacity;
|
||||||
|
//fprintf(stderr, "INDEX %p\n", index);fflush(stderr);
|
||||||
|
simgc_ptrset_node_t* node = set->buckets[index];
|
||||||
|
|
||||||
|
while (node) {
|
||||||
|
//fprintf(stderr, "CHECKING %p\n", node);fflush(stderr);
|
||||||
|
if (node->key == ptr) {
|
||||||
|
//fprintf(stderr, "FOUND %p\n", ptr);fflush(stderr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
node = node->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "NOT FOUND %p\n", ptr);fflush(stderr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int simgc_init(simgc_t* gc) {
|
||||||
|
SIMGC_CREATELOCK(gc->alloclock);
|
||||||
|
gc->sdata = NULL;
|
||||||
|
gc->udata = NULL;
|
||||||
|
//gc->allocations = NULL;
|
||||||
|
gc->pointers = simgc_ptrset_create(gc);
|
||||||
|
gc->threads = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
simgc_thread_t* simgc_begin_inner(simgc_t* gc, void* stackbase) {
|
||||||
|
simgc_thread_t* t = SIMGC_SYSMALLOC(sizeof(simgc_thread_t));
|
||||||
|
if (t == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
t->sdata = NULL;
|
||||||
|
t->udata = NULL;
|
||||||
|
t->stackbase = stackbase;
|
||||||
|
t->stacktop = NULL;
|
||||||
|
t->gc = gc;
|
||||||
|
t->iomode = 0;
|
||||||
|
|
||||||
|
t->next = gc->threads;
|
||||||
|
gc->threads = t;
|
||||||
|
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simgc_end_inner(simgc_thread_t* ctx) {
|
||||||
|
if (ctx == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
simgc_t* gc = ctx->gc;
|
||||||
|
simgc_thread_t* prev = NULL;
|
||||||
|
simgc_thread_t* thr = gc->threads;
|
||||||
|
while (thr != NULL) {
|
||||||
|
if (thr == ctx) {
|
||||||
|
if (prev == NULL) {
|
||||||
|
gc->threads = ctx->next;
|
||||||
|
} else {
|
||||||
|
prev->next = ctx->next;
|
||||||
|
}
|
||||||
|
SIMGC_SYSFREE(ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
thr = thr->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* simgc_alloc(simgc_t* gc, size_t sz) {
|
||||||
|
if (gc == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
while ((sz & SIMGC_GRANULARITY) != 0) sz++;
|
||||||
|
simgc_allocation_t* alloc = SIMGC_SYSMALLOC(sizeof(simgc_allocation_t) + sz);
|
||||||
|
if (alloc == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
void* ptr = alloc+1;
|
||||||
|
alloc->sizeflg = sz;
|
||||||
|
alloc->next = gc->allocations;
|
||||||
|
gc->allocations = alloc;
|
||||||
|
|
||||||
|
simgc_ptrset_add(gc->pointers, ptr);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
simgc_allocation_t* simgc_lookup(simgc_t* gc, void* ptr) {
|
||||||
|
if ((((uintptr_t)ptr) > 1000) && simgc_ptrset_has(gc->pointers, ptr)) {
|
||||||
|
return ptr-sizeof(simgc_allocation_t);
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int simgc_recmark(simgc_t* gc, void* ptr);
|
||||||
|
int simgc_recmark(simgc_t* gc, void* ptr) {
|
||||||
|
fprintf(stderr, "MARK %p\n", ptr);fflush(stderr);
|
||||||
|
int n = 0;
|
||||||
|
simgc_allocation_t* alloc = simgc_lookup(gc, ptr);
|
||||||
|
if (alloc != NULL) {
|
||||||
|
fprintf(stderr, "SPECULATIVE HIT %p\n", ptr);fflush(stderr);
|
||||||
|
}
|
||||||
|
if (alloc == NULL || alloc->sizeflg & 1) {
|
||||||
|
fprintf(stderr, "MISS %p\n", ptr);fflush(stderr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "HIT %p\n", ptr);fflush(stderr);
|
||||||
|
n = 1;
|
||||||
|
alloc->sizeflg = alloc->sizeflg | 1;
|
||||||
|
size_t sz = (alloc->sizeflg >> 3) << 3;
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < sz; i += sizeof(void*)) {
|
||||||
|
n += simgc_recmark(gc, *((void**)(ptr + i)));
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int simgc_markstack(simgc_t* gc, void* stackbase, void* stacktop) {
|
||||||
|
int n = 0;
|
||||||
|
// The stack generally grows top-down, but here we simplify it
|
||||||
|
if (((uintptr_t)stackbase) > ((uintptr_t)stacktop)) {
|
||||||
|
void* x = stacktop;
|
||||||
|
stacktop = stackbase;
|
||||||
|
stackbase = x;
|
||||||
|
}
|
||||||
|
while ((((uintptr_t)stackbase)%SIMGC_GRANULARITY) != 0) stackbase++;
|
||||||
|
while ((((uintptr_t)stacktop)%SIMGC_GRANULARITY) != 0) stacktop--;
|
||||||
|
void* p = stackbase;
|
||||||
|
while (((uintptr_t)p) < ((uintptr_t)stacktop)) {
|
||||||
|
n += simgc_recmark(gc, *((void**)p));
|
||||||
|
p += sizeof(void*);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int simgc_quicksweep(simgc_t* gc) {
|
||||||
|
int n = 0;
|
||||||
|
simgc_allocation_t* prev = NULL;
|
||||||
|
simgc_allocation_t* alloc = gc->allocations;
|
||||||
|
while (alloc != NULL) {
|
||||||
|
if (alloc->sizeflg & 1) {
|
||||||
|
alloc->sizeflg = (alloc->sizeflg >> 1) << 1; // Clear the "marked" bit
|
||||||
|
prev = alloc;
|
||||||
|
alloc = alloc->next;
|
||||||
|
} else {
|
||||||
|
simgc_allocation_t* next = alloc->next;
|
||||||
|
if (prev == NULL) {
|
||||||
|
gc->allocations = alloc->next;
|
||||||
|
} else {
|
||||||
|
prev->next = alloc->next;
|
||||||
|
}
|
||||||
|
simgc_ptrset_remove(gc->pointers, alloc);
|
||||||
|
SIMGC_SYSFREE(alloc);
|
||||||
|
alloc = next;
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
simgc_thread_t* simgc_threadbystack(simgc_t* gc, void* stacktop) {
|
||||||
|
return gc->threads;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simgc_beginio(simgc_t* gc) {
|
||||||
|
simgc_thread_t* t;
|
||||||
|
t = simgc_threadbystack(gc, &t);
|
||||||
|
if (t == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t->iomode = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void simgc_endio(simgc_t* gc) {
|
||||||
|
simgc_thread_t* t;
|
||||||
|
t = simgc_threadbystack(gc, &t);
|
||||||
|
if (t == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t->iomode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int simgc_reclaim(simgc_t* gc) {
|
||||||
|
intptr_t dummyval = 123;
|
||||||
|
void* stacktop = &dummyval;
|
||||||
|
simgc_thread_t* t = simgc_threadbystack(gc, stacktop);
|
||||||
|
if (t == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
t->stacktop = stacktop;
|
||||||
|
int n = simgc_markstack(gc, t->stackbase, t->stacktop);
|
||||||
|
fprintf(stderr, "Marked %d\n", n);
|
||||||
|
int o = simgc_quicksweep(gc);
|
||||||
|
fprintf(stderr, "Swept %d\n", o);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From ifndef SIMGC_IMPLEMENTATION_ALREADY:
|
||||||
|
#endif
|
||||||
|
// From ifdef SIMGC_IMPLEMENTATION
|
||||||
|
#endif
|
591
stdio.c
Normal file
591
stdio.c
Normal file
@@ -0,0 +1,591 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include "../kernel/fcntl.h"
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
FILE* stdin;
|
||||||
|
FILE* stdout;
|
||||||
|
FILE* stderr;
|
||||||
|
|
||||||
|
// In the object-oriented version, we can just malloc from the class
|
||||||
|
// like it's a struct, as long as the class pointer is filled in!
|
||||||
|
#ifdef LIBC_OOP
|
||||||
|
#define FILE_internals _libc_FILE
|
||||||
|
#else
|
||||||
|
#define FILE_internals FILE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
FILE* _libc_openfd(int fd) {
|
||||||
|
FILE_internals* result = malloc(sizeof(FILE_internals));
|
||||||
|
if (result) {
|
||||||
|
#ifdef LIBC_OOP
|
||||||
|
// Need to set the special class field as well as regular fields
|
||||||
|
#warning TODO class field
|
||||||
|
#else
|
||||||
|
// Nothing special to set, just the regular fields
|
||||||
|
#endif
|
||||||
|
result->fd = fd;
|
||||||
|
result->ungot = -1;
|
||||||
|
}
|
||||||
|
return (void*) result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _libc_stdio_init() {
|
||||||
|
stdin = _libc_openfd(0);
|
||||||
|
stdout = _libc_openfd(1);
|
||||||
|
stderr = _libc_openfd(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* fopen(const char* name, const char* mode) {
|
||||||
|
int has_r = 0;
|
||||||
|
int has_w = 0;
|
||||||
|
int has_a = 0;
|
||||||
|
int has_b = 0;
|
||||||
|
int has_plus = 0;
|
||||||
|
|
||||||
|
printf("open mode: \"%s\"\n", mode);
|
||||||
|
|
||||||
|
for (char* m = mode; *m; m++) {
|
||||||
|
switch (*m) {
|
||||||
|
case 'r':
|
||||||
|
if (has_r || has_w || has_a) {
|
||||||
|
return NULL; // Invalid mode
|
||||||
|
}
|
||||||
|
has_r = 1;
|
||||||
|
break;
|
||||||
|
case 'w':
|
||||||
|
if (has_r || has_w || has_a) {
|
||||||
|
return NULL; // Invalid mode
|
||||||
|
}
|
||||||
|
has_w = 1;
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
if (has_r || has_w || has_a) {
|
||||||
|
return NULL; // Invalid mode
|
||||||
|
}
|
||||||
|
has_a = 1;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
if (has_b) {
|
||||||
|
return NULL; // Invalid mode
|
||||||
|
}
|
||||||
|
has_b = 1;
|
||||||
|
break;
|
||||||
|
case '+':
|
||||||
|
if (has_plus) {
|
||||||
|
return NULL; // Invalid mode
|
||||||
|
}
|
||||||
|
has_plus = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return NULL; // Invalid mode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int o_mode = 0;
|
||||||
|
if (has_r) {
|
||||||
|
if (has_plus) {
|
||||||
|
o_mode |= O_RDWR;
|
||||||
|
} else {
|
||||||
|
o_mode = O_RDONLY;
|
||||||
|
}
|
||||||
|
} else if (has_w) {
|
||||||
|
o_mode = O_WRONLY;
|
||||||
|
o_mode |= O_CREATE;
|
||||||
|
if (has_plus) {
|
||||||
|
o_mode |= O_TRUNC;
|
||||||
|
}
|
||||||
|
} else if (has_a) {
|
||||||
|
o_mode = O_WRONLY;
|
||||||
|
o_mode = O_APPEND;
|
||||||
|
if (has_plus) {
|
||||||
|
o_mode |= O_CREATE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
FATAL("This should be unreachable.");
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE_internals* result = malloc(sizeof(FILE_internals));
|
||||||
|
if (!result) {
|
||||||
|
//printf("Malloc failed\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
result->fd = open(name, o_mode);
|
||||||
|
if (result->fd <= 0) {
|
||||||
|
//printf("Open failed, used mode %d got %d\n", o_mode, result->fd);
|
||||||
|
free(result);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
result->ungot = -1;
|
||||||
|
result->eof = 0;
|
||||||
|
|
||||||
|
return (FILE*)result;
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE* freopen(const char* name, const char* mode, FILE* f) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
int fclose(FILE* f) {
|
||||||
|
if (f == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
close(((FILE_internals*)f)->fd);
|
||||||
|
free(f);
|
||||||
|
return 0; // TODO: Return -1 if it fails
|
||||||
|
}
|
||||||
|
|
||||||
|
int fflush(FILE* f) {
|
||||||
|
return 0; // TODO: This function needs to be implemented for buffered streams
|
||||||
|
}
|
||||||
|
|
||||||
|
int feof(FILE* f) {
|
||||||
|
if (f == NULL) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return f->eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fread(void* buffer, size_t size, size_t nmemb, FILE* f) {
|
||||||
|
// TODO: See note in calloc() about possibly checking size calculation
|
||||||
|
char* charbuff = buffer;
|
||||||
|
size_t realsize = size*nmemb;
|
||||||
|
if (realsize > 0 && ((FILE_internals*)f)->ungot != -1) {
|
||||||
|
*charbuff++ = (char) ((FILE_internals*)f)->ungot;
|
||||||
|
((FILE_internals*)f)->ungot = -1;
|
||||||
|
realsize--;
|
||||||
|
}
|
||||||
|
size_t realresult = read(((FILE_internals*)f)->fd, charbuff, realsize);
|
||||||
|
if (realresult == realsize) {
|
||||||
|
return nmemb;
|
||||||
|
} else {
|
||||||
|
((FILE_internals*)f)->eof = 1;
|
||||||
|
return realresult / size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t fwrite(void* buffer, size_t size, size_t nmemb, FILE* f) {
|
||||||
|
// TODO: See note in calloc() about possibly checking size calculation
|
||||||
|
size_t realsize = size*nmemb;
|
||||||
|
size_t realresult = write(((FILE_internals*)f)->fd, buffer, realsize);
|
||||||
|
if (realresult == realsize) {
|
||||||
|
return nmemb;
|
||||||
|
} else {
|
||||||
|
return realresult / size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getc(FILE* f) {
|
||||||
|
unsigned char foo;
|
||||||
|
if (fread(&foo, 1, 1, f) == 1) {
|
||||||
|
return (int) foo;
|
||||||
|
} else {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int fgetc(FILE* f) {
|
||||||
|
return getc(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ungetc(int c, FILE* f) {
|
||||||
|
if (((FILE_internals*)f)->ungot == -1) {
|
||||||
|
return EOF;
|
||||||
|
} else {
|
||||||
|
((FILE_internals*)f)->ungot = (int)((unsigned char)c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int putc(int c, FILE* f) {
|
||||||
|
unsigned char chbuf = (unsigned char) c;
|
||||||
|
if (fwrite(&chbuf, 1, 1, f) != 1) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
return chbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int putchar(int c) {
|
||||||
|
return putc(c, stdout);
|
||||||
|
}
|
||||||
|
|
||||||
|
int fputc(int c, FILE* f) {
|
||||||
|
return putc(c, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
char* fgets(char* str, int size, FILE* f) {
|
||||||
|
int i = 0;
|
||||||
|
int ch;
|
||||||
|
while (i < size-1) {
|
||||||
|
ch = getc(f);
|
||||||
|
//printf("Got character '%c'\n", ch);
|
||||||
|
if (ch == EOF) {
|
||||||
|
if (i == 0) {
|
||||||
|
return NULL; // This is important for a program to be able to detect EOF!
|
||||||
|
}
|
||||||
|
goto fgets_finished;
|
||||||
|
}
|
||||||
|
str[i++] = (char) ch;
|
||||||
|
if (ch == '\n') {
|
||||||
|
goto fgets_finished;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fgets_finished: // Write terminating zero at i and return
|
||||||
|
str[i] = 0;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fputs(const char* str, FILE* f) {
|
||||||
|
int n = strlen(str);
|
||||||
|
if (fwrite(str, 1, n, f) != n) {
|
||||||
|
return EOF;
|
||||||
|
} else {
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libc_dprintf_backend(const char* str, int n, void* udata) {
|
||||||
|
int fd = (int)((intptr_t)udata);
|
||||||
|
return write(fd, str, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libc_fprintf_backend(const char* str, int n, void* udata) {
|
||||||
|
FILE* f = udata;
|
||||||
|
return fwrite(str, 1, n, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libc_sprintf_backend(const char* str, int n, void* udata) {
|
||||||
|
char** strvar = udata;
|
||||||
|
char* s = *strvar;
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
*s++ = str[i];
|
||||||
|
}
|
||||||
|
*s = 0;
|
||||||
|
*strvar = s;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct _libc_snprintf_args {
|
||||||
|
char* str;
|
||||||
|
size_t i;
|
||||||
|
size_t sz;
|
||||||
|
};
|
||||||
|
|
||||||
|
int _libc_snprintf_backend(const char* str, int n, void* udata) {
|
||||||
|
struct _libc_snprintf_args* args = udata;
|
||||||
|
char* s = args->str;
|
||||||
|
|
||||||
|
for (int i = 0; i < n; i++) {
|
||||||
|
if (args->i >= args->sz-1) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
args->str[args->i] = str[i];
|
||||||
|
args->i++;
|
||||||
|
}
|
||||||
|
args->str[args->i+1] = 0;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _LIBC_PRINTF_CALLCONV printf(const char* fmt, ...) {
|
||||||
|
void* udata = (void*)((uintptr_t)1); // stdout
|
||||||
|
va_list varargs;
|
||||||
|
va_start(varargs, fmt);
|
||||||
|
uintptr_t result = _libc_vfnprintf(&_libc_dprintf_backend, udata, fmt, varargs);
|
||||||
|
va_end(varargs);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
int _LIBC_PRINTF_CALLCONV sprintf(char *buf, const char* fmt, ...) {
|
||||||
|
void* udata = &buf;
|
||||||
|
va_list varargs;
|
||||||
|
va_start(varargs, fmt);
|
||||||
|
uintptr_t result = _libc_vfnprintf(&_libc_sprintf_backend, udata, fmt, varargs);
|
||||||
|
va_end(varargs);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
int _LIBC_PRINTF_CALLCONV snprintf(char *buf, size_t n, const char* fmt, ...) {
|
||||||
|
struct _libc_snprintf_args args;
|
||||||
|
args.str = buf;
|
||||||
|
args.sz = n;
|
||||||
|
args.i = 0;
|
||||||
|
void* udata = &args;
|
||||||
|
va_list varargs;
|
||||||
|
va_start(varargs, fmt);
|
||||||
|
uintptr_t result = _libc_vfnprintf(&_libc_snprintf_backend, udata, fmt, varargs);
|
||||||
|
va_end(varargs);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
int _LIBC_PRINTF_CALLCONV dprintf(int fd, const char* fmt, ...) {
|
||||||
|
void* udata = (void*)((uintptr_t)fd);
|
||||||
|
va_list varargs;
|
||||||
|
va_start(varargs, fmt);
|
||||||
|
uintptr_t result = _libc_vfnprintf(&_libc_dprintf_backend, udata, fmt, varargs);
|
||||||
|
va_end(varargs);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _LIBC_PRINTF_CALLCONV fprintf(FILE* f, const char* fmt, ...) {
|
||||||
|
void* udata = f;
|
||||||
|
va_list varargs;
|
||||||
|
va_start(varargs, fmt);
|
||||||
|
uintptr_t result = _libc_vfnprintf(&_libc_fprintf_backend, udata, fmt, varargs);
|
||||||
|
va_end(varargs);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int _LIBC_PRINTF_CALLCONV vfprintf(FILE* f, const char* fmt, va_list list) {
|
||||||
|
void* udata = f;
|
||||||
|
uintptr_t result = _libc_vfnprintf(&_libc_fprintf_backend, udata, fmt, list);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
int _LIBC_PRINTF_CALLCONV vsnprintf(char* buf, size_t n, const char* fmt, va_list list) {
|
||||||
|
struct _libc_snprintf_args args;
|
||||||
|
args.str = buf;
|
||||||
|
args.sz = n;
|
||||||
|
args.i = 0;
|
||||||
|
void* udata = &args;
|
||||||
|
uintptr_t result = _libc_vfnprintf(&_libc_snprintf_backend, udata, fmt, list);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// These are non-standard, but the other *printf functions need to be implemented somehow,
|
||||||
|
// so fnprintf/vfnprintf just use a callback function for output of n bytes of string output.
|
||||||
|
int _LIBC_PRINTF_CALLCONV _libc_fnprintf(_libc_fnprintf_fn_t fn, void* udata, const char* fmt, ...) {
|
||||||
|
va_list varargs;
|
||||||
|
va_start(varargs, fmt);
|
||||||
|
uintptr_t result = _libc_vfnprintf(fn, udata, fmt, varargs);
|
||||||
|
va_end(varargs);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DUMPTOFN() \
|
||||||
|
if (dayswithoutincident) { \
|
||||||
|
if (fn(f-dayswithoutincident, dayswithoutincident, udata) != dayswithoutincident) { \
|
||||||
|
return EOF; \
|
||||||
|
} \
|
||||||
|
written += dayswithoutincident; \
|
||||||
|
dayswithoutincident = 0; \
|
||||||
|
}
|
||||||
|
|
||||||
|
int _LIBC_PRINTF_CALLCONV _libc_vfnprintf(_libc_fnprintf_fn_t fn, void* udata, const char* fmt, va_list list) {
|
||||||
|
int dayswithoutincident = 0;
|
||||||
|
int written = 0;
|
||||||
|
const char* f = fmt;
|
||||||
|
int c;
|
||||||
|
while ((c = *f)) {
|
||||||
|
if (c == '%') {
|
||||||
|
DUMPTOFN();
|
||||||
|
int has_decimals = 0;
|
||||||
|
int decimals = 0;
|
||||||
|
nextctrl:
|
||||||
|
int tc = *(f+1);
|
||||||
|
int longcount = 0; // for counting %ld/%lld
|
||||||
|
switch (tc) {
|
||||||
|
case '%': {
|
||||||
|
f++;
|
||||||
|
dayswithoutincident++; // Just let the second '%' be printed with the next string part
|
||||||
|
} break;
|
||||||
|
case '.': {
|
||||||
|
has_decimals = 1;
|
||||||
|
f++;
|
||||||
|
} goto nextctrl;
|
||||||
|
case '0':
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9': {
|
||||||
|
decimals = decimals * 10 + (tc - '0');
|
||||||
|
f++;
|
||||||
|
} goto nextctrl;
|
||||||
|
case 'f': {
|
||||||
|
char buf[20];
|
||||||
|
int i = 20;
|
||||||
|
double fval = va_arg(list, double);
|
||||||
|
//fval = -543.210987654321;
|
||||||
|
long ival = (long) fval;
|
||||||
|
int isneg = ival < 0;
|
||||||
|
unsigned long uval = isneg ? -ival : ival;
|
||||||
|
do {
|
||||||
|
buf[--i] = (char)('0' + uval % 10);
|
||||||
|
uval /= 10;
|
||||||
|
} while (uval > 0);
|
||||||
|
if (ival < 0) {
|
||||||
|
buf[--i] = '-';
|
||||||
|
}
|
||||||
|
int nwr = fn(buf+i, 20-i, udata);
|
||||||
|
if (nwr != 20-i) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
written += nwr;
|
||||||
|
if (!has_decimals) {
|
||||||
|
decimals = 6;
|
||||||
|
}
|
||||||
|
double x = fabs(fval - (double) ival);
|
||||||
|
if (fn(".", 1, udata) != 1) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
written++;
|
||||||
|
while (decimals > 0) {
|
||||||
|
x *= 10;
|
||||||
|
decimals--;
|
||||||
|
int ix = (int) x;
|
||||||
|
char xch = (char) ('0'+(ix%10));
|
||||||
|
if (fn(&xch, 1, udata) != 1) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
written++;
|
||||||
|
}
|
||||||
|
f++;
|
||||||
|
} break;
|
||||||
|
case 'S': { // Formatted substring, I thought there was a standard % for it
|
||||||
|
char* s = va_arg(list, char*);
|
||||||
|
if (!s) {
|
||||||
|
s = "(null)";
|
||||||
|
}
|
||||||
|
int len = strlen(s);
|
||||||
|
int nwr = _libc_vfnprintf(fn, udata, s, list);
|
||||||
|
if (nwr == EOF) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
written += nwr;
|
||||||
|
f++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 's': {
|
||||||
|
char* s = va_arg(list, char*);
|
||||||
|
if (!s) {
|
||||||
|
s = "(null)";
|
||||||
|
}
|
||||||
|
int len = strlen(s);
|
||||||
|
int nwr = fn(s, len, udata);
|
||||||
|
if (nwr != len) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
written += nwr;
|
||||||
|
f++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'c': {
|
||||||
|
int chr = va_arg(list, int);
|
||||||
|
char chrc = (char) chr;
|
||||||
|
if (fn(&chrc, 1, udata) != 1) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
written++;
|
||||||
|
f++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'l': // %ld/%lx is just handled as a special case of %d/%x
|
||||||
|
longcount++;
|
||||||
|
f++;
|
||||||
|
goto nextctrl;
|
||||||
|
|
||||||
|
case 'u': // Unsigned is just handled as a special case of %d
|
||||||
|
case 'd': {
|
||||||
|
// TODO: Testing/edge case for negative maximum?
|
||||||
|
char buf[20];
|
||||||
|
int i = 20;
|
||||||
|
if (longcount) {
|
||||||
|
long val = va_arg(list, long);
|
||||||
|
int isneg = ((tc == 'd') && (val < 0));
|
||||||
|
unsigned long uval = isneg ? -val : val;
|
||||||
|
// Not actually needed, unless you want a full string: buf[i--] = '0';
|
||||||
|
do {
|
||||||
|
buf[--i] = (char)('0' + uval % 10);
|
||||||
|
uval /= 10;
|
||||||
|
} while (uval > 0);
|
||||||
|
if (isneg) {
|
||||||
|
buf[--i] = '-';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
int val = va_arg(list, int);
|
||||||
|
int isneg = ((tc == 'd') && (val < 0));
|
||||||
|
unsigned int uval = isneg ? -val : val;
|
||||||
|
// Not actually needed, unless you want a full string: buf[i--] = '0';
|
||||||
|
do {
|
||||||
|
buf[--i] = (char)('0' + uval % 10);
|
||||||
|
uval /= 10;
|
||||||
|
} while (uval > 0);
|
||||||
|
if (isneg) {
|
||||||
|
buf[--i] = '-';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int nwr = fn(buf+i, 20-i, udata);
|
||||||
|
if (nwr != 20-i) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
written += nwr;
|
||||||
|
f++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case 'p': // Pointer is treated as %lx
|
||||||
|
longcount++;
|
||||||
|
case 'x':
|
||||||
|
case 'X': { // Hex is handled a separate case to %d because the loop is slightly slower and sign is never used
|
||||||
|
const char* digits = (tc == 'x') ? "0123456789abcdef" : "0123456789ABCDEF";
|
||||||
|
char buf[16]; // Size is easier to predict for hex, two characters of digits per byte
|
||||||
|
int i = 16;
|
||||||
|
if (longcount) {
|
||||||
|
unsigned long uval = va_arg(list, unsigned long);
|
||||||
|
// Not actually needed, unless you want a full string: buf[i--] = '0';
|
||||||
|
do {
|
||||||
|
buf[--i] = digits[uval % 16];
|
||||||
|
uval /= 16;
|
||||||
|
} while (uval > 0);
|
||||||
|
} else {
|
||||||
|
unsigned int uval = va_arg(list, unsigned int);
|
||||||
|
// Not actually needed, unless you want a full string: buf[i--] = '0';
|
||||||
|
do {
|
||||||
|
buf[--i] = digits[uval % 16];
|
||||||
|
uval /= 16;
|
||||||
|
} while (uval > 0);
|
||||||
|
}
|
||||||
|
int nwr = fn(buf+i, 16-i, udata);
|
||||||
|
if (nwr != 16-i) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
written += nwr;
|
||||||
|
f++;
|
||||||
|
} break;
|
||||||
|
|
||||||
|
default: { // For now just print %x??? when 'x' is unknown, but this is probably unsafe and an error should be reported properly instead (TODO)
|
||||||
|
// Also skip the argument (assume all arguments are word-sized for now)
|
||||||
|
void* _ignored = va_arg(list, void*);
|
||||||
|
if (fn(f, 2, udata) != 2) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
if (fn("???", 3, udata) != 3) {
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
written+=5;
|
||||||
|
f++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dayswithoutincident++;
|
||||||
|
}
|
||||||
|
f++;
|
||||||
|
}
|
||||||
|
DUMPTOFN();
|
||||||
|
return written;
|
||||||
|
}
|
||||||
|
|
||||||
|
void perror(const char* errormsg) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
195
stdlib.c
Normal file
195
stdlib.c
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "internal.h"
|
||||||
|
|
||||||
|
/* DESIGN NOTE: At program entry the environment variables are just an
|
||||||
|
* array of "key=value" strings allocated on/near the stack by the
|
||||||
|
* kernel. When actively modifying environment variables the structure
|
||||||
|
* needs to be reallocated, so the system initially just uses the
|
||||||
|
* preallocated copy but keeps a _libc_env_reallocated flag to tell it
|
||||||
|
* if it's using a malloc'd copy so it can be freed properly. This means
|
||||||
|
* the system is optimised for programs that don't use environment
|
||||||
|
* variables much so it doesn't rely on memory allocation in those
|
||||||
|
* cases but may be slightly inefficient in cases where you do make
|
||||||
|
* heavy use of them (copying the whole table on every change instead of
|
||||||
|
* just using an optimised structure from the start).
|
||||||
|
*/
|
||||||
|
const char** _libc_env_variable;
|
||||||
|
int _libc_env_count;
|
||||||
|
int _libc_env_reallocated;
|
||||||
|
|
||||||
|
void _libc_env_init(const char** envv) {
|
||||||
|
_libc_env_variable = envv;
|
||||||
|
_libc_env_count = 0;
|
||||||
|
_libc_env_reallocated = 0;
|
||||||
|
while (envv != NULL && envv[_libc_env_count] != NULL) {
|
||||||
|
_libc_env_count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* _libc_env_match(const char* env, const char* key) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; key[i] != 0; i++) {
|
||||||
|
if (env[i] != key[i]) {
|
||||||
|
return 0; // false, env doesn't match given key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (env[i] != '=') {
|
||||||
|
return 0; // false, env key is longer than given key
|
||||||
|
}
|
||||||
|
return env+i+1; // true, env string starts with key followed by "="
|
||||||
|
}
|
||||||
|
|
||||||
|
char* getenv(const char* key) {
|
||||||
|
for (int i = 0; i < _libc_env_count; i++) {
|
||||||
|
const char* tmp;
|
||||||
|
if ((tmp = _libc_env_match(_libc_env_variable[i], key)) != NULL) {
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int setenv(const char* key, const char* value, int overwrite) {
|
||||||
|
int exists = -1;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < _libc_env_count; i++) {
|
||||||
|
const char* tmp;
|
||||||
|
if ((tmp = _libc_env_match(_libc_env_variable[i], key)) != NULL) {
|
||||||
|
if (overwrite) {
|
||||||
|
exists = i;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int newsize;
|
||||||
|
newsize = _libc_env_count + (exists >= 0 ? 1 : 0);
|
||||||
|
char* newentry = malloc(strlen(key)+strlen(value)+2);
|
||||||
|
sprintf(newentry, "%s=%s", key, value);
|
||||||
|
const char** oldptr = _libc_env_variable;
|
||||||
|
const char** newptr = malloc(newsize * sizeof(char*));
|
||||||
|
for (i = 0; i < _libc_env_count; i++) {
|
||||||
|
const char* tmp;
|
||||||
|
if (i == exists) {
|
||||||
|
newptr[i] = newentry;
|
||||||
|
} else {
|
||||||
|
newptr[i] = strdup(oldptr[i]);
|
||||||
|
}
|
||||||
|
if (_libc_env_reallocated) {
|
||||||
|
free(oldptr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (i < newsize) {
|
||||||
|
newptr[i] = newentry;
|
||||||
|
}
|
||||||
|
_libc_env_variable = newptr;
|
||||||
|
if (_libc_env_reallocated) {
|
||||||
|
free(oldptr);
|
||||||
|
}
|
||||||
|
_libc_env_reallocated = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int unsetenv(const char* key) {
|
||||||
|
int exists = -1;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < _libc_env_count; i++) {
|
||||||
|
const char* tmp;
|
||||||
|
if ((tmp = _libc_env_match(_libc_env_variable[i], key)) != NULL) {
|
||||||
|
exists = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (exists < 0) {
|
||||||
|
return 0; // Nothing to do, env var already doesn't exist
|
||||||
|
}
|
||||||
|
int newsize = _libc_env_count - 1;
|
||||||
|
const char** oldptr = _libc_env_variable;
|
||||||
|
const char** newptr = malloc(newsize * sizeof(char*));
|
||||||
|
for (i = 0; i < _libc_env_count; i++) {
|
||||||
|
const char* tmp;
|
||||||
|
if (i >= exists) {
|
||||||
|
newptr[i] = strdup(oldptr[i-1]);
|
||||||
|
} else {
|
||||||
|
newptr[i] = strdup(oldptr[i]);
|
||||||
|
}
|
||||||
|
if (_libc_env_reallocated) {
|
||||||
|
free(oldptr[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_libc_env_variable = newptr;
|
||||||
|
if (_libc_env_reallocated) {
|
||||||
|
free(oldptr);
|
||||||
|
}
|
||||||
|
_libc_env_reallocated = 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int system(const char* cmd) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
void abort() {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
double atof(const char* str) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
int _libc_charnum(char c, int base) {
|
||||||
|
int n;
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
n = c - '0';
|
||||||
|
} else if (c >= 'A' && c <= 'F') {
|
||||||
|
n = 10 + c - 'A';
|
||||||
|
} else if (c >= 'a' && c <= 'f') {
|
||||||
|
n = 10 + c - 'a';
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (n < base) {
|
||||||
|
return n;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long strtol(const char* str, char**endvar, int base) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
long long strtoll(const char* str, char**endvar, int base) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long strtoul(const char* str, char**endvar, int base) {
|
||||||
|
return strtoull(str, endvar, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long long strtoull(const char* str, char**endvar, int base) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
float strtof(const char* str, char**endvar) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
double strtod(const char* str, char**endvar) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
long double strtold(const char* str, char**endvar) {
|
||||||
|
UNIMPLEMENTED();
|
||||||
|
}
|
399
string.c
Normal file
399
string.c
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
// Copyright (c) 2025, Zak Fenton
|
||||||
|
// Zak Fenton's libc is licensed under the Mulan PSL v2. You can use this
|
||||||
|
// software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
// You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
// http://license.coscl.org.cn/MulanPSL2
|
||||||
|
// THIS SOFTWARE IS PROVIDED ON AN “AS IS” BASIS, WITHOUT warranties of
|
||||||
|
// any kind, either express or implied, including but not limited to
|
||||||
|
// non-infringement, merchantability or fit for a particular purpose.
|
||||||
|
// See the Mulan PSL v2 for more details.
|
||||||
|
|
||||||
|
// For auditing purposes, this is NEW CODE
|
||||||
|
|
||||||
|
#ifdef KERNEL_MODE
|
||||||
|
#define size_t long
|
||||||
|
#define NULL ((void*)0ULL)
|
||||||
|
#else
|
||||||
|
#include <string.h>
|
||||||
|
#include "internal.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
//ifdef _ZCC
|
||||||
|
#ifdef NOT_USED_YET
|
||||||
|
/* Works like memset except assumes n is a multiple of 8 and src>=dst+8.
|
||||||
|
* Doesn't return a useful value.
|
||||||
|
*/
|
||||||
|
void __naked memset_quick64(void* dst, uint64 v, uint64 n) __asm {
|
||||||
|
add a3, a0, a2
|
||||||
|
.setloop:
|
||||||
|
sd a1, 0(a0)
|
||||||
|
addi a0, a0, 8
|
||||||
|
bne a0, a3, .setloop
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
void __naked memset_quick(void* dst, uint64 v, uint64 n) __asm {
|
||||||
|
add a3, a0, a2
|
||||||
|
.setloopa:
|
||||||
|
sb a1, 0(a0)
|
||||||
|
addi a0, a0, 1
|
||||||
|
bne a0, a3, .setloopa
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
void* __naked memset_opt(void* dst, uint64 v, uint64 n) __asm {
|
||||||
|
add a3, a0, a2
|
||||||
|
add a4, a0, zero
|
||||||
|
beq a2, zero, .endopt
|
||||||
|
addi a6, zero, 16
|
||||||
|
blt a2, a6, .setloopoptshort
|
||||||
|
addi a6, zero, 128
|
||||||
|
blt a6, a2, .setloopoptlong
|
||||||
|
.setloopopt:
|
||||||
|
sb a1, 0(a4)
|
||||||
|
addi a4, a4, 1
|
||||||
|
andi a5, a4, 7
|
||||||
|
beq a5, zero, .setloopopt64
|
||||||
|
.setloopstartopt:
|
||||||
|
bne a4, a3, .setloopopt
|
||||||
|
.endopt:
|
||||||
|
ret
|
||||||
|
.setloopoptshort:
|
||||||
|
sb a1, 0(a4)
|
||||||
|
addi a4, a4, 1
|
||||||
|
bne a4, a3, .setloopoptshort
|
||||||
|
ret
|
||||||
|
.setloopopt64adjust:
|
||||||
|
addi a3, a3, -1
|
||||||
|
sb a1, 0(a3)
|
||||||
|
.setloopopt64:
|
||||||
|
bne a1, zero, .setloopstartopt
|
||||||
|
andi a6, a3, 7
|
||||||
|
bne a6, zero, .setloopopt64adjust
|
||||||
|
//addi a6, zero, 8
|
||||||
|
.setloopopt64b:
|
||||||
|
//sub a5, a3, a4
|
||||||
|
//blt a5, a6, .setloopstartopt
|
||||||
|
sd a1, 0(a4)
|
||||||
|
addi a4, a4, 8
|
||||||
|
blt a4, a3, .setloopopt64b
|
||||||
|
//j .setloopstartopt
|
||||||
|
ret
|
||||||
|
.setloopoptlong:
|
||||||
|
bne a1, zero, .setloopstartopt
|
||||||
|
andi a6, a2, 127
|
||||||
|
bne a6, zero, .setloopstartopt
|
||||||
|
.setloopoptlongb:
|
||||||
|
sd zero, 0(a4)
|
||||||
|
sd zero, 8(a4)
|
||||||
|
sd zero, 16(a4)
|
||||||
|
sd zero, 24(a4)
|
||||||
|
sd zero, 32(a4)
|
||||||
|
sd zero, 40(a4)
|
||||||
|
sd zero, 48(a4)
|
||||||
|
sd zero, 56(a4)
|
||||||
|
sd zero, 64(a4)
|
||||||
|
sd zero, 72(a4)
|
||||||
|
sd zero, 80(a4)
|
||||||
|
sd zero, 88(a4)
|
||||||
|
sd zero, 96(a4)
|
||||||
|
sd zero, 104(a4)
|
||||||
|
sd zero, 112(a4)
|
||||||
|
sd zero, 120(a4)
|
||||||
|
addi a4, a4, 128
|
||||||
|
bne a4, a3, .setloopoptlongb
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
void* __naked memcpy_opt(void* dst, void* src, uint64 n) __asm {
|
||||||
|
add a3, a0, a2
|
||||||
|
add a4, a0, zero
|
||||||
|
beq a2, zero, .endcpy
|
||||||
|
addi a6, zero, 16
|
||||||
|
blt a2, a6, .cpyloopoptshort
|
||||||
|
addi a6, zero, 128
|
||||||
|
blt a6, a2, .cpyloopoptlong
|
||||||
|
.cpyloopopt:
|
||||||
|
lb a6, 0(a1)
|
||||||
|
sb a6, 0(a4)
|
||||||
|
addi a4, a4, 1
|
||||||
|
addi a1, a1, 1
|
||||||
|
andi a5, a4, 7
|
||||||
|
beq a5, zero, .cpyloopopt64
|
||||||
|
.cpyloopstartopt:
|
||||||
|
bne a4, a3, .cpyloopopt
|
||||||
|
.endcpy:
|
||||||
|
ret
|
||||||
|
.cpyloopoptshort:
|
||||||
|
lb a6, 0(a1)
|
||||||
|
sb a6, 0(a4)
|
||||||
|
addi a4, a4, 1
|
||||||
|
addi a1, a1, 1
|
||||||
|
bne a4, a3, .cpyloopoptshort
|
||||||
|
ret
|
||||||
|
.cpyloopopt64adjust:
|
||||||
|
addi a3, a3, -1
|
||||||
|
sub a5, a3, a4
|
||||||
|
add a5, a5, a1
|
||||||
|
lb a6, 0(a5)
|
||||||
|
sb a6, 0(a3)
|
||||||
|
.cpyloopopt64:
|
||||||
|
andi a6, a3, 7
|
||||||
|
bne a6, zero, .cpyloopopt64adjust
|
||||||
|
//addi a6, zero, 8
|
||||||
|
.cpyloopopt64b:
|
||||||
|
//sub a5, a3, a4
|
||||||
|
//blt a5, a6, .setloopstartopt
|
||||||
|
ld a6, 0(a1)
|
||||||
|
sd a6, 0(a4)
|
||||||
|
addi a4, a4, 8
|
||||||
|
addi a1, a1, 8
|
||||||
|
blt a4, a3, .cpyloopopt64b
|
||||||
|
//j .setloopstartopt
|
||||||
|
ret
|
||||||
|
.cpyloopoptlong:
|
||||||
|
andi a6, a2, 127
|
||||||
|
bne a6, zero, .cpyloopstartopt
|
||||||
|
.cpyloopoptlongb:
|
||||||
|
ld a6, 0(a1)
|
||||||
|
sd a6, 0(a4)
|
||||||
|
ld a6, 8(a1)
|
||||||
|
sd a6, 8(a4)
|
||||||
|
ld a6, 16(a1)
|
||||||
|
sd a6, 16(a4)
|
||||||
|
ld a6, 24(a1)
|
||||||
|
sd a6, 24(a4)
|
||||||
|
ld a6, 32(a1)
|
||||||
|
sd a6, 32(a4)
|
||||||
|
ld a6, 40(a1)
|
||||||
|
sd a6, 40(a4)
|
||||||
|
ld a6, 48(a1)
|
||||||
|
sd a6, 48(a4)
|
||||||
|
ld a6, 56(a1)
|
||||||
|
sd a6, 56(a4)
|
||||||
|
ld a6, 64(a1)
|
||||||
|
sd a6, 64(a4)
|
||||||
|
ld a6, 72(a1)
|
||||||
|
sd a6, 72(a4)
|
||||||
|
ld a6, 80(a1)
|
||||||
|
sd a6, 80(a4)
|
||||||
|
ld a6, 88(a1)
|
||||||
|
sd a6, 88(a4)
|
||||||
|
ld a6, 96(a1)
|
||||||
|
sd a6, 96(a4)
|
||||||
|
ld a6, 104(a1)
|
||||||
|
sd a6, 104(a4)
|
||||||
|
ld a6, 112(a1)
|
||||||
|
sd a6, 112(a4)
|
||||||
|
ld a6, 120(a1)
|
||||||
|
sd a6, 120(a4)
|
||||||
|
addi a4, a4, 128
|
||||||
|
addi a1, a1, 128
|
||||||
|
bne a4, a3, .cpyloopoptlongb
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
// Works like memcpy except assumes n is a multiple of 8 and src>=dst+8.
|
||||||
|
// Doesn't return a useful value.
|
||||||
|
void __naked memcpy_quick64(void* dst, void* src, uint64 n) __asm {
|
||||||
|
add a3, a0, a2
|
||||||
|
.cpyloop:
|
||||||
|
ld a4, 0(a1)
|
||||||
|
addi a1, a1, 8
|
||||||
|
sd a4, 0(a0)
|
||||||
|
addi a0, a0, 8
|
||||||
|
bne a0, a3, .cpyloop
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
// Expands a byte to a word.
|
||||||
|
uint64 __naked expandbyte_quick64(int b) __asm {
|
||||||
|
andi a1, a0, 255
|
||||||
|
slli a0, a0, 8
|
||||||
|
or a0, a0, a1
|
||||||
|
slli a0, a0, 8
|
||||||
|
or a0, a0, a1
|
||||||
|
slli a0, a0, 8
|
||||||
|
or a0, a0, a1
|
||||||
|
slli a0, a0, 8
|
||||||
|
or a0, a0, a1
|
||||||
|
slli a0, a0, 8
|
||||||
|
or a0, a0, a1
|
||||||
|
slli a0, a0, 8
|
||||||
|
or a0, a0, a1
|
||||||
|
slli a0, a0, 8
|
||||||
|
or a0, a0, a1
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Copied from my preexisting number parser in numbered.c
|
||||||
|
unsigned long long _libc_scandec(const char** strvar) {
|
||||||
|
unsigned long long val = 0;
|
||||||
|
const char* s = *strvar;
|
||||||
|
char c;
|
||||||
|
while ((c = *s) >= '0' && c <= '9') {
|
||||||
|
unsigned long long oldval = val;
|
||||||
|
val = val * 10 + c - '0';
|
||||||
|
if (val / 10 != oldval) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
*strvar = s;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
long long atoll(const char* str) {
|
||||||
|
if (*str == '-') {
|
||||||
|
str++;
|
||||||
|
long long x = (long long) _libc_scandec(&str);
|
||||||
|
return -x;
|
||||||
|
} else if (*str == '+') {
|
||||||
|
str++;
|
||||||
|
return (long long) _libc_scandec(&str);
|
||||||
|
} else {
|
||||||
|
return (long long) _libc_scandec(&str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
long atol(const char* str) {
|
||||||
|
return (long) atoll(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
int atoi(const char* str) {
|
||||||
|
return (int) atoll(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t strlen(const char* foo) {
|
||||||
|
if (foo == NULL) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
size_t i = 0;
|
||||||
|
while (foo[i] != 0) i++;
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void* memcpy(void* dst, const void* src, size_t nbytes) {
|
||||||
|
char* cdst = (char*) dst;
|
||||||
|
const char* csrc = (char*) src;
|
||||||
|
size_t i = 0;
|
||||||
|
for (i = 0; i < nbytes; i++) {
|
||||||
|
cdst[i] = csrc[i];
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* memset(void* mem, int byt, size_t nbytes) {
|
||||||
|
char* tmp = mem;
|
||||||
|
for (size_t i = 0; i < nbytes; i++) {
|
||||||
|
tmp[i] = (char) byt;
|
||||||
|
}
|
||||||
|
return mem;
|
||||||
|
}
|
||||||
|
|
||||||
|
int strcmp(const char* a, const char* b) {
|
||||||
|
while (*a == *b) {
|
||||||
|
if (*a == 0) {
|
||||||
|
return 0; // Got to the end, strings are equal
|
||||||
|
}
|
||||||
|
a++;
|
||||||
|
b++;
|
||||||
|
}
|
||||||
|
return *a - *b;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* strcat(char* dst, const char* src) {
|
||||||
|
char* end = dst;
|
||||||
|
while (*end) { // Find the terminating zero of the dst string
|
||||||
|
end++;
|
||||||
|
}
|
||||||
|
while (*src) { // Overwrite the end of dst from src until it's terminating zero
|
||||||
|
*end++ = *src++;
|
||||||
|
}
|
||||||
|
*end = 0; // Add terminating zero back to dst
|
||||||
|
return dst; // Return the start of the dst string
|
||||||
|
}
|
||||||
|
|
||||||
|
char* strcpy(char *dst, const char* src) {
|
||||||
|
char *d = dst;
|
||||||
|
while (*src) {
|
||||||
|
*d++ = *src++;
|
||||||
|
}
|
||||||
|
*d = 0;
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* strncpy(char* dst, const char* src, size_t n) {
|
||||||
|
size_t i = 0;
|
||||||
|
char *d = dst;
|
||||||
|
while (*src) {
|
||||||
|
*d++ = *src++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
while (i < n) { // TODO: Is this right??
|
||||||
|
dst[i] = 0;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return dst;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef KERNEL_MODE
|
||||||
|
char* strdup(const char* src) {
|
||||||
|
char* result = malloc(strlen(src) + 1);
|
||||||
|
if (result) {
|
||||||
|
strcpy(result, src);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* strndup(const char* str, size_t n) {
|
||||||
|
size_t resultlen = strlen(str);
|
||||||
|
if (resultlen > n) {
|
||||||
|
resultlen = n;
|
||||||
|
}
|
||||||
|
char* result = malloc(resultlen + 1);
|
||||||
|
if (result) {
|
||||||
|
for (size_t i = 0; i < resultlen; i++) {
|
||||||
|
result[i] = str[i];
|
||||||
|
}
|
||||||
|
str[resultlen] = 0;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const char* strpbrk(const char* str, const char* search) {
|
||||||
|
char c;
|
||||||
|
while ((c = *str)) {
|
||||||
|
const char* s = search;
|
||||||
|
while (*s++) {
|
||||||
|
if (c == *s) {
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strchr(const char* str, int chr) {
|
||||||
|
int c;
|
||||||
|
while ((c = *str)) {
|
||||||
|
if (c == chr) {
|
||||||
|
return (char*) str;
|
||||||
|
}
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *strrchr(const char* str, int chr) {
|
||||||
|
int c;
|
||||||
|
char* result = NULL;
|
||||||
|
while ((c = *str)) {
|
||||||
|
if (c == chr) {
|
||||||
|
result = (char*) str;
|
||||||
|
}
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
Reference in New Issue
Block a user