Browse Source

blib wip

master
Mathieu Serandour 6 months ago
parent
commit
8aae31fc60
  1. 47
      blib/Makefile
  2. BIN
      blib/blib.a
  3. 15
      blib/include/alloc.h
  4. 175
      blib/include/dirent.h
  5. 51
      blib/include/string.h
  6. 722
      blib/include/unistd.h
  7. 406
      blib/src/alloc.c
  8. 12
      blib/src/dirent.c
  9. 353
      blib/src/string.c
  10. 13
      blib/src/syscall.s
  11. 262
      blib/src/unistd.c

47
blib/Makefile

@ -0,0 +1,47 @@
.PHONY: all clean
BIN_FILE:=blib.a
CC := x86_64-elf-gcc
AR := x86_64-elf-ar
LD := x86_64-elf-ld
ASM:=nasm
CFLAGS := -O3 -mgeneral-regs-only \
-ffreestanding -Iinclude/ -fno-pie -fno-stack-protector
LDFLAGS := -shared -fno-pie
ARFLAGS:=rc
ASM_FLAGS := -felf64
CFILES :=$(shell find src -name "*.c")
SFILES :=$(shell find src -name "*.s")
OBJ := $(SFILES:.s=.s.o) \
$(CFILES:.c=.c.o)
all: $(BIN_FILE)
%.c.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
%.s.o: %.s
$(ASM) $(ASM_FLAGS) $< -o $@
$(BIN_FILE): $(OBJ)
# $(LD) $(LDFLAGS) $(OBJ) -o $(BIN_FILE)
$(AR) $(ARFLAGS) $(BIN_FILE) $(OBJ)
# ranlib $(BIN_FILE)
clean:
rm -rf $(OBJ) *.a *.elf

BIN
blib/blib.a

Binary file not shown.

15
blib/include/alloc.h

@ -0,0 +1,15 @@
#pragma once
#include <stddef.h>
/**
* this file includes alloc functions:
* - malloc
* - realloc
* - free
*
*/
void* malloc(size_t size);
void free(void* p);
void* realloc(void* ptr, size_t size);

175
blib/include/dirent.h

@ -0,0 +1,175 @@
/* Copyright (C) 1991-2021 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */
/*
* POSIX Standard: 5.1.2 Directory Operations <dirent.h>
*/
#ifndef _DIRENT_H
#define _DIRENT_H 1
#ifdef ISSOU_CA_DOIT_PAS_ETRE_DEFINI_CA
#include "unistd.h"
typedef unsigned long long ino_t;
struct dirent {
ino_t d_ino;
off_t d_off;
unsigned short int d_reclen;
unsigned char d_type;
char d_name[256]; /* We must not include limits.h! */
};
typedef struct DIR DIR;
/* File types for `d_type'. */
enum
{
DT_UNKNOWN = 0,
# define DT_UNKNOWN DT_UNKNOWN
DT_FIFO = 1,
# define DT_FIFO DT_FIFO
DT_CHR = 2,
# define DT_CHR DT_CHR
DT_DIR = 4,
# define DT_DIR DT_DIR
DT_BLK = 6,
# define DT_BLK DT_BLK
DT_REG = 8,
# define DT_REG DT_REG
DT_LNK = 10,
# define DT_LNK DT_LNK
DT_SOCK = 12,
# define DT_SOCK DT_SOCK
DT_WHT = 14
# define DT_WHT DT_WHT
};
/* Convert between stat structure types and directory types. */
// # define IFTODT(mode) (((mode) & 0170000) >> 12)
// # define DTTOIF(dirtype) ((dirtype) << 12)
/* This is the data type of directory stream objects.
The actual structure is opaque to users. */
/* Open a directory stream on NAME.
Return a DIR stream on the directory, or NULL if it could not be opened.
This function is a possible cancellation point and therefore not
marked with __THROW. */
extern DIR *opendir (const char *__name);
/* Same as opendir, but open the stream on the file descriptor FD.
This function is a possible cancellation point and therefore not
marked with __THROW. */
//extern DIR *fdopendir (int __fd);
/* Close the directory stream DIRP.
Return 0 if successful, -1 if not.
This function is a possible cancellation point and therefore not
marked with __THROW. */
extern int closedir (DIR *__dirp);
/* Read a directory entry from DIRP. Return a pointer to a `struct
dirent' describing the entry, or NULL for EOF or error. The
storage returned may be overwritten by a later readdir call on the
same DIR stream.
If the Large File Support API is selected we have to use the
appropriate interface.
This function is a possible cancellation point and therefore not
marked with __THROW. */
extern struct dirent *readdir (DIR *__dirp);
/* Rewind DIRP to the beginning of the directory. */
extern void rewinddir (DIR *__dirp) __THROW;
/* Seek to position POS on DIRP. */
extern void seekdir (DIR *__dirp, long int __pos) __THROW;
/* Return the current position of DIRP. */
extern long int telldir (DIR *__dirp) __THROW;
/* Return the file descriptor used by DIRP. */
extern int dirfd (DIR *__dirp) __THROW;
/* `MAXNAMLEN' is the BSD name for what POSIX calls `NAME_MAX'. */
#ifdef NAME_MAX
# define MAXNAMLEN NAME_MAX
#else
# define MAXNAMLEN 255
#endif
#define __need_size_t
#include <stddef.h>
/* Scan the directory DIR, calling SELECTOR on each directory entry.
Entries for which SELECT returns nonzero are individually malloc'd,
sorted using qsort with CMP, and collected in a malloc'd array in
*NAMELIST. Returns the number of entries selected, or -1 on error.
This function is a cancellation point and therefore not marked with
__THROW. */
# ifndef __USE_FILE_OFFSET64
extern int scandir (const char *__restrict __dir,
struct dirent ***__restrict __namelist,
int (*__selector) (const struct dirent *),
int (*__cmp) (const struct dirent **,
const struct dirent **));
/* Similar to `scandir' but a relative DIR name is interpreted relative
to the directory for which DFD is a descriptor.
This function is a cancellation point and therefore not marked with
__THROW. */
extern int scandirat (int __dfd, const char *__restrict __dir,
struct dirent ***__restrict __namelist,
int (*__selector) (const struct dirent *),
int (*__cmp) (const struct dirent **,
const struct dirent **))
__nonnull ((2, 3));
/* Read directory entries from FD into BUF, reading at most NBYTES.
Reading starts at offset *BASEP, and *BASEP is updated with the new
position after reading. Returns the number of bytes read; zero when at
end of directory; or -1 for errors. */
extern __ssize_t getdirentries (int __fd, char *__restrict __buf,
size_t __nbytes,
__off_t *__restrict __basep)
__THROW __nonnull ((2, 4));
#endif
#endif /* dirent.h */
#endif /* dirent.h */

51
blib/include/string.h

@ -0,0 +1,51 @@
#ifndef KSTRING_H
#define KSTRING_H
#include <stdint.h>
#include <stddef.h>
#ifndef __ATTR_PURE__
#define __ATTR_PURE__ __attribute__((__pure__))
#endif
void * memccpy (void * __restrict__, const void * __restrict__, int, size_t);
const void * memchr (const void *, int, size_t) __ATTR_PURE__;
int memcmp (const void *, const void *, size_t) __ATTR_PURE__;
void * memcpy (void * __restrict__, const void * __restrict__, size_t);
void * memset (void *, int, size_t);
//void * memmem (const void *, size_t, const void *, size_t) __ATTR_PURE__;
void * memmove (void *, const void *, size_t);
//void * memrchr (const void *, int, size_t) __ATTR_PURE__;
size_t strlen (const char* str) __ATTR_PURE__;
size_t strnlen(const char* str, size_t n) __ATTR_PURE__;
int strcmp (const char* str1, const char* str2) __ATTR_PURE__;
int strncmp(const char* str1, const char* str2, size_t n) __ATTR_PURE__;
const char* strchr (const char *s, int c) __ATTR_PURE__;
const char* strrchr(const char *s, int c) __ATTR_PURE__;
const char* strstr(const char *haystack, const char *needle) __ATTR_PURE__;
char* strcpy (char* __restrict__ dst, const char* __restrict__ src);
char* strncpy(char* __restrict__ dst, const char* __restrict__ src, size_t n);
char* strcat(char * __restrict__ dest, const char * __restrict__ src);
char* strncat(char * __restrict__ dest, const char * __restrict__ src, size_t n);
char* strtok(char* __restrict__ str, const char* __restrict__ delim);
char* strtok_r(char* __restrict__ str, const char* __restrict__ delim, char** __restrict__ saveptr);
// return 0 if the check sum is 0
// this is equivalent to memsum(table, size) == 0
int checksum(const void* table, size_t size);
int memsum(const void* ptr, size_t size);
#endif//KSTRING_H

722
blib/include/unistd.h

@ -0,0 +1,722 @@
#ifndef _UNISTD_H
#define _UNISTD_H 1
#include <stdint.h>
#include <stddef.h>
/* Get values of POSIX options:
If these symbols are defined, the corresponding features are
always available. If not, they may be available sometimes.
The current values can be obtained with `sysconf'.
_POSIX_JOB_CONTROL Job control is supported.
_POSIX_SAVED_IDS Processes have a saved set-user-ID
and a saved set-group-ID.
_POSIX_REALTIME_SIGNALS Real-time, queued signals are supported.
_POSIX_PRIORITY_SCHEDULING Priority scheduling is supported.
_POSIX_TIMERS POSIX.4 clocks and timers are supported.
_POSIX_ASYNCHRONOUS_IO Asynchronous I/O is supported.
_POSIX_PRIORITIZED_IO Prioritized asynchronous I/O is supported.
_POSIX_SYNCHRONIZED_IO Synchronizing file data is supported.
_POSIX_FSYNC The fsync function is present.
_POSIX_MAPPED_FILES Mapping of files to memory is supported.
_POSIX_MEMLOCK Locking of all memory is supported.
_POSIX_MEMLOCK_RANGE Locking of ranges of memory is supported.
_POSIX_MEMORY_PROTECTION Setting of memory protections is supported.
_POSIX_MESSAGE_PASSING POSIX.4 message queues are supported.
_POSIX_SEMAPHORES POSIX.4 counting semaphores are supported.
_POSIX_SHARED_MEMORY_OBJECTS POSIX.4 shared memory objects are supported.
_POSIX_THREADS POSIX.1c pthreads are supported.
_POSIX_THREAD_ATTR_STACKADDR Thread stack address attribute option supported.
_POSIX_THREAD_ATTR_STACKSIZE Thread stack size attribute option supported.
_POSIX_THREAD_SAFE_FUNCTIONS Thread-safe functions are supported.
_POSIX_THREAD_PRIORITY_SCHEDULING
POSIX.1c thread execution scheduling supported.
_POSIX_THREAD_PRIO_INHERIT Thread priority inheritance option supported.
_POSIX_THREAD_PRIO_PROTECT Thread priority protection option supported.
_POSIX_THREAD_PROCESS_SHARED Process-shared synchronization supported.
_POSIX_PII Protocol-independent interfaces are supported.
_POSIX_PII_XTI XTI protocol-indep. interfaces are supported.
_POSIX_PII_SOCKET Socket protocol-indep. interfaces are supported.
_POSIX_PII_INTERNET Internet family of protocols supported.
_POSIX_PII_INTERNET_STREAM Connection-mode Internet protocol supported.
_POSIX_PII_INTERNET_DGRAM Connectionless Internet protocol supported.
_POSIX_PII_OSI ISO/OSI family of protocols supported.
_POSIX_PII_OSI_COTS Connection-mode ISO/OSI service supported.
_POSIX_PII_OSI_CLTS Connectionless ISO/OSI service supported.
_POSIX_POLL Implementation supports `poll' function.
_POSIX_SELECT Implementation supports `select' and `pselect'.
_XOPEN_REALTIME X/Open realtime support is available.
_XOPEN_REALTIME_THREADS X/Open realtime thread support is available.
_XOPEN_SHM Shared memory interface according to XPG4.2.
_XBS5_ILP32_OFF32 Implementation provides environment with 32-bit
int, long, pointer, and off_t types.
_XBS5_ILP32_OFFBIG Implementation provides environment with 32-bit
int, long, and pointer and off_t with at least
64 bits.
_XBS5_LP64_OFF64 Implementation provides environment with 32-bit
int, and 64-bit long, pointer, and off_t types.
_XBS5_LPBIG_OFFBIG Implementation provides environment with at
least 32 bits int and long, pointer, and off_t
with at least 64 bits.
If any of these symbols is defined as -1, the corresponding option is not
true for any file. If any is defined as other than -1, the corresponding
option is true for all files. If a symbol is not defined at all, the value
for a specific file can be obtained from `pathconf' and `fpathconf'.
_POSIX_CHOWN_RESTRICTED Only the super user can use `chown' to change
the owner of a file. `chown' can only be used
to change the group ID of a file to a group of
which the calling process is a member.
_POSIX_NO_TRUNC Pathname components longer than
NAME_MAX generate an error.
_POSIX_VDISABLE If defined, if the value of an element of the
`c_cc' member of `struct termios' is
_POSIX_VDISABLE, no character will have the
effect associated with that element.
_POSIX_SYNC_IO Synchronous I/O may be performed.
_POSIX_ASYNC_IO Asynchronous I/O may be performed.
_POSIX_PRIO_IO Prioritized Asynchronous I/O may be performed.
Support for the Large File Support interface is not generally available.
If it is available the following constants are defined to one.
_LFS64_LARGEFILE Low-level I/O supports large files.
_LFS64_STDIO Standard I/O supports large files.
*/
/* Standard file descriptors. */
#define STDIN_FILENO 0 /* Standard input. */
#define STDOUT_FILENO 1 /* Standard output. */
#define STDERR_FILENO 2 /* Standard error output. */
#define __need_size_t
#define __need_NULL
#include <stddef.h>
typedef int pid_t;
// not implemented yet.....
#if 0
/* Values for the second argument to access.
These may be OR'd together. */
#define R_OK 4 /* Test for read permission. */
#define W_OK 2 /* Test for write permission. */
#define X_OK 1 /* Test for execute permission. */
#define F_OK 0 /* Test for existence. */
/* Test for access to NAME using the real UID and real GID. */
extern int access (const char *__name, int __type) __THROW __nonnull ((1));
/* Create a one-way communication channel (pipe).
If successful, two file descriptors are stored in PIPEDES;
bytes written on PIPEDES[1] can be read from PIPEDES[0].
Returns 0 if successful, -1 if not. */
extern int pipe (int __pipedes[2]) __THROW __wur;
/* Schedule an alarm. In SECONDS seconds, the process will get a SIGALRM.
If SECONDS is zero, any currently scheduled alarm will be cancelled.
The function returns the number of seconds remaining until the last
alarm scheduled would have signaled, or zero if there wasn't one.
There is no return value to indicate an error, but you can set `errno'
to 0 and check its value after calling `alarm', and this might tell you.
The signal may come late due to processor scheduling. */
extern unsigned int alarm (unsigned int __seconds) __THROW;
/* Set an alarm to go off (generating a SIGALRM signal) in VALUE
microseconds. If INTERVAL is nonzero, when the alarm goes off, the
timer is reset to go off every INTERVAL microseconds thereafter.
Returns the number of microseconds remaining before the alarm. */
extern __useconds_t ualarm (__useconds_t __value, __useconds_t __interval)
__THROW;
/* Change the owner and group of FILE. */
extern int chown (const char *__file, __uid_t __owner, __gid_t __group)
__THROW __nonnull ((1)) __wur;
//#if defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K8
/* Change the owner and group of the file that FD is open on. */
extern int fchown (int __fd, __uid_t __owner, __gid_t __group) __THROW __wur;
/* Change owner and group of FILE, if it is a symbolic
link the ownership of the symbolic link is changed. */
extern int lchown (const char *__file, __uid_t __owner, __gid_t __group)
__THROW __nonnull ((1)) __wur;
/* Suspend the process until a signal arrives.
This always returns -1 and sets `errno' to EINTR.
This function is a cancellation point and therefore not marked with
__THROW. */
extern int pause (void);
extern int fchdir (int __fd) __THROW __wur;
/* Replace the current process, executing PATH with arguments ARGV and
environment ENVP. ARGV and ENVP are terminated by NULL pointers. */
extern int execve (const char *__path, char *const __argv[],
char *const __envp[]) __THROW __nonnull ((1, 2));
/* Execute the file FD refers to, overlaying the running program image.
ARGV and ENVP are passed to the new program, as for `execve'. */
extern int fexecve (int __fd, char *const __argv[], char *const __envp[])
__THROW __nonnull ((2));
/* Execute PATH with arguments ARGV and environment from `environ'. */
extern int execv (const char *__path, char *const __argv[])
__THROW __nonnull ((1, 2));
/* Execute PATH with all arguments after PATH until a NULL pointer,
and the argument after that for environment. */
extern int execle (const char *__path, const char *__arg, ...)
__THROW __nonnull ((1, 2));
/* Execute PATH with all arguments after PATH until
a NULL pointer and environment from `environ'. */
extern int execl (const char *__path, const char *__arg, ...)
__THROW __nonnull ((1, 2));
/* Execute FILE, searching in the `PATH' environment variable if it contains
no slashes, with arguments ARGV and environment from `environ'. */
extern int execvp (const char *__file, char *const __argv[])
__THROW __nonnull ((1, 2));
/* Execute FILE, searching in the `PATH' environment variable if
it contains no slashes, with all arguments after FILE until a
NULL pointer and environment from `environ'. */
extern int execlp (const char *__file, const char *__arg, ...)
__THROW __nonnull ((1, 2));
/* Get file-specific configuration information about PATH. */
extern long int pathconf (const char *__path, int __name)
__THROW __nonnull ((1));
/* Get file-specific configuration about descriptor FD. */
extern long int fpathconf (int __fd, int __name) __THROW;
/* Get the value of the system variable NAME. */
extern long int sysconf (int __name) __THROW;
/* Get the value of the string-valued system variable NAME. */
extern size_t confstr (int __name, char *__buf, size_t __len) __THROW
__attr_access ((__write_only__, 2, 3));
/* Get the process group ID of the calling process. */
extern __pid_t getpgrp (void) __THROW;
/* Get the process group ID of process PID. */
extern __pid_t __getpgid (__pid_t __pid) __THROW;
extern __pid_t getpgid (__pid_t __pid) __THROW;
/* Set the process group ID of the process matching PID to PGID.
If PID is zero, the current process's process group ID is set.
If PGID is zero, the process ID of the process is used. */
extern int setpgid (__pid_t __pid, __pid_t __pgid) __THROW;
/* Both System V and BSD have `setpgrp' functions, but with different
calling conventions. The BSD function is the same as POSIX.1 `setpgid'
(above). The System V function takes no arguments and puts the calling
process in its on group like `setpgid (0, 0)'.
New programs should always use `setpgid' instead.
GNU provides the POSIX.1 function. */
/* Set the process group ID of the calling process to its own PID.
This is exactly the same as `setpgid (0, 0)'. */
extern int setpgrp (void) __THROW;
/* Create a new session with the calling process as its leader.
The process group IDs of the session and the calling process
are set to the process ID of the calling process, which is returned. */
extern __pid_t setsid (void) __THROW;
/* Return the session ID of the given process. */
extern __pid_t getsid (__pid_t __pid) __THROW;
/* Get the real user ID of the calling process. */
extern __uid_t getuid (void) __THROW;
/* Get the effective user ID of the calling process. */
extern __uid_t geteuid (void) __THROW;
/* Get the real group ID of the calling process. */
extern __gid_t getgid (void) __THROW;
/* Get the effective group ID of the calling process. */
extern __gid_t getegid (void) __THROW;
/* If SIZE is zero, return the number of supplementary groups
the calling process is in. Otherwise, fill in the group IDs
of its supplementary groups in LIST and return the number written. */
extern int getgroups (int __size, __gid_t __list[]) __THROW __wur
__attr_access ((__write_only__, 2, 1));
/* Set the user ID of the calling process to UID.
If the calling process is the super-user, set the real
and effective user IDs, and the saved set-user-ID to UID;
if not, the effective user ID is set to UID. */
extern int setuid (__uid_t __uid) __THROW __wur;
/* Set the group ID of the calling process to GID.
If the calling process is the super-user, set the real
and effective group IDs, and the saved set-group-ID to GID;
if not, the effective group ID is set to GID. */
extern int setgid (__gid_t __gid) __THROW __wur;
/* Set the real group ID of the calling process to RGID,
and the effective group ID of the calling process to EGID. */
extern int setregid (__gid_t __rgid, __gid_t __egid) __THROW __wur;
/* Set the effective group ID of the calling process to GID. */
extern int setegid (__gid_t __gid) __THROW __wur;
/* Fetch the real user ID, effective user ID, and saved-set user ID,
of the calling process. */
extern int getresuid (__uid_t *__ruid, __uid_t *__euid, __uid_t *__suid)
__THROW;
/* Fetch the real group ID, effective group ID, and saved-set group ID,
of the calling process. */
extern int getresgid (__gid_t *__rgid, __gid_t *__egid, __gid_t *__sgid)
__THROW;
/* Set the real user ID, effective user ID, and saved-set user ID,
of the calling process to RUID, EUID, and SUID, respectively. */
extern int setresuid (__uid_t __ruid, __uid_t __euid, __uid_t __suid)
__THROW __wur;
/* Set the real group ID, effective group ID, and saved-set group ID,
of the calling process to RGID, EGID, and SGID, respectively. */
extern int setresgid (__gid_t __rgid, __gid_t __egid, __gid_t __sgid)
__THROW __wur;
/* Clone the calling process, creating an exact copy.
Return -1 for errors, 0 to the new process,
and the process ID of the new process to the old process. */
extern __pid_t fork (void) __THROWNL;
/* Clone the calling process, but without copying the whole address space.
The calling process is suspended until the new process exits or is
replaced by a call to `execve'. Return -1 for errors, 0 to the new process,
and the process ID of the new process to the old process. */
extern __pid_t vfork (void) __THROW;
/* Return the pathname of the terminal FD is open on, or NULL on errors.
The returned storage is good only until the next call to this function. */
extern char *ttyname (int __fd) __THROW;
/* Store at most BUFLEN characters of the pathname of the terminal FD is
open on in BUF. Return 0 on success, otherwise an error number. */
extern int ttyname_r (int __fd, char *__buf, size_t __buflen)
__THROW __nonnull ((2)) __wur __attr_access ((__write_only__, 2, 3));
/* Return 1 if FD is a valid descriptor associated
with a terminal, zero if not. */
extern int isatty (int __fd) __THROW;
/* Return the index into the active-logins file (utmp) for
the controlling terminal. */
extern int ttyslot (void) __THROW;
/* Make a link to FROM named TO. */
extern int link (const char *__from, const char *__to)
__THROW __nonnull ((1, 2)) __wur;
/* Like link but relative paths in TO and FROM are interpreted relative
to FROMFD and TOFD respectively. */
extern int linkat (int __fromfd, const char *__from, int __tofd,
const char *__to, int __flags)
__THROW __nonnull ((2, 4)) __wur;
/* Make a symbolic link to FROM named TO. */
extern int symlink (const char *__from, const char *__to)
__THROW __nonnull ((1, 2)) __wur;
/* Read the contents of the symbolic link PATH into no more than
LEN bytes of BUF. The contents are not null-terminated.
Returns the number of characters read, or -1 for errors. */
extern ssize_t readlink (const char *__restrict __path,
char *__restrict __buf, size_t __len)
__THROW __nonnull ((1, 2)) __wur __attr_access ((__write_only__, 2, 3));
/* Like symlink but a relative path in TO is interpreted relative to TOFD. */
extern int symlinkat (const char *__from, int __tofd,
const char *__to) __THROW __nonnull ((1, 3)) __wur;
/* Like readlink but a relative PATH is interpreted relative to FD. */
extern ssize_t readlinkat (int __fd, const char *__restrict __path,
char *__restrict __buf, size_t __len)
__THROW __nonnull ((2, 3)) __wur __attr_access ((__write_only__, 3, 4));
/* Remove the link NAME. */
extern int unlink (const char *__name) __THROW __nonnull ((1));
/* Remove the link NAME relative to FD. */
extern int unlinkat (int __fd, const char *__name, int __flag)
__THROW __nonnull ((2));
/* Remove the directory PATH. */
extern int rmdir (const char *__path) __THROW __nonnull ((1));
/* Return the foreground process group ID of FD. */
extern __pid_t tcgetpgrp (int __fd) __THROW;
/* Set the foreground process group ID of FD set PGRP_ID. */
extern int tcsetpgrp (int __fd, __pid_t __pgrp_id) __THROW;
/* Return the login name of the user.
This function is a possible cancellation point and therefore not
marked with __THROW. */
extern char *getlogin (void);
/* Return at most NAME_LEN characters of the login name of the user in NAME.
If it cannot be determined or some other error occurred, return the error
code. Otherwise return 0.
This function is a possible cancellation point and therefore not
marked with __THROW. */
extern int getlogin_r (char *__name, size_t __name_len) __nonnull ((1))
__attr_access ((__write_only__, 1, 2));
/* Set the login name returned by `getlogin'. */
extern int setlogin (const char *__name) __THROW __nonnull ((1));
/* Put the name of the current host in no more than LEN bytes of NAME.
The result is null-terminated if LEN is large enough for the full
name and the terminator. */
extern int gethostname (char *__name, size_t __len) __THROW __nonnull ((1))
__attr_access ((__write_only__, 1, 2));
/* Set the name of the current host to NAME, which is LEN bytes long.
This call is restricted to the super-user. */
extern int sethostname (const char *__name, size_t __len)
__THROW __nonnull ((1)) __wur __attr_access ((__read_only__, 1, 2));
/* Set the current machine's Internet number to ID.
This call is restricted to the super-user. */
extern int sethostid (long int __id) __THROW __wur;
/* Get and set the NIS (aka YP) domain name, if any.
Called just like `gethostname' and `sethostname'.
The NIS domain name is usually the empty string when not using NIS. */
extern int getdomainname (char *__name, size_t __len)
__THROW __nonnull ((1)) __wur __attr_access ((__write_only__, 1, 2));
extern int setdomainname (const char *__name, size_t __len)
__THROW __nonnull ((1)) __wur __attr_access ((__read_only__, 1, 2));
/* Revoke access permissions to all processes currently communicating
with the control terminal, and then send a SIGHUP signal to the process
group of the control terminal. */
extern int vhangup (void) __THROW;
/* Revoke the access of all descriptors currently open on FILE. */
extern int revoke (const char *__file) __THROW __nonnull ((1)) __wur;
/* Enable statistical profiling, writing samples of the PC into at most
SIZE bytes of SAMPLE_BUFFER; every processor clock tick while profiling
is enabled, the system examines the user PC and increments
SAMPLE_BUFFER[((PC - OFFSET) / 2) * SCALE / 65536]. If SCALE is zero,
disable profiling. Returns zero on success, -1 on error. */
extern int profil (unsigned short int *__sample_buffer, size_t __size,
size_t __offset, unsigned int __scale)
__THROW __nonnull ((1));
/* Turn accounting on if NAME is an existing file. The system will then write
a record for each process as it terminates, to this file. If NAME is NULL,
turn accounting off. This call is restricted to the super-user. */
extern int acct (const char *__name) __THROW;
/* Successive calls return the shells listed in `/etc/shells'. */
extern char *getusershell (void) __THROW;
extern void endusershell (void) __THROW; /* Discard cached info. */
extern void setusershell (void) __THROW; /* Rewind and re-read the file. */
/* Put the program in the background, and dissociate from the controlling
terminal. If NOCHDIR is zero, do `chdir ("/")'. If NOCLOSE is zero,
redirects stdin, stdout, and stderr to /dev/null. */
extern int daemon (int __nochdir, int __noclose) __THROW __wur;
/* Make PATH be the root directory (the starting point for absolute paths).
This call is restricted to the super-user. */
extern int chroot (const char *__path) __THROW __nonnull ((1)) __wur;
/* Prompt with PROMPT and read a string from the terminal without echoing.
Uses /dev/tty if possible; otherwise stderr and stdin. */
extern char *getpass (const char *__prompt) __nonnull ((1));
/* Make all changes done to FD actually appear on disk.
This function is a cancellation point and therefore not marked with
__THROW. */
extern int fsync (int __fd);
/* Return identifier for the current host. */
extern long int gethostid (void);
/* Make all changes done to all files actually appear on disk. */
extern void sync (void) __THROW;
/* Return the maximum number of file descriptors
the current process could possibly have. */
extern int getdtablesize (void) __THROW;
/* Truncate FILE to LENGTH bytes. */
extern int truncate (const char *__file, __off_t __length)
__THROW __nonnull ((1)) __wur;
/* Truncate the file FD is open on to LENGTH bytes. */
extern int ftruncate (int __fd, __off_t __length) __THROW __wur;
/* NOTE: These declarations also appear in <fcntl.h>; be sure to keep both
files consistent. Some systems have them there and some here, and some
software depends on the macros being defined without including both. */
/* `lockf' is a simpler interface to the locking facilities of `fcntl'.
LEN is always relative to the current file position.
The CMD argument is one of the following.
This function is a cancellation point and therefore not marked with
__THROW. */
# define F_ULOCK 0 /* Unlock a previously locked region. */
# define F_LOCK 1 /* Lock a region for exclusive use. */
# define F_TLOCK 2 /* Test and lock a region for exclusive use. */
# define F_TEST 3 /* Test a region for other processes locks. */
extern int lockf (int __fd, int __cmd, __off_t __len) __wur;
/* Synchronize at least the data part of a file with the underlying
media. */
extern int fdatasync (int __fildes);
/* One-way hash PHRASE, returning a string suitable for storage in the
user database. SALT selects the one-way function to use, and
ensures that no two users' hashes are the same, even if they use
the same passphrase. The return value points to static storage
which will be overwritten by the next call to crypt. */
extern char *crypt (const char *__key, const char *__salt)
__THROW __nonnull ((1, 2));
/* Swab pairs bytes in the first N bytes of the area pointed to by
FROM and copy the result to TO. The value of TO must not be in the
range [FROM - N + 1, FROM - 1]. If N is odd the first byte in FROM
is without partner. */
extern void swab (const void *__restrict __from, void *__restrict __to,
ssize_t __n) __THROW __nonnull ((1, 2))
__attr_access ((__read_only__, 1, 3))
__attr_access ((__write_only__, 2, 3));
/* Return the name of the controlling terminal. */
extern char *ctermid (char *__s) __THROW;
/* Return the name of the current user. */
extern char *cuserid (char *__s);
extern int pthread_atfork (void (*__prepare) (void),
void (*__parent) (void),
void (*__child) (void)) __THROW;
/* Write LENGTH bytes of randomness starting at BUFFER. Return 0 on
success or -1 on error. */
int getentropy (void *__buffer, size_t __length) __wur
__attr_access ((__write_only__, 1, 2));
#endif
typedef uint64_t off_t;
/* Values for the WHENCE argument to lseek. */
# define SEEK_SET 0 /* Seek from beginning of file. */
# define SEEK_CUR 1 /* Seek from current position. */
# define SEEK_END 2 /* Seek from end of file. */
extern off_t lseek (int __fd, int64_t __offset, int __whence);
extern int close (int __fd);
/* Read NBYTES into BUF from FD. Return the
number read, -1 for errors or 0 for EOF.
*/
extern size_t read (int __fd, void *__buf, size_t __nbytes);
/* Write N bytes of BUF to FD. Return the number written, or -1.
This function is a cancellation point and therefore not marked with
__THROW. */
extern size_t write (int __fd, const void *__buf, size_t __n);
/* Read NBYTES into BUF from FD at the given position OFFSET without
changing the file pointer. Return the number read, -1 for errors
or 0 for EOF.
This function is a cancellation point and therefore not marked with
__THROW. */
extern size_t pread (int fd, void* buf, size_t nbytes, off_t offset);
/* Write N bytes of BUF to FD at the given position OFFSET without
changing the file pointer. Return the number written, or -1.
This function is a cancellation point and therefore not marked with
__THROW. */
extern size_t pwrite (int fd, const void* buf, size_t n, off_t offset);
/* Make the process sleep for SECONDS seconds, or until a signal arrives
and is not ignored. The function returns the number of seconds less
than SECONDS which it actually slept (thus zero if it slept the full time).
If a signal handler does a `longjmp' or modifies the handling of the
SIGALRM signal while inside `sleep' call, the handling of the SIGALRM
signal afterwards is undefined. There is no return value to indicate
error, but if `sleep' returns SECONDS, it probably didn't work.
This function is a cancellation point and therefore not marked with
__THROW. */
extern unsigned int sleep (unsigned int __seconds);
/* Sleep USECONDS microseconds, or until a signal arrives that is not blocked
or ignored.
This function is a cancellation point and therefore not marked with
__THROW. */
extern int usleep (uint64_t __useconds);
/* NULL-terminated array of "NAME=VALUE" environment variables. */
extern char **__environ;
/* Terminate program execution with the low-order 8 bits of STATUS. */
extern void _exit (int __status) __attribute__ ((__noreturn__));
/* Return the number of bytes in a page. This is the system's page size,
which is not necessarily the same as the hardware page size. */
extern int getpagesize (void) __attribute__ ((__const__));
/* Set the end of accessible data space (aka "the break") to ADDR.
Returns zero on success and -1 for errors (with errno set). */
extern int brk (void *__addr);
/* Increase or decrease the end of accessible data space by DELTA bytes.
If successful, returns the address the previous end of data space
(i.e. the beginning of the new space, if DELTA > 0);
returns (void *) -1 for errors (with errno set). */
extern void *sbrk (uint64_t __delta);
/*
return 0 if successfull, -1 if error
*/
extern int forkexec(const char* cmdline);
/* Execute PATH with arguments ARGV and environment from `environ'. */
extern int execv (const char *__path, char *const __argv[]);
/* Change the process's working directory to PATH. */
extern int chdir (const char *__path);
/* Get the pathname of the current working directory,
and put it in SIZE bytes of BUF. Returns NULL if the
directory couldn't be determined or SIZE was too small.
If successful, returns BUF. In GNU, if BUF is NULL,
an array is allocated with `malloc'; the array is SIZE
bytes long, unless SIZE == 0, in which case it is as
big as necessary. */
extern char *getcwd (char *__buf, size_t __size);
/* Get the process ID of the calling process. */
extern pid_t getpid (void);
/* Get the process ID of the calling process's parent. */
extern pid_t getppid (void);
/* Invoke `system call' number SYSNO, passing it the remaining arguments.
This is completely system-dependent, and not often useful.
In Unix, `syscall' sets `errno' for all errors and most calls return -1
for errors; in many systems you cannot pass arguments or get return
values for all system calls (`pipe', `fork', and `getppid' typically
among them).
In Mach, all system calls take normal arguments and always return an
error code (zero for success). */
extern uint64_t syscall (long int __sysno, const void* args, size_t args_sz);
/* Duplicate FD, returning a new file descriptor on the same file. */
extern int dup (int __fd);
/* Duplicate FD to FD2, closing FD2 and making it open on the same file. */
extern int dup2 (int __fd, int __fd2);
typedef enum mode_t {
IFDIR = 0x4000,
} mode_t;
int open (const char *pathname, int flags, mode_t mode);
#endif /* unistd.h */

406
blib/src/alloc.c

@ -0,0 +1,406 @@
#include "alloc.h"
#include <unistd.h>
#include <stdint.h>
#include <string.h>
#define MIN_EXPAND_SIZE 4096
#define MIN_SEGMENT_SIZE 32
#define MAX(X,Y) (X >= Y ? X : Y)
typedef struct seg_header {
struct seg_header *next;
uint32_t size;
// boolean variable
uint32_t free;
} seg_header;
#define assert(X)
#define log_heap(X,Y)
// assert that the header is 8-byte alligned
// this is important so that every allocation
// is 8-byte alligned too
_Static_assert(sizeof(seg_header) % 8 == 0, "seg_header must be 8-byte alligned");
// segment headers represent a linked list
// going downward in address space
/**
* 0 | node0
* | ////
* | ////
* | ////
* | node1
* | ////
* | ////
* | ////
* ...
* | nodeN
* | free
* | free
* | free
* BRK ----
*
* node n -> node n-1
*
*
* split:
* node n+1 -> node n
*
* node n+1 -> new_node
* new_node -> node n
* new_node.size = node n.size - SIZE - sizeof(node)
*
*/
// we need to get the heap base address
// with a sbrk call to set this variable
// at runtime
// we could do that with a crt0.S file
static void *heap_begin = NULL;
static size_t heap_size = 0;
static size_t n_allocations = 0;
// sum of the available heap ranges,
// without the last free segment:
// indice of how fragmented
// the heap is
// TODO: use this to unfragment the whole
// heap when this number is too big
//static size_t fragmented_available_size = 0;
static seg_header* current_segment = NULL;
// @todo
#define heap_assert_seg(X)
static void defragment(void);
/**
* expand the heap by size bytes
*/
static int expand_heap(size_t size) {
if(sbrk(size) == (void*)-1) {
// out of memory :(
return -1;
}
// create a new segment in the extra space
seg_header* new_segment = heap_begin + heap_size;
new_segment->next = current_segment;
new_segment->size = size - sizeof(seg_header);
new_segment->free = 1;
current_segment = new_segment;
heap_size += size;
return 0;
}
// O(1) free
void __attribute__((noinline)) free(void *ptr) {
log_heap("free(%lx)", ptr);
seg_header* header = ptr - sizeof(seg_header);
heap_assert_seg(header);
assert(header->free == 0);
header->free = 1;
static int i = 0;
// defragment the heap every N frees
if((i++ % 32) == 0)
defragment();
n_allocations--;
}
/**
* current_segment shouldn't be NULL
*
*/
static void defragment(void) {
assert(current_segment != NULL);
seg_header* pred2 = NULL;
seg_header* pred = current_segment;
for(seg_header* seg = current_segment->next;
seg != NULL;
) {
heap_assert_seg(seg);
/**
* || seg || pred |
* ||
* \/
* || SEG |
*
*
*/
// we can merge these two nodes
if(seg->free && pred->free) {
if(!pred2)
// pred is the head
current_segment = seg;
else
pred2->next = seg;
seg->size += sizeof(seg_header) + pred->size;
// pred2 doesn't change!
pred = seg;
seg = seg->next;
continue;
}
else {
pred2 = pred;
pred = seg;
seg = seg->next;
}
}
}
// return the node preceding the argument
// in the linked list
// O(n) sequential research
static seg_header* find_pred(seg_header* node) {
for(seg_header* seg = current_segment;
seg != NULL;
seg = seg->next) {
if(seg->next == node)
return node;
}
return NULL;
}
// try to merge the node with the next one
// we suppose that the argument is free
static inline void try_merge(seg_header* free_node) {
assert(free_node->free);
seg_header* next = free_node->next;
if(!next)
return;
/*
* insert a new segment between to_split and pred
* return the new segment
*
* | next | free_node |
* | F R E E | F R E E |
* | size1 | size0 |
*
* ||
* \/
*
* | next |
* | F R E E |
* | size0 + size1 |
*
**/
// we can merge!
if(next->free) {
next->size += free_node->size;
// if the argument is the head
// of the list, the head should
// become the
if(free_node == current_segment) {
current_segment = next;
return;
}
// if not, we must find the preceding
// node in the linked list
seg_header* seg = find_pred(free_node);
// now make it point on the
// new merged node which is
// the 'next' node
seg->next = next;
}
}
/*
* insert a new segment between to_split and pred
* return the new segment
* | to_split |
* | F R E E |
* | size0 |
* ||
* \/
*
* | to_split | new |
* | F R E E | F R E E |
* | size |size0-size|
**/
static seg_header* split_segment(seg_header* pred, seg_header* tosplit, size_t size) {
seg_header* new_segment = (void*)tosplit + sizeof(seg_header) + size;
if(pred != NULL)
pred->next = new_segment;
new_segment->next = tosplit;
new_segment->free = 1;
new_segment->size = tosplit->size // size to split
- size // size reserved
- sizeof(seg_header); // new segment header
tosplit->size = size;
return new_segment;
}
void* __attribute__((noinline)) malloc(size_t size) {
if(heap_begin == NULL) {
// initialize the heap
heap_begin = sbrk(0);
heap_size = 0;
}
//assert(current_segment->free == 1);
// align the size to assure that
// the whole structure is alligned
size = ((size + 7 ) / 8) * 8;
if(size < MIN_SEGMENT_SIZE)
size = MIN_SEGMENT_SIZE;
// search for a big enough pool
seg_header* seg = current_segment;
seg_header* pred = NULL;
while(1) {
if(seg == NULL) {
break;
}
heap_assert_seg(seg);
if(!seg->free || seg->size < size) {
// this segment is not right, check the next one
pred = seg;
// keep the preceding node in memory
// we need it when spliting the current
// segment
seg = seg->next;
continue;
}
// we found a satisfying segment!
if(seg->size >= size + sizeof(seg_header) + MIN_SEGMENT_SIZE) {
// we don't take the whole space
// get the inserted segment
seg_header* new_seg = split_segment(pred, seg, size);
if(pred == NULL) {
// seg == current_segment
// the 'current' segment should
// be the last in the list.
// => advance the current one
current_segment = new_seg;
}
else {
// put the new node in the linked list
pred->next = new_seg;
}
// mark seg as allocated,
// leaving the new node free
}
// else, the segment is not big enough to
// be splitted, we mark it allocated as is,
// wasting a bit of memory
seg->free = 0;
// one allocation
n_allocations++;
log_heap(" --> %lx", (void*)seg+sizeof(seg_header));
return (void *)seg + sizeof(seg_header);
}
// no available segment in the heap
// let's expand
if(expand_heap(MAX(size+sizeof(seg_header), MIN_EXPAND_SIZE)) == -1) {
// out of memory
return NULL;
}
// retrty now that we are sure that the memory is avaiable
return malloc(size);
}
// O(n) in case of freeing (size < oldsize)
void* realloc(void* ptr, size_t size) {
if(ptr == NULL)
return malloc(size);
if(size == 0) {
free(ptr);
return NULL;
}
seg_header* header = ptr - sizeof(seg_header);
uint32_t header_size = header->size;
if(size < header_size) {
// its not worth reallocating
if(size > header_size / 2
|| header_size-size < MIN_SEGMENT_SIZE * 2)
return ptr;
}
unsigned cpsize = header_size;
if(cpsize > size)
cpsize = size;
void* new_ptr = malloc(size);
memcpy(new_ptr, ptr, cpsize);
free(ptr);
// malloc increments the number of allocations
// but we just reallocated
// n_allocations--;
return new_ptr;
}

12
blib/src/dirent.c

@ -0,0 +1,12 @@
#include "dirent.h"
typedef struct DIR {
int fd;
struct dirent* dirent;
// struct dirent dirent_buf;
} DIR;
DIR *opendir (const char *__name) {
}

353
blib/src/string.c

@ -0,0 +1,353 @@
#include "string.h"
#include <stdint.h>
size_t strlen(const char* str) {
const char* ptr = str;
int len = 0;
while(*(ptr++) != '\0')
len++;
return len;
}
size_t strnlen(const char* str, size_t n) {
int len = 0;
while(*(str++) != '\0' && n--)
len++;
return len;
}
char* strcpy(char* dst, const char* src) {
char c;
char* pdst = dst;
do {
c = *(src++);
*(pdst++) = c;
}
while(c != '\0');
return dst;
}
char* strncpy(char* dst, const char* src, size_t n) {
char c;
char* pdst = dst;
do {
c = *(src++);
*(pdst++) = c;
n--;
}
while(c != '\0' && n > 0);
if(c != '\0')
*pdst = '\0';
dst = '\0';
return dst;
}
int strcmp(const char* str1, const char* str2) {
int d;
while(1) {
char c1 = *(str1++);
char c2 = *(str2++);
d = c1-c2;
if(!c1 || !c2 || d)
break;
}
return d;
}
int strncmp(const char* str1, const char* str2, size_t n) {
int d = 0;
while(n-- > 0) {
char c1 = *(str1++);
char c2 = *(str2++);
d = c1-c2;
if(!c1 || !c2 || d)
break;
}
return d;
}
const char* strchr (const char *_s, int c) {
const char* s=_s;
char curr;
while(1) {
curr = *s;
if(curr == c)
return s;
else if(curr == '\0')
break;
s++;
}
return NULL;
}
const char* strrchr(const char *s, int c) {
char curr;
const char* found = NULL;
while(1) {
curr = *s;
if(curr == c)
found = s;
else if(curr == '\0')
break;
s++;
}
return found;
}
const char *strstr(const char *haystack, const char *needle) {
int i = 0;
char c, ci;
while(1) {
ci = needle[i];
if(ci == '\0')
return haystack - i - 1;
c = *(haystack++);
if(c == ci)
i++;
else if(c == '\0')
return NULL;
else
i = 0;
}
}
char* strcat(char *dest, const char *src) {
while(*(dest++)) ;
return strcpy(dest-1, src);
}
char *strncat(char *dest, const char *src, size_t n) {
char* ret = dest;
while(*(dest++)) ;
strncpy(--dest, src, n);
return ret;
}
void * memccpy (void* dst, const void *src, int c, size_t n) {
for(; n > 0; n--) {
char d = *(char*)(src++) = *(char*)(dst++);
if(d == c)
return dst;
}
return NULL;
}
const void* memchr (const void *_buf, int _ch, size_t n) {
uint8_t ch = *(uint8_t*)(&_ch);
const