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 | +- |
| A | calloc.c | | | 19 | +++++++++++++++++++ |
| A | execve.c | | | 25 | +++++++++++++++++++++++++ |
| A | execvp.c | | | 62 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | fork.c | | | 21 | +++++++++++++++++++++ |
| M | libc.h | | | 54 | ++++++++++++++++++++++++++++++++++++++++++++++++------ |
| A | malloc.c | | | 73 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | memcpy.c | | | 15 | +++++++++++++++ |
| A | memset.c | | | 14 | ++++++++++++++ |
| M | mkfile | | | 15 | +++++++++++++++ |
| A | mmap.c | | | 28 | ++++++++++++++++++++++++++++ |
| A | mount.c | | | 30 | ++++++++++++++++++++++++++++++ |
| A | munmap.c | | | 19 | +++++++++++++++++++ |
| A | realloc.c | | | 38 | ++++++++++++++++++++++++++++++++++++++ |
| A | strchr.c | | | 16 | ++++++++++++++++ |
| A | strcmp.c | | | 14 | ++++++++++++++ |
| A | strtok.c | | | 42 | ++++++++++++++++++++++++++++++++++++++++++ |
| A | waitpid.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;
+}