lib: c: combine libc and ulibc

libc is now made up of several independent components, each of which is individually compiled into a static library.
they are then all combined into a single shared library.
This commit is contained in:
2026-03-06 20:12:58 +00:00
parent 267b893bf4
commit 68714fa0e5
33 changed files with 1695 additions and 8483 deletions

View File

@@ -1,36 +1,30 @@
set(source_dirs string stdio)
foreach (dir ${source_dirs})
file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c)
file(GLOB dir_headers ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.h)
set(sources ${sources} ${dir_sources})
set(headers ${headers} ${dir_headers})
endforeach (dir)
file(GLOB runtime_sources
${CMAKE_CURRENT_SOURCE_DIR}/runtime/${CMAKE_SYSTEM_PROCESSOR}/*.s)
set_property(SOURCE ${runtime_sources} PROPERTY LANGUAGE C)
set(source_dirs core malloc)
set(public_include_dirs
${CMAKE_CURRENT_SOURCE_DIR}/include)
add_subdirectory(runtime)
foreach (dir ${source_dirs})
add_subdirectory(${dir})
set(sources ${sources} ${component_sources})
set(headers ${headers} ${component_headers})
set(public_include_dirs ${public_include_dirs} ${component_public_include_dirs})
endforeach (dir)
rosetta_add_library(SHARED
NAME libc
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
SOURCES ${sources}
HEADERS ${headers})
rosetta_add_object_library(
NAME libc-rt STATIC
SOURCES ${runtime_sources})
sysroot_add_library(
NAME libc
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
sysroot_add_object_library(
NAME libc-rt
LIB_DIR /usr/lib)
bsp_add_library(
NAME libc
LIB_DIR /usr/lib)
target_link_libraries(libc libmango)
target_compile_definitions(libc PRIVATE ENABLE_GLOBAL_HEAP=1)

View File

@@ -0,0 +1,23 @@
set(source_dirs stdio string)
foreach (dir ${source_dirs})
file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c)
file(GLOB dir_headers ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.h)
set(sources ${sources} ${dir_sources})
set(headers ${headers} ${dir_headers})
endforeach (dir)
set(component_sources ${sources} PARENT_SCOPE)
set(component_headers ${headers} PARENT_SCOPE)
rosetta_add_library(STATIC
NAME libc-core
PUBLIC_INCLUDE_DIRS ${public_include_dirs}
SOURCES ${sources}
HEADERS ${headers})
sysroot_add_library(
NAME libc-core
HEADER_DIR /usr/include
LIB_DIR /usr/lib)

View File

@@ -0,0 +1,342 @@
#include <errno.h>
const char *strerror(int errnum)
{
switch (errnum) {
case SUCCESS:
return "Success";
case EPERM:
return "Operation not permitted";
case ENOENT:
return "No such file or directory";
case ESRCH:
return "No such process";
case EINTR:
return "Interrupted system call";
case EIO:
return "Input/output error";
case ENXIO:
return "Device not configured";
case E2BIG:
return "Argument list too long";
case ENOEXEC:
return "Exec format error";
case EBADF:
return "Bad file descriptor";
case ECHILD:
return "No child processes";
case EDEADLK:
return "Resource deadlock avoided";
case ENOMEM:
return "Cannot allocate memory";
case EACCES:
return "Permission denied";
case EFAULT:
return "Bad address";
case ENOTBLK:
return "Block device required";
case EBUSY:
return "Resource busy";
case EEXIST:
return "File exists";
case EXDEV:
return "Cross-device link";
case ENODEV:
return "Operation not supported by device";
case ENOTDIR:
return "Not a directory";
case EISDIR:
return "Is a directory";
case EINVAL:
return "Invalid argument";
case ENFILE:
return "Too many open files in system";
case EMFILE:
return "Too many open files";
case ENOTTY:
return "Inappropriate ioctl for device";
case ETXTBSY:
return "Text file busy";
case EFBIG:
return "File too large";
case ENOSPC:
return "No space left on device";
case ESPIPE:
return "Illegal seek";
case EROFS:
return "Read-only file system";
case EMLINK:
return "Too many links";
case EPIPE:
return "Broken pipe";
case EDOM:
return "Numerical argument out of domain";
case ERANGE:
return "Result too large";
case EAGAIN:
return "Resource temporarily unavailable";
case EINPROGRESS:
return "Operation now in progress";
case EALREADY:
return "Operation already in progress";
case ENOTSOCK:
return "Socket operation on non-socket";
case EDESTADDRREQ:
return "Destination address required";
case EMSGSIZE:
return "Message too long";
case EPROTOTYPE:
return "Protocol wrong type for socket";
case ENOPROTOOPT:
return "Protocol not available";
case EPROTONOSUPPORT:
return "Protocol not supported";
case ESOCKTNOSUPPORT:
return "Socket type not supported";
case ENOTSUP:
return "Operation not supported";
case EPFNOSUPPORT:
return "Protocol family not supported";
case EAFNOSUPPORT:
return "Address family not supported by protocol family";
case EADDRINUSE:
return "Address already in use";
case EADDRNOTAVAIL:
return "Can't assign requested address";
case ENETDOWN:
return "Network is down";
case ENETUNREACH:
return "Network is unreachable";
case ENETRESET:
return "Network dropped connection on reset";
case ECONNABORTED:
return "Software caused connection abort";
case ECONNRESET:
return "Connection reset by peer";
case ENOBUFS:
return "No buffer space available";
case EISCONN:
return "Socket is already connected";
case ENOTCONN:
return "Socket is not connected";
case ESHUTDOWN:
return "Can't send after socket shutdown";
case ETOOMANYREFS:
return "Too many references: can't splice";
case ETIMEDOUT:
return "Operation timed out";
case ECONNREFUSED:
return "Connection refused";
case ELOOP:
return "Too many levels of symbolic links";
case ENAMETOOLONG:
return "File name too long";
case EHOSTDOWN:
return "Host is down";
case EHOSTUNREACH:
return "No route to host";
case ENOTEMPTY:
return "Directory not empty";
case EPROCLIM:
return "Too many processes";
case EUSERS:
return "Too many users";
case EDQUOT:
return "Disc quota exceeded";
case ESTALE:
return "Stale NFS file handle";
case EREMOTE:
return "Too many levels of remote in path";
case EBADRPC:
return "RPC struct is bad";
case ERPCMISMATCH:
return "RPC version wrong";
case EPROGUNAVAIL:
return "RPC prog. not avail";
case EPROGMISMATCH:
return "Program version wrong";
case EPROCUNAVAIL:
return "Bad procedure for program";
case ENOLCK:
return "No locks available";
case ENOSYS:
return "Function not implemented";
case EFTYPE:
return "Inappropriate file type or format";
case EAUTH:
return "Authentication error";
case ENEEDAUTH:
return "Need authenticator";
case EPWROFF:
return "Device power is off";
case EDEVERR:
return "Device error";
case EOVERFLOW:
return "Value too large to be stored in data type";
case EBADEXEC:
return "Bad executable (or shared library)";
case EBADARCH:
return "Bad CPU type in executable";
case ESHLIBVERS:
return "Shared library version mismatch";
case EBADMACHO:
return "Malformed Mach-o file";
case ECANCELED:
return "Operation canceled";
case EIDRM:
return "Identifier removed";
case ENOMSG:
return "No message of desired type";
case EILSEQ:
return "Illegal byte sequence";
case ENOATTR:
return "Attribute not found";
case EBADMSG:
return "Bad message";
case EMULTIHOP:
return "EMULTIHOP (Reserved)";
case ENODATA:
return "No message available on STREAM";
case ENOLINK:
return "ENOLINK (Reserved)";
case ENOSR:
return "No STREAM resources";
case ENOSTR:
return "Not a STREAM";
case EPROTO:
return "Protocol error";
case ETIME:
return "STREAM ioctl timeout";
case EOPNOTSUPP:
return "Operation not supported on socket";
case ENOPOLICY:
return "Policy not found";
case ENOTRECOVERABLE:
return "State not recoverable";
case EOWNERDEAD:
return "Previous owner died";
case EQFULL:
return "Interface output queue is full";
default:
return "Unknown error";
}
}
#define ENUM_STR(x) \
case x: \
return #x
const char *strerror_code(int errnum)
{
switch (errnum) {
ENUM_STR(SUCCESS);
ENUM_STR(EPERM);
ENUM_STR(ENOENT);
ENUM_STR(ESRCH);
ENUM_STR(EINTR);
ENUM_STR(EIO);
ENUM_STR(ENXIO);
ENUM_STR(E2BIG);
ENUM_STR(ENOEXEC);
ENUM_STR(EBADF);
ENUM_STR(ECHILD);
ENUM_STR(EDEADLK);
ENUM_STR(ENOMEM);
ENUM_STR(EACCES);
ENUM_STR(EFAULT);
ENUM_STR(ENOTBLK);
ENUM_STR(EBUSY);
ENUM_STR(EEXIST);
ENUM_STR(EXDEV);
ENUM_STR(ENODEV);
ENUM_STR(ENOTDIR);
ENUM_STR(EISDIR);
ENUM_STR(EINVAL);
ENUM_STR(ENFILE);
ENUM_STR(EMFILE);
ENUM_STR(ENOTTY);
ENUM_STR(ETXTBSY);
ENUM_STR(EFBIG);
ENUM_STR(ENOSPC);
ENUM_STR(ESPIPE);
ENUM_STR(EROFS);
ENUM_STR(EMLINK);
ENUM_STR(EPIPE);
ENUM_STR(EDOM);
ENUM_STR(ERANGE);
ENUM_STR(EAGAIN);
ENUM_STR(EINPROGRESS);
ENUM_STR(EALREADY);
ENUM_STR(ENOTSOCK);
ENUM_STR(EDESTADDRREQ);
ENUM_STR(EMSGSIZE);
ENUM_STR(EPROTOTYPE);
ENUM_STR(ENOPROTOOPT);
ENUM_STR(EPROTONOSUPPORT);
ENUM_STR(ESOCKTNOSUPPORT);
ENUM_STR(ENOTSUP);
ENUM_STR(EPFNOSUPPORT);
ENUM_STR(EAFNOSUPPORT);
ENUM_STR(EADDRINUSE);
ENUM_STR(EADDRNOTAVAIL);
ENUM_STR(ENETDOWN);
ENUM_STR(ENETUNREACH);
ENUM_STR(ENETRESET);
ENUM_STR(ECONNABORTED);
ENUM_STR(ECONNRESET);
ENUM_STR(ENOBUFS);
ENUM_STR(EISCONN);
ENUM_STR(ENOTCONN);
ENUM_STR(ESHUTDOWN);
ENUM_STR(ETOOMANYREFS);
ENUM_STR(ETIMEDOUT);
ENUM_STR(ECONNREFUSED);
ENUM_STR(ELOOP);
ENUM_STR(ENAMETOOLONG);
ENUM_STR(EHOSTDOWN);
ENUM_STR(EHOSTUNREACH);
ENUM_STR(ENOTEMPTY);
ENUM_STR(EPROCLIM);
ENUM_STR(EUSERS);
ENUM_STR(EDQUOT);
ENUM_STR(ESTALE);
ENUM_STR(EREMOTE);
ENUM_STR(EBADRPC);
ENUM_STR(ERPCMISMATCH);
ENUM_STR(EPROGUNAVAIL);
ENUM_STR(EPROGMISMATCH);
ENUM_STR(EPROCUNAVAIL);
ENUM_STR(ENOLCK);
ENUM_STR(ENOSYS);
ENUM_STR(EFTYPE);
ENUM_STR(EAUTH);
ENUM_STR(ENEEDAUTH);
ENUM_STR(EPWROFF);
ENUM_STR(EDEVERR);
ENUM_STR(EOVERFLOW);
ENUM_STR(EBADEXEC);
ENUM_STR(EBADARCH);
ENUM_STR(ESHLIBVERS);
ENUM_STR(EBADMACHO);
ENUM_STR(ECANCELED);
ENUM_STR(EIDRM);
ENUM_STR(ENOMSG);
ENUM_STR(EILSEQ);
ENUM_STR(ENOATTR);
ENUM_STR(EBADMSG);
ENUM_STR(EMULTIHOP);
ENUM_STR(ENODATA);
ENUM_STR(ENOLINK);
ENUM_STR(ENOSR);
ENUM_STR(ENOSTR);
ENUM_STR(EPROTO);
ENUM_STR(ETIME);
ENUM_STR(EOPNOTSUPP);
ENUM_STR(ENOPOLICY);
ENUM_STR(ENOTRECOVERABLE);
ENUM_STR(EOWNERDEAD);
ENUM_STR(EQFULL);
default:
return "";
}
}

142
lib/libc/include/errno.h Normal file
View File

@@ -0,0 +1,142 @@
#ifndef ERRNO_H_
#define ERRNO_H_
#define SUCCESS 0 /* Success */
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* Input/output error */
#define ENXIO 6 /* Device not configured */
#define E2BIG 7 /* Argument list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file descriptor */
#define ECHILD 10 /* No child processes */
#define EDEADLK 11 /* Resource deadlock avoided */
#define ENOMEM 12 /* Cannot allocate memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device / Resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* Operation not supported by device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* Too many open files in system */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Inappropriate ioctl for device */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
/* math software */
#define EDOM 33 /* Numerical argument out of domain */
#define ERANGE 34 /* Result too large */
/* non-blocking and interrupt i/o */
#define EAGAIN 35 /* Resource temporarily unavailable */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define EINPROGRESS 36 /* Operation now in progress */
#define EALREADY 37 /* Operation already in progress */
/* ipc/network software -- argument errors */
#define ENOTSOCK 38 /* Socket operation on non-socket */
#define EDESTADDRREQ 39 /* Destination address required */
#define EMSGSIZE 40 /* Message too long */
#define EPROTOTYPE 41 /* Protocol wrong type for socket */
#define ENOPROTOOPT 42 /* Protocol not available */
#define EPROTONOSUPPORT 43 /* Protocol not supported */
#define ESOCKTNOSUPPORT 44 /* Socket type not supported */
#define ENOTSUP 45 /* Operation not supported */
#define EPFNOSUPPORT 46 /* Protocol family not supported */
#define EAFNOSUPPORT 47 /* Address family not supported by protocol family */
#define EADDRINUSE 48 /* Address already in use */
#define EADDRNOTAVAIL 49 /* Can't assign requested address */
/* ipc/network software -- operational errors */
#define ENETDOWN 50 /* Network is down */
#define ENETUNREACH 51 /* Network is unreachable */
#define ENETRESET 52 /* Network dropped connection on reset */
#define ECONNABORTED 53 /* Software caused connection abort */
#define ECONNRESET 54 /* Connection reset by peer */
#define ENOBUFS 55 /* No buffer space available */
#define EISCONN 56 /* Socket is already connected */
#define ENOTCONN 57 /* Socket is not connected */
#define ESHUTDOWN 58 /* Can't send after socket shutdown */
#define ETOOMANYREFS 59 /* Too many references: can't splice */
#define ETIMEDOUT 60 /* Operation timed out */
#define ECONNREFUSED 61 /* Connection refused */
#define ELOOP 62 /* Too many levels of symbolic links */
#define ENAMETOOLONG 63 /* File name too long */
#define EHOSTDOWN 64 /* Host is down */
#define EHOSTUNREACH 65 /* No route to host */
#define ENOTEMPTY 66 /* Directory not empty */
/* quotas & mush */
#define EPROCLIM 67 /* Too many processes */
#define EUSERS 68 /* Too many users */
#define EDQUOT 69 /* Disc quota exceeded */
/* Network File System */
#define ESTALE 70 /* Stale NFS file handle */
#define EREMOTE 71 /* Too many levels of remote in path */
#define EBADRPC 72 /* RPC struct is bad */
#define ERPCMISMATCH 73 /* RPC version wrong */
#define EPROGUNAVAIL 74 /* RPC prog. not avail */
#define EPROGMISMATCH 75 /* Program version wrong */
#define EPROCUNAVAIL 76 /* Bad procedure for program */
#define ENOLCK 77 /* No locks available */
#define ENOSYS 78 /* Function not implemented */
#define EFTYPE 79 /* Inappropriate file type or format */
#define EAUTH 80 /* Authentication error */
#define ENEEDAUTH 81 /* Need authenticator */
/* Intelligent device errors */
#define EPWROFF 82 /* Device power is off */
#define EDEVERR 83 /* Device error, e.g. paper out */
#define EOVERFLOW 84 /* Value too large to be stored in data type */
/* Program loading errors */
#define EBADEXEC 85 /* Bad executable */
#define EBADARCH 86 /* Bad CPU type in executable */
#define ESHLIBVERS 87 /* Shared library version mismatch */
#define EBADMACHO 88 /* Malformed Macho file */
#define ECANCELED 89 /* Operation canceled */
#define EIDRM 90 /* Identifier removed */
#define ENOMSG 91 /* No message of desired type */
#define EILSEQ 92 /* Illegal byte sequence */
#define ENOATTR 93 /* Attribute not found */
#define EBADMSG 94 /* Bad message */
#define EMULTIHOP 95 /* Reserved */
#define ENODATA 96 /* No message available on STREAM */
#define ENOLINK 97 /* Reserved */
#define ENOSR 98 /* No STREAM resources */
#define ENOSTR 99 /* Not a STREAM */
#define EPROTO 100 /* Protocol error */
#define ETIME 101 /* STREAM ioctl timeout */
#define EOPNOTSUPP 102 /* Operation not supported on socket */
#define ENOPOLICY 103 /* No such policy registered */
#define ENOTRECOVERABLE 104 /* State not recoverable */
#define EOWNERDEAD 105 /* Previous owner died */
#define EQFULL 106 /* Interface output queue is full */
#define ELAST 106 /* Must be equal largest errno */
#endif

13
lib/libc/include/stdlib.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef STDLIB_H_
#define STDLIB_H_
#include <stddef.h>
extern void abort(void);
extern void *malloc(size_t count);
extern void *calloc(size_t count, size_t size);
extern void *realloc(void *p, size_t count);
extern void free(void *p);
#endif

View File

@@ -3,6 +3,9 @@
#include <stddef.h>
extern const char *strerror(int errnum);
extern const char *strerror_code(int errnum);
extern size_t strlen(const char *s);
extern int strcmp(const char *s1, const char *s2);

View File

@@ -0,0 +1,9 @@
#ifndef UNISTD_H_
#define UNISTD_H_
#include <stdint.h>
extern int open(const char *path, int flags);
extern int close(int fd);
#endif

View File

@@ -0,0 +1,33 @@
set(source_dirs stdlib)
file(GLOB sources *.c *.h)
foreach (dir ${source_dirs})
file(GLOB dir_sources ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.c)
file(GLOB dir_headers ${CMAKE_CURRENT_SOURCE_DIR}/${dir}/*.h)
set(sources ${sources} ${dir_sources})
set(headers ${headers} ${dir_headers})
endforeach (dir)
file(GLOB_RECURSE sub_headers ${CMAKE_CURRENT_SOURCE_DIR}/include/*.h)
set(headers ${headers} ${sub_headers})
set(component_sources ${sources} PARENT_SCOPE)
set(component_headers ${headers} PARENT_SCOPE)
set(component_public_include_dirs ${CMAKE_CURRENT_SOURCE_DIR}/include PARENT_SCOPE)
rosetta_add_library(STATIC
NAME libc-malloc
PUBLIC_INCLUDE_DIRS
${public_include_dirs}
${CMAKE_CURRENT_SOURCE_DIR}/include
SOURCES ${sources}
HEADERS ${headers})
sysroot_add_library(
NAME libc-malloc
HEADER_DIR /usr/include
LIB_DIR /usr/lib)
target_link_libraries(libc-malloc libc-core libmango)

112
lib/libc/malloc/heap.c Normal file
View File

@@ -0,0 +1,112 @@
#include "liballoc.h"
#include <heap/heap.h>
#include <mango/handle.h>
#include <mango/log.h>
#include <mango/status.h>
#include <mango/task.h>
#include <mango/vm.h>
#include <stdio.h>
#define HEAP_REGION_SIZE 0x40000000
#define HEAP_EXPAND_INCREMENT 0x100000
void *heap_alloc(heap_t *heap, size_t sz)
{
return _lbmalloc(heap, sz);
}
void *heap_realloc(heap_t *heap, void *p, size_t sz)
{
return _lbrealloc(heap, p, sz);
}
void *heap_calloc(heap_t *heap, size_t num, size_t itemsz)
{
return _lbcalloc(heap, num, itemsz);
}
void heap_free(heap_t *heap, void *p)
{
_lbfree(heap, p);
}
static kern_status_t init_heap_region(heap_t *heap)
{
kern_handle_t self, address_space;
task_self(&self);
task_get_address_space(self, &address_space);
kern_handle_close(self);
kern_status_t status = vm_region_create(
address_space,
"libc-heap",
9,
VM_REGION_ANY_OFFSET,
HEAP_REGION_SIZE,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
&heap->heap_region,
&heap->heap_base);
kern_handle_close(address_space);
if (status != KERN_OK) {
return status;
}
return KERN_OK;
}
static kern_status_t expand_heap(heap_t *heap)
{
kern_handle_t vmo;
kern_status_t status = vm_object_create(
"libc-heap-data",
14,
HEAP_EXPAND_INCREMENT,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
&vmo);
if (status != KERN_OK) {
return status;
}
virt_addr_t base = 0;
status = vm_region_map_relative(
heap->heap_region,
heap->heap_sys_alloc,
vmo,
0,
HEAP_EXPAND_INCREMENT,
VM_PROT_READ | VM_PROT_WRITE | VM_PROT_USER,
&base);
kern_handle_close(vmo);
heap->heap_sys_alloc += HEAP_EXPAND_INCREMENT;
return status;
}
void *heap_expand(heap_t *heap, size_t size)
{
kern_status_t status = KERN_OK;
if (heap->heap_region == KERN_HANDLE_INVALID) {
status = init_heap_region(heap);
}
if (status != KERN_OK) {
return NULL;
}
while (heap->heap_req_alloc + size > heap->heap_sys_alloc) {
status = expand_heap(heap);
if (status != KERN_OK) {
return NULL;
}
}
void *p = (void *)(heap->heap_base + heap->heap_req_alloc);
heap->heap_req_alloc += size;
return p;
}

View File

@@ -0,0 +1,16 @@
#ifndef HEAP__LIBALLOC_H_
#define HEAP__LIBALLOC_H_
struct liballoc_major;
struct liballoc_minor;
#define HEAP_INIT \
{ \
.heap_region = KERN_HANDLE_INVALID, \
.heap_liballoc = { \
.l_pageSize = 4096, \
.l_pageCount = 16, \
}, \
}
#endif

View File

@@ -0,0 +1,50 @@
#ifndef HEAP_H_
#define HEAP_H_
#include <heap/_liballoc.h>
#include <mango/types.h>
#include <stddef.h>
typedef enum heap_result {
HEAP_OK = 0,
HEAP_ERR_NO_MEMORY,
HEAP_ERR_INVALID_ARGUMENT,
} heap_result_t;
typedef struct heap {
kern_handle_t heap_region;
/* amount of space requested from the heap by the user */
size_t heap_req_alloc;
/* amount of space requested from the system by the heap */
size_t heap_sys_alloc;
/* base address of the heap */
virt_addr_t heap_base;
union {
struct {
struct liballoc_major *l_memRoot;
struct liballoc_major *l_bestBet;
unsigned int l_pageSize;
unsigned int l_pageCount;
unsigned long long l_allocated;
unsigned long long l_inuse;
long long l_warningCount;
long long l_errorCount;
long long l_possibleOverruns;
} heap_liballoc;
};
} heap_t;
extern kern_status_t heap_init(heap_t *heap, size_t size);
extern kern_status_t heap_destroy(heap_t *heap);
extern void *heap_alloc(heap_t *heap, size_t sz);
extern void *heap_realloc(heap_t *heap, void *p, size_t sz);
extern void *heap_calloc(heap_t *heap, size_t num, size_t itemsz);
extern void heap_free(heap_t *heap, void *p);
extern void *heap_expand(heap_t *heap, size_t size);
#endif

834
lib/libc/malloc/liballoc.c Normal file
View File

@@ -0,0 +1,834 @@
#include "liballoc.h"
/** Durand's Amazing Super Duper Memory functions. */
#define VERSION "1.1"
#define ALIGNMENT \
16ul // 4ul ///< This is the byte alignment
// that memory must be allocated on. IMPORTANT for GTK and other
// stuff.
#define ALIGN_TYPE char /// unsigned char[16] /// unsigned short
#define ALIGN_INFO \
sizeof(ALIGN_TYPE) * 16 ///< Alignment information is stored right
///< before the pointer. This is the number of
///< bytes of information stored there.
#define USE_CASE1
#define USE_CASE2
#define USE_CASE3
#define USE_CASE4
#define USE_CASE5
/** This macro will conveniently align our pointer upwards */
#define ALIGN(ptr) \
if (ALIGNMENT > 1) { \
uintptr_t diff; \
ptr = (void *)((uintptr_t)ptr + ALIGN_INFO); \
diff = (uintptr_t)ptr & (ALIGNMENT - 1); \
if (diff != 0) { \
diff = ALIGNMENT - diff; \
ptr = (void *)((uintptr_t)ptr + diff); \
} \
*((ALIGN_TYPE *)((uintptr_t)ptr - ALIGN_INFO)) \
= diff + ALIGN_INFO; \
}
#define UNALIGN(ptr) \
if (ALIGNMENT > 1) { \
uintptr_t diff \
= *((ALIGN_TYPE *)((uintptr_t)ptr - ALIGN_INFO)); \
if (diff < (ALIGNMENT + ALIGN_INFO)) { \
ptr = (void *)((uintptr_t)ptr - diff); \
} \
}
#define LIBALLOC_MAGIC 0xc001c0de
#define LIBALLOC_DEAD 0xdeaddead
#if defined DEBUG || defined INFO
#include <stdio.h>
#include <stdlib.h>
#define FLUSH() fflush(stdout)
#endif
/** A structure found at the top of all system allocated
* memory blocks. It details the usage of the memory block.
*/
struct liballoc_major {
struct liballoc_major *prev; ///< Linked list information.
struct liballoc_major *next; ///< Linked list information.
unsigned int pages; ///< The number of pages in the block.
unsigned int size; ///< The number of pages in the block.
unsigned int usage; ///< The number of bytes used in the block.
struct liballoc_minor *first; ///< A pointer to the first allocated
///< memory in the block.
};
/** This is a structure found at the beginning of all
* sections in a major block which were allocated by a
* malloc, calloc, realloc call.
*/
struct liballoc_minor {
struct liballoc_minor *prev; ///< Linked list information.
struct liballoc_minor *next; ///< Linked list information.
struct liballoc_major *block; ///< The owning block. A pointer to the
///< major structure.
unsigned int magic; ///< A magic number to idenfity correctness.
unsigned int size; ///< The size of the memory allocated. Could be 1
///< byte or more.
unsigned int req_size; ///< The size of memory requested.
};
#if 0
static struct liballoc_major *l_memRoot
= NULL; ///< The root memory block acquired from the system.
static struct liballoc_major *l_bestBet
= NULL; ///< The major with the most free memory.
static unsigned int l_pageSize
= 4096; ///< The size of an individual page. Set up in liballoc_init.
static unsigned int l_pageCount = 16; ///< The number of pages to request per
///< chunk. Set up in liballoc_init.
static unsigned long long l_allocated
= 0; ///< Running total of allocated memory.
static unsigned long long l_inuse = 0; ///< Running total of used memory.
static long long l_warningCount = 0; ///< Number of warnings encountered
static long long l_errorCount = 0; ///< Number of actual errors
static long long l_possibleOverruns = 0; ///< Number of possible overruns
#endif
// *********** HELPER FUNCTIONS *******************************
static void *liballoc_memset(void *s, int c, size_t n)
{
unsigned int i;
for (i = 0; i < n; i++)
((char *)s)[i] = c;
return s;
}
static void *liballoc_memcpy(void *s1, const void *s2, size_t n)
{
char *cdest;
char *csrc;
unsigned int *ldest = (unsigned int *)s1;
unsigned int *lsrc = (unsigned int *)s2;
while (n >= sizeof(unsigned int)) {
*ldest++ = *lsrc++;
n -= sizeof(unsigned int);
}
cdest = (char *)ldest;
csrc = (char *)lsrc;
while (n > 0) {
*cdest++ = *csrc++;
n -= 1;
}
return s1;
}
#if defined DEBUG || defined INFO
static void liballoc_dump()
{
#ifdef DEBUG
struct liballoc_major *maj = l_memRoot;
struct liballoc_minor *min = NULL;
#endif
printf("liballoc: ------ Memory data ---------------\n");
printf("liballoc: System memory allocated: %i bytes\n", l_allocated);
printf("liballoc: Memory in used (malloc'ed): %i bytes\n", l_inuse);
printf("liballoc: Warning count: %i\n", l_warningCount);
printf("liballoc: Error count: %i\n", l_errorCount);
printf("liballoc: Possible overruns: %i\n", l_possibleOverruns);
#ifdef DEBUG
while (maj != NULL) {
printf("liballoc: %x: total = %i, used = %i\n",
maj,
maj->size,
maj->usage);
min = maj->first;
while (min != NULL) {
printf("liballoc: %x: %i bytes\n", min, min->size);
min = min->next;
}
maj = maj->next;
}
#endif
FLUSH();
}
#endif
#define CTX(n) (heap->heap_liballoc.n)
// ***************************************************************
static struct liballoc_major *allocate_new_page(heap_t *heap, unsigned int size)
{
unsigned int st;
struct liballoc_major *maj;
// This is how much space is required.
st = size + sizeof(struct liballoc_major);
st += sizeof(struct liballoc_minor);
// Perfect amount of space?
if ((st % CTX(l_pageSize)) == 0)
st = st / (CTX(l_pageSize));
else
st = st / (CTX(l_pageSize)) + 1;
// No, add the buffer.
// Make sure it's >= the minimum size.
if (st < CTX(l_pageCount))
st = CTX(l_pageCount);
maj = (struct liballoc_major *)liballoc_alloc(heap, st);
if (maj == NULL) {
CTX(l_warningCount) += 1;
#if defined DEBUG || defined INFO
printf("liballoc: WARNING: liballoc_alloc( %i ) return NULL\n",
st);
FLUSH();
#endif
return NULL; // uh oh, we ran out of memory.
}
maj->prev = NULL;
maj->next = NULL;
maj->pages = st;
maj->size = st * CTX(l_pageSize);
maj->usage = sizeof(struct liballoc_major);
maj->first = NULL;
CTX(l_allocated) += maj->size;
#ifdef DEBUG
printf("liballoc: Resource allocated %x of %i pages (%i bytes) for %i "
"size.\n",
maj,
st,
maj->size,
size);
printf("liballoc: Total memory usage = %i KB\n",
(int)((l_allocated / (1024))));
FLUSH();
#endif
return maj;
}
void *PREFIX(malloc)(heap_t *heap, size_t req_size)
{
int startedBet = 0;
unsigned long long bestSize = 0;
void *p = NULL;
uintptr_t diff;
struct liballoc_major *maj;
struct liballoc_minor *min;
struct liballoc_minor *new_min;
unsigned long size = req_size;
// For alignment, we adjust size so there's enough space to align.
if (ALIGNMENT > 1) {
size += ALIGNMENT + ALIGN_INFO;
}
// So, ideally, we really want an alignment of 0 or 1 in order
// to save space.
liballoc_lock(heap);
if (size == 0) {
CTX(l_warningCount) += 1;
#if defined DEBUG || defined INFO
printf("liballoc: WARNING: alloc( 0 ) called from %x\n",
__builtin_return_address(0));
FLUSH();
#endif
liballoc_unlock(heap);
return PREFIX(malloc)(heap, 1);
}
if (CTX(l_memRoot) == NULL) {
#if defined DEBUG || defined INFO
#ifdef DEBUG
printf("liballoc: initialization of liballoc " VERSION "\n");
#endif
atexit(liballoc_dump);
FLUSH();
#endif
// This is the first time we are being used.
CTX(l_memRoot) = allocate_new_page(heap, size);
if (CTX(l_memRoot) == NULL) {
liballoc_unlock(heap);
#ifdef DEBUG
printf("liballoc: initial l_memRoot initialization "
"failed\n",
p);
FLUSH();
#endif
return NULL;
}
#ifdef DEBUG
printf("liballoc: set up first memory major %x\n", l_memRoot);
FLUSH();
#endif
}
#ifdef DEBUG
printf("liballoc: %x PREFIX(malloc)( %i ): ",
__builtin_return_address(0),
size);
FLUSH();
#endif
// Now we need to bounce through every major and find enough space....
maj = CTX(l_memRoot);
startedBet = 0;
// Start at the best bet....
if (CTX(l_bestBet) != NULL) {
bestSize = CTX(l_bestBet)->size - CTX(l_bestBet)->usage;
if (bestSize > (size + sizeof(struct liballoc_minor))) {
maj = CTX(l_bestBet);
startedBet = 1;
}
}
while (maj != NULL) {
diff = maj->size - maj->usage;
// free memory in the block
if (bestSize < diff) {
// Hmm.. this one has more memory then our bestBet.
// Remember!
CTX(l_bestBet) = maj;
bestSize = diff;
}
#ifdef USE_CASE1
// CASE 1: There is not enough space in this major block.
if (diff < (size + sizeof(struct liballoc_minor))) {
#ifdef DEBUG
printf("CASE 1: Insufficient space in block %x\n", maj);
FLUSH();
#endif
// Another major block next to this one?
if (maj->next != NULL) {
maj = maj->next; // Hop to that one.
continue;
}
if (startedBet == 1) // If we started at the best bet,
{ // let's start all over again.
maj = CTX(l_memRoot);
startedBet = 0;
continue;
}
// Create a new major block next to this one and...
maj->next = allocate_new_page(
heap,
size); // next one will be okay.
if (maj->next == NULL)
break; // no more memory.
maj->next->prev = maj;
maj = maj->next;
// .. fall through to CASE 2 ..
}
#endif
#ifdef USE_CASE2
// CASE 2: It's a brand new block.
if (maj->first == NULL) {
maj->first
= (struct liballoc_minor
*)((uintptr_t)maj
+ sizeof(struct liballoc_major));
maj->first->magic = LIBALLOC_MAGIC;
maj->first->prev = NULL;
maj->first->next = NULL;
maj->first->block = maj;
maj->first->size = size;
maj->first->req_size = req_size;
maj->usage += size + sizeof(struct liballoc_minor);
CTX(l_inuse) += size;
p = (void *)((uintptr_t)(maj->first)
+ sizeof(struct liballoc_minor));
ALIGN(p);
#ifdef DEBUG
printf("CASE 2: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(heap); // release the lock
return p;
}
#endif
#ifdef USE_CASE3
// CASE 3: Block in use and enough space at the start of the
// block.
diff = (uintptr_t)(maj->first);
diff -= (uintptr_t)maj;
diff -= sizeof(struct liballoc_major);
if (diff >= (size + sizeof(struct liballoc_minor))) {
// Yes, space in front. Squeeze in.
maj->first->prev
= (struct liballoc_minor
*)((uintptr_t)maj
+ sizeof(struct liballoc_major));
maj->first->prev->next = maj->first;
maj->first = maj->first->prev;
maj->first->magic = LIBALLOC_MAGIC;
maj->first->prev = NULL;
maj->first->block = maj;
maj->first->size = size;
maj->first->req_size = req_size;
maj->usage += size + sizeof(struct liballoc_minor);
CTX(l_inuse) += size;
p = (void *)((uintptr_t)(maj->first)
+ sizeof(struct liballoc_minor));
ALIGN(p);
#ifdef DEBUG
printf("CASE 3: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(heap); // release the lock
return p;
}
#endif
#ifdef USE_CASE4
// CASE 4: There is enough space in this block. But is it
// contiguous?
min = maj->first;
// Looping within the block now...
while (min != NULL) {
// CASE 4.1: End of minors in a block. Space from last
// and end?
if (min->next == NULL) {
// the rest of this block is free... is it big
// enough?
diff = (uintptr_t)(maj) + maj->size;
diff -= (uintptr_t)min;
diff -= sizeof(struct liballoc_minor);
diff -= min->size;
// minus already existing usage..
if (diff
>= (size + sizeof(struct liballoc_minor))) {
// yay....
min->next
= (struct liballoc_minor
*)((uintptr_t)min
+ sizeof(
struct
liballoc_minor)
+ min->size);
min->next->prev = min;
min = min->next;
min->next = NULL;
min->magic = LIBALLOC_MAGIC;
min->block = maj;
min->size = size;
min->req_size = req_size;
maj->usage += size
+ sizeof(struct
liballoc_minor);
CTX(l_inuse) += size;
p = (void *)((uintptr_t)min
+ sizeof(struct
liballoc_minor));
ALIGN(p);
#ifdef DEBUG
printf("CASE 4.1: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(
heap); // release the lock
return p;
}
}
// CASE 4.2: Is there space between two minors?
if (min->next != NULL) {
// is the difference between here and next big
// enough?
diff = (uintptr_t)(min->next);
diff -= (uintptr_t)min;
diff -= sizeof(struct liballoc_minor);
diff -= min->size;
// minus our existing usage.
if (diff
>= (size + sizeof(struct liballoc_minor))) {
// yay......
new_min = (struct liballoc_minor
*)((uintptr_t)min
+ sizeof(
struct
liballoc_minor)
+ min->size);
new_min->magic = LIBALLOC_MAGIC;
new_min->next = min->next;
new_min->prev = min;
new_min->size = size;
new_min->req_size = req_size;
new_min->block = maj;
min->next->prev = new_min;
min->next = new_min;
maj->usage += size
+ sizeof(struct
liballoc_minor);
CTX(l_inuse) += size;
p = (void *)((uintptr_t)new_min
+ sizeof(struct
liballoc_minor));
ALIGN(p);
#ifdef DEBUG
printf("CASE 4.2: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(
heap); // release the lock
return p;
}
} // min->next != NULL
min = min->next;
} // while min != NULL ...
#endif
#ifdef USE_CASE5
// CASE 5: Block full! Ensure next block and loop.
if (maj->next == NULL) {
#ifdef DEBUG
printf("CASE 5: block full\n");
FLUSH();
#endif
if (startedBet == 1) {
maj = CTX(l_memRoot);
startedBet = 0;
continue;
}
// we've run out. we need more...
maj->next = allocate_new_page(
heap,
size); // next one guaranteed to be okay
if (maj->next == NULL)
break; // uh oh, no more memory.....
maj->next->prev = maj;
}
#endif
maj = maj->next;
} // while (maj != NULL)
liballoc_unlock(heap); // release the lock
#ifdef DEBUG
printf("All cases exhausted. No memory available.\n");
FLUSH();
#endif
#if defined DEBUG || defined INFO
printf("liballoc: WARNING: PREFIX(malloc)( %i ) returning NULL.\n",
size);
liballoc_dump();
FLUSH();
#endif
return NULL;
}
void PREFIX(free)(heap_t *heap, void *ptr)
{
struct liballoc_minor *min;
struct liballoc_major *maj;
if (ptr == NULL) {
CTX(l_warningCount) += 1;
#if defined DEBUG || defined INFO
printf("liballoc: WARNING: PREFIX(free)( NULL ) called from "
"%x\n",
__builtin_return_address(0));
FLUSH();
#endif
return;
}
UNALIGN(ptr);
liballoc_lock(heap); // lockit
min = (struct liballoc_minor *)((uintptr_t)ptr
- sizeof(struct liballoc_minor));
if (min->magic != LIBALLOC_MAGIC) {
CTX(l_errorCount) += 1;
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
if (((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF))
|| ((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF))
|| ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))) {
CTX(l_possibleOverruns) += 1;
#if defined DEBUG || defined INFO
printf("liballoc: ERROR: Possible 1-3 byte overrun for "
"magic %x != %x\n",
min->magic,
LIBALLOC_MAGIC);
FLUSH();
#endif
}
if (min->magic == LIBALLOC_DEAD) {
#if defined DEBUG || defined INFO
printf("liballoc: ERROR: multiple PREFIX(free)() "
"attempt on %x from %x.\n",
ptr,
__builtin_return_address(0));
FLUSH();
#endif
} else {
#if defined DEBUG || defined INFO
printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called "
"from %x\n",
ptr,
__builtin_return_address(0));
FLUSH();
#endif
}
// being lied to...
liballoc_unlock(heap); // release the lock
return;
}
#ifdef DEBUG
printf("liballoc: %x PREFIX(free)( %x ): ",
__builtin_return_address(0),
ptr);
FLUSH();
#endif
maj = min->block;
CTX(l_inuse) -= min->size;
maj->usage -= (min->size + sizeof(struct liballoc_minor));
min->magic = LIBALLOC_DEAD; // No mojo.
if (min->next != NULL)
min->next->prev = min->prev;
if (min->prev != NULL)
min->prev->next = min->next;
if (min->prev == NULL)
maj->first = min->next;
// Might empty the block. This was the first
// minor.
// We need to clean up after the majors now....
if (maj->first == NULL) // Block completely unused.
{
if (CTX(l_memRoot) == maj)
CTX(l_memRoot) = maj->next;
if (CTX(l_bestBet) == maj)
CTX(l_bestBet) = NULL;
if (maj->prev != NULL)
maj->prev->next = maj->next;
if (maj->next != NULL)
maj->next->prev = maj->prev;
CTX(l_allocated) -= maj->size;
liballoc_free(heap, maj, maj->pages);
} else {
if (CTX(l_bestBet) != NULL) {
int bestSize
= CTX(l_bestBet)->size - CTX(l_bestBet)->usage;
int majSize = maj->size - maj->usage;
if (majSize > bestSize)
CTX(l_bestBet) = maj;
}
}
#ifdef DEBUG
printf("OK\n");
FLUSH();
#endif
liballoc_unlock(heap); // release the lock
}
void *PREFIX(calloc)(heap_t *heap, size_t nobj, size_t size)
{
int real_size;
void *p;
real_size = nobj * size;
p = PREFIX(malloc)(heap, real_size);
liballoc_memset(p, 0, real_size);
return p;
}
void *PREFIX(realloc)(heap_t *heap, void *p, size_t size)
{
void *ptr;
struct liballoc_minor *min;
unsigned int real_size;
// Honour the case of size == 0 => free old and return NULL
if (size == 0) {
PREFIX(free)(heap, p);
return NULL;
}
// In the case of a NULL pointer, return a simple malloc.
if (p == NULL)
return PREFIX(malloc)(heap, size);
// Unalign the pointer if required.
ptr = p;
UNALIGN(ptr);
liballoc_lock(heap); // lockit
min = (struct liballoc_minor *)((uintptr_t)ptr
- sizeof(struct liballoc_minor));
// Ensure it is a valid structure.
if (min->magic != LIBALLOC_MAGIC) {
CTX(l_errorCount) += 1;
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
if (((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF))
|| ((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF))
|| ((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF))) {
CTX(l_possibleOverruns) += 1;
#if defined DEBUG || defined INFO
printf("liballoc: ERROR: Possible 1-3 byte overrun for "
"magic %x != %x\n",
min->magic,
LIBALLOC_MAGIC);
FLUSH();
#endif
}
if (min->magic == LIBALLOC_DEAD) {
#if defined DEBUG || defined INFO
printf("liballoc: ERROR: multiple PREFIX(free)() "
"attempt on %x from %x.\n",
ptr,
__builtin_return_address(0));
FLUSH();
#endif
} else {
#if defined DEBUG || defined INFO
printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called "
"from %x\n",
ptr,
__builtin_return_address(0));
FLUSH();
#endif
}
// being lied to...
liballoc_unlock(heap); // release the lock
return NULL;
}
// Definitely a memory block.
real_size = min->req_size;
if (real_size >= size) {
min->req_size = size;
liballoc_unlock(heap);
return p;
}
liballoc_unlock(heap);
// If we got here then we're reallocating to a block bigger than us.
ptr = PREFIX(malloc)(heap, size); // We need to allocate new memory
liballoc_memcpy(ptr, p, real_size);
PREFIX(free)(heap, p);
return ptr;
}
int liballoc_lock(heap_t *heap)
{
/* TODO */
return 0;
}
int liballoc_unlock(heap_t *heap)
{
/* TODO */
return 0;
}
void *liballoc_alloc(heap_t *heap, size_t sz)
{
return heap_expand(heap, sz);
}
int liballoc_free(heap_t *heap, void *p, size_t sz)
{
/* TODO */
return 0;
}

View File

@@ -0,0 +1,76 @@
#ifndef _LIBALLOC_H
#define _LIBALLOC_H
#include <heap/heap.h>
#include <stddef.h>
/** \defgroup ALLOCHOOKS liballoc hooks
*
* These are the OS specific functions which need to
* be implemented on any platform that the library
* is expected to work on.
*/
/** @{ */
// If we are told to not define our own size_t, then we skip the define.
// #define _HAVE_UINTPTR_T
// typedef unsigned long uintptr_t;
// This lets you prefix malloc and friends
#define PREFIX(func) _lb##func
#ifdef __cplusplus
extern "C" {
#endif
/** This function is supposed to lock the memory data structures. It
* could be as simple as disabling interrupts or acquiring a spinlock.
* It's up to you to decide.
*
* \return 0 if the lock was acquired successfully. Anything else is
* failure.
*/
extern int liballoc_lock(heap_t *);
/** This function unlocks what was previously locked by the liballoc_lock
* function. If it disabled interrupts, it enables interrupts. If it
* had acquiried a spinlock, it releases the spinlock. etc.
*
* \return 0 if the lock was successfully released.
*/
extern int liballoc_unlock(heap_t *);
/** This is the hook into the local system which allocates pages. It
* accepts an integer parameter which is the number of pages
* required. The page size was set up in the liballoc_init function.
*
* \return NULL if the pages were not allocated.
* \return A pointer to the allocated memory.
*/
extern void *liballoc_alloc(heap_t *, size_t);
/** This frees previously allocated memory. The void* parameter passed
* to the function is the exact same value returned from a previous
* liballoc_alloc call.
*
* The integer value is the number of pages to free.
*
* \return 0 if the memory was successfully freed.
*/
extern int liballoc_free(heap_t *, void *, size_t);
extern void *PREFIX(malloc)(heap_t *, size_t); ///< The standard function.
extern void *PREFIX(
realloc)(heap_t *, void *, size_t); ///< The standard function.
extern void *PREFIX(
calloc)(heap_t *, size_t, size_t); ///< The standard function.
extern void PREFIX(free)(heap_t *, void *); ///< The standard function.
#ifdef __cplusplus
}
#endif
/** @} */
#endif

View File

@@ -0,0 +1,44 @@
#include <heap/heap.h>
#ifdef ENABLE_GLOBAL_HEAP
static heap_t global_heap = HEAP_INIT;
void *malloc(size_t count)
{
return heap_alloc(&global_heap, count);
}
void *calloc(size_t count, size_t size)
{
return heap_calloc(&global_heap, count, size);
}
void *realloc(void *p, size_t count)
{
return heap_realloc(&global_heap, p, count);
}
void free(void *p)
{
heap_free(&global_heap, p);
}
#else
void *malloc(size_t count)
{
return NULL;
}
void *calloc(size_t count, size_t size)
{
return NULL;
}
void *realloc(void *p, size_t count)
{
return NULL;
}
void free(void *p)
{
}
#endif

View File

@@ -0,0 +1,11 @@
file(GLOB runtime_sources
${CMAKE_CURRENT_SOURCE_DIR}/${CMAKE_SYSTEM_PROCESSOR}/*.s)
set_property(SOURCE ${runtime_sources} PROPERTY LANGUAGE C)
rosetta_add_object_library(
NAME libc-runtime STATIC
SOURCES ${runtime_sources})
sysroot_add_object_library(
NAME libc-runtime
LIB_DIR /usr/lib)