Initial commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
build
|
||||
@@ -0,0 +1,72 @@
|
||||
# Files
|
||||
HEADERS=$(shell find include -type f -name "*.h")
|
||||
INSTALL_HEADERS=$(filter-out include/_libc/%,$(HEADERS))
|
||||
OBJ_CRT=$(O)/obj/crt0.o
|
||||
SRC_LIBC=$(shell find src -type f -name "*.c")
|
||||
OBJ_LIBC=$(SRC_LIBC:src/%.c=$(O)/libc/%.o)
|
||||
SRC_DIR_LIBC=$(shell find src/* -type d)
|
||||
DIR_LIBC=$(SRC_DIR_LIBC:src/%=$(O)/libc/%)
|
||||
STATIC_LIBS=$(O)/lib/libc.a
|
||||
SHARED_LIBS=
|
||||
|
||||
# Build
|
||||
CFLAGS=-mno-sse \
|
||||
-mno-sse2 \
|
||||
-mno-mmx \
|
||||
-I include \
|
||||
-ffreestanding \
|
||||
-Wall \
|
||||
-Wextra \
|
||||
-Werror \
|
||||
-zmax-page-size=4096
|
||||
LDFLAGS=-nostdlib
|
||||
CC=$(CROSS_COMPILE)gcc
|
||||
|
||||
O=build
|
||||
DESTDIR?=/usr/local
|
||||
LIBS=$(STATIC_LIBS) $(SHARED_LIBS)
|
||||
|
||||
### General rules
|
||||
|
||||
all: mkdirs $(LIBS) $(OBJ_CRT)
|
||||
|
||||
mkdirs:
|
||||
mkdir -p $(O)/obj $(O)/lib $(DIR_LIBC)
|
||||
|
||||
clean:
|
||||
rm -rf $(O)
|
||||
|
||||
### Install rules
|
||||
|
||||
install-crt: mkdirs $(OBJ_CRT)
|
||||
$(foreach obj,$(OBJ_CRT), \
|
||||
install -Dm 0644 $(obj) $(obj:$(O)/obj/%.o=$(DESTDIR)/lib/%.o); \
|
||||
)
|
||||
|
||||
install-static-libs: mkdirs $(STATIC_LIBS)
|
||||
$(foreach lib,$(STATIC_LIBS), \
|
||||
install -Dm 0644 $(lib) $(DESTDIR)/$(lib:$(O)/%=%); \
|
||||
)
|
||||
|
||||
install-headers: mkdirs $(INSTALL_HEADERS)
|
||||
$(foreach hdr,$(INSTALL_HEADERS), \
|
||||
install -Dm 0644 $(hdr) $(DESTDIR)/$(hdr:$(O)/%=%); \
|
||||
)
|
||||
|
||||
install: install-crt install-static-libs install-headers
|
||||
|
||||
### CRT objects
|
||||
|
||||
$(O)/obj/crt%.o: crt/crt%.c $(HEADERS)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
|
||||
### lib
|
||||
|
||||
$(O)/lib/libc.a: $(OBJ_LIBC)
|
||||
$(CROSS_COMPILE)ar rcs $@
|
||||
$(foreach obj,$(OBJ_LIBC), \
|
||||
$(CROSS_COMPILE)ar rs $@ $(obj); \
|
||||
)
|
||||
|
||||
$(O)/libc/%.o: src/%.c $(HEADERS)
|
||||
$(CC) $(CFLAGS) -c -o $@ $<
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <_libc/stdio.h>
|
||||
#include <_libc/signal.h>
|
||||
|
||||
// XXX: envp
|
||||
extern int main(int argc, char **argv);
|
||||
|
||||
extern char **environ;
|
||||
|
||||
void _start(void *_arg) {
|
||||
uintptr_t arg = (uintptr_t) _arg;
|
||||
// arg: argp page number << 24 | 12 bit page count << 12 | 12 bit argc
|
||||
char **argp = (char **) ((arg >> 12) & ~0xFFF);
|
||||
int argc = arg & 0xFFF;
|
||||
//__libc_vecp_pages = (arg >> 12) & 0xFFF;
|
||||
|
||||
// TODO: better handling for this
|
||||
environ = &argp[argc + 1];
|
||||
|
||||
__libc_signal_init();
|
||||
|
||||
fwrite("Test\n", 1, 5, stdout);
|
||||
|
||||
exit(main(argc, argp));
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
_Noreturn void __libc_abort_init(const char *reason);
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
struct list_head {
|
||||
struct list_head *prev, *next;
|
||||
};
|
||||
|
||||
#define LIST_HEAD(name) \
|
||||
struct list_head name = { &name, &name }
|
||||
|
||||
#define list_for_each(pos, head) \
|
||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
||||
|
||||
#define list_for_each_entry(pos, head, member) \
|
||||
for (pos = list_entry((head)->next, typeof(*pos), member); \
|
||||
&pos->member != (head); \
|
||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
||||
|
||||
#define list_entry(link, type, member) ({ \
|
||||
const typeof (((type *) 0)->member) *__memb = (link); \
|
||||
(type *) ((char *) __memb - offsetof(type, member)); \
|
||||
})
|
||||
|
||||
#define list_next_entry(pos, member) \
|
||||
list_entry((pos)->member.next, typeof(*(pos)), member)
|
||||
|
||||
#define list_first_entry(ptr, type, member) \
|
||||
list_entry((ptr)->next, type, member)
|
||||
|
||||
#define list_for_each_safe(pos, n, head) \
|
||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
||||
pos = n, n = pos->next)
|
||||
|
||||
static inline void list_head_init(struct list_head *list) {
|
||||
list->next = list;
|
||||
list->prev = list;
|
||||
}
|
||||
|
||||
static inline void __list_add(struct list_head *new,
|
||||
struct list_head *prev,
|
||||
struct list_head *next) {
|
||||
next->prev = new;
|
||||
new->next = next;
|
||||
new->prev = prev;
|
||||
prev->next = new;
|
||||
}
|
||||
|
||||
static inline void list_add(struct list_head *new, struct list_head *head) {
|
||||
__list_add(new, head, head->next);
|
||||
}
|
||||
|
||||
static inline void list_add_tail(struct list_head *new, struct list_head *head) {
|
||||
__list_add(new, head->prev, head);
|
||||
}
|
||||
|
||||
static inline void __list_del(struct list_head *prev, struct list_head *next) {
|
||||
next->prev = prev;
|
||||
prev->next = next;
|
||||
}
|
||||
|
||||
static inline void list_del(struct list_head *entry) {
|
||||
__list_del(entry->prev, entry->next);
|
||||
}
|
||||
|
||||
static inline int list_empty(const struct list_head *head) {
|
||||
return head->next == head;
|
||||
}
|
||||
|
||||
static inline void list_del_init(struct list_head *entry) {
|
||||
__list_del(entry->prev, entry->next);
|
||||
list_head_init(entry);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#include <_libc/list.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define BLOCK_ALLOC 1
|
||||
#define BLOCK_MMAP 2
|
||||
#define BLOCK_MAGIC_MASK 0xFFFFFFC
|
||||
#define BLOCK_MAGIC 0xBAD8EA0
|
||||
|
||||
// Fits ~56 blocks of 256
|
||||
#define SMALL_ZONE_ELEM 256
|
||||
#define SMALL_ZONE_SIZE (4 * 0x1000)
|
||||
// Fits ~31 block of 2K
|
||||
#define MID_ZONE_ELEM 2048
|
||||
#define MID_ZONE_SIZE (16 * 0x1000)
|
||||
// Fits ~15 blocks of 8K
|
||||
#define LARGE_ZONE_ELEM 8192
|
||||
#define LARGE_ZONE_SIZE (32 * 0x1000)
|
||||
// Larger objects are allocated directly using mmap()
|
||||
|
||||
struct block {
|
||||
struct block *prev, *next;
|
||||
uint32_t flags, size;
|
||||
};
|
||||
|
||||
struct zone {
|
||||
size_t size;
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
extern struct list_head small_zone_list, mid_zone_list, large_zone_list;
|
||||
|
||||
struct zone *zone_create(size_t size);
|
||||
void zone_destroy(struct zone *zone);
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#define __LIBC_SIGNAL_STACK_SIZE 4096
|
||||
|
||||
void __libc_signal_init(void);
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#include <sys/types.h>
|
||||
|
||||
#define FILE_MODE_READ (1 << 0)
|
||||
#define FILE_MODE_WRITE (1 << 1)
|
||||
#define FILE_MODE_APPEND (1 << 2)
|
||||
#define FILE_MODE_TRUNC (1 << 3)
|
||||
#define FILE_MODE_CREAT (1 << 4)
|
||||
|
||||
#define FILE_FLAG_ERROR (1 << 16)
|
||||
#define FILE_FLAG_EOF (1 << 17)
|
||||
|
||||
struct __FILE {
|
||||
void *ctx;
|
||||
void *buf;
|
||||
|
||||
ssize_t (*write)(void *ctx, const void *data, size_t len);
|
||||
ssize_t (*read) (void *ctx, void *data, size_t len);
|
||||
off_t (*seek) (void *ctx, off_t offset, int whence);
|
||||
int (*close)(void *ctx);
|
||||
|
||||
void (*free) (void *ctx, struct __FILE *fp);
|
||||
|
||||
int fd, flags, buf_mode;
|
||||
size_t wrbuf, rdbuf, rdbufpos;
|
||||
};
|
||||
|
||||
struct __FILE *__libc_file_create(void);
|
||||
int __libc_file_open_path(struct __FILE *fp, const char *pathname, const char *mode);
|
||||
int __libc_file_open_fd(struct __FILE *fp, int fd, int flags);
|
||||
int __libc_file_mode(const char *mode);
|
||||
int __libc_file_flush_read(struct __FILE *fp);
|
||||
int __libc_file_flush_write(struct __FILE *fp);
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
static inline long __syscall0(long n) {
|
||||
unsigned long ret;
|
||||
asm volatile ("syscall"
|
||||
:"=a"(ret)
|
||||
:"a"(n)
|
||||
:"rcx","r11","memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long __syscall1(long n, long a1) {
|
||||
unsigned long ret;
|
||||
asm volatile ("syscall"
|
||||
:"=a"(ret)
|
||||
:"a"(n),"D"(a1)
|
||||
:"rcx","r11","memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long __syscall2(long n, long a1, long a2) {
|
||||
unsigned long ret;
|
||||
asm volatile ("syscall"
|
||||
:"=a"(ret)
|
||||
:"a"(n),"D"(a1),"S"(a2)
|
||||
:"rcx","r11","memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long __syscall3(long n, long a1, long a2, long a3) {
|
||||
unsigned long ret;
|
||||
asm volatile ("syscall"
|
||||
:"=a"(ret)
|
||||
:"a"(n),"D"(a1),"S"(a2),"d"(a3)
|
||||
:"rcx","r11","memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline long __syscall6(long n, long a1, long a2, long a3, long a4, long a5, long a6) {
|
||||
unsigned long ret;
|
||||
register long r10 __asm__("r10") = a4;
|
||||
register long r8 __asm__("r8") = a5;
|
||||
register long r9 __asm__("r9") = a6;
|
||||
asm volatile ("syscall"
|
||||
:"=a"(ret)
|
||||
:"a"(n),"D"(a1),"S"(a2),"d"(a3),"r"(r10),"r"(r8),"r"(r9)
|
||||
:"rcx","r11","memory");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define SET_ERRNO(t, r) ({ \
|
||||
t res = (t) r; \
|
||||
if (res < 0) { \
|
||||
errno = -res; \
|
||||
} \
|
||||
((int) res) < 0 ? (t) -1 : res; \
|
||||
})
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#define _assert_stringify_line(x) #x
|
||||
#define _assert_line(x) _assert_stringify_line(x)
|
||||
#if !defined(NDEBUG)
|
||||
#define assert(c) \
|
||||
if (!(c)) { _assert_fail(__func__, __FILE__ ":" _assert_line(__LINE__) ": Assertion `" #c "' failed." ); }
|
||||
#else
|
||||
#define assert(c)
|
||||
#endif
|
||||
|
||||
_Noreturn void _assert_fail(const char *func, const char *msg);
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
|
||||
#define __Malloc __attribute__((malloc))
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include <ygg/errno.h>
|
||||
|
||||
extern int errno;
|
||||
@@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
#include <ygg/fcntl.h>
|
||||
|
||||
int open(const char *pathname, int flags, mode_t mode);
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include <ygg/signum.h>
|
||||
|
||||
#define SIG_DFL _sig_dfl
|
||||
#define SIG_ERR ((sighandler_t) -1)
|
||||
#define SIG_HOLD _sig_hold
|
||||
#define SIG_IGN _sig_ign
|
||||
|
||||
typedef void (*sighandler_t) (int);
|
||||
|
||||
extern void _sig_dfl(int signum);
|
||||
extern void _sig_hold(int signum);
|
||||
extern void _sig_ign(int signum);
|
||||
|
||||
sighandler_t signal(int signum, sighandler_t handler);
|
||||
int sigaltstack(const stack_t *ss, stack_t *old_ss);
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
// Exact-width integer types
|
||||
typedef signed char int8_t;
|
||||
typedef unsigned char uint8_t;
|
||||
|
||||
typedef signed short int16_t;
|
||||
typedef unsigned short uint16_t;
|
||||
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned int uint32_t;
|
||||
|
||||
typedef signed long int64_t;
|
||||
typedef unsigned long uint64_t;
|
||||
|
||||
// Integer types capable of holding object pointers
|
||||
typedef int64_t intptr_t;
|
||||
typedef uint64_t uintptr_t;
|
||||
|
||||
// Greatest-width integer types
|
||||
typedef int64_t intmax_t;
|
||||
typedef uint64_t uintmax_t;
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
|
||||
#define EOF -1
|
||||
#define BUFSIZ 8192
|
||||
#define _IOLBF 1
|
||||
#define _IONBF 2
|
||||
#define TMP_MAX 10000
|
||||
#define FOPEN_MAX 8 // TODO
|
||||
#define FILENAME_MAX 1024
|
||||
|
||||
typedef struct __FILE FILE;
|
||||
|
||||
extern FILE *const stdin;
|
||||
extern FILE *const stdout;
|
||||
extern FILE *const stderr;
|
||||
|
||||
FILE *fopen(const char *pathname, const char *mode);
|
||||
int fclose(FILE *fp);
|
||||
|
||||
void flockfile(FILE *fp);
|
||||
void funlockfile(FILE *fp);
|
||||
|
||||
//// _unlocked functions
|
||||
size_t fwrite_unlocked(const void *data, size_t size, size_t nmemb, FILE *fp);
|
||||
size_t fread_unlocked(void *data, size_t size, size_t nmemb, FILE *fp);
|
||||
int fgetc_unlocked(FILE *fp);
|
||||
int fputc_unlocked(int ch, FILE *fp);
|
||||
|
||||
//// Regular functions
|
||||
size_t fwrite(const void *data, size_t size, size_t nmemb, FILE *fp);
|
||||
size_t fread(void *data, size_t size, size_t nmemb, FILE *fp);
|
||||
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
#include <bits/attr.h>
|
||||
#include <stddef.h>
|
||||
|
||||
__Malloc void *malloc(size_t size);
|
||||
void free(void *ptr);
|
||||
|
||||
// XXX: POSIX doesn't define _Noreturn attribute on those?
|
||||
void _Exit(int status);
|
||||
void exit(int status);
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include <stddef.h>
|
||||
|
||||
void *memccpy(void *restrict dst, const void *restrict src, int c, size_t len);
|
||||
void *memchr(const void *ptr, int v, size_t len);
|
||||
int memcmp(const void *p0, const void *p1, size_t len);
|
||||
void *memcpy(void *dest, const void *src, size_t n);
|
||||
void *memmove(void *dst, const void *src, size_t len);
|
||||
void *memset(void *dest, int c, size_t n);
|
||||
|
||||
char *stpcpy(char *restrict dst, const char *restrict src);
|
||||
char *stpncpy(char *restrict dst, const char *restrict src, size_t len);
|
||||
char *strcat(char *dst, const char *src);
|
||||
char *strchr(const char *str, int chr);
|
||||
int strcmp(const char *a, const char *b);
|
||||
int strcoll(const char *a, const char *b);
|
||||
// TODO: strcoll_l
|
||||
char *strcpy(char *restrict dst, const char *restrict src);
|
||||
size_t strcspn(const char *a, const char *b);
|
||||
char *strdup(const char *str);
|
||||
char *strerror(int errnum);
|
||||
// TODO: strerror_l
|
||||
int strerror_r(int errnum, char *dst, size_t lim);
|
||||
size_t strlen(const char *str);
|
||||
char *strncat(char *restrict dst, const char *restrict src, size_t len);
|
||||
int strncmp(const char *a, const char *b, size_t len);
|
||||
char *strncpy(char *restrict dst, const char *restrict src, size_t len);
|
||||
char *strndup(const char *str, size_t len);
|
||||
size_t strnlen(const char *str, size_t len);
|
||||
char *strpbrk(const char *str, const char *set);
|
||||
char *strrchr(const char *str, int chr);
|
||||
char *strsignal(int signum);
|
||||
size_t strspn(const char *a, const char *b);
|
||||
char *strstr(const char *a, const char *b);
|
||||
char *strtok(char *restrict str, const char *restrict delim);
|
||||
char *strtok_r(char *restrict str, const char *restrict delim, char **restrict saveptr);
|
||||
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
#include <ygg/mman.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
|
||||
int munmap(void *addr, size_t length);
|
||||
@@ -0,0 +1,3 @@
|
||||
#pragma once
|
||||
#include <stddef.h> // size_t
|
||||
#include <ygg/types.h>
|
||||
@@ -0,0 +1,338 @@
|
||||
#pragma once
|
||||
#include <sys/types.h> // size_t, ssize_t
|
||||
|
||||
extern char **environ;
|
||||
|
||||
|
||||
//// Defines
|
||||
// POSIX conformance
|
||||
#undef _POSIX_ADVISORY_INFO
|
||||
#undef _POSIX_ASYNCHRONOUS_IO
|
||||
#undef _POSIX_BARRIERS
|
||||
#define _POSIX_CHOWN_RESTRICTED 200809L
|
||||
#undef _POSIX_CLOCK_SELECTION
|
||||
#undef _POSIX_CPU_TIME
|
||||
#undef _POSIX_FSYNC // TODO: maybe I'll add this on a per-file basis
|
||||
#undef _POSIX_IPV6 // I don't even support IPv4 yet lol
|
||||
#define _POSIX_JOB_CONTROL 200809L
|
||||
#undef _POSIX_MAPPED_FILES // TODO: I'll implement this eventually
|
||||
#undef _POSIX_MEMLOCK
|
||||
#undef _POSIX_MEMLOCK_RANGE
|
||||
#undef _POSIX_MEMORY_PROTECTION
|
||||
#undef _POSIX_MESSAGE_PASSING
|
||||
#undef _POSIX_MONOTONIC_CLOCK // TODO
|
||||
#define _POSIX_NO_TRUNC 200809L
|
||||
#undef _POSIX_PRIORITIZED_IO
|
||||
#undef _POSIX_PRIORITY_SCHEDULING // TODO: maybe just define that and ignore the priorities
|
||||
#undef _POSIX_RAW_SOCKETS // TODO: the kernel kinda supports them, but pending rewrite
|
||||
#undef _POSIX_READER_WRITER_LOCKS
|
||||
#undef _POSIX_REALTIME_SIGNALS
|
||||
#undef _POSIX_REGEXP // TODO
|
||||
#undef _POSIX_SAVED_IDS // TODO?
|
||||
#undef _POSIX_SEMAPHORES
|
||||
#undef _POSIX_SHARED_MEMORY_OBJECTS // TODO
|
||||
#define _POSIX_SHELL 200809L
|
||||
#undef _POSIX_SPAWN // TODO?
|
||||
#undef _POSIX_SPIN_LOCKS // TODO?
|
||||
#undef _POSIX_SPORADIC_SERVER
|
||||
#undef _POSIX_SYNCHRONIZED_IO
|
||||
#undef _POSIX_THREAD_ATTR_STACKADDR
|
||||
#undef _POSIX_THREAD_ATTR_STACKSIZE
|
||||
#undef _POSIX_THREAD_CPUTIME
|
||||
#undef _POSIX_THREAD_PRIO_INHERIT
|
||||
#undef _POSIX_THREAD_PRIO_PROTECT
|
||||
#undef _POSIX_THREAD_PRIORITY_SCHEDULING
|
||||
#undef _POSIX_THREAD_PROCESS_SHARED
|
||||
#undef _POSIX_THREAD_ROBUST_PRIO_INHERIT
|
||||
#undef _POSIX_THREAD_ROBUST_PRIO_PROTECT
|
||||
#define _POSIX_THREAD_SAFE_FUNCTIONS 200809L
|
||||
#undef _POSIX_THREAD_SPORADIC_SERVER
|
||||
#undef _POSIX_THREADS // TODO
|
||||
#undef _POSIX_TIMEOUTS // TODO?
|
||||
#undef _POSIX_TIMERS // TODO
|
||||
#undef _POSIX_TRACE // TODO?
|
||||
#undef _POSIX_TRACE_EVENT_FILTER
|
||||
#undef _POSIX_TRACE_INHERIT
|
||||
#undef _POSIX_TRACE_LOG
|
||||
#undef _POSIX_TYPED_MEMORY_OBJECTS
|
||||
#define _POSIX_V6_LP64_OFF64 200809L
|
||||
#define _POSIX_V7_LP64_OFF64 200809L
|
||||
#undef _POSIX2_C_BIND // Dunno what that is
|
||||
#undef _POSIX2_C_DEV // Ditto
|
||||
#undef _POSIX2_CHAR_TERM
|
||||
#undef _POSIX2_FORT_DEV // Lel
|
||||
#undef _POSIX2_FORT_RUN // Lmao
|
||||
#undef _POSIX2_LOCALEDEV
|
||||
#undef _POSIX2_PBS
|
||||
#undef _POSIX2_PBS_ACCOUNTING
|
||||
#undef _POSIX2_PBS_CHECKPOINT
|
||||
#undef _POSIX2_PBS_LOCATE
|
||||
#undef _POSIX2_PBS_MESSAGE
|
||||
#undef _POSIX2_PBS_TRACK
|
||||
#undef _POSIX2_SW_DEV
|
||||
#undef _POSIX2_UPE
|
||||
#undef _XOPEN_CRYPT
|
||||
#undef _XOPEN_ENH_I18N
|
||||
#undef _XOPEN_REALTIME
|
||||
#undef _XOPEN_SHM
|
||||
#undef _XOPEN_STREAMS
|
||||
#undef _XOPEN_UUCP
|
||||
|
||||
// TODO: merge these with kernel's fcntl.h
|
||||
#define SEEK_SET 0
|
||||
#define SEEK_CUR 1
|
||||
#define SEEK_END 2
|
||||
|
||||
#define R_OK 4
|
||||
#define W_OK 2
|
||||
#define X_OK 1
|
||||
#define F_OK 0
|
||||
|
||||
// No POSIX advisory locks
|
||||
|
||||
#define _PC_2_SYMLINKS 1
|
||||
#define _PC_ALLOC_SIZE_MIN 2
|
||||
#define _PC_ASYNC_IO 3
|
||||
#define _PC_CHOWN_RESTRICTED 4
|
||||
#define _PC_FILESIZEBITS 5
|
||||
#define _PC_LINK_MAX 6
|
||||
#define _PC_MAX_CANON 7
|
||||
#define _PC_MAX_INPUT 8
|
||||
#define _PC_NAME_MAX 9
|
||||
#define _PC_NO_TRUNC 10
|
||||
#define _PC_PATH_MAX 11
|
||||
#define _PC_PIPE_BUF 12
|
||||
#define _PC_PRIO_IO 13
|
||||
#define _PC_REC_INCR_XFER_SIZE 14
|
||||
#define _PC_REC_MAX_XFER_SIZE 15
|
||||
#define _PC_REC_MIN_XFER_SIZE 16
|
||||
#define _PC_REC_XFER_ALIGN 17
|
||||
#define _PC_SYMLINK_MAX 18
|
||||
#define _PC_SYNC_IO 19
|
||||
#define _PC_TIMESTAMP_RESOLUTION 20
|
||||
#define _PC_VDISABLE 21
|
||||
|
||||
#define _SC_2_C_BIND 1
|
||||
#define _SC_2_C_DEV 2
|
||||
#define _SC_2_CHAR_TERM 3
|
||||
#define _SC_2_FORT_DEV 4
|
||||
#define _SC_2_FORT_RUN 5
|
||||
#define _SC_2_LOCALEDEF 6
|
||||
#define _SC_2_PBS 7
|
||||
#define _SC_2_PBS_ACCOUNTING 8
|
||||
#define _SC_2_PBS_CHECKPOINT 9
|
||||
#define _SC_2_PBS_LOCATE 10
|
||||
#define _SC_2_PBS_MESSAGE 11
|
||||
#define _SC_2_PBS_TRACK 12
|
||||
#define _SC_2_SW_DEV 13
|
||||
#define _SC_2_UPE 14
|
||||
#define _SC_2_VERSION 15
|
||||
#define _SC_ADVISORY_INFO 16
|
||||
#define _SC_AIO_LISTIO_MAX 17
|
||||
#define _SC_AIO_MAX 18
|
||||
#define _SC_AIO_PRIO_DELTA_MAX 19
|
||||
#define _SC_ARG_MAX 20
|
||||
#define _SC_ASYNCHRONOUS_IO 21
|
||||
#define _SC_ATEXIT_MAX 22
|
||||
#define _SC_BARRIERS 23
|
||||
#define _SC_BC_BASE_MAX 24
|
||||
#define _SC_BC_DIM_MAX 25
|
||||
#define _SC_BC_SCALE_MAX 26
|
||||
#define _SC_BC_STRING_MAX 27
|
||||
#define _SC_CHILD_MAX 28
|
||||
#define _SC_CLK_TCK 29
|
||||
#define _SC_CLOCK_SELECTION 30
|
||||
#define _SC_COLL_WEIGHTS_MAX 31
|
||||
#define _SC_CPUTIME 32
|
||||
#define _SC_DELAYTIMER_MAX 33
|
||||
#define _SC_EXPR_NEST_MAX 34
|
||||
#define _SC_FSYNC 35
|
||||
#define _SC_GETGR_R_SIZE_MAX 36
|
||||
#define _SC_GETPW_R_SIZE_MAX 37
|
||||
#define _SC_HOST_NAME_MAX 38
|
||||
#define _SC_IOV_MAX 39
|
||||
#define _SC_IPV6 40
|
||||
#define _SC_JOB_CONTROL 41
|
||||
#define _SC_LINE_MAX 42
|
||||
#define _SC_LOGIN_NAME_MAX 43
|
||||
#define _SC_MAPPED_FILES 44
|
||||
#define _SC_MEMLOCK 45
|
||||
#define _SC_MEMLOCK_RANGE 46
|
||||
#define _SC_MEMORY_PROTECTION 47
|
||||
#define _SC_MESSAGE_PASSING 48
|
||||
#define _SC_MONOTONIC_CLOCK 49
|
||||
#define _SC_MQ_OPEN_MAX 50
|
||||
#define _SC_MQ_PRIO_MAX 51
|
||||
#define _SC_NGROUPS_MAX 52
|
||||
#define _SC_OPEN_MAX 53
|
||||
#define _SC_PAGE_SIZE 54
|
||||
#define _SC_PAGESIZE 55
|
||||
#define _SC_PRIORITIZED_IO 56
|
||||
#define _SC_PRIORITY_SCHEDULING 57
|
||||
#define _SC_RAW_SOCKETS 58
|
||||
#define _SC_RE_DUP_MAX 59
|
||||
#define _SC_READER_WRITER_LOCKS 60
|
||||
#define _SC_REALTIME_SIGNALS 61
|
||||
#define _SC_REGEXP 62
|
||||
#define _SC_RTSIG_MAX 63
|
||||
#define _SC_SAVED_IDS 64
|
||||
#define _SC_SEM_NSEMS_MAX 65
|
||||
#define _SC_SEM_VALUE_MAX 66
|
||||
#define _SC_SEMAPHORES 67
|
||||
#define _SC_SHARED_MEMORY_OBJECTS 68
|
||||
#define _SC_SHELL 69
|
||||
#define _SC_SIGQUEUE_MAX 70
|
||||
#define _SC_SPAWN 71
|
||||
#define _SC_SPIN_LOCKS 72
|
||||
#define _SC_SPORADIC_SERVER 73
|
||||
#define _SC_SS_REPL_MAX 74
|
||||
#define _SC_STREAM_MAX 75
|
||||
#define _SC_SYMLOOP_MAX 76
|
||||
#define _SC_SYNCHRONIZED_IO 77
|
||||
#define _SC_THREAD_ATTR_STACKADDR 78
|
||||
#define _SC_THREAD_ATTR_STACKSIZE 79
|
||||
#define _SC_THREAD_CPUTIME 80
|
||||
#define _SC_THREAD_DESTRUCTOR_ITERATIONS 81
|
||||
#define _SC_THREAD_KEYS_MAX 82
|
||||
#define _SC_THREAD_PRIO_INHERIT 83
|
||||
#define _SC_THREAD_PRIO_PROTECT 84
|
||||
#define _SC_THREAD_PRIORITY_SCHEDULING 85
|
||||
#define _SC_THREAD_PROCESS_SHARED 86
|
||||
#define _SC_THREAD_ROBUST_PRIO_INHERIT 87
|
||||
#define _SC_THREAD_ROBUST_PRIO_PROTECT 88
|
||||
#define _SC_THREAD_SAFE_FUNCTIONS 89
|
||||
#define _SC_THREAD_SPORADIC_SERVER 90
|
||||
#define _SC_THREAD_STACK_MIN 91
|
||||
#define _SC_THREAD_THREADS_MAX 92
|
||||
#define _SC_THREADS 93
|
||||
#define _SC_TIMEOUTS 94
|
||||
#define _SC_TIMER_MAX 95
|
||||
#define _SC_TIMERS 96
|
||||
#define _SC_TRACE 97
|
||||
#define _SC_TRACE_EVENT_FILTER 98
|
||||
#define _SC_TRACE_EVENT_NAME_MAX 99
|
||||
#define _SC_TRACE_INHERIT 100
|
||||
#define _SC_TRACE_LOG 101
|
||||
#define _SC_TRACE_NAME_MAX 102
|
||||
#define _SC_TRACE_SYS_MAX 103
|
||||
#define _SC_TRACE_USER_EVENT_MAX 104
|
||||
#define _SC_TTY_NAME_MAX 105
|
||||
#define _SC_TYPED_MEMORY_OBJECTS 106
|
||||
#define _SC_TZNAME_MAX 107
|
||||
#define _SC_V7_ILP32_OFF32 108
|
||||
#define _SC_V7_ILP32_OFFBIG 109
|
||||
#define _SC_V7_LP64_OFF64 110
|
||||
#define _SC_V7_LPBIG_OFFBIG 111
|
||||
#define _SC_V6_ILP32_OFF32 112
|
||||
#define _SC_V6_ILP32_OFFBIG 113
|
||||
#define _SC_V6_LP64_OFF64 114
|
||||
#define _SC_V6_LPBIG_OFFBIG 115
|
||||
#define _SC_VERSION 116
|
||||
#define _SC_XOPEN_CRYPT 117
|
||||
#define _SC_XOPEN_ENH_I18N 118
|
||||
#define _SC_XOPEN_REALTIME 119
|
||||
#define _SC_XOPEN_REALTIME_THREADS 120
|
||||
#define _SC_XOPEN_SHM 121
|
||||
#define _SC_XOPEN_STREAMS 122
|
||||
#define _SC_XOPEN_UNIX 123
|
||||
#define _SC_XOPEN_UUCP 124
|
||||
#define _SC_XOPEN_VERSION 125
|
||||
|
||||
#define _POSIX_VDISABLE 0
|
||||
|
||||
#define STDERR_FILENO 2
|
||||
#define STDOUT_FILENO 1
|
||||
#define STDIN_FILENO 0
|
||||
|
||||
// File control
|
||||
int access(const char *pathname, int acc); //+
|
||||
int chdir(const char *pathname); //+
|
||||
int chown(const char *pathname, uid_t uid, gid_t gid); //+
|
||||
int close(int fd); //+
|
||||
int dup(int fd); //+
|
||||
int dup2(int oldfd, int newfd); //+
|
||||
int execl(const char *pathname, const char *arg, ...); //+
|
||||
int execle(const char *pathname, const char *arg, ...); //+
|
||||
int execlp(const char *file, const char *arg, ...); //-
|
||||
int execv(const char *pathname, char *const argv[]); //+
|
||||
int execve(const char *pathname, char *const argv[], char *const envp[]); //+
|
||||
int execvp(const char *file, char *const argv[]); //-
|
||||
int faccessat(int dfd, const char *pathname, int mode, int flags); //-
|
||||
int fchdir(int dfd); //-
|
||||
int fchown(int dfd, uid_t uid, gid_t gid); //-
|
||||
int fchownat(int dfd, const char *pathname, uid_t uid, gid_t gid, int flags); //-
|
||||
int fdatasync(int fd); //?
|
||||
int fexecve(int fd, char *const argv[], char *const argp[]); //-
|
||||
long fpathconf(int fd, int name); //-
|
||||
int fsync(int fd); //?
|
||||
int ftruncate(int fd, off_t size); //-
|
||||
char *getcwd(char *buf, size_t lim); //+
|
||||
int isatty(int fd); //+
|
||||
int lchown(const char *pathname, uid_t uid, gid_t gid); //-
|
||||
int link(const char *oldpath, const char *newpath); //-
|
||||
int linkat(int old_dfd, const char *oldpath, int new_dfd, const char *newpath, int flags); //-
|
||||
int lockf(int fd, int cmd, off_t len); //-
|
||||
off_t lseek(int fd, off_t off, int whence); //+
|
||||
long pathconf(const char *pathname, int name); //+
|
||||
int pipe(int fds[2]); //+
|
||||
ssize_t pread(int fd, void *buf, size_t count, off_t offset); //-
|
||||
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); //-
|
||||
ssize_t read(int fd, void *buf, size_t count); //+
|
||||
ssize_t readlink(const char *restrict pathname, char *restrict buf, size_t lim); //-
|
||||
ssize_t readlinkat(int dfd, const char *restrict pathname, char *restrict buf, size_t lim); //-
|
||||
int rmdir(const char *dirname); //+
|
||||
int symlink(const char *target, const char *linkpath); //-
|
||||
int symlinkat(const char *target, int linkdfd, const char *linkpath); //-
|
||||
void sync(void); //+
|
||||
int truncate(const char *pathname, off_t size); //-
|
||||
int unlink(const char *pathname); //+
|
||||
int unlinkat(int dfd, const char *pathname, int flags); //-
|
||||
ssize_t write(int fd, const void *buf, size_t count); //+
|
||||
|
||||
// Access control
|
||||
gid_t getegid(void); //+
|
||||
uid_t geteuid(void); //+
|
||||
gid_t getgid(void); //+
|
||||
int getgroups(int size, gid_t list[]); //?
|
||||
uid_t getuid(void); //+
|
||||
int setegid(gid_t egid); //-
|
||||
int seteuid(uid_t euid); //-
|
||||
int setgid(gid_t gid); //+
|
||||
int setregid(gid_t rgid, gid_t egid); //-
|
||||
int setreuid(uid_t ruid, uid_t euid); //-
|
||||
int setuid(uid_t uid); //+
|
||||
|
||||
// System control
|
||||
size_t confstr(int name, char *buf, size_t lim); //+
|
||||
long gethostid(void); //+
|
||||
int gethostname(char *buf, size_t lim); //+
|
||||
char *getlogin(void); //W
|
||||
int getlogin_r(char *buf, size_t lim); //-
|
||||
long sysconf(int name); //-
|
||||
|
||||
// getopt
|
||||
int getopt(int argc, char *const argv[], const char *optstr); //
|
||||
|
||||
// Process control
|
||||
_Noreturn void _exit(int status); //+
|
||||
pid_t fork(void); //+
|
||||
pid_t getpgid(pid_t pid); //+
|
||||
pid_t getpgrp(void); //+
|
||||
pid_t getpid(void); //+
|
||||
pid_t getppid(void); //-
|
||||
pid_t getsid(void); //-
|
||||
int nice(int inc); //+
|
||||
int pause(void); //+
|
||||
int setpgid(pid_t pid, pid_t pgid); //+
|
||||
pid_t setpgrp(void); //+
|
||||
pid_t setsid(void); //-
|
||||
unsigned int sleep(unsigned int sec); //+
|
||||
pid_t tcgetprgp(int fd); //+
|
||||
int tcsetpgrp(int fd, pid_t pgrp); //+
|
||||
char *ttyname(int fd); //W
|
||||
int ttyname_r(int fd, char *buf, size_t size); //?
|
||||
|
||||
// Helpers and crypt
|
||||
char *crypt(const char *key, const char *salt); //
|
||||
void encrypt(char block[64], int edflag); //
|
||||
void swab(const void *from, void *to, ssize_t n); //
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
static char *dummy[] = { (char *) 0 };
|
||||
char **environ = (char **) &dummy;
|
||||
@@ -0,0 +1,3 @@
|
||||
#include <errno.h>
|
||||
|
||||
int errno = 0;
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <_libc/abort.h>
|
||||
|
||||
_Noreturn void __libc_abort_init(const char *reason) {
|
||||
static const char prefix[] = "libc abort: ";
|
||||
char ln = '\n';
|
||||
write(STDERR_FILENO, prefix, sizeof(prefix) - 1);
|
||||
write(STDERR_FILENO, reason, strlen(reason));
|
||||
write(STDERR_FILENO, &ln, 1);
|
||||
_exit(-1);
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// TODO: move to a proper place once I do abort()
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
_Noreturn void _assert_fail(const char *func, const char *msg) {
|
||||
static const char msg0[] = "In function `";
|
||||
static const char msg1[] = "':\n";
|
||||
write(STDERR_FILENO, msg0, sizeof(msg0) - 1);
|
||||
write(STDERR_FILENO, func, strlen(func));
|
||||
write(STDERR_FILENO, msg1, sizeof(msg1) - 1);
|
||||
write(STDERR_FILENO, msg, strlen(msg));
|
||||
write(STDERR_FILENO, msg1 + 2, 1);
|
||||
|
||||
_exit(-1);
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
|
||||
void exit(int status) {
|
||||
// TODO: call atexit()s here
|
||||
_Exit(status);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#include <_libc/malloc.h>
|
||||
#include <sys/mman.h>
|
||||
#include <assert.h>
|
||||
|
||||
void free(void *ptr) {
|
||||
if (!ptr) {
|
||||
return;
|
||||
}
|
||||
struct block *block = ptr - sizeof(struct block);
|
||||
|
||||
if ((block->flags & BLOCK_MAGIC_MASK) != BLOCK_MAGIC) {
|
||||
while (1);
|
||||
}
|
||||
if (!(block->flags & BLOCK_ALLOC)) {
|
||||
while (1);
|
||||
}
|
||||
|
||||
if (block->flags & BLOCK_MMAP) {
|
||||
void *base = (void *) ((uintptr_t) block & ~0xFFF);
|
||||
size_t len = block->size + 0x1000;
|
||||
munmap(base, len);
|
||||
return;
|
||||
}
|
||||
|
||||
block->flags &= ~BLOCK_ALLOC;
|
||||
struct block *prev, *next;
|
||||
prev = block->prev;
|
||||
next = block->next;
|
||||
|
||||
if (prev && !(prev->flags & BLOCK_ALLOC)) {
|
||||
block->flags = 0;
|
||||
prev->next = next;
|
||||
if (next) {
|
||||
next->prev = prev;
|
||||
}
|
||||
prev->size += block->size + sizeof(struct block);
|
||||
|
||||
block = prev;
|
||||
}
|
||||
|
||||
if (next && !(next->flags & BLOCK_ALLOC)) {
|
||||
next->flags = 0;
|
||||
|
||||
if (next->next) {
|
||||
next->next->prev = block;
|
||||
}
|
||||
block->next = next->next;
|
||||
block->size += next->size + sizeof(struct block);
|
||||
}
|
||||
|
||||
if (!block->prev && !block->next) {
|
||||
struct zone *zone = (void *) block - sizeof(struct zone);
|
||||
assert(!((uintptr_t) zone & 0xFFF));
|
||||
list_del(&zone->list);
|
||||
zone_destroy(zone);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
#include <_libc/malloc.h>
|
||||
#include <_libc/list.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
// Small zone allocation function
|
||||
// XXX: This is absolute bullshit: meet my first fit allocator
|
||||
static void *zone_alloc(struct zone *zone, size_t count) {
|
||||
struct block *begin = (struct block *) &zone[1];
|
||||
|
||||
count = (count + 15) & ~15;
|
||||
|
||||
for (struct block *block = begin; block; block = block->next) {
|
||||
if (block->flags & BLOCK_ALLOC) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count == block->size) {
|
||||
block->flags |= BLOCK_ALLOC;
|
||||
void *ptr = &block[1];
|
||||
memset(ptr, 0, count);
|
||||
return ptr;
|
||||
} else if (block->size >= count + sizeof(struct block)) {
|
||||
// Insert new block after this one
|
||||
struct block *cur_next = block->next;
|
||||
struct block *new_block = (struct block *) (((uintptr_t) block) + sizeof(struct block) + count);
|
||||
if (cur_next) {
|
||||
cur_next->prev = new_block;
|
||||
}
|
||||
new_block->next = cur_next;
|
||||
new_block->prev = block;
|
||||
new_block->size = block->size - sizeof(struct block) - count;
|
||||
new_block->flags = BLOCK_MAGIC;
|
||||
block->next = new_block;
|
||||
block->size = count;
|
||||
block->flags |= 1;
|
||||
void *ptr = &block[1];
|
||||
memset(ptr, 0, count);
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
///
|
||||
|
||||
static void *alloc_from(struct list_head *head, size_t zone_size, size_t size) {
|
||||
struct zone *zone;
|
||||
void *ptr;
|
||||
|
||||
try_again:
|
||||
list_for_each_entry(zone, head, list) {
|
||||
if ((ptr = zone_alloc(zone, size))) {
|
||||
return ptr;
|
||||
}
|
||||
}
|
||||
|
||||
zone = zone_create(zone_size);
|
||||
if (!zone) {
|
||||
return NULL;
|
||||
}
|
||||
list_add(&zone->list, head);
|
||||
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
void *malloc(size_t size) {
|
||||
if (size <= SMALL_ZONE_ELEM) {
|
||||
return alloc_from(&small_zone_list, SMALL_ZONE_SIZE, size);
|
||||
} else if (size <= MID_ZONE_ELEM) {
|
||||
return alloc_from(&mid_zone_list, MID_ZONE_SIZE, size);
|
||||
} else if (size <= LARGE_ZONE_ELEM) {
|
||||
return alloc_from(&large_zone_list, LARGE_ZONE_SIZE, size);
|
||||
} else {
|
||||
size_t pages_needed = (size + 0xFFF) & ~0xFFF;
|
||||
void *pages = mmap(NULL, pages_needed + 0x1000, 0, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (pages == MAP_FAILED) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct block *block = pages + 0x1000 - sizeof(struct block);
|
||||
block->flags = BLOCK_MAGIC | BLOCK_ALLOC | BLOCK_MMAP;
|
||||
block->size = pages_needed;
|
||||
|
||||
return pages + 0x1000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#include <_libc/malloc.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
void *realloc(void *old, size_t size) {
|
||||
// TODO: maybe optimize this
|
||||
void *ptr = malloc(size);
|
||||
if (!ptr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (old) {
|
||||
struct block *old_block = old - sizeof(struct block);
|
||||
size_t less_size = size;
|
||||
if (less_size > old_block->size) {
|
||||
less_size = old_block->size;
|
||||
}
|
||||
assert((old_block->flags & BLOCK_MAGIC_MASK) == BLOCK_MAGIC);
|
||||
memcpy(ptr, old, less_size);
|
||||
free(old);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#include <_libc/malloc.h>
|
||||
#include <sys/mman.h>
|
||||
#include <assert.h>
|
||||
|
||||
LIST_HEAD(small_zone_list);
|
||||
LIST_HEAD(mid_zone_list);
|
||||
LIST_HEAD(large_zone_list);
|
||||
|
||||
struct zone *zone_create(size_t size) {
|
||||
void *pages = mmap(NULL, size, 0, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (pages == MAP_FAILED) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct zone *zone = pages;
|
||||
struct block *head = pages + sizeof(struct zone);
|
||||
|
||||
zone->size = size - sizeof(struct zone);
|
||||
list_head_init(&zone->list);
|
||||
|
||||
head->size = size - sizeof(struct zone) - sizeof(struct block);
|
||||
head->flags = BLOCK_MAGIC;
|
||||
head->prev = NULL;
|
||||
head->next = NULL;
|
||||
|
||||
return zone;
|
||||
}
|
||||
|
||||
void zone_destroy(struct zone *zone) {
|
||||
assert(!((uintptr_t) zone & 0xFFF));
|
||||
munmap(zone, zone->size + sizeof(struct zone));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <stdlib.h>
|
||||
#include <_libc/signal.h>
|
||||
|
||||
void _sig_dfl(int signum) {
|
||||
exit(signum << 8);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Yggdrasil's signal implementation details
|
||||
*/
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <_libc/abort.h>
|
||||
#include <_libc/signal.h>
|
||||
#include <_libc/syscalls.h>
|
||||
|
||||
static sighandler_t signal_handlers[NSIG];
|
||||
|
||||
// _Noreturn because this function *must* end up
|
||||
// calling sigreturn syscall
|
||||
static _Noreturn void __libc_signal_handle(int signum) {
|
||||
if (signum <= 0 || signum >= NSIG) {
|
||||
// TODO: abort()
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (signal_handlers[signum]) {
|
||||
signal_handlers[signum](signum);
|
||||
} else {
|
||||
_sig_dfl(signum);
|
||||
}
|
||||
|
||||
__syscall0(SYSCALL_NR_SIGRETURN);
|
||||
// To enforce _Noreturn
|
||||
while (1);
|
||||
}
|
||||
|
||||
void __libc_signal_init(void) {
|
||||
stack_t ss;
|
||||
void *sig_stack;
|
||||
|
||||
sig_stack = malloc(__LIBC_SIGNAL_STACK_SIZE);
|
||||
if (sig_stack == NULL) {
|
||||
__libc_abort_init("Failed to allocate signal stack");
|
||||
}
|
||||
|
||||
// Tell kernel about signal stack
|
||||
ss.ss_sp = sig_stack;
|
||||
ss.ss_size = __LIBC_SIGNAL_STACK_SIZE;
|
||||
if (sigaltstack(&ss, NULL) != 0) {
|
||||
__libc_abort_init("Failed to set signal stack");
|
||||
}
|
||||
|
||||
// Tell kernel about signal entry
|
||||
__syscall1(SYSCALL_NRX_SIGENTRY, (long) __libc_signal_handle);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <_libc/syscalls.h>
|
||||
|
||||
int sigaltstack(const stack_t *ss, stack_t *old_ss) {
|
||||
return SET_ERRNO(int, __syscall2(SYSCALL_NR_SIGALTSTACK, (long) ss, (long) old_ss));
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <_libc/stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int fgetc_unlocked(FILE *fp) {
|
||||
if (fp->buf_mode == _IONBF) {
|
||||
unsigned char c;
|
||||
if (fread_unlocked(&c, sizeof(c), 1, fp) == 1) {
|
||||
return c;
|
||||
}
|
||||
return EOF;
|
||||
}
|
||||
|
||||
if (fp->flags & FILE_FLAG_EOF) {
|
||||
return 0;
|
||||
}
|
||||
if (!(fp->flags & FILE_MODE_READ)) {
|
||||
errno = EBADF;
|
||||
fp->flags |= FILE_FLAG_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__libc_file_flush_write(fp);
|
||||
|
||||
if (fp->rdbufpos >= fp->rdbuf) {
|
||||
// Reached end of readbuf
|
||||
// TODO: arbitrary buffer size setting?
|
||||
ssize_t bread = fp->read(fp->ctx, fp->buf, BUFSIZ);
|
||||
|
||||
if (bread < 0) {
|
||||
fp->flags |= FILE_FLAG_ERROR;
|
||||
return EOF;
|
||||
}
|
||||
if (bread == 0) {
|
||||
fp->flags |= FILE_FLAG_EOF;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
fp->rdbufpos = 0;
|
||||
fp->rdbuf = bread;
|
||||
}
|
||||
|
||||
return ((char *) fp->buf)[fp->rdbufpos++];
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
#include <_libc/stdio.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static void file_default_free(void *ctx, FILE *fp) {
|
||||
(void) ctx;
|
||||
free(fp);
|
||||
}
|
||||
|
||||
FILE *__libc_file_create(void) {
|
||||
FILE *res = malloc(sizeof(FILE) + BUFSIZ);
|
||||
if (!res) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
memset(res, 0, sizeof(FILE));
|
||||
|
||||
res->free = file_default_free;
|
||||
res->buf = ((void *) res) + sizeof(FILE);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int __libc_file_mode(const char *mode) {
|
||||
int flags = 0;
|
||||
switch (*mode++) {
|
||||
case 'r':
|
||||
flags |= FILE_MODE_READ;
|
||||
break;
|
||||
case 'w':
|
||||
flags |= FILE_MODE_WRITE | FILE_MODE_CREAT | FILE_MODE_TRUNC;
|
||||
break;
|
||||
case 'a':
|
||||
flags |= FILE_MODE_WRITE | FILE_MODE_CREAT | FILE_MODE_APPEND;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
int __libc_file_flush_read(FILE *fp) {
|
||||
if ((fp->flags & FILE_MODE_READ) && fp->seek) {
|
||||
// TODO: off_t
|
||||
long count = fp->rdbuf - fp->rdbufpos;
|
||||
if (count < 0) {
|
||||
count = fp->seek(fp->ctx, count, SEEK_CUR);
|
||||
// Reset file read buffer
|
||||
fp->rdbuf = 0;
|
||||
fp->rdbufpos = 0;
|
||||
if (count < 0) {
|
||||
fp->flags |= FILE_FLAG_ERROR;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __libc_file_flush_write(FILE *fp) {
|
||||
if (fp->flags & FILE_MODE_WRITE) {
|
||||
size_t rem = fp->wrbuf;
|
||||
size_t off = 0;
|
||||
|
||||
fp->wrbuf = 0;
|
||||
|
||||
while (rem) {
|
||||
ssize_t bwrite = fp->write(fp->ctx, fp->buf + off, rem);
|
||||
|
||||
if (bwrite < 0) {
|
||||
fp->flags |= FILE_FLAG_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (bwrite == 0) {
|
||||
fp->flags |= FILE_FLAG_EOF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
rem -= bwrite;
|
||||
off += bwrite;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
#include <_libc/stdio.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static ssize_t file_read(void *ctx, void *buf, size_t lim);
|
||||
static ssize_t file_write(void *ctx, const void *buf, size_t lim);
|
||||
static int file_close(void *ctx);
|
||||
|
||||
char _stdin_buf[BUFSIZ];
|
||||
char _stdout_buf[BUFSIZ];
|
||||
char _stderr_buf[BUFSIZ];
|
||||
|
||||
FILE _stdin = {
|
||||
.buf = _stdin_buf,
|
||||
.buf_mode = _IOLBF,
|
||||
.ctx = &_stdin,
|
||||
.fd = STDIN_FILENO,
|
||||
.free = NULL,
|
||||
.read = file_read,
|
||||
.write = file_write,
|
||||
.close = file_close,
|
||||
.flags = FILE_MODE_READ
|
||||
};
|
||||
FILE _stdout = {
|
||||
.buf = _stdout_buf,
|
||||
.buf_mode = _IOLBF,
|
||||
.ctx = &_stdout,
|
||||
.fd = STDOUT_FILENO,
|
||||
.free = NULL,
|
||||
.read = file_read,
|
||||
.write = file_write,
|
||||
.close = file_close,
|
||||
.flags = FILE_MODE_WRITE
|
||||
};
|
||||
FILE _stderr = {
|
||||
.buf = _stderr_buf,
|
||||
.buf_mode = _IONBF,
|
||||
.ctx = &_stdout,
|
||||
.fd = STDERR_FILENO,
|
||||
.free = NULL,
|
||||
.read = file_read,
|
||||
.write = file_write,
|
||||
.close = file_close,
|
||||
.flags = FILE_MODE_WRITE
|
||||
};
|
||||
|
||||
FILE *const stdin = &_stdin;
|
||||
FILE *const stdout = &_stdout;
|
||||
FILE *const stderr = &_stderr;
|
||||
|
||||
static ssize_t file_read(void *ctx, void *buf, size_t lim) {
|
||||
return read(((FILE *) ctx)->fd, buf, lim);
|
||||
}
|
||||
|
||||
static ssize_t file_write(void *ctx, const void *buf, size_t lim) {
|
||||
return write(((FILE *) ctx)->fd, buf, lim);
|
||||
}
|
||||
|
||||
static int file_close(void *ctx) {
|
||||
return close(((FILE *) ctx)->fd);
|
||||
}
|
||||
|
||||
static long file_seek(void *ctx, long off, int whence) {
|
||||
return lseek(((FILE *) ctx)->fd, off, whence);
|
||||
}
|
||||
|
||||
int __libc_file_open_fd(FILE *fp, int fd, int flags) {
|
||||
// TODO: disallow certain combinations of params
|
||||
if (flags & FILE_MODE_READ) {
|
||||
fp->flags |= FILE_MODE_READ;
|
||||
}
|
||||
if (flags & FILE_MODE_WRITE) {
|
||||
fp->flags |= FILE_MODE_WRITE;
|
||||
}
|
||||
|
||||
fp->fd = fd;
|
||||
fp->ctx = fp;
|
||||
|
||||
fp->read = file_read;
|
||||
fp->write = file_write;
|
||||
fp->close = file_close;
|
||||
fp->seek = file_seek;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __libc_file_open_path(FILE *fp, const char *pathname, const char *mode) {
|
||||
int flags, c_flags = 0;
|
||||
if ((flags = __libc_file_mode(mode)) == -1) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!(flags & (FILE_MODE_WRITE | FILE_MODE_READ))) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flags & FILE_MODE_WRITE) {
|
||||
if (flags & FILE_MODE_READ) {
|
||||
c_flags |= O_RDWR;
|
||||
} else {
|
||||
c_flags |= O_WRONLY;
|
||||
}
|
||||
} else {
|
||||
c_flags |= O_RDONLY;
|
||||
}
|
||||
if (flags & FILE_MODE_CREAT) {
|
||||
c_flags |= O_CREAT;
|
||||
}
|
||||
if (flags & FILE_MODE_TRUNC) {
|
||||
c_flags |= O_TRUNC;
|
||||
}
|
||||
|
||||
int fd = open(pathname, c_flags, 0666);
|
||||
if (fd < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (__libc_file_open_fd(fp, fd, flags) != 0) {
|
||||
int e = errno;
|
||||
close(fd);
|
||||
errno = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void flockfile(FILE *fp) {
|
||||
// TODO: pthread mutices
|
||||
(void) fp;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#include <_libc/stdio.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
FILE *fopen(const char *pathname, const char *mode) {
|
||||
FILE *fp = __libc_file_create();
|
||||
if (!fp) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (__libc_file_open_path(fp, pathname, mode) != 0) {
|
||||
int e = errno;
|
||||
fclose(fp);
|
||||
errno = e;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fp;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#include <_libc/stdio.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
int fputc_unlocked(int ch, FILE *fp) {
|
||||
if (fp->buf_mode == _IONBF) {
|
||||
unsigned char c = ch;
|
||||
if (fwrite_unlocked(&c, sizeof(c), 1, fp) == 1) {
|
||||
return c;
|
||||
}
|
||||
return EOF;
|
||||
}
|
||||
if (!(fp->flags & FILE_MODE_WRITE)) {
|
||||
errno = EBADF;
|
||||
fp->flags |= FILE_FLAG_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__libc_file_flush_read(fp);
|
||||
|
||||
((char *) fp->buf)[fp->wrbuf++] = ch;
|
||||
|
||||
if ((fp->buf_mode == _IOLBF && ch == '\n') || fp->wrbuf >= BUFSIZ) {
|
||||
if (__libc_file_flush_write(fp) != 0) {
|
||||
return EOF;
|
||||
}
|
||||
}
|
||||
|
||||
return ch;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
size_t fread(void *buf, size_t size, size_t nmemb, FILE *fp) {
|
||||
flockfile(fp);
|
||||
size_t r = fread_unlocked(buf, size, nmemb, fp);
|
||||
funlockfile(fp);
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#include <_libc/stdio.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
size_t fread_unlocked(void *buf, size_t size, size_t nmemb, FILE *fp) {
|
||||
// TODO: buffering
|
||||
if (!(fp->flags & FILE_MODE_READ)) {
|
||||
errno = EBADF;
|
||||
fp->flags |= FILE_FLAG_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t rem = size * nmemb;
|
||||
size_t off = 0;
|
||||
fp->flags &= ~FILE_FLAG_EOF;
|
||||
while (rem) {
|
||||
ssize_t bread = fp->read(fp->ctx, buf + off, rem);
|
||||
if (bread < 0) {
|
||||
fp->flags |= FILE_FLAG_ERROR;
|
||||
return off / size;
|
||||
}
|
||||
if (bread == 0) {
|
||||
fp->flags |= FILE_FLAG_EOF;
|
||||
return off / size;
|
||||
}
|
||||
off += bread;
|
||||
rem -= bread;
|
||||
}
|
||||
|
||||
return off / size;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <stdio.h>
|
||||
|
||||
void funlockfile(FILE *fp) {
|
||||
// TODO: pthread mutices
|
||||
(void) fp;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <stdio.h>
|
||||
|
||||
size_t fwrite(const void *data, size_t size, size_t nmemb, FILE *fp) {
|
||||
flockfile(fp);
|
||||
size_t r = fwrite_unlocked(data, size, nmemb, fp);
|
||||
funlockfile(fp);
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#include <_libc/stdio.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
|
||||
size_t fwrite_unlocked(const void *ptr, size_t size, size_t nmemb, FILE *fp) {
|
||||
assert(fp);
|
||||
if (fp->flags & FILE_FLAG_EOF) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!(fp->flags & FILE_MODE_WRITE)) {
|
||||
errno = EBADF;
|
||||
fp->flags |= FILE_FLAG_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fp->buf_mode == _IONBF) {
|
||||
size_t rem = size * nmemb;
|
||||
size_t off = 0;
|
||||
|
||||
fp->flags &= ~FILE_FLAG_EOF;
|
||||
while (rem) {
|
||||
ssize_t res = fp->write(fp->ctx, ptr + off, rem);
|
||||
if (res < 0) {
|
||||
// Signalled error
|
||||
fp->flags |= FILE_FLAG_ERROR;
|
||||
return off / size;
|
||||
}
|
||||
if (res == 0) {
|
||||
// Signalled EOF
|
||||
fp->flags |= FILE_FLAG_EOF;
|
||||
return off /size;
|
||||
}
|
||||
off += res;
|
||||
rem -= res;
|
||||
}
|
||||
|
||||
return off / size;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < size * nmemb; i += size) {
|
||||
for (size_t b = 0; b < size; ++b) {
|
||||
int r = fputc_unlocked(((char *) ptr)[i + b], fp);
|
||||
|
||||
if (r < 0) {
|
||||
return i / size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nmemb;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <string.h>
|
||||
|
||||
void *memccpy(void *dst, const void *src, int c, size_t len) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
((unsigned char *) dst)[i] = ((unsigned char *) src)[i];
|
||||
if (((unsigned char *) dst)[i] == c) {
|
||||
return dst + i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <string.h>
|
||||
|
||||
void *memchr(const void *ptr, int v, size_t len) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if (((unsigned char *) ptr)[i] == v) {
|
||||
return (void *) ptr + i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <string.h>
|
||||
|
||||
int memcmp(const void *p0, const void *p1, size_t n) {
|
||||
int diff;
|
||||
for (size_t i = 0; i < n; ++i) {
|
||||
diff = ((unsigned char *) p0)[i] - ((unsigned char *) p1)[i];
|
||||
if (diff) {
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <string.h>
|
||||
|
||||
void *memcpy(void *dst, const void *src, size_t sz) {
|
||||
for (size_t i = 0; i < sz; ++i) {
|
||||
((unsigned char *) dst)[i] = ((unsigned char *) src)[i];
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include <string.h>
|
||||
|
||||
void *memmove(void *dest, const void *src, size_t n) {
|
||||
if (dest == src) {
|
||||
return dest;
|
||||
}
|
||||
|
||||
if ((src + n) <= dest || (dest + n) <= src) {
|
||||
return memcpy(dest, src, n);
|
||||
}
|
||||
|
||||
if (dest < src) {
|
||||
ptrdiff_t a = src - dest;
|
||||
memcpy( dest, src, a);
|
||||
memcpy((void *) src, src + a, n - a);
|
||||
} else {
|
||||
ptrdiff_t a = dest - src;
|
||||
memcpy( dest + a, dest, n - a);
|
||||
memcpy( dest, src, a);
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <string.h>
|
||||
|
||||
void *memset(void *ptr, int v, size_t len) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
((unsigned char *) ptr)[i] = v;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include <string.h>
|
||||
|
||||
char *stpcpy(char *dest, const char *src) {
|
||||
do {
|
||||
*dest = *src;
|
||||
if (!*src++) {
|
||||
return dest;
|
||||
}
|
||||
++dest;
|
||||
} while (1);
|
||||
}
|
||||
|
||||
char *stpncpy(char *dest, const char *src, size_t n) {
|
||||
if (!n) {
|
||||
return dest;
|
||||
}
|
||||
do {
|
||||
*dest = *src;
|
||||
if (!*src++) {
|
||||
return dest;
|
||||
}
|
||||
++dest;
|
||||
if (!--n) {
|
||||
return dest;
|
||||
}
|
||||
} while (1);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#include <string.h>
|
||||
|
||||
char *strcat(char *dst, const char *src) {
|
||||
size_t len = strlen(dst);
|
||||
for (size_t i = 0;; ++i) {
|
||||
dst[len + i] = src[i];
|
||||
if (!src[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strncat(char *dst, const char *src, size_t n) {
|
||||
size_t d = strlen(dst);
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < n && src[i]; ++i) {
|
||||
dst[d + i] = src[i];
|
||||
}
|
||||
dst[d + i] = 0;
|
||||
|
||||
return dst;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#include <string.h>
|
||||
|
||||
char *strchr(const char *str, int chr) {
|
||||
for (; *str; ++str) {
|
||||
if (*str == chr) {
|
||||
return (char *) str;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *strrchr(const char *str, int chr) {
|
||||
size_t len = strlen(str);
|
||||
if (!len) {
|
||||
return NULL;
|
||||
}
|
||||
while (--len) {
|
||||
if (str[len] == chr) {
|
||||
return (char *) &str[len];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include <string.h>
|
||||
|
||||
int strcmp(const char *a, const char *b) {
|
||||
for (;; ++a, ++b) {
|
||||
int delta = *a - *b;
|
||||
if (delta) {
|
||||
return delta;
|
||||
}
|
||||
if (!*a) { // Implies !*b
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int strncmp(const char *a, const char *b, size_t lim) {
|
||||
for (; lim; ++a, ++b, --lim) {
|
||||
int delta = *a - *b;
|
||||
if (delta) {
|
||||
return delta;
|
||||
}
|
||||
if (!*a) { // Implies !*b
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <string.h>
|
||||
|
||||
// XXX: Not actually implemented - current locale is C
|
||||
int strcoll(const char *a, const char *b) {
|
||||
return strcmp(a, b);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#include <string.h>
|
||||
|
||||
char *strcpy(char *dst, const char *src) {
|
||||
size_t i;
|
||||
for (i = 0;; ++i) {
|
||||
dst[i] = src[i];
|
||||
if (!src[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
|
||||
char *strncpy(char *dst, const char *src, size_t n) {
|
||||
size_t i;
|
||||
for (i = 0; i < n; ++i) {
|
||||
dst[i] = src[i];
|
||||
if (!src[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
char *strdup(const char *str) {
|
||||
char *ptr = malloc(strlen(str) + 1);
|
||||
if (ptr) {
|
||||
strcpy(ptr, str);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
char *strndup(const char *str, size_t len) {
|
||||
char *ptr;
|
||||
size_t l = strnlen(str, len);
|
||||
ptr = malloc(l + 1);
|
||||
if (ptr) {
|
||||
strncpy(ptr, str, l);
|
||||
ptr[l] = 0;
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include <string.h>
|
||||
|
||||
// "Lower" group of errors
|
||||
static const char *error0[64] = {};
|
||||
|
||||
char *strerror(int errnum) {
|
||||
if (!errnum) {
|
||||
return "success";
|
||||
}
|
||||
if (errnum < 0 || errnum >= 64 || !error0[errnum]) {
|
||||
return "unknown error";
|
||||
}
|
||||
return (char *) error0[errnum];
|
||||
}
|
||||
|
||||
int strerror_r(int errnum, char *buf, size_t len) {
|
||||
const char *err = strerror(errnum);
|
||||
if (!len) {
|
||||
return -1;
|
||||
}
|
||||
strncpy(buf, err, len - 1);
|
||||
buf[len - 1] = 0;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#include <string.h>
|
||||
|
||||
size_t strlen(const char *s) {
|
||||
size_t r;
|
||||
for (r = 0; s[r]; ++r);
|
||||
return r;
|
||||
}
|
||||
|
||||
size_t strnlen(const char *s, size_t len) {
|
||||
size_t r;
|
||||
for (r = 0; r < len && s[r]; ++r);
|
||||
return r;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <string.h>
|
||||
|
||||
char *strpbrk(const char *str, const char *accept) {
|
||||
for (; *str; ++str) {
|
||||
if (strchr(accept, *str)) {
|
||||
return (char *) str;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <ygg/signum.h>
|
||||
#include <string.h>
|
||||
|
||||
static const char *signal0[NSIG] = {
|
||||
};
|
||||
|
||||
char *strsignal(int signum) {
|
||||
if (signum <= 0 || signum >= NSIG) {
|
||||
return "unknown signal";
|
||||
}
|
||||
return (char *) signal0[signum];
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#include <string.h>
|
||||
|
||||
size_t strspn(const char *s, const char *accept) {
|
||||
size_t l = 0;
|
||||
|
||||
while (*s) {
|
||||
if (!strchr(accept, *s)) {
|
||||
return l;
|
||||
}
|
||||
++l;
|
||||
++s;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
size_t strcspn(const char *s, const char *reject) {
|
||||
size_t l = 0;
|
||||
|
||||
while (*s) {
|
||||
if (strchr(reject, *s)) {
|
||||
return l;
|
||||
}
|
||||
++l;
|
||||
++s;
|
||||
}
|
||||
return l;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#include <string.h>
|
||||
|
||||
char *_strstr(const char *haystack, const char *needle) {
|
||||
// TODO: maybe use KMP algorithm for small needle sizes
|
||||
size_t n = strlen(needle);
|
||||
if (!*needle && !*haystack) {
|
||||
return (char *) haystack;
|
||||
}
|
||||
|
||||
for (size_t i = 0; haystack[i]; ++i) {
|
||||
if (!strncmp(haystack + i, needle, n)) {
|
||||
return (char *) haystack + i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
#include <string.h>
|
||||
|
||||
char *strtok_r(char *str, const char *delim, char **saveptr) {
|
||||
char *token;
|
||||
|
||||
if (!str) {
|
||||
str = *saveptr;
|
||||
}
|
||||
|
||||
// Skip leading delimiter
|
||||
str += strspn(str, delim);
|
||||
if (!*str) {
|
||||
*saveptr = str;
|
||||
// No next token - NULL
|
||||
return NULL;
|
||||
}
|
||||
|
||||
token = str;
|
||||
str = strpbrk(str, delim);
|
||||
if (str) {
|
||||
// Have a delimiter
|
||||
*str = 0;
|
||||
*saveptr = str + 1;
|
||||
} else {
|
||||
// Point to end
|
||||
*saveptr = token + strlen(token);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
// TODO: throw an error "programmer" for using this
|
||||
char *strtok(char *str, const char *delim) {
|
||||
static char *saveptr;
|
||||
if (str) {
|
||||
saveptr = NULL;
|
||||
}
|
||||
return strtok_r(str, delim, &saveptr);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int open(const char *pathname, int flags, mode_t mode) {
|
||||
return SET_ERRNO(int, __syscall3(SYSCALL_NR_OPEN, (long) pathname, flags, mode));
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <sys/mman.h>
|
||||
#include <errno.h>
|
||||
|
||||
void *mmap(void *hint, size_t length, int prot, int flags, int fd, off_t offset) {
|
||||
intptr_t res = (intptr_t) __syscall6(SYSCALL_NR_MMAP,
|
||||
(long) hint,
|
||||
length,
|
||||
(long) prot,
|
||||
(long) flags,
|
||||
(long) fd,
|
||||
offset);
|
||||
if (res < 0) {
|
||||
errno = (int) -res;
|
||||
return (void *) -1;
|
||||
} else {
|
||||
return (void *) res;
|
||||
}
|
||||
}
|
||||
|
||||
int munmap(void *ptr, size_t len) {
|
||||
return SET_ERRNO(int, __syscall2(SYSCALL_NR_MUNMAP, (long) ptr, len));
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
_Noreturn void _exit(int status) {
|
||||
__syscall1(SYSCALL_NR_EXIT, status);
|
||||
while (1);
|
||||
}
|
||||
|
||||
_Noreturn void _Exit(int status) __attribute__((alias("_exit")));
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <unistd.h>
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <errno.h>
|
||||
|
||||
int access(const char *pathname, int mode) {
|
||||
return SET_ERRNO(int, __syscall2(SYSCALL_NR_ACCESS, (long) pathname, mode));
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int chdir(const char *pathname) {
|
||||
return SET_ERRNO(int, __syscall1(SYSCALL_NR_CHDIR, (long) pathname));
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int chown(const char *pathname, uid_t uid, gid_t gid) {
|
||||
return SET_ERRNO(int, __syscall3(SYSCALL_NR_CHOWN, (long) pathname, uid, gid));
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int close(int fd) {
|
||||
__syscall1(SYSCALL_NR_CLOSE, fd);
|
||||
errno = 0;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
size_t confstr(int name, char *buf, size_t len) {
|
||||
(void) name;
|
||||
(void) buf;
|
||||
(void) len;
|
||||
// TODO: _CS_PATH
|
||||
errno = EINVAL;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int dup(int oldfd) {
|
||||
return SET_ERRNO(int, __syscall1(SYSCALL_NR_DUP, oldfd));
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int dup2(int oldfd, int newfd) {
|
||||
return SET_ERRNO(int, __syscall2(SYSCALL_NR_DUP2, oldfd, newfd));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
int execl(const char *pathname, const char *arg, ...) {
|
||||
va_list args;
|
||||
size_t argc;
|
||||
int res;
|
||||
|
||||
if (!arg) {
|
||||
// execv pathname without arguments
|
||||
return execv(pathname, (char *const *) &arg);
|
||||
}
|
||||
|
||||
// 1. collect arg count
|
||||
va_start(args, arg);
|
||||
while (va_arg(args, const char *)) {
|
||||
++argc;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
// 2. allocate space for args
|
||||
char **argv = malloc(sizeof(char *) * (argc + 1));
|
||||
if (!argv) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 3. copy args
|
||||
va_start(args, arg);
|
||||
for (size_t i = 0; i < argc; ++i) {
|
||||
argv[i] = va_arg(args, char *);
|
||||
}
|
||||
va_end(args);
|
||||
argv[argc] = NULL;
|
||||
|
||||
res = execv(pathname, argv);
|
||||
|
||||
// Won't return normally, so free()
|
||||
free(argv);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
int execle(const char *pathname, const char *arg, ...) {
|
||||
va_list args;
|
||||
char *const *envp;
|
||||
size_t argc;
|
||||
int res;
|
||||
|
||||
if (!arg) {
|
||||
va_start(args, arg);
|
||||
char *const *envp = va_arg(args, char *const *);
|
||||
va_end(args);
|
||||
|
||||
return execve(pathname, (char *const *) &arg, envp);
|
||||
}
|
||||
|
||||
// 1. collect arg count
|
||||
va_start(args, arg);
|
||||
while (va_arg(args, const char *)) {
|
||||
++argc;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
// 2. allocate space for args
|
||||
char **argv = malloc(sizeof(char *) * (argc + 1));
|
||||
if (!argv) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// 3. copy args
|
||||
va_start(args, arg);
|
||||
for (size_t i = 0; i < argc; ++i) {
|
||||
argv[i] = va_arg(args, char *);
|
||||
}
|
||||
envp = va_arg(args, char *const *);
|
||||
va_end(args);
|
||||
argv[argc] = NULL;
|
||||
|
||||
res = execve(pathname, argv, envp);
|
||||
|
||||
// Won't return normally, so free()
|
||||
free(argv);
|
||||
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int execlp(const char *file, const char *arg, ...) {
|
||||
(void) file;
|
||||
(void) arg;
|
||||
// TODO: PATH search impl.
|
||||
assert(0 && "function not implemented");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <unistd.h>
|
||||
|
||||
int execv(const char *pathname, char *const argv[]) {
|
||||
return execve(pathname, argv, environ);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int execve(const char *pathname, char *const argv[], char *const envp[]) {
|
||||
return SET_ERRNO(int, __syscall3(SYSCALL_NR_EXECVE, (long) pathname, (long) argv, (long) envp));
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int execvp(const char *file, char *const argv[]) {
|
||||
(void) file;
|
||||
(void) argv;
|
||||
// TODO: PATH search impl.
|
||||
assert(0 && "function not implemented");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int faccessat(int dfd, const char *pathname, int mode, int flags) {
|
||||
(void) dfd;
|
||||
(void) pathname;
|
||||
(void) mode;
|
||||
(void) flags;
|
||||
assert(0 && "system call not yet implemented");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int fchdir(int dfd) {
|
||||
(void) dfd;
|
||||
assert(0 && "system call not yet implemented");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int fchown(int fd, uid_t uid, gid_t gid) {
|
||||
(void) fd;
|
||||
(void) uid;
|
||||
(void) gid;
|
||||
assert(0 && "system call not yet implemented");
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int fchownat(int dfd, const char *pathname, uid_t uid, gid_t gid, int flags) {
|
||||
(void) dfd;
|
||||
(void) pathname;
|
||||
(void) uid;
|
||||
(void) gid;
|
||||
(void) flags;
|
||||
assert(0 && "system call not yet implemented");
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int fdatasync(int fd) {
|
||||
(void) fd;
|
||||
// FS is synchronous lol
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int fexecve(int fd, char *const argv[], char *const envp[]) {
|
||||
(void) fd;
|
||||
(void) argv;
|
||||
(void) envp;
|
||||
assert(0 && "system call not yet implemented");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
pid_t fork(void) {
|
||||
return SET_ERRNO(pid_t, __syscall0(SYSCALL_NR_FORK));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
long fpathconf(int fd, int name) {
|
||||
(void) fd;
|
||||
(void) name;
|
||||
assert(0 && "system call not yet implemented");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int fsync(int fd) {
|
||||
(void) fd;
|
||||
// FS is synchronous lol
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <ygg/syscall.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int ftruncate(int fd, off_t size) {
|
||||
(void) fd;
|
||||
(void) size;
|
||||
assert(0 && "system call not yet implemented");
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
char *getcwd(char *buf, size_t size) {
|
||||
if (SET_ERRNO(int, __syscall2(SYSCALL_NR_GETCWD, (long) buf, size)) == 0) {
|
||||
return buf;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <unistd.h>
|
||||
|
||||
gid_t getegid(void) {
|
||||
// TODO: differentiate between gid and egid
|
||||
return getgid();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
#include <unistd.h>
|
||||
|
||||
uid_t geteuid(void) {
|
||||
// TODO: differentiate between uid and euid
|
||||
return getuid();
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
gid_t getgid(void) {
|
||||
return __syscall0(SYSCALL_NR_GETGID);
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <unistd.h>
|
||||
|
||||
int getgroups(int size, gid_t list[]) {
|
||||
(void) size;
|
||||
(void) list;
|
||||
// TODO: supplementary groups
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#include <unistd.h>
|
||||
|
||||
long gethostid(void) {
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
// TODO: sys/utsname.h
|
||||
#include <ygg/utsname.h>
|
||||
extern int uname(struct utsname *buf);
|
||||
|
||||
int gethostname(char *name, size_t len) {
|
||||
// Use uname to retrieve hostname
|
||||
struct utsname v;
|
||||
if (!len || uname(&v) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
strncpy(name, v.nodename, len - 1);
|
||||
name[len] = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
int getlogin_r(char *buf, size_t bufsize) {
|
||||
(void) buf;
|
||||
(void) bufsize;
|
||||
// TODO: read pwd for username
|
||||
errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <_libc/syscalls.h>
|
||||
#include <ygg/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
|
||||
pid_t getpgid(pid_t pid) {
|
||||
return SET_ERRNO(pid_t, __syscall1(SYSCALL_NR_GETPGID, pid));
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user