libc

libc
git clone http://194.87.232.205/libc
Log | Files | Refs | README

commit d2aa68d70e312446d01bd451d8e6b172b67d8291
parent edd48c2ebee2920dc577f72fc5cbe493accf2c3a
Author: evenfri <evenfri@noreply.codeberg.org>
Date:   Fri, 24 Jul 2026 16:46:22 +0200

feat: many new functions (#3)

Co-authored-by: evenfri <evenfri256@gmail.com>
Reviewed-on: https://codeberg.org/evenfri/libc/pulls/3

Diffstat:
M_exit.c | 2+-
Acalloc.c | 19+++++++++++++++++++
Aexecve.c | 25+++++++++++++++++++++++++
Aexecvp.c | 62++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Afork.c | 21+++++++++++++++++++++
Mlibc.h | 54++++++++++++++++++++++++++++++++++++++++++++++++------
Amalloc.c | 73+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amemcpy.c | 15+++++++++++++++
Amemset.c | 14++++++++++++++
Mmkfile | 15+++++++++++++++
Ammap.c | 28++++++++++++++++++++++++++++
Amount.c | 30++++++++++++++++++++++++++++++
Amunmap.c | 19+++++++++++++++++++
Arealloc.c | 38++++++++++++++++++++++++++++++++++++++
Astrchr.c | 16++++++++++++++++
Astrcmp.c | 14++++++++++++++
Astrtok.c | 42++++++++++++++++++++++++++++++++++++++++++
Awaitpid.c | 24++++++++++++++++++++++++
18 files changed, 504 insertions(+), 7 deletions(-)

diff --git a/_exit.c b/_exit.c @@ -6,7 +6,7 @@ #include "libc.h" void _exit(int status) { - __asm__ volatile ( + asm volatile ( "syscall" : : "a"(sys_exit), "D"(status) diff --git a/calloc.c b/calloc.c @@ -0,0 +1,19 @@ +/* + * calloc.c — allocate and clear memory + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +void* calloc(size_t nmemb, size_t size) { + size_t total = nmemb * size; + if (nmemb != 0 && total / nmemb != size) { + return NULL; + } + + void *ptr = malloc(total); + if (ptr != NULL) { + memset(ptr, 0, total); + } + return ptr; +} diff --git a/execve.c b/execve.c @@ -0,0 +1,25 @@ +/* + * execve.c — execute program + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +int execve(const char *path, char *const argv[], char *const envp[]) { + long ret; + + asm volatile ( + "syscall" + : "=a"(ret) + : "a"(sys_execve), + "D"(path), + "S"(argv), + "d"(envp) + : "rcx", "r11", "memory" + ); + + if (ret < 0) { + return -1; + } + return 0; +} diff --git a/execvp.c b/execvp.c @@ -0,0 +1,62 @@ +/* + * execvp.c — execute a file, searching PATH + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +char **environ; + +int execvp(const char *file, char *const argv[]) { + if (strchr(file, '/') != 0) { + return execve(file, argv, environ); + } + + const char *path_env = NULL; + if (environ != NULL) { + for (char **env = environ; *env != NULL; ++env) { + if (env[0][0] == 'P' && env[0][1] == 'A' && + env[0][2] == 'T' && env[0][3] == 'H' && env[0][4] == '=') { + path_env = *env + 5; + break; + } + } + } + + if (path_env == NULL || *path_env == '\0') { + path_env = "/bin"; + } + + char path_buf[1024]; + size_t file_len = strlen(file); + + const char *p = path_env; + while (*p != '\0') { + const char *start = p; + while (*p != '\0' && *p != ':') { + p++; + } + + size_t dir_len = p - start; + + if (dir_len == 0) { + if (file_len + 1 < sizeof(path_buf)) { + memcpy(path_buf, file, file_len + 1); + execve(path_buf, argv, environ); + } + } else { + if (dir_len + 1 + file_len + 1 < sizeof(path_buf)) { + memcpy(path_buf, start, dir_len); + path_buf[dir_len] = '/'; + memcpy(path_buf + dir_len + 1, file, file_len + 1); + execve(path_buf, argv, environ); + } + } + + if (*p == ':') { + p++; + } + } + + return -1; +} diff --git a/fork.c b/fork.c @@ -0,0 +1,21 @@ +/* + * fork.c — fork system call wrapper + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +#define sigchld 17 + +int fork(void) { + long ret; + + asm volatile ( + "syscall" + : "=a"(ret) + : "a"(sys_clone), "D"((long)sigchld), "S"(0L) + : "rcx", "r11", "memory" + ); + + return (int)ret; +} diff --git a/libc.h b/libc.h @@ -3,15 +3,16 @@ * Copyright (C) 2026. All rights reserved. */ -#ifndef _libc_h -#define _libc_h +#ifndef libc_h +#define libc_h /* base types */ typedef unsigned long size_t; +typedef unsigned long ulong_t; typedef long ssize_t; -#ifndef null -#define null ((void*)0) +#ifndef NULL +#define NULL ((void*)0) #endif #define stdin 0 @@ -29,7 +30,24 @@ typedef long ssize_t; #define sys_write 1 #define sys_open 2 #define sys_close 3 +#define sys_mmap 9 +#define sys_munmap 11 +#define sys_brk 12 +#define sys_clone 56 +#define sys_execve 59 #define sys_exit 60 +#define sys_waitpid 61 +#define sys_mount 165 + +/* mmap flags */ +#define prot_read 0x1 +#define prot_write 0x2 +#define map_private 0x02 +#define map_anonymous 0x20 +#define map_failed ((void*)-1) + +/* variables */ +extern char **environ; /* function prototypes */ ssize_t read(int fd, void *buf, size_t count); @@ -38,8 +56,32 @@ int open(const char *filename, int flags, int mode); int close(int fd); void _exit(int status); void exit(int status); +int execve(const char *path, char *const argv[], char *const envp[]); +int execvp(const char *file, char *const argv[]); +int fork(void); +int waitpid(int pid, int *status, int options); +int mount(const char *source, + const char *target, + const char *filesystemtype, + ulong_t mountflags, + const void *data); + +/* memory prototypes */ +void* mmap(void *addr, size_t length, int prot, int flags, int fd, long offset); +int munmap(void *addr, size_t length); +void* memset(void *s, int c, size_t n); +void* memcpy(void *dest, const void *src, size_t n); + +/* alloc prototypes */ +void* malloc(size_t size); +void free(void *ptr); +void* calloc(size_t nmemb, size_t size); +void* realloc(void *ptr, size_t size); /* string functions prototypes */ -size_t strlen(const char* str); +size_t strlen(const char *str); +int strchr(const char *s, int c); +int strcmp(const char *s1, const char *s2); +char* strtok(char *str, const char *delim); -#endif /* _libc_h */ +#endif /* libc_h */ diff --git a/malloc.c b/malloc.c @@ -0,0 +1,73 @@ +/* + * malloc.c — basic memory allocator + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +#define align_size 16 +#define align_mask (align_size - 1) + +struct block_header { + size_t size; + int is_free; + struct block_header *next; +}; + +typedef struct block_header block_header_t; + +static block_header_t *glb_free_list = NULL; + +static size_t align(size_t n) { + return (n + align_mask) & ~align_mask; +} + +void* malloc(size_t size) { + if (size == 0) { + return NULL; + } + + size_t total_size = align(size + sizeof(block_header_t)); + block_header_t *curr = glb_free_list; + block_header_t *prev = NULL; + + while (curr != NULL) { + if (curr->is_free && curr->size >= total_size) { + curr->is_free = 0; + return (void*)(curr + 1); + } + prev = curr; + curr = curr->next; + } + + size_t alloc_size = total_size < 4096 ? 4096 : total_size; + block_header_t *block = mmap(NULL, alloc_size, + prot_read | prot_write, + map_private | map_anonymous, + -1, 0); + + if (block == map_failed) { + return NULL; + } + + block->size = alloc_size; + block->is_free = 0; + block->next = NULL; + + if (prev != NULL) { + prev->next = block; + } else { + glb_free_list = block; + } + + return (void*)(block + 1); +} + +void free(void *ptr) { + if (ptr == NULL) { + return; + } + + block_header_t *header = (block_header_t*)ptr - 1; + header->is_free = 1; +} diff --git a/memcpy.c b/memcpy.c @@ -0,0 +1,15 @@ +/* + * memcpy.c — copy memory area + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +void* memcpy(void *dest, const void *src, size_t n) { + char *d = dest; + const char *s = src; + while (n--) { + *d++ = *s++; + } + return dest; +} diff --git a/memset.c b/memset.c @@ -0,0 +1,14 @@ +/* + * memset.c — fill memory with a constant byte + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +void* memset(void *s, int c, size_t n) { + unsigned char *p = s; + while (n--) { + *p++ = (unsigned char)c; + } + return s; +} diff --git a/mkfile b/mkfile @@ -12,7 +12,22 @@ ofiles = start.$o \ write.$o \ open.$o \ close.$o \ + execve.$o \ + execvp.$o \ + fork.$o \ + waitpid.$o \ + mount.$o \ + mmap.$o \ + munmap.$o \ + malloc.$o \ + calloc.$o \ + realloc.$o \ strlen.$o \ + strchr.$o \ + strcmp.$o \ + strtok.$o \ + memset.$o \ + memcpy.$o \ stack_chk.$o \ hfiles = libc.h \ diff --git a/mmap.c b/mmap.c @@ -0,0 +1,28 @@ +/* + * mmap.c — mmap system call wrapper + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +void* mmap(void *addr, size_t length, int prot, int flags, int fd, long offset) { + long ret; + register long r10 asm("r10") = (long)flags; + register long r8 asm("r8") = (long)fd; + register long r9 asm("r9") = offset; + + asm volatile ( + "syscall" + : "=a"(ret) + : "a"(sys_mmap), + "D"(addr), + "S"(length), + "d"(prot), + "r"(r10), + "r"(r8), + "r"(r9) + : "rcx", "r11", "memory" + ); + + return (void*)ret; +} diff --git a/mount.c b/mount.c @@ -0,0 +1,30 @@ +/* + * mount.c — mount system call wrapper + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +int mount(const char *source, + const char *target, + const char *filesystemtype, + ulong_t mountflags, + const void *data) { + long ret; + register long r10 asm("r10") = (long)mountflags; + register long r8 asm("r8") = (long)data; + + asm volatile ( + "syscall" + : "=a"(ret) + : "a"(sys_mount), + "D"(source), + "S"(target), + "d"(filesystemtype), + "r"(r10), + "r"(r8) + : "rcx", "r11", "memory" + ); + + return (int)ret; +} diff --git a/munmap.c b/munmap.c @@ -0,0 +1,19 @@ +/* + * munmap.c — munmap system call wrapper + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +int munmap(void *addr, size_t length) { + long ret; + + asm volatile ( + "syscall" + : "=a"(ret) + : "a"(sys_munmap), "D"(addr), "S"(length) + : "rcx", "r11", "memory" + ); + + return (int)ret; +} diff --git a/realloc.c b/realloc.c @@ -0,0 +1,38 @@ +/* + * realloc.c — reallocate memory block + * Copyright (C) 2026. All rights reserved. + */ + +#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); + } + if (size == 0) { + free(ptr); + return NULL; + } + + block_header_t *header = (block_header_t*)ptr - 1; + size_t old_size = header->size - sizeof(block_header_t); + + if (old_size >= size) { + return ptr; + } + + void *new_ptr = malloc(size); + if (new_ptr != NULL) { + memcpy(new_ptr, ptr, old_size); + free(ptr); + } + return new_ptr; +} diff --git a/strchr.c b/strchr.c @@ -0,0 +1,16 @@ +/* + * strchr.c — locate character in string + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +int strchr(const char *s, int c) { + while (*s) { + if (*s == (char)c) { + return 1; + } + s++; + } + return 0; +} diff --git a/strcmp.c b/strcmp.c @@ -0,0 +1,14 @@ +/* + * strcmp.c — compare two strings + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +int strcmp(const char *s1, const char *s2) { + while (*s1 && *s2 && (*s1 == *s2)) { + s1++; + s2++; + } + return (unsigned char)*s1 - (unsigned char)*s2; +} diff --git a/strtok.c b/strtok.c @@ -0,0 +1,42 @@ +/* + * strtok.c — extract tokens from string + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +char* strtok(char *str, const char *delim) { + static char *glb_next_token = NULL; + + if (str != NULL) { + glb_next_token = str; + } + + if (glb_next_token == NULL || *glb_next_token == '\0') { + return NULL; + } + + char *token_start = glb_next_token; + while (*token_start && strchr(delim, *token_start)) { + token_start++; + } + + if (*token_start == '\0') { + glb_next_token = NULL; + return NULL; + } + + char *token_end = token_start; + while (*token_end && !strchr(delim, *token_end)) { + token_end++; + } + + if (*token_end != '\0') { + *token_end = '\0'; + glb_next_token = token_end + 1; + } else { + glb_next_token = NULL; + } + + return token_start; +} diff --git a/waitpid.c b/waitpid.c @@ -0,0 +1,24 @@ +/* + * waitpid.c — waitpid system call wrapper + * Copyright (C) 2026. All rights reserved. + */ + +#include "libc.h" + +int waitpid(int pid, int *status, int options) { + long ret; + register long r10 asm("r10") = 0; + + asm volatile ( + "syscall" + : "=a"(ret) + : "a"(sys_waitpid), + "D"((long)pid), + "S"(status), + "d"((long)options), + "r"(r10) + : "rcx", "r11", "memory" + ); + + return (int)ret; +}