libc

my libc
git clone git://git.evenfri.pw/libc.git
Log | Files | Refs | README

commit 9edcb271159648c4dc1ab9d9991a7a9cf0c59494
parent 801dbeeec59548cdb0c940cd91a43672846570a3
Author: evenfri <evenfri256@gmail.com>
Date:   Mon,  5 Oct 2026 23:47:16 +0800

add l,fstat, fseek, update files

Diffstat:
M_exit.c | 2+-
Mcalloc.c | 5+++--
Mchdir.c | 2+-
Mclose.c | 2+-
Mexecve.c | 2+-
Mexecvp.c | 65++++++++++++++++++++++++++++++++++++++++++++---------------------
Mfork.c | 2+-
Afstat.c | 17+++++++++++++++++
Mgetcwd.c | 2+-
Mgetdents.c | 4++--
Mlibc.h | 70+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Alseek.c | 17+++++++++++++++++
Alstat.c | 17+++++++++++++++++
Mmalloc.c | 35++++++++++++++++++++++-------------
Mmkdir.c | 2+-
Mmkfile | 5+++++
Mmmap.c | 4++--
Mmount.c | 13+++++++------
Mmunmap.c | 2+-
Mopen.c | 2+-
Apoll.c | 17+++++++++++++++++
Mread.c | 2+-
Mrealloc.c | 11++---------
Mrmdir.c | 2+-
Astat.c | 17+++++++++++++++++
Mstrchr.c | 8+++++---
Msyscall.c | 16+++-------------
Munlink.c | 2+-
Mutime.c | 2+-
Mwaitpid.c | 2+-
Mwrite.c | 2+-
31 files changed, 258 insertions(+), 93 deletions(-)

diff --git a/_exit.c b/_exit.c @@ -6,7 +6,7 @@ #include "libc.h" void _exit(int status) { - syscall(SYS_exit, status); + syscall(SYS_exit, (long)status, 0, 0, 0, 0, 0); for (;;) {} } diff --git a/calloc.c b/calloc.c @@ -6,11 +6,12 @@ #include "libc.h" void* calloc(size_t nmemb, size_t size) { - size_t total = nmemb * size; - if (nmemb != 0 && total / nmemb != size) { + if (nmemb != 0 && size > (size_t)-1 / nmemb) { return NULL; } + size_t total = nmemb * size; + void *ptr = malloc(total); if (ptr != NULL) { memset(ptr, 0, total); diff --git a/chdir.c b/chdir.c @@ -6,7 +6,7 @@ #include "libc.h" int chdir(const char *path) { - int ret = syscall(SYS_chdir, path); + int ret = syscall(SYS_chdir, (long)path, 0, 0, 0, 0, 0); if (ret < 0) { errno = -ret; diff --git a/close.c b/close.c @@ -6,7 +6,7 @@ #include "libc.h" int close(int fd) { - int ret = syscall(SYS_close, fd); + int ret = syscall(SYS_close, (long)fd, 0, 0, 0, 0, 0); if (ret < 0) { errno = -ret; diff --git a/execve.c b/execve.c @@ -6,7 +6,7 @@ #include "libc.h" int execve(const char *path, char *const argv[], char *const envp[]) { - int ret = syscall(SYS_execve, path, argv, envp); + int ret = syscall(SYS_execve, (long)path, (long)argv, (long)envp, 0, 0, 0); if (ret < 0) { errno = -ret; diff --git a/execvp.c b/execvp.c @@ -11,55 +11,78 @@ int execvp(const char *file, char *const argv[]) { static char *empty_env[] = { NULL }; char **env = (environ != NULL) ? environ : empty_env; - if (strchr(file, '/') != 0) { + if (file == NULL || *file == '\0') { + errno = ENOENT; + return -1; + } + + if (strchr(file, '/') != NULL) { return execve(file, argv, env); } const char *path_env = NULL; - if (env != NULL) { - for (char **ep = env; *ep != NULL; ++ep) { - if (ep[0][0] == 'P' && ep[0][1] == 'A' && - ep[0][2] == 'T' && ep[0][3] == 'H' && ep[0][4] == '=') { - path_env = *ep + 5; - break; - } + for (char **ep = env; *ep != NULL; ++ep) { + if (ep[0][0] == 'P' && ep[0][1] == 'A' && + ep[0][2] == 'T' && ep[0][3] == 'H' && ep[0][4] == '=') { + path_env = *ep + 5; + break; } } - if (path_env == NULL || *path_env == '\0') { - path_env = "/bin"; + if (path_env == NULL) { + path_env = "/bin:/usr/bin"; } char path_buf[1024]; size_t file_len = strlen(file); + int saved_errno = ENOENT; + + if (file_len >= sizeof(path_buf)) { + errno = ENAMETOOLONG; + return -1; + } const char *p = path_env; - while (*p != '\0') { + for (;;) { const char *start = p; while (*p != '\0' && *p != ':') { p++; } - size_t dir_len = p - start; + size_t dir_len = (size_t)(p - start); + size_t needed = file_len + 1; - if (dir_len == 0) { - if (file_len + 1 < sizeof(path_buf)) { - memcpy(path_buf, file, file_len + 1); - execve(path_buf, argv, env); + if (dir_len != 0) { + if (dir_len > sizeof(path_buf) - needed - 1) { + saved_errno = ENAMETOOLONG; + goto next_path; } - } else { - if (dir_len + 1 + file_len + 1 < sizeof(path_buf)) { + needed += dir_len + 1; + } + + if (needed <= sizeof(path_buf)) { + if (dir_len == 0) { + memcpy(path_buf, file, file_len + 1); + } else { memcpy(path_buf, start, dir_len); path_buf[dir_len] = '/'; memcpy(path_buf + dir_len + 1, file, file_len + 1); - execve(path_buf, argv, env); } + + if (execve(path_buf, argv, env) == -1) { + saved_errno = errno; + } + } else { + saved_errno = ENAMETOOLONG; } - if (*p == ':') { - p++; +next_path: + if (*p == '\0') { + break; } + p++; } + errno = saved_errno; return -1; } diff --git a/fork.c b/fork.c @@ -6,7 +6,7 @@ #include "libc.h" int fork(void) { - int ret = syscall(SYS_clone, (long)SIGCHLD, 0L, 0L, 0L, 0L); + int ret = syscall(SYS_clone, (long)SIGCHLD, 0, 0, 0, 0, 0); if (ret < 0) { errno = -ret; diff --git a/fstat.c b/fstat.c @@ -0,0 +1,17 @@ +/* + * fstat.c - fstat system call + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +int fstat(int fd, struct stat *statbuf) { + int ret = syscall(SYS_fstat, (long)fd, (long)statbuf, 0, 0, 0, 0); + + if (ret < 0) { + errno = -ret; + return -1; + } + + return ret; +} diff --git a/getcwd.c b/getcwd.c @@ -6,7 +6,7 @@ #include "libc.h" char *getcwd(char *buf, size_t size) { - int ret = syscall(SYS_getcwd, buf, size); + long ret = syscall(SYS_getcwd, (long)buf, (long)size, 0, 0, 0, 0); if (ret < 0) { errno = -ret; diff --git a/getdents.c b/getdents.c @@ -5,8 +5,8 @@ #include "libc.h" -int getdents64(int fd, struct linux_dirent64 *dirp, unsigned int count) { - int ret = syscall(SYS_getdents64, fd, (long)dirp, count); +ssize_t getdents64(int fd, struct linux_dirent64 *dirp, size_t count) { + ssize_t ret = syscall(SYS_getdents64, (long)fd, (long)dirp, (long)count, 0, 0, 0); if (ret < 0) { errno = -ret; return -1; diff --git a/libc.h b/libc.h @@ -9,7 +9,9 @@ /* base types */ typedef unsigned long size_t; typedef unsigned long ulong_t; +typedef unsigned long nfds_t; typedef long ssize_t; +typedef long off_t; #ifndef NULL #define NULL ((void*)0) @@ -31,8 +33,57 @@ struct linux_dirent64 { char d_name[]; }; +struct timespec { + long tv_sec; + long tv_nsec; +}; + +struct stat { + unsigned long st_dev; + unsigned long st_ino; + unsigned long st_nlink; + unsigned int st_mode; + unsigned int st_uid; + unsigned int st_gid; + unsigned int __pad0; + unsigned long st_rdev; + long st_size; + long st_blksize; + long st_blocks; + struct timespec st_atim; + struct timespec st_mtim; + struct timespec st_ctim; + long __reserved[3]; +}; + +struct pollfd { + int fd; + short events; + short revents; +}; + +struct block_header { + size_t size; + size_t requested_size; + int is_free; + struct block_header *next; +} __attribute__((aligned(16))); + +typedef struct block_header block_header_t; + +struct utimbuf { + long actime; + long modtime; +}; + + #define SIGCHLD 17 +/* errno values used by the libc implementation */ +#define ENOENT 2 +#define EACCES 13 +#define ENAMETOOLONG 36 + /* open flags */ #define O_RDONLY 00 #define O_WRONLY 01 @@ -46,6 +97,11 @@ struct linux_dirent64 { #define SYS_write 1 #define SYS_open 2 #define SYS_close 3 +#define SYS_stat 4 +#define SYS_fstat 5 +#define SYS_lstat 6 +#define SYS_poll 7 +#define SYS_lseek 8 #define SYS_mmap 9 #define SYS_munmap 11 #define SYS_brk 12 @@ -73,7 +129,7 @@ struct linux_dirent64 { extern char **environ; /* syscall function */ -long syscall(long num, ...); +long syscall(long num, long a1, long a2, long a3, long a4, long a5, long a6); /* io */ ssize_t read(int fd, void *buf, size_t count); @@ -97,7 +153,12 @@ int mkdir(const char *path, unsigned int mode); int rmdir(const char *path); int unlink(const char *path); char *getcwd(char *buf, size_t size); -int getdents64(int fd, struct linux_dirent64 *dirp, unsigned int count); +ssize_t getdents64(int fd, struct linux_dirent64 *dirp, size_t count); +int stat(const char *pathname, struct stat *statbuf); +int fstat(int fd, struct stat *statbuf); +int lstat(const char *pathname, struct stat *statbuf); +int poll(struct pollfd *fds, nfds_t nfds, int timeout); +off_t lseek(int fd, off_t offset, int whence); /* memory */ void* mmap(void *addr, size_t length, int prot, int flags, int fd, long offset); @@ -112,11 +173,6 @@ void* calloc(size_t nmemb, size_t size); void* realloc(void *ptr, size_t size); /* utime */ -struct utimbuf { - long actime; - long modtime; -}; - int utime(const char *path, const struct utimbuf *times); /* string functions */ diff --git a/lseek.c b/lseek.c @@ -0,0 +1,17 @@ +/* + * lseek.c - lseek system call + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +off_t lseek(int fd, off_t offset, int whence) { + off_t ret = syscall(SYS_lseek, (long)fd, (long)offset, (long)whence, 0, 0, 0); + + if (ret < 0) { + errno = -ret; + return -1; + } + + return ret; +} diff --git a/lstat.c b/lstat.c @@ -0,0 +1,17 @@ +/* + * lstat.c - lstat system call + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +int lstat(const char *pathname, struct stat *statbuf) { + int ret = syscall(SYS_lstat, (long)pathname, (long)statbuf, 0, 0, 0, 0); + + if (ret < 0) { + errno = -ret; + return -1; + } + + return ret; +} diff --git a/malloc.c b/malloc.c @@ -7,19 +7,17 @@ #define ALIGN_SIZE 16 #define ALIGN_MASK (ALIGN_SIZE - 1) - -struct block_header { - size_t size; - int is_free; - struct block_header *next; -} __attribute__((aligned(16))); - -typedef struct block_header block_header_t; +#define MIN_ALLOC_SIZE 4096 static block_header_t *free_list = NULL; -static size_t align(size_t n) { - return (n + ALIGN_MASK) & ~ALIGN_MASK; +static int align_size(size_t n, size_t *result) { + if (n > (size_t)-1 - ALIGN_MASK) { + return -1; + } + + *result = (n + ALIGN_MASK) & ~ALIGN_MASK; + return 0; } void* malloc(size_t size) { @@ -27,20 +25,29 @@ void* malloc(size_t size) { return NULL; } - size_t total_size = align(size + sizeof(block_header_t)); - block_header_t *curr = free_list; + if (size > (size_t)-1 - sizeof(block_header_t)) { + return NULL; + } + + size_t total_size; + if (align_size(size + sizeof(block_header_t), &total_size) < 0) { + return NULL; + } + + block_header_t *curr = free_list; block_header_t *prev = NULL; while (curr != NULL) { if (curr->is_free && curr->size >= total_size) { curr->is_free = 0; + curr->requested_size = size; return (void*)(curr + 1); } prev = curr; curr = curr->next; } - size_t alloc_size = total_size < 4096 ? 4096 : total_size; + size_t alloc_size = total_size < MIN_ALLOC_SIZE ? MIN_ALLOC_SIZE : total_size; block_header_t *block = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, @@ -51,6 +58,7 @@ void* malloc(size_t size) { } block->size = alloc_size; + block->requested_size = size; block->is_free = 0; block->next = NULL; @@ -70,4 +78,5 @@ void free(void *ptr) { block_header_t *header = (block_header_t*)ptr - 1; header->is_free = 1; + header->requested_size = 0; } diff --git a/mkdir.c b/mkdir.c @@ -6,7 +6,7 @@ #include "libc.h" int mkdir(const char *path, unsigned int mode) { - int ret = syscall(SYS_mkdir, path, mode); + int ret = syscall(SYS_mkdir, (long)path, (long)mode, 0, 0, 0, 0); if (ret < 0) { errno = -ret; diff --git a/mkfile b/mkfile @@ -31,6 +31,11 @@ ofiles = start.$o \ rmdir.$o \ unlink.$o \ getdents.$o \ + stat.$o \ + fstat.$o \ + lstat.$o \ + poll.$o \ + lseek.$o \ utime.$o \ errno.$o \ strlen.$o \ diff --git a/mmap.c b/mmap.c @@ -6,8 +6,8 @@ #include "libc.h" void* mmap(void *addr, size_t length, int prot, int flags, int fd, long offset) { - long ret = syscall(SYS_mmap, addr, length, prot, (long)flags, (long)fd, - offset); + long ret = syscall(SYS_mmap, (long)addr, (long)length, (long)prot, + (long)flags, (long)fd, (long)offset); if (ret < 0) { errno = -ret; diff --git a/mount.c b/mount.c @@ -8,12 +8,13 @@ int mount(const char *src, const char *trg, const char *fstype, ulong_t flags, const void *data) { - int ret = syscall(SYS_mount, - src, - trg, - fstype, - flags, - data); + int ret = syscall(SYS_mount, + (long)src, + (long)trg, + (long)fstype, + (long)flags, + (long)data, + 0); if (ret < 0) { errno = -ret; diff --git a/munmap.c b/munmap.c @@ -6,7 +6,7 @@ #include "libc.h" int munmap(void *addr, size_t length) { - long ret = syscall(SYS_munmap, addr, length); + long ret = syscall(SYS_munmap, (long)addr, (long)length, 0, 0, 0, 0); if (ret < 0) { errno = -ret; diff --git a/open.c b/open.c @@ -6,7 +6,7 @@ #include "libc.h" int open(const char *filename, int flags, int mode) { - int ret = syscall(SYS_open, filename, flags, mode); + int ret = syscall(SYS_open, (long)filename, (long)flags, (long)mode, 0, 0, 0); if (ret < 0) { errno = -ret; diff --git a/poll.c b/poll.c @@ -0,0 +1,17 @@ +/* + * poll.c - pollsystem call + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +int poll(struct pollfd *fds, nfds_t nfds, int timeout) { + int ret = syscall(SYS_poll, (long)fds, (long)nfds, (long)timeout, 0, 0, 0); + + if (ret < 0) { + errno = -ret; + return -1; + } + + return ret; +} diff --git a/read.c b/read.c @@ -6,7 +6,7 @@ #include "libc.h" ssize_t read(int fd, void *buf, size_t count) { - int ret = syscall(SYS_read, fd, buf, count); + ssize_t ret = syscall(SYS_read, (long)fd, (long)buf, (long)count, 0, 0, 0); if (ret < 0) { errno = -ret; diff --git a/realloc.c b/realloc.c @@ -5,14 +5,6 @@ #include "libc.h" -struct block_header { - size_t size; - int is_free; - struct block_header *next; -}; - -typedef struct block_header block_header_t; - void* realloc(void *ptr, size_t size) { if (ptr == NULL) { return malloc(size); @@ -23,9 +15,10 @@ void* realloc(void *ptr, size_t size) { } block_header_t *header = (block_header_t*)ptr - 1; - size_t old_size = header->size - sizeof(block_header_t); + size_t old_size = header->requested_size; if (old_size >= size) { + header->requested_size = size; return ptr; } diff --git a/rmdir.c b/rmdir.c @@ -6,7 +6,7 @@ #include "libc.h" int rmdir(const char *path) { - int ret = syscall(SYS_rmdir, path); + int ret = syscall(SYS_rmdir, (long)path, 0, 0, 0, 0, 0); if (ret < 0) { errno = -ret; diff --git a/stat.c b/stat.c @@ -0,0 +1,17 @@ +/* + * stat.c - stat system call + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +int stat(const char *pathname, struct stat *statbuf) { + int ret = syscall(SYS_stat, (long)pathname, (long)statbuf, 0, 0, 0, 0); + + if (ret < 0) { + errno = -ret; + return -1; + } + + return ret; +} diff --git a/strchr.c b/strchr.c @@ -6,16 +6,18 @@ #include "libc.h" char *strchr(const char *s, int c) { - char chr = (char)c; + unsigned char chr = (unsigned char)c; while (*s != '\0') { - if (*s == chr) + if ((unsigned char)*s == chr) { return (char *)s; + } s++; } - if (chr == '\0') + if (chr == '\0') { return (char *)s; + } return NULL; } diff --git a/syscall.c b/syscall.c @@ -3,12 +3,11 @@ * Copyright (C) 2026. All rights reserved. */ -#include <stdarg.h> #include "libc.h" static inline long call(long n, long a1, long a2, long a3, long a4, long a5, long a6) { - unsigned long ret; + long ret; register long r10 __asm__("r10") = a4; register long r8 __asm__("r8") = a5; @@ -20,15 +19,6 @@ static inline long call(long n, long a1, long a2, long a3, long a4, long a5, lon return ret; } -long syscall(long num, ...) { - va_list valist; - long args[6] = {0, 0, 0, 0, 0, 0}; - - va_start(valist, num); - for (int i = 0; i < 6; i++) { - args[i] = va_arg(valist, long); - } - va_end(valist); - - return call(num, args[0], args[1], args[2], args[3], args[4], args[5]); +long syscall(long num, long a1, long a2, long a3, long a4, long a5, long a6) { + return call(num, a1, a2, a3, a4, a5, a6); } diff --git a/unlink.c b/unlink.c @@ -6,7 +6,7 @@ #include "libc.h" int unlink(const char *path) { - int ret = syscall(SYS_unlink, path); + int ret = syscall(SYS_unlink, (long)path, 0, 0, 0, 0, 0); if (ret < 0) { errno = -ret; diff --git a/utime.c b/utime.c @@ -6,7 +6,7 @@ #include "libc.h" int utime(const char *path, const struct utimbuf *times) { - int ret = syscall(SYS_utime, path, times); + int ret = syscall(SYS_utime, (long)path, (long)times, 0, 0, 0, 0); if (ret < 0) { errno = -ret; return -1; diff --git a/waitpid.c b/waitpid.c @@ -6,7 +6,7 @@ #include "libc.h" int waitpid(int pid, int *status, int options) { - int ret = syscall(SYS_wait4, pid, status, options, NULL); + int ret = syscall(SYS_wait4, (long)pid, (long)status, (long)options, 0, 0, 0); if (ret < 0) { errno = -ret; diff --git a/write.c b/write.c @@ -6,7 +6,7 @@ #include "libc.h" ssize_t write(int fd, const void *buf, size_t count) { - int ret = syscall(SYS_write, fd, buf, count); + ssize_t ret = syscall(SYS_write, (long)fd, (long)buf, (long)count, 0, 0, 0); if (ret < 0) { errno = -ret;