init commit
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
*.o
|
||||||
|
*.a
|
||||||
|
obj/
|
||||||
|
lib/
|
||||||
|
config.mak
|
||||||
40
Makefile
Normal file
40
Makefile
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
CC ?= gcc
|
||||||
|
AR ?= ar
|
||||||
|
RANLIB ?= ranlib
|
||||||
|
CFLAGS ?= -Os -fno-builtin -ffreestanding -nostdinc
|
||||||
|
LDFLAGS ?= -nostdlib -static
|
||||||
|
|
||||||
|
-include config.mak
|
||||||
|
ARCH ?= x86_64
|
||||||
|
|
||||||
|
CFLAGS += -I. -I include
|
||||||
|
|
||||||
|
SRC_DIRS = src/string src/stdio src/stdlib src/internal
|
||||||
|
OBJ_DIR = obj
|
||||||
|
LIB_DIR = lib
|
||||||
|
|
||||||
|
SRCS := $(shell find $(SRC_DIRS) -name '*.c' 2>/dev/null)
|
||||||
|
OBJS := $(SRCS:%=$(OBJ_DIR)/%.o)
|
||||||
|
CRT_OBJ := crt/crt1.o
|
||||||
|
|
||||||
|
.PHONY: all clean distclean
|
||||||
|
|
||||||
|
all: $(LIB_DIR)/libc.a $(CRT_OBJ)
|
||||||
|
|
||||||
|
$(OBJ_DIR)/%.c.o: %.c
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
$(LIB_DIR)/libc.a: $(OBJS)
|
||||||
|
@mkdir -p $(LIB_DIR)
|
||||||
|
$(AR) crs $@ $^
|
||||||
|
$(RANLIB) $@
|
||||||
|
|
||||||
|
crt/crt1.o: crt/crt1.c
|
||||||
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(OBJ_DIR) $(LIB_DIR)
|
||||||
|
|
||||||
|
distclean: clean
|
||||||
|
rm -f config.mak
|
||||||
56
README.md
Normal file
56
README.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
# elibc — Standard C Library for Elyz
|
||||||
|
|
||||||
|
Minimal C library for the Elyz OS, based on musl's organisational principles
|
||||||
|
but adapted to Elyz's capability-based, syscall-less architecture.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
elibc/
|
||||||
|
├── arch/ # Architecture-specific code
|
||||||
|
│ ├── generic/ # Fallback implementation & abstract interfaces
|
||||||
|
│ │ ├── kcall.h # Kernel-call abstraction (no syscalls in Elyz)
|
||||||
|
│ │ ├── startup_info.h # Process-startup description
|
||||||
|
│ │ └── bits/ # Type-size definitions
|
||||||
|
│ └── x86_64/ # x86_64 port
|
||||||
|
│ ├── kcall.h # Kernel-call placeholder (ABI TBD)
|
||||||
|
│ ├── startup_info.h # x86_64 startup layout (ABI TBD)
|
||||||
|
│ ├── atomic_arch.h # Locked cmpxchg / atomic ops
|
||||||
|
│ └── bits/
|
||||||
|
├── include/ # Public headers (POSIX-like API)
|
||||||
|
├── src/ # Source implementations
|
||||||
|
│ ├── internal/ # Libc state, errno, bump allocator (temporary)
|
||||||
|
│ ├── string/ # Pure-C string ops (memcpy, strlen, etc.)
|
||||||
|
│ ├── stdio/ # (reserved)
|
||||||
|
│ └── stdlib/ # atoi, etc.
|
||||||
|
├── crt/ # C runtime entry point
|
||||||
|
├── Makefile
|
||||||
|
└── configure
|
||||||
|
```
|
||||||
|
|
||||||
|
## Key differences from a traditional libc (glibc/musl)
|
||||||
|
|
||||||
|
| Traditional (Linux) | Elyz / elibc |
|
||||||
|
|---|---|
|
||||||
|
| `syscall`/`int 0x80` | Capability invocation → PM Actor messaging |
|
||||||
|
| `brk`/`sbrk` | `ELYZ_OP_ALLOCATE` via `elyz_kcall` |
|
||||||
|
| `_exit` syscall | `ELYZ_OP_EXIT` via kcall |
|
||||||
|
| `errno` via TLS | `__errno_location` (plain global for now) |
|
||||||
|
|
||||||
|
## Porting to a new arch
|
||||||
|
|
||||||
|
1. Create `arch/<name>/` with:
|
||||||
|
- `kcall.h` — kernel-call mechanism
|
||||||
|
- `startup_info.h` — process-startup layout
|
||||||
|
- `arch.mak` — arch-specific compiler/linker flags
|
||||||
|
- `bits/alltypes.h.in` — type sizes
|
||||||
|
- `atomic_arch.h` — atomic ops (optional, fallback exists)
|
||||||
|
2. Add detection in `configure`
|
||||||
|
3. Build: `./configure && make`
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
```
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
```
|
||||||
3
arch/generic/arch.mak
Normal file
3
arch/generic/arch.mak
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Generic architecture flags — override per port
|
||||||
|
ARCH_CFLAGS :=
|
||||||
|
ARCH_LDFLAGS :=
|
||||||
7
arch/generic/bits/alltypes.h.in
Normal file
7
arch/generic/bits/alltypes.h.in
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
/* Generic type sizes — override per arch if different */
|
||||||
|
TYPEDEF int ptrdiff_t;
|
||||||
|
TYPEDEF unsigned long size_t;
|
||||||
|
TYPEDEF long ssize_t;
|
||||||
|
TYPEDEF unsigned long uintptr_t;
|
||||||
|
TYPEDEF long intptr_t;
|
||||||
|
TYPEDEF int wchar_t;
|
||||||
30
arch/generic/kcall.h
Normal file
30
arch/generic/kcall.h
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
#ifndef _ELIBC_KCALL_H
|
||||||
|
#define _ELIBC_KCALL_H
|
||||||
|
|
||||||
|
/* Elyz kernel-call abstraction.
|
||||||
|
*
|
||||||
|
* Elyz has NO syscall instruction. Communication with the kernel and PM
|
||||||
|
* actors happens through capability invocation — a mechanism defined by the
|
||||||
|
* kernel ABI (not finalised yet). This header describes the abstract
|
||||||
|
* interface; the arch-specific implementation (arch/<arch>/kcall.h) fills in
|
||||||
|
* the concrete mechanism.
|
||||||
|
*
|
||||||
|
* Current state: STUB — returns -ENOSYS until the Elyz kernel ABI is
|
||||||
|
* stabilised.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define ELYZ_OP_ALLOCATE 1
|
||||||
|
#define ELYZ_OP_FREE 2
|
||||||
|
#define ELYZ_OP_CARVE 3
|
||||||
|
#define ELYZ_OP_EXIT 4
|
||||||
|
|
||||||
|
struct elyz_kcall {
|
||||||
|
unsigned long opcode;
|
||||||
|
unsigned long arg1;
|
||||||
|
unsigned long arg2;
|
||||||
|
unsigned short channel_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
long __kcall(struct elyz_kcall *msg);
|
||||||
|
|
||||||
|
#endif
|
||||||
22
arch/generic/startup_info.h
Normal file
22
arch/generic/startup_info.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#ifndef _ELIBC_STARTUP_INFO_H
|
||||||
|
#define _ELIBC_STARTUP_INFO_H
|
||||||
|
|
||||||
|
/* Process-startup information block.
|
||||||
|
*
|
||||||
|
* The Elyz loader passes an opaque structure to every new process.
|
||||||
|
* Layout and content are arch-defined (see arch/<arch>/startup_info.h).
|
||||||
|
* At minimum the process receives:
|
||||||
|
* - an initial memory pool (capability / region)
|
||||||
|
* - argc / argv from the parent
|
||||||
|
* - a capability-wallet (CNode) root
|
||||||
|
*/
|
||||||
|
|
||||||
|
struct elyz_startup {
|
||||||
|
unsigned long initial_cnode_cap;
|
||||||
|
unsigned long initial_pool_addr;
|
||||||
|
unsigned long initial_pool_size;
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
3
arch/x86_64/arch.mak
Normal file
3
arch/x86_64/arch.mak
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# x86_64 architecture flags
|
||||||
|
ARCH_CFLAGS := -m64
|
||||||
|
ARCH_LDFLAGS := -m elf_x86_64
|
||||||
26
arch/x86_64/atomic_arch.h
Normal file
26
arch/x86_64/atomic_arch.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef _ELIBC_ATOMIC_ARCH_H
|
||||||
|
#define _ELIBC_ATOMIC_ARCH_H
|
||||||
|
|
||||||
|
/* x86_64: minimal atomic ops via locked cmpxchg (CPU-local, no syscall) */
|
||||||
|
|
||||||
|
static inline int a_cas(volatile int *p, int t, int s)
|
||||||
|
{
|
||||||
|
int old;
|
||||||
|
__asm__ volatile ("lock; cmpxchg %3, %1"
|
||||||
|
: "=a"(old), "=m"(*p)
|
||||||
|
: "a"(t), "r"(s), "m"(*p)
|
||||||
|
: "memory");
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void a_inc(volatile int *p)
|
||||||
|
{
|
||||||
|
__asm__ volatile ("lock; incl %0" : "=m"(*p) : "m"(*p) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void a_dec(volatile int *p)
|
||||||
|
{
|
||||||
|
__asm__ volatile ("lock; decl %0" : "=m"(*p) : "m"(*p) : "memory");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
6
arch/x86_64/bits/alltypes.h.in
Normal file
6
arch/x86_64/bits/alltypes.h.in
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
TYPEDEF int ptrdiff_t;
|
||||||
|
TYPEDEF unsigned long size_t;
|
||||||
|
TYPEDEF long ssize_t;
|
||||||
|
TYPEDEF unsigned long uintptr_t;
|
||||||
|
TYPEDEF long intptr_t;
|
||||||
|
TYPEDEF int wchar_t;
|
||||||
21
arch/x86_64/kcall.h
Normal file
21
arch/x86_64/kcall.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef _ELIBC_X86_64_KCALL_H
|
||||||
|
#define _ELIBC_X86_64_KCALL_H
|
||||||
|
|
||||||
|
#include <arch/generic/kcall.h>
|
||||||
|
|
||||||
|
/* x86_64: placeholder — Elyz kernel ABI not yet defined.
|
||||||
|
*
|
||||||
|
* When the ABI exists this will contain either:
|
||||||
|
* - a direct userspace→actor message-pipe write, or
|
||||||
|
* - a lightweight kernel entry that routes via the PMRouter.
|
||||||
|
*
|
||||||
|
* For now: return -ENOSYS and let the CPU halt.
|
||||||
|
*/
|
||||||
|
static inline long __kcall(struct elyz_kcall *msg)
|
||||||
|
{
|
||||||
|
(void)msg;
|
||||||
|
for (;;) __asm__ volatile("hlt");
|
||||||
|
return -38; /* -ENOSYS */
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
16
arch/x86_64/startup_info.h
Normal file
16
arch/x86_64/startup_info.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
#ifndef _ELIBC_X86_64_STARTUP_INFO_H
|
||||||
|
#define _ELIBC_X86_64_STARTUP_INFO_H
|
||||||
|
|
||||||
|
/* x86_64 process-startup ABI.
|
||||||
|
*
|
||||||
|
* The loader places an elyz_startup block at a known location (e.g. in a
|
||||||
|
* register or on a special stack page). The exact ABI depends on the
|
||||||
|
* kernel-to-userspace handoff which is not yet implemented.
|
||||||
|
*
|
||||||
|
* Current state: STUB — the process receives argc/argv on the stack as a
|
||||||
|
* fallback, and the initial memory pool comes from a fixed test region.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <arch/generic/startup_info.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
21
configure
vendored
Executable file
21
configure
vendored
Executable file
@@ -0,0 +1,21 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Minimal configure for elibc — detects target architecture
|
||||||
|
|
||||||
|
echo "Configuring elibc..."
|
||||||
|
|
||||||
|
# Detect architecture
|
||||||
|
case "$(uname -m)" in
|
||||||
|
x86_64|amd64)
|
||||||
|
ARCH=x86_64
|
||||||
|
;;
|
||||||
|
aarch64|arm64)
|
||||||
|
ARCH=aarch64
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Warning: unknown arch $(uname -m), falling back to x86_64"
|
||||||
|
ARCH=x86_64
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
echo "ARCH := $ARCH" > config.mak
|
||||||
|
echo "Configured for $ARCH"
|
||||||
32
crt/crt1.c
Normal file
32
crt/crt1.c
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/* Minimal C runtime — entry point before main.
|
||||||
|
*
|
||||||
|
* Elyz process startup:
|
||||||
|
* the loader transfers control here with an initial capability wallet
|
||||||
|
* (CNode) and a pool of untyped memory. No traditional syscalls exist;
|
||||||
|
* all kernel interaction goes through capability invocation.
|
||||||
|
*
|
||||||
|
* Current state: STUB — the kernel ABI is under construction.
|
||||||
|
* - argc/argv passed on stack (convention inherited from limine boot)
|
||||||
|
* - initial memory pool not yet wired; __libc_init sets up a tiny bump
|
||||||
|
* arena for development.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void _start(void)
|
||||||
|
{
|
||||||
|
extern int main(int, char **, char **);
|
||||||
|
extern void __libc_init(void);
|
||||||
|
|
||||||
|
register long *args __asm__("rsp");
|
||||||
|
int argc = (int)args[0];
|
||||||
|
char **argv = (char **)(args + 1);
|
||||||
|
char **envp = argv + argc + 1;
|
||||||
|
|
||||||
|
__libc_init();
|
||||||
|
|
||||||
|
int ret = main(argc, argv, envp);
|
||||||
|
|
||||||
|
/* No _exit syscall in Elyz — send an Exit message to the PM actor.
|
||||||
|
* For now: infinite halt. */
|
||||||
|
for (;;) __asm__ volatile("hlt");
|
||||||
|
(void)ret;
|
||||||
|
}
|
||||||
42
include/errno.h
Normal file
42
include/errno.h
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#ifndef _ELIBC_ERRNO_H
|
||||||
|
#define _ELIBC_ERRNO_H
|
||||||
|
|
||||||
|
#define EPERM 1
|
||||||
|
#define ENOENT 2
|
||||||
|
#define ESRCH 3
|
||||||
|
#define EINTR 4
|
||||||
|
#define EIO 5
|
||||||
|
#define ENXIO 6
|
||||||
|
#define E2BIG 7
|
||||||
|
#define ENOEXEC 8
|
||||||
|
#define EBADF 9
|
||||||
|
#define ECHILD 10
|
||||||
|
#define EAGAIN 11
|
||||||
|
#define ENOMEM 12
|
||||||
|
#define EACCES 13
|
||||||
|
#define EFAULT 14
|
||||||
|
#define EBUSY 16
|
||||||
|
#define EEXIST 17
|
||||||
|
#define EXDEV 18
|
||||||
|
#define ENODEV 19
|
||||||
|
#define ENOTDIR 20
|
||||||
|
#define EISDIR 21
|
||||||
|
#define EINVAL 22
|
||||||
|
#define ENFILE 23
|
||||||
|
#define EMFILE 24
|
||||||
|
#define ENOTTY 25
|
||||||
|
#define EFBIG 27
|
||||||
|
#define ENOSPC 28
|
||||||
|
#define ESPIPE 29
|
||||||
|
#define EROFS 30
|
||||||
|
#define EMLINK 31
|
||||||
|
#define EPIPE 32
|
||||||
|
#define EDOM 33
|
||||||
|
#define ERANGE 34
|
||||||
|
#define EDEADLK 35
|
||||||
|
#define ENOSYS 38
|
||||||
|
|
||||||
|
extern int *__errno_location(void);
|
||||||
|
#define errno (*__errno_location())
|
||||||
|
|
||||||
|
#endif
|
||||||
26
include/limits.h
Normal file
26
include/limits.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#ifndef _ELIBC_LIMITS_H
|
||||||
|
#define _ELIBC_LIMITS_H
|
||||||
|
|
||||||
|
#define CHAR_BIT 8
|
||||||
|
|
||||||
|
#define SCHAR_MIN (-128)
|
||||||
|
#define SCHAR_MAX 127
|
||||||
|
#define UCHAR_MAX 255
|
||||||
|
|
||||||
|
#define SHRT_MIN (-32768)
|
||||||
|
#define SHRT_MAX 32767
|
||||||
|
#define USHRT_MAX 65535
|
||||||
|
|
||||||
|
#define INT_MIN (-2147483647 - 1)
|
||||||
|
#define INT_MAX 2147483647
|
||||||
|
#define UINT_MAX 4294967295U
|
||||||
|
|
||||||
|
#define LONG_MIN (-9223372036854775807L - 1)
|
||||||
|
#define LONG_MAX 9223372036854775807L
|
||||||
|
#define ULONG_MAX 18446744073709551615UL
|
||||||
|
|
||||||
|
#define LLONG_MIN (-9223372036854775807LL - 1)
|
||||||
|
#define LLONG_MAX 9223372036854775807LL
|
||||||
|
#define ULLONG_MAX 18446744073709551615ULL
|
||||||
|
|
||||||
|
#endif
|
||||||
10
include/stdarg.h
Normal file
10
include/stdarg.h
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#ifndef _ELIBC_STDARG_H
|
||||||
|
#define _ELIBC_STDARG_H
|
||||||
|
|
||||||
|
typedef __builtin_va_list va_list;
|
||||||
|
#define va_start(v, l) __builtin_va_start(v, l)
|
||||||
|
#define va_end(v) __builtin_va_end(v)
|
||||||
|
#define va_arg(v, t) __builtin_va_arg(v, t)
|
||||||
|
#define va_copy(d, s) __builtin_va_copy(d, s)
|
||||||
|
|
||||||
|
#endif
|
||||||
9
include/stdbool.h
Normal file
9
include/stdbool.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef _ELIBC_STDBOOL_H
|
||||||
|
#define _ELIBC_STDBOOL_H
|
||||||
|
|
||||||
|
#define bool _Bool
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
#define __bool_true_false_are_defined 1
|
||||||
|
|
||||||
|
#endif
|
||||||
11
include/stddef.h
Normal file
11
include/stddef.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef _ELIBC_STDDEF_H
|
||||||
|
#define _ELIBC_STDDEF_H
|
||||||
|
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
typedef __PTRDIFF_TYPE__ ptrdiff_t;
|
||||||
|
typedef __WCHAR_TYPE__ wchar_t;
|
||||||
|
|
||||||
|
#define NULL ((void *)0)
|
||||||
|
#define offsetof(type, member) __builtin_offsetof(type, member)
|
||||||
|
|
||||||
|
#endif
|
||||||
18
include/stdint.h
Normal file
18
include/stdint.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef _ELIBC_STDINT_H
|
||||||
|
#define _ELIBC_STDINT_H
|
||||||
|
|
||||||
|
typedef signed char int8_t;
|
||||||
|
typedef short int16_t;
|
||||||
|
typedef int int32_t;
|
||||||
|
typedef long long int64_t;
|
||||||
|
|
||||||
|
typedef unsigned char uint8_t;
|
||||||
|
typedef unsigned short uint16_t;
|
||||||
|
typedef unsigned int uint32_t;
|
||||||
|
typedef unsigned long long uint64_t;
|
||||||
|
|
||||||
|
typedef __SIZE_TYPE__ size_t;
|
||||||
|
typedef __UINTPTR_TYPE__ uintptr_t;
|
||||||
|
typedef __INTPTR_TYPE__ intptr_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
18
include/stdlib.h
Normal file
18
include/stdlib.h
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
#ifndef _ELIBC_STDLIB_H
|
||||||
|
#define _ELIBC_STDLIB_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void *malloc(size_t);
|
||||||
|
void *calloc(size_t, size_t);
|
||||||
|
void *realloc(void *, size_t);
|
||||||
|
void free(void *);
|
||||||
|
|
||||||
|
void exit(int) __attribute__((noreturn));
|
||||||
|
void abort(void) __attribute__((noreturn));
|
||||||
|
|
||||||
|
int atoi(const char *);
|
||||||
|
long atol(const char *);
|
||||||
|
long long atoll(const char *);
|
||||||
|
|
||||||
|
#endif
|
||||||
21
include/string.h
Normal file
21
include/string.h
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#ifndef _ELIBC_STRING_H
|
||||||
|
#define _ELIBC_STRING_H
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void *memcpy(void *restrict, const void *restrict, size_t);
|
||||||
|
void *memmove(void *, const void *, size_t);
|
||||||
|
void *memset(void *, int, size_t);
|
||||||
|
int memcmp(const void *, const void *, size_t);
|
||||||
|
void *memchr(const void *, int, size_t);
|
||||||
|
|
||||||
|
size_t strlen(const char *);
|
||||||
|
int strcmp(const char *, const char *);
|
||||||
|
int strncmp(const char *, const char *, size_t);
|
||||||
|
char *strcpy(char *restrict, const char *restrict);
|
||||||
|
char *strncpy(char *restrict, const char *restrict, size_t);
|
||||||
|
char *strcat(char *restrict, const char *restrict);
|
||||||
|
char *strchr(const char *, int);
|
||||||
|
char *strrchr(const char *, int);
|
||||||
|
|
||||||
|
#endif
|
||||||
7
src/internal/errno.c
Normal file
7
src/internal/errno.c
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include <errno.h>
|
||||||
|
#include "libc.h"
|
||||||
|
|
||||||
|
int *__errno_location(void)
|
||||||
|
{
|
||||||
|
return &__errno;
|
||||||
|
}
|
||||||
23
src/internal/libc.c
Normal file
23
src/internal/libc.c
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#include "libc.h"
|
||||||
|
|
||||||
|
/* Initial memory pool — small bump arena for early development.
|
||||||
|
* When the PM-actor path is wired this will request memory via
|
||||||
|
* elyz_kcall with ELYZ_OP_ALLOCATE.
|
||||||
|
*/
|
||||||
|
#define EARLY_HEAP_SIZE (64UL * 1024 * 1024)
|
||||||
|
static unsigned char __early_heap[EARLY_HEAP_SIZE];
|
||||||
|
|
||||||
|
struct __libc __libc = {
|
||||||
|
.heap_base = (unsigned long)__early_heap,
|
||||||
|
.heap_size = EARLY_HEAP_SIZE,
|
||||||
|
.heap_used = 0,
|
||||||
|
.threaded = 0,
|
||||||
|
.progname = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
int __errno = 0;
|
||||||
|
|
||||||
|
void __libc_init(void)
|
||||||
|
{
|
||||||
|
/* Future: read startup_info from loader, wire capabilities */
|
||||||
|
}
|
||||||
28
src/internal/libc.h
Normal file
28
src/internal/libc.h
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#ifndef _ELIBC_INTERNAL_LIBC_H
|
||||||
|
#define _ELIBC_INTERNAL_LIBC_H
|
||||||
|
|
||||||
|
/* Internal libc state.
|
||||||
|
*
|
||||||
|
* This structure is the single global anchor for elibc. Fields are added
|
||||||
|
* as the kernel ABI stabilises (e.g. CNode root, PM router channel pool,
|
||||||
|
* initial capability tokens).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <arch/generic/startup_info.h>
|
||||||
|
|
||||||
|
struct __libc {
|
||||||
|
/* Initial pool — bump-allocated until the PM-actor path is wired */
|
||||||
|
unsigned long heap_base;
|
||||||
|
unsigned long heap_size;
|
||||||
|
unsigned long heap_used;
|
||||||
|
|
||||||
|
int threaded;
|
||||||
|
char *progname;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct __libc __libc;
|
||||||
|
extern int __errno;
|
||||||
|
|
||||||
|
void __libc_init(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
52
src/internal/malloc.c
Normal file
52
src/internal/malloc.c
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
/* Bump allocator on the initial memory pool.
|
||||||
|
*
|
||||||
|
* Temporary — until the PM-actor malloc path is implemented.
|
||||||
|
* Thread-safe: no — __libc.heap_used is guarded by nothing yet.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include "libc.h"
|
||||||
|
|
||||||
|
void *malloc(size_t size)
|
||||||
|
{
|
||||||
|
if (size == 0) size = 1;
|
||||||
|
|
||||||
|
unsigned long heap = __libc.heap_base;
|
||||||
|
unsigned long used = __libc.heap_used;
|
||||||
|
|
||||||
|
if (used + size > __libc.heap_size)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
void *ptr = (void *)(heap + used);
|
||||||
|
__libc.heap_used = used + size;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void free(void *ptr)
|
||||||
|
{
|
||||||
|
(void)ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *calloc(size_t nmemb, size_t size)
|
||||||
|
{
|
||||||
|
size_t total = nmemb * size;
|
||||||
|
void *p = malloc(total);
|
||||||
|
if (!p) return 0;
|
||||||
|
for (size_t i = 0; i < total; i++)
|
||||||
|
((unsigned char *)p)[i] = 0;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *realloc(void *ptr, size_t size)
|
||||||
|
{
|
||||||
|
if (!ptr) return malloc(size);
|
||||||
|
if (size == 0) { free(ptr); return 0; }
|
||||||
|
/* Bump allocator cannot shrink/grow in place — always allocate + copy */
|
||||||
|
void *newp = malloc(size);
|
||||||
|
if (!newp) return 0;
|
||||||
|
unsigned long old = __libc.heap_used - size;
|
||||||
|
if (old > __libc.heap_used) old = __libc.heap_used;
|
||||||
|
for (size_t i = 0; i < old; i++)
|
||||||
|
((unsigned char *)newp)[i] = ((unsigned char *)ptr)[i];
|
||||||
|
return newp;
|
||||||
|
}
|
||||||
11
src/string/memcmp.c
Normal file
11
src/string/memcmp.c
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int memcmp(const void *vl, const void *vr, size_t n)
|
||||||
|
{
|
||||||
|
const unsigned char *l = vl, *r = vr;
|
||||||
|
for (size_t i = 0; i < n; i++) {
|
||||||
|
if (l[i] != r[i])
|
||||||
|
return l[i] - r[i];
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
10
src/string/memcpy.c
Normal file
10
src/string/memcpy.c
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void *memcpy(void *restrict dest, const void *restrict src, size_t n)
|
||||||
|
{
|
||||||
|
unsigned char *d = dest;
|
||||||
|
const unsigned char *s = src;
|
||||||
|
for (size_t i = 0; i < n; i++)
|
||||||
|
d[i] = s[i];
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
9
src/string/memset.c
Normal file
9
src/string/memset.c
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void *memset(void *dest, int c, size_t n)
|
||||||
|
{
|
||||||
|
unsigned char *d = dest;
|
||||||
|
for (size_t i = 0; i < n; i++)
|
||||||
|
d[i] = (unsigned char)c;
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
7
src/string/strcmp.c
Normal file
7
src/string/strcmp.c
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int strcmp(const char *l, const char *r)
|
||||||
|
{
|
||||||
|
while (*l && *l == *r) l++, r++;
|
||||||
|
return *(unsigned char *)l - *(unsigned char *)r;
|
||||||
|
}
|
||||||
8
src/string/strlen.c
Normal file
8
src/string/strlen.c
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
size_t strlen(const char *s)
|
||||||
|
{
|
||||||
|
const char *p = s;
|
||||||
|
while (*p) p++;
|
||||||
|
return p - s;
|
||||||
|
}
|
||||||
33
tests/test_basic.c
Normal file
33
tests/test_basic.c
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
#include <assert.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
/* memcpy */
|
||||||
|
char src[] = "hello world";
|
||||||
|
char dst[64];
|
||||||
|
memcpy(dst, src, 12);
|
||||||
|
dst[12] = 0;
|
||||||
|
assert(strcmp(dst, "hello world") == 0);
|
||||||
|
|
||||||
|
/* strlen */
|
||||||
|
assert(strlen("") == 0);
|
||||||
|
assert(strlen("abc") == 3);
|
||||||
|
|
||||||
|
/* memset */
|
||||||
|
char buf[10];
|
||||||
|
memset(buf, 0xAB, 10);
|
||||||
|
for (int i = 0; i < 10; i++) assert((unsigned char)buf[i] == 0xAB);
|
||||||
|
|
||||||
|
/* memcmp */
|
||||||
|
assert(memcmp("abc", "abc", 3) == 0);
|
||||||
|
assert(memcmp("abc", "abd", 3) < 0);
|
||||||
|
|
||||||
|
/* strcmp */
|
||||||
|
assert(strcmp("hello", "hello") == 0);
|
||||||
|
assert(strcmp("abc", "def") < 0);
|
||||||
|
|
||||||
|
printf("ALL STRING TESTS PASSED\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
28
tests/test_string.c
Normal file
28
tests/test_string.c
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
typedef unsigned long size_t;
|
||||||
|
void *memcpy(void *restrict d, const void *restrict s, size_t n);
|
||||||
|
void *memset(void *d, int c, size_t n);
|
||||||
|
int memcmp(const void *l, const void *r, size_t n);
|
||||||
|
size_t strlen(const char *s);
|
||||||
|
int strcmp(const char *l, const char *r);
|
||||||
|
|
||||||
|
void _start(void)
|
||||||
|
{
|
||||||
|
int code = 0;
|
||||||
|
char src[] = "hello world", dst[64];
|
||||||
|
memcpy(dst, src, 12); dst[12] = 0;
|
||||||
|
if (strcmp(dst, "hello world") != 0) code = 1;
|
||||||
|
else if (strlen("") != 0) code = 2;
|
||||||
|
else if (strlen("abc") != 3) code = 3;
|
||||||
|
else {
|
||||||
|
char buf[10];
|
||||||
|
memset(buf, 0xAB, 10);
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
if ((unsigned char)buf[i] != 0xAB) { code = 4; break; }
|
||||||
|
}
|
||||||
|
if (code == 0 && memcmp("abc", "abc", 3) != 0) code = 5;
|
||||||
|
if (code == 0 && memcmp("abc", "abd", 3) >= 0) code = 6;
|
||||||
|
if (code == 0 && strcmp("hello", "hello") != 0) code = 7;
|
||||||
|
if (code == 0 && strcmp("abc", "def") >= 0) code = 8;
|
||||||
|
|
||||||
|
__asm__ volatile ("mov $60, %%eax\n syscall" : : "D"(code) : "rax");
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user