diff --git a/libraries/wutcrt/crt0_rpl.s b/libraries/wutcrt/crt0_rpl.s index b54ea5a29..d26cac549 100644 --- a/libraries/wutcrt/crt0_rpl.s +++ b/libraries/wutcrt/crt0_rpl.s @@ -17,12 +17,14 @@ __rpl_start: load: # Load bl __init_wut - # rpl files use wutmalloc instead of the custom heap - bl __init_wut_malloc + # rpl files uses a special RPL version of wutmalloc + bl __init_wut_malloc_rpl bl __eabi lwz 3, 0x8(1) lwz 4, 0xC(1) bl rpl_entry + lwz 0, 0x14(1) + mtlr 0 addi 1, 1, 0x10 blr @@ -33,4 +35,3 @@ unload: bl rpl_entry addi 1, 1, 0x10 b exit - diff --git a/libraries/wutmalloc/wut_malloc_rpl.c b/libraries/wutmalloc/wut_malloc_rpl.c new file mode 100644 index 000000000..6d9a81b3c --- /dev/null +++ b/libraries/wutmalloc/wut_malloc_rpl.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * A special version of wutmalloc for RPLs. + * + * RPLs can't reliable assume that the main application is using ExpHeap, + * which means that MEMGetSizeForMBlockExpHeap can't be used for realloc. + * This version co-allocates a header alongside the memory to be able to + * reallocate the memory. + */ +void +__init_wut_malloc_rpl(void) +{ +} + +void +__fini_wut_malloc_rpl(void) +{ +} + +#define WUT_MALLOC_RPL_CANARY (0x376296a9) + +struct wut_alloc_header_rpl +{ + uint32_t canary; + size_t size; + size_t offset; +}; + +static struct wut_alloc_header_rpl *get_alloc_header(const void* ptr) +{ + struct wut_alloc_header_rpl *header = (struct wut_alloc_header_rpl*)ptr - 1; + assert(header->canary == WUT_MALLOC_RPL_CANARY); + if(header->canary != WUT_MALLOC_RPL_CANARY) + OSFatal("WUT detected a memory corruption in get_alloc_header"); + return header; +} + +static void *get_alloc_base(struct wut_alloc_header_rpl* header) +{ + return (char*)header - header->offset; +} + +void * +_malloc_r(struct _reent *r, size_t size) +{ + return _memalign_r(r, 0x40, size); +} + +void +_free_r(struct _reent *r, void *ptr) +{ + if (ptr) { + void *basePtr = get_alloc_base(get_alloc_header(ptr)); + MEMFreeToDefaultHeap(basePtr); + } +} + +void * +_realloc_r(struct _reent *r, void *ptr, size_t size) +{ + void *new_ptr = _malloc_r(r, size); + if (!new_ptr) { + r->_errno = ENOMEM; + return new_ptr; + } + + if (ptr) { + struct wut_alloc_header_rpl *header = get_alloc_header(ptr); + size_t old_size = header->size; + memcpy(new_ptr, ptr, old_size <= size ? old_size : size); + MEMFreeToDefaultHeap(get_alloc_base(header)); + } + return new_ptr; +} + +void * +_calloc_r(struct _reent *r, size_t num, size_t size) +{ + void *ptr = _malloc_r(r, num * size); + if (ptr) { + memset(ptr, 0, num * size); + } else { + r->_errno = ENOMEM; + } + return ptr; +} + +void * +_memalign_r(struct _reent *r, size_t align, size_t size) +{ + if(align < 0x40) + align = 0x40; + size_t offset; + void* basePtr; + if(sizeof(struct wut_alloc_header_rpl) > align) + offset = align - (sizeof(struct wut_alloc_header_rpl) % align); + else + offset = align - sizeof(struct wut_alloc_header_rpl); + basePtr = MEMAllocFromDefaultHeapEx(offset + sizeof(struct wut_alloc_header_rpl) + size, align); + if (!basePtr) { + r->_errno = ENOMEM; + return basePtr; + } + struct wut_alloc_header_rpl *header = (struct wut_alloc_header_rpl*)((char*)basePtr + offset); + header->canary = WUT_MALLOC_RPL_CANARY; + header->size = size; + header->offset = offset; + return (header+1); +} + +struct mallinfo _mallinfo_r(struct _reent *r) +{ + struct mallinfo info = { 0 }; + return info; +} + +void +_malloc_stats_r(struct _reent *r) +{ +} + +int +_mallopt_r(struct _reent *r, int param, int value) +{ + return 0; +} + +size_t +_malloc_usable_size_r(struct _reent *r, void *ptr) +{ + return 0; // we do not know the total available size +} + +void * +_valloc_r(struct _reent *r, size_t size) +{ + return _memalign_r(r, OS_PAGE_SIZE, size); +} + +void * +_pvalloc_r(struct _reent *r, size_t size) +{ + return _memalign_r(r, OS_PAGE_SIZE, (size + (OS_PAGE_SIZE - 1)) & ~(OS_PAGE_SIZE - 1)); +} + +int +_malloc_trim_r(struct _reent *r, size_t pad) +{ + return 0; +} \ No newline at end of file