<|start_filename|>include/stdint.h<|end_filename|>
#ifndef _STDINT_H_
#define _STDINT_H_

typedef unsigned char	uint8_t;
typedef unsigned short	uint16_t;
typedef unsigned long	uint32_t;
typedef unsigned long long uint64_t;

typedef char		int8_t;
typedef short		int16_t;
typedef int		int32_t;
typedef long long	int64_t;

#endif


<|start_filename|>include/stdarg.h<|end_filename|>
typedef unsigned char *va_list;

#define va_start(list, param) (list = (va_list)&param + sizeof(param))
#define va_arg(list, type) (* (type *)((list += sizeof(type)) - sizeof(type)))
#define va_end(list)



<|start_filename|>include/stdio.h<|end_filename|>
#ifndef _STDIO_H_
#define _STDIO_H_

#include "stddef.h"

#define NULL 0

#define EOF -1

#define STDIN_FILENO	0
#define STDOUT_FILENO	1
#define STDERR_FILENO	2

#define FOPEN_MAX	255
#define FILENAME_MAX	255

#define SEEK_SET	0
#define SEEK_CURR	1
#define SEEK_END	2

typedef long fpos_t;

typedef struct {
	int fd;
	fpos_t pos;

	char mode;
	char eof;
} FILE;

static const FILE stdout = {
	.fd = 0,
	.pos = 0,
};

static const FILE stdin = {
	.fd = 1,
	.pos = 0,
};

static const FILE stderr = {
	.fd = 2,
	.pos = 0,
};

int printf(const char *restrict format, ...);
char *fgets(char *str, int n, FILE *stream);

FILE *fopen(const char *filename, const char *mode);
int fclose(FILE *stream);

int feof(FILE *stream);
long int ftell(FILE *stream);
int fseek(FILE *stream, long int offset, int whence);

int fgetc(FILE *stream);

void rewind(FILE *stream);

#endif


<|start_filename|>arch/amd64/syscall.asm<|end_filename|>
global syscall

section .text

syscall:
	push rbp
	mov rbp, rsp

	mov rax, rdi ; syscall
	mov rdi, rsi
	mov rsi, rdx
	mov rdx, rcx
	mov r10, r8
	mov r8, r9
	mov r9, [rsp] 	; Copy instead of pop
			; removing an argument if it's not passed in will trash the stack
	syscall

	pop rbp
	ret

section .data


<|start_filename|>tests/brk/test.c<|end_filename|>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <assert.h>

int main()
{
	void *res;
	void *current_brk, *old_brk;
	const size_t offset = 0x1000;

	printf("Checking brk(0) returns -1\n");
	assert(brk(0) == -1);
	printf("PASSED\n\n");

	printf("Checking sbrk(0) returns current break\n");
	current_brk = (void *)(size_t)sbrk(NULL);
	assert(current_brk);
	printf("PASSED\n\n");

	printf("Checking brk(current_brk + offset) returns 0\n");
	res = (void *)(size_t)brk((void *)(current_brk + offset));
	assert(res == 0);
	printf("PASSED\n\n");

	printf("Checking program break was increased\n");
	old_brk = current_brk;
	current_brk = (void *)(size_t)sbrk(NULL);
	printf("old_brk: %p current_brk: %p\n", old_brk, current_brk);
	assert((void *)(old_brk + offset) == current_brk);
	printf("PASSED\n\n");

	printf("Checking sbrk(offset) returned previous break\n");
	old_brk = current_brk;
	res = (void *)(size_t)sbrk(offset);
	assert(res == old_brk);
	printf("PASSED\n\n");

	printf("Checking sbrk(offset) increased program break\n");
	current_brk = (void *)(size_t)sbrk(NULL);
	printf("old_brk: %p, current_brk: %p\n", old_brk, current_brk);
	assert(current_brk >= (old_brk + offset));
	printf("PASSED\n\n");

	return 0;
}


<|start_filename|>src/syscall.h<|end_filename|>
#ifndef _SYSCALL_H_
#define _SYSCALL_H_

#define SYS_read	0
#define SYS_write	1
#define SYS_open	2
#define SYS_close	3
#define SYS_lseek	8

#define SYS_mmap	9
#define SYS_mprotect	10

#define SYS_brk		12

#define SYS_exit	60

#define SYS_fsync 	74
#define SYS_fdatasync 	75

extern long syscall();

#endif


<|start_filename|>arch/amd64/entry.asm<|end_filename|>
global _start

section .text

extern main

_start:
	xor rbp, rbp
	pop rdi
	mov rsi, rsp
	call main

	mov rdi, rax ; Move the return value of main to the error code arg of sys_exit
	mov rax, 60 ; sys_exit
	syscall
	
	


<|start_filename|>src/brk.c<|end_filename|>
#include "stdlib.h"

#include "syscall.h"

int brk(void *addr)
{
	long ret = syscall(SYS_brk, addr);
	if (ret != (long)addr)
		return -1;

	return 0;
}

void *sbrk(size_t increment)
{
	void *current_brk = (void *)syscall(SYS_brk, 0);
	if (!increment) return current_brk;

	if (brk(current_brk + increment) == 0)
		return current_brk;
	
	return (void *)(-1);
}


<|start_filename|>include/stddef.h<|end_filename|>
#ifndef _STDDEF_H_
#define _STDDEF_H_ 1

#define NULL 0

typedef unsigned long size_t;
typedef long ssize_t;
typedef long intptr_t;

#endif


<|start_filename|>Makefile<|end_filename|>
CC = clang
LD = clang
AS = nasm

ARCH=amd64

CFLAGS = -Wall -pipe -Iinclude/ -std=gnu11 -nostdlib -ffreestanding $(OPTIMIZATION)
LFLAGS = $(CFLAGS) -Llib/
ASFLAGS = -f elf64

OPTIMIZATION = -O2

DEBUG = no
ifeq ($(DEBUG), yes)
	CFLAGS += -g
endif

MLIBC_SOURCES = $(wildcard src/*.c)
MLIBC_SOURCES += $(wildcard arch/${ARCH}/*.asm)

TMP_OBJECTS = $(MLIBC_SOURCES:.c=.o)
MLIBC_OBJECTS = $(TMP_OBJECTS:.asm=.o)

LIB_DIR = lib

mlibc: $(MLIBC_OBJECTS)
	ar rcs $(LIB_DIR)/libminimalc.a $(MLIBC_OBJECTS)

%.o: %.c
	$(CC) $(CFLAGS) -c $< -o $@

%.o: %.asm
	$(AS) $(ASFLAGS) $< -o $@

clean:
	find . -type f \( -name "*.o" -o -name "*.a" \) -exec rm {} \;

.PHONY: clean


<|start_filename|>src/string.c<|end_filename|>
#include "stdlib.h"
#include "stdarg.h"
#include "stdio.h"
#include "string.h"

#include "syscall.h"

int vsprintf(char *str, const char *format, va_list arg)
{
	strcpy(str, format);
	return 0;
}

int printf(const char *format, ...)
{
	char str[1024] = {0};

	va_list args;
	va_start(args, format);
	vsprintf(str, format, args);
	va_end(args);

	syscall(SYS_write, stdout.fd, str, strlen(str-1));
	return 0;
}

char *strcat(char *dest, const char *src)
{
	char *dp = dest, *sp = (char *)src;
	while (*(dp+1)) dp++;
	while (*(sp+1)) *(dp++) = *(sp++);
	return dest;
}

char *strchr(const char *s, int c)
{
	while (*s != (char)c)
		if (!*s++) return NULL;

	return (char *)s;
}

int strcmp(const char *a, const char *b)
{
	int pos = 0;
	while (a[pos] != '\0') {
		if (b[pos] == '\0') return 1;
		else if (a[pos] < b[pos]) return -1;
		else if (a[pos] > b[pos]) return 1;
		pos++;
	}

	return 0;
}

char *strcpy(char *dest, const char *src)
{
	int pos = 0;

	while (1) {
		dest[pos] = src[pos];
		if (!dest[pos]) break;
		pos++;
	}

	return dest;
}

char *strncpy(char *dest, const char *src, size_t n)
{
	int pos = 0, pad = 0;

	while (pos < n) {
		if (!pad) {
			dest[pos] = src[pos];
		} else {
			dest[pos] = 0;
		}

		if (!dest[pos])
			pad = 1;
	}

	return dest;
}

size_t strlen(const char *str)
{
	size_t n = 0;
	while (str[n+1]) n++;
	return n;
}

char *strstr(const char *haystack, const char *needle)
{
	char *hpos = (char *)haystack;

	if (!*needle) return (char *)haystack;
	while (*hpos && strlen(hpos) >= strlen(needle)) {
		char *a = hpos, *b = (char *)needle;
		while (*a && *b && *a == *b) {
			a++;
			b++;
		}

		if (*b == '\0')
			return hpos;

		hpos++;
	}

	return NULL;
}

char *strpbrk(const char *haystack, const char *needle)
{
	const char *c1, *c2;
	for (c1 = haystack; *c1 != '\0'; ++c1) {
		for (c2 = needle; *c2 != '\0'; ++c2) {
			if (*c1 == *c2) {
				return (char *)c1;
			}
		}
	}
	return NULL;
}

static char *tok = NULL;
char *strtok(char *str, const char *delim)
{
	char *start, *end;
	start = (str != NULL ? str : tok);
	if (start == NULL)
		return NULL;

	end = strpbrk(start, delim);
	if (end) {
		*end = '\0';
		tok = end + 1;
	} else {
		tok = NULL;
	}
	return start;
}

int ipow(int base, int exp)
{
	int res = 1;
	for (int i = 0; i < exp; i++)
		res *= exp;

	return res;
}

unsigned long int strtoul(const char *nptr, char **endptr, int base)
{
	unsigned long pos = 0, val = 0;

	if (!base)
		base = 10;

	char charset_start = '0', charset_end = '9';

	for (const char *p = nptr; *p; p++) {
		if (*p == ' ' || *p == '\t')
			continue;

		if (!(charset_start <= *p <= charset_end))
			return 0;

		val += (*p - charset_start) * ipow(base, pos);
		++pos;
	}

	return val;
}




<|start_filename|>src/memory.c<|end_filename|>
#include "stdlib.h"
#include "stdint.h"
#include "string.h"

#include "brk.h"

#define ALLOC_INFO_SIZE sizeof(struct alloc_info)
#define info_from_alloc(alloc) (struct alloc_info *)(alloc - sizeof(struct alloc_info))

struct alloc_info {
	size_t size;
};

void *malloc(size_t size)
{
	void *mem = sbrk(size + ALLOC_INFO_SIZE) + ALLOC_INFO_SIZE;
	if ((long)mem == -1)
		return NULL;

	struct alloc_info *header = info_from_alloc(mem);
	header->size = size;

	return (void *)mem;
}


void *calloc(size_t count, size_t size)
{
	void *mem = malloc(count * size);
	if ((long)mem == -1)
		return NULL;

	memset(mem, 0, (count * size));
	return mem;
}

void *realloc(void *p, size_t size)
{
	void *buf = malloc(size);
	if (p != NULL) {
		struct alloc_info *header = info_from_alloc(p);
		memcpy(buf, p, header->size);
	}
	return buf;
}


void free(void *p)
{
}

void *memcpy(void *dest, const void *src, size_t n)
{
	for (int i = 0; i < n; i++)
		((uint8_t *)dest)[i] = ((uint8_t *)src)[i];

	return dest;
}


void *memset(void *s, int c, size_t n)
{
	for (int i = 0; i < n; i++)
		((uint8_t *)s)[i] = (uint8_t)c;

	return s;
}


void *memmove(void *dest, const void *src, size_t n)
{
	char *buf = malloc(n);
	memcpy(buf, src, n);
	memcpy(dest, buf, n);
	free(buf);

	return dest;
}	



<|start_filename|>src/brk.h<|end_filename|>
#ifndef _BRK_H_
#define _BRK_H_ 1

int brk(void *addr);
void *sbrk(intptr_t increment);

#endif
