stable malloc
This commit is contained in:
@@ -339,15 +339,6 @@ int main(void)
|
|||||||
walk(tdata);
|
walk(tdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
tdata = malloc(sizeof(struct thread_start_data));
|
|
||||||
tdata->thread_index=0;
|
|
||||||
tdata->root=root;
|
|
||||||
tdata->working_set_size=working_set_size;
|
|
||||||
// clock_t tic2 = clock();
|
|
||||||
for (int i = 0; i < 64000; i++) {
|
|
||||||
walk(tdata);
|
|
||||||
}
|
|
||||||
|
|
||||||
// clock_t toc2 = clock();
|
// clock_t toc2 = clock();
|
||||||
// printf("Elapsed build walk: %f seconds\n", (double)(toc2 - tic2) / CLOCKS_PER_SEC);
|
// printf("Elapsed build walk: %f seconds\n", (double)(toc2 - tic2) / CLOCKS_PER_SEC);
|
||||||
// #endif
|
// #endif
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
# Send assembler file to remote machine to run
|
# Send assembler file to remote machine to run
|
||||||
scp start.S home-1:/home/akilan/cheri/output/sdk/bin/
|
scp start.S home-1:/home/akilan/cheri/output/sdk/bin/
|
||||||
scp main.c home-1:/home/akilan/cheri/output/sdk/bin/
|
scp main.c home-1:/home/akilan/cheri/output/sdk/bin/
|
||||||
|
scp malloc_test.c home-1:/home/akilan/cheri/output/sdk/bin/
|
||||||
scp malloc.c home-1:/home/akilan/cheri/output/sdk/bin/
|
scp malloc.c home-1:/home/akilan/cheri/output/sdk/bin/
|
||||||
|
scp link.ld home-1:/home/akilan/cheri/output/sdk/bin/
|
||||||
|
|
||||||
# scp cheri.S home:/home/akilan/cheri/output/sdk/bin/
|
# scp cheri.S home:/home/akilan/cheri/output/sdk/bin/
|
||||||
|
|
||||||
@@ -13,10 +15,10 @@ scp malloc.c home-1:/home/akilan/cheri/output/sdk/bin/
|
|||||||
# ssh home-1 'cd /home/akilan/cheri/output/sdk/bin/ && ./clang --target=riscv64-unknown-elf -march=rv64gcxcheri -mabi=lp64d -nostdlib -nostartfiles -Wl,-Ttext=0x80000000 -o testC start.S main.c'
|
# ssh home-1 'cd /home/akilan/cheri/output/sdk/bin/ && ./clang --target=riscv64-unknown-elf -march=rv64gcxcheri -mabi=lp64d -nostdlib -nostartfiles -Wl,-Ttext=0x80000000 -o testC start.S main.c'
|
||||||
|
|
||||||
# Malloc test implementation
|
# Malloc test implementation
|
||||||
ssh home-1 'cd /home/akilan/cheri/output/sdk/bin/ && ./clang --target=riscv64-unknown-elf -march=rv64gcxcheri -mabi=lp64d -nostdlib -nostartfiles -fno-builtin-malloc -mcmodel=medany -Wl,-Ttext=0x80000000 -o testC start.S main.c malloc.c'
|
ssh home-1 'cd /home/akilan/cheri/output/sdk/bin/ && ./clang --target=riscv64-unknown-elf -march=rv64gcxcheri -mabi=lp64d -DDEFINE_MALLOC -DDEFINE_FREE -nostdlib -nostartfiles -fno-builtin-malloc -mcmodel=medany -T link.ld -o testC start.S main.c malloc.c malloc_test.c'
|
||||||
|
|
||||||
# Disassembly ouput
|
# Disassembly ouput
|
||||||
ssh home-1 'cd /home/akilan/cheri/output/sdk/bin/ && ./llvm-objdump -d testC'
|
# ssh home-1 'cd /home/akilan/cheri/output/sdk/bin/ && ./llvm-objdump -d testC'
|
||||||
|
|
||||||
# Copy file back for testing
|
# Copy file back for testing
|
||||||
scp home-1:/home/akilan/cheri/output/sdk/bin/testC ../
|
scp home-1:/home/akilan/cheri/output/sdk/bin/testC ../
|
||||||
|
|||||||
19
Tests/isa/CPrograms/link.ld
Normal file
19
Tests/isa/CPrograms/link.ld
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
OUTPUT_ARCH( "riscv" )
|
||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x80000000;
|
||||||
|
.text.init : { *(.text.init) }
|
||||||
|
. = ALIGN(0x1000);
|
||||||
|
.tohost : { *(.tohost) }
|
||||||
|
. = ALIGN(0x1000);
|
||||||
|
.text : { *(.text) }
|
||||||
|
. = ALIGN(0x1000);
|
||||||
|
.data : { *(.data) }
|
||||||
|
.bss : { *(.bss) }
|
||||||
|
_end = .;
|
||||||
|
|
||||||
|
__malloc_start = .;
|
||||||
|
. = . + 512;
|
||||||
|
}
|
||||||
@@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include "riscv_test.h"
|
#include "riscv_test.h"
|
||||||
|
|
||||||
|
// void free(void *ptr);
|
||||||
|
// void *malloc(size_t size);
|
||||||
void free(void * __capability ptr);
|
void free(void * __capability ptr);
|
||||||
void * __capability malloc(size_t size);
|
void * __capability malloc(size_t size);
|
||||||
|
|
||||||
@@ -82,12 +84,12 @@ int main(void) {
|
|||||||
while (1);
|
while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(&b);
|
// free(b);
|
||||||
b = NULL;
|
// b = NULL;
|
||||||
|
|
||||||
if (b[0] == 'B') {
|
// if (b[0] == 'B') {
|
||||||
while (1);
|
// while (1);
|
||||||
}
|
// }
|
||||||
|
|
||||||
char * __capability c = malloc(16);
|
char * __capability c = malloc(16);
|
||||||
|
|
||||||
|
|||||||
@@ -13,19 +13,22 @@
|
|||||||
// | | (Distance 1 between address)
|
// | | (Distance 1 between address)
|
||||||
// [1, 2, 3. ....... n] -> virtual
|
// [1, 2, 3. ....... n] -> virtual
|
||||||
|
|
||||||
#define HEAP_SIZE 65536 // 64 KB heap
|
void* tiny_malloc(size_t);
|
||||||
|
void tiny_free(void*);
|
||||||
|
|
||||||
#define PHYS_BASE 0x80000000
|
// #define HEAP_SIZE 65536 // 64 KB heap
|
||||||
#define VIRT_BASE 0xFFFFFFFF80000000
|
|
||||||
|
|
||||||
static char heap[HEAP_SIZE];
|
// #define PHYS_BASE 0x80000000
|
||||||
static size_t bump = 0;
|
// #define VIRT_BASE 0xFFFFFFFF80000000
|
||||||
|
|
||||||
static void * __capability free_list = NULL;
|
// static char heap[HEAP_SIZE];
|
||||||
|
// static size_t bump = 0;
|
||||||
|
|
||||||
typedef struct free_node {
|
// static void * __capability free_list = NULL;
|
||||||
void * __capability next;
|
|
||||||
} free_node_t;
|
// typedef struct free_node {
|
||||||
|
// void * __capability next;
|
||||||
|
// } free_node_t;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -45,53 +48,61 @@ static inline void * __capability add_delta(void * __capability cap, int offset)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Malloc wrapper
|
||||||
void * __capability malloc(size_t size) {
|
void * __capability malloc(size_t size) {
|
||||||
|
|
||||||
// Align to 8 bytes (important for capability safety)
|
void *raw = tiny_malloc(size);
|
||||||
size = (size + 7) & ~7;
|
|
||||||
|
|
||||||
if (bump + size > HEAP_SIZE)
|
void *__capability cap = (void *__capability)raw;
|
||||||
return NULL;
|
|
||||||
|
cap = cheri_bounds_set(cap, size);
|
||||||
|
|
||||||
void * __capability base = cheri_ddc_get();
|
cap = add_delta(cap, 12);
|
||||||
|
|
||||||
uintptr_t addr = (uintptr_t)(heap + bump);
|
// // Align to 8 bytes (important for capability safety)
|
||||||
|
// size = (size + 7) & ~7;
|
||||||
|
|
||||||
// Create capability to this region
|
// if (bump + size > HEAP_SIZE)
|
||||||
void * __capability cap = cheri_address_set(base, addr);
|
// return NULL;
|
||||||
|
|
||||||
// Enforce bounds (this is the key CHERI feature)
|
// void * __capability base = cheri_ddc_get();
|
||||||
cap = cheri_bounds_set(cap, size);
|
|
||||||
|
|
||||||
// Hard-coded delta value
|
// uintptr_t addr = (uintptr_t)(heap + bump);
|
||||||
cap = add_delta(cap, 10);
|
|
||||||
|
|
||||||
bump += size;
|
// // Create capability to this region
|
||||||
|
// void * __capability cap = cheri_address_set(base, addr);
|
||||||
|
|
||||||
|
// // Enforce bounds (this is the key CHERI feature)
|
||||||
|
// cap = cheri_bounds_set(cap, size);
|
||||||
|
|
||||||
|
// // Hard-coded delta value
|
||||||
|
// cap = add_delta(cap, 10);
|
||||||
|
|
||||||
|
// bump += size;
|
||||||
|
|
||||||
return cap;
|
return cap;
|
||||||
}
|
}
|
||||||
|
|
||||||
void bump_reset(void) {
|
// void bump_reset(void) {
|
||||||
bump = 0;
|
// bump = 0;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Can only free if it's in a stack
|
// Free wrapper
|
||||||
// Need to write a free †hat can work
|
|
||||||
// in any sequence
|
|
||||||
// In regular malloc the freelist
|
|
||||||
// is maintained from mmap.
|
|
||||||
void free(void * __capability ptr) {
|
void free(void * __capability ptr) {
|
||||||
if (!ptr) return;
|
// if (!ptr) return;
|
||||||
|
|
||||||
uintptr_t addr = cheri_address_get(ptr);
|
// uintptr_t addr = cheri_address_get(ptr);
|
||||||
size_t size = cheri_length_get(ptr);
|
// size_t size = cheri_length_get(ptr);
|
||||||
|
|
||||||
// Check if this is the most recent allocation
|
// // Check if this is the most recent allocation
|
||||||
if ((char *)addr + size == heap + bump) {
|
// if ((char *)addr + size == heap + bump) {
|
||||||
bump -= size;
|
// bump -= size;
|
||||||
}
|
// }
|
||||||
|
|
||||||
// *ptr = NULL;
|
// Extract raw address from capability
|
||||||
|
void *raw = (void *)cheri_address_get(ptr);
|
||||||
|
|
||||||
|
tiny_free(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quick tests
|
// Quick tests
|
||||||
|
|||||||
601
Tests/isa/CPrograms/malloc_test.c
Normal file
601
Tests/isa/CPrograms/malloc_test.c
Normal file
@@ -0,0 +1,601 @@
|
|||||||
|
// https://github.com/32bitmicro/newlib-nano-1.0/blob/master/newlib/libc/machine/xstormy16/tiny-malloc.c
|
||||||
|
|
||||||
|
/* A replacement malloc with:
|
||||||
|
- Much reduced code size;
|
||||||
|
- Smaller RAM footprint;
|
||||||
|
- The ability to handle downward-growing heaps;
|
||||||
|
but
|
||||||
|
- Slower;
|
||||||
|
- Probably higher memory fragmentation;
|
||||||
|
- Doesn't support threads (but, if it did support threads,
|
||||||
|
it wouldn't need a global lock, only a compare-and-swap instruction);
|
||||||
|
- Assumes the maximum alignment required is the alignment of a pointer;
|
||||||
|
- Assumes that memory is already there and doesn't need to be allocated.
|
||||||
|
|
||||||
|
* Synopsis of public routines
|
||||||
|
|
||||||
|
malloc(size_t n);
|
||||||
|
Return a pointer to a newly allocated chunk of at least n bytes, or null
|
||||||
|
if no space is available.
|
||||||
|
free(void* p);
|
||||||
|
Release the chunk of memory pointed to by p, or no effect if p is null.
|
||||||
|
realloc(void* p, size_t n);
|
||||||
|
Return a pointer to a chunk of size n that contains the same data
|
||||||
|
as does chunk p up to the minimum of (n, p's size) bytes, or null
|
||||||
|
if no space is available. The returned pointer may or may not be
|
||||||
|
the same as p. If p is null, equivalent to malloc. Unless the
|
||||||
|
#define REALLOC_ZERO_BYTES_FREES below is set, realloc with a
|
||||||
|
size argument of zero (re)allocates a minimum-sized chunk.
|
||||||
|
memalign(size_t alignment, size_t n);
|
||||||
|
Return a pointer to a newly allocated chunk of n bytes, aligned
|
||||||
|
in accord with the alignment argument, which must be a power of
|
||||||
|
two. Will fail if 'alignment' is too large.
|
||||||
|
calloc(size_t unit, size_t quantity);
|
||||||
|
Returns a pointer to quantity * unit bytes, with all locations
|
||||||
|
set to zero.
|
||||||
|
cfree(void* p);
|
||||||
|
Equivalent to free(p).
|
||||||
|
malloc_trim(size_t pad);
|
||||||
|
Release all but pad bytes of freed top-most memory back
|
||||||
|
to the system. Return 1 if successful, else 0.
|
||||||
|
malloc_usable_size(void* p);
|
||||||
|
Report the number usable allocated bytes associated with allocated
|
||||||
|
chunk p. This may or may not report more bytes than were requested,
|
||||||
|
due to alignment and minimum size constraints.
|
||||||
|
malloc_stats();
|
||||||
|
Prints brief summary statistics on stderr.
|
||||||
|
mallinfo()
|
||||||
|
Returns (by copy) a struct containing various summary statistics.
|
||||||
|
mallopt(int parameter_number, int parameter_value)
|
||||||
|
Changes one of the tunable parameters described below. Returns
|
||||||
|
1 if successful in changing the parameter, else 0. Actually, returns 0
|
||||||
|
always, as no parameter can be changed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef __xstormy16__
|
||||||
|
#define MALLOC_DIRECTION -1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MALLOC_DIRECTION
|
||||||
|
#define MALLOC_DIRECTION 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
void* tiny_malloc(size_t);
|
||||||
|
void tiny_free(void*);
|
||||||
|
// void* realloc(void*, size_t);
|
||||||
|
// void* memalign(size_t, size_t);
|
||||||
|
// void* valloc(size_t);
|
||||||
|
// void* pvalloc(size_t);
|
||||||
|
// void* calloc(size_t, size_t);
|
||||||
|
// void cfree(void*);
|
||||||
|
// int malloc_trim(size_t);
|
||||||
|
// size_t malloc_usable_size(void*);
|
||||||
|
// void malloc_stats(void);
|
||||||
|
// int mallopt(int, int);
|
||||||
|
// struct mallinfo mallinfo(void);
|
||||||
|
|
||||||
|
typedef struct freelist_entry {
|
||||||
|
size_t size;
|
||||||
|
struct freelist_entry *next;
|
||||||
|
} *fle;
|
||||||
|
|
||||||
|
extern void * __malloc_end;
|
||||||
|
extern fle __malloc_freelist;
|
||||||
|
|
||||||
|
/* Return the number of bytes that need to be added to X to make it
|
||||||
|
aligned to an ALIGN boundary. ALIGN must be a power of 2. */
|
||||||
|
#define M_ALIGN(x, align) (-(size_t)(x) & ((align) - 1))
|
||||||
|
|
||||||
|
/* Return the number of bytes that need to be subtracted from X to make it
|
||||||
|
aligned to an ALIGN boundary. ALIGN must be a power of 2. */
|
||||||
|
#define M_ALIGN_SUB(x, align) ((size_t)(x) & ((align) - 1))
|
||||||
|
|
||||||
|
extern char *__malloc_start;
|
||||||
|
|
||||||
|
/* This is the minimum gap allowed between __malloc_end and the top of
|
||||||
|
the stack. This is only checked for when __malloc_end is
|
||||||
|
decreased; if instead the stack grows into the heap, silent data
|
||||||
|
corruption will result. */
|
||||||
|
#define MALLOC_MINIMUM_GAP 32
|
||||||
|
|
||||||
|
#ifdef __xstormy16__
|
||||||
|
register void * stack_pointer asm ("r15");
|
||||||
|
#define MALLOC_LIMIT stack_pointer
|
||||||
|
#else
|
||||||
|
#define MALLOC_LIMIT __builtin_frame_address (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if MALLOC_DIRECTION < 0
|
||||||
|
#define CAN_ALLOC_P(required) \
|
||||||
|
(((size_t) __malloc_end - (size_t)MALLOC_LIMIT \
|
||||||
|
- MALLOC_MINIMUM_GAP) >= (required))
|
||||||
|
#else
|
||||||
|
#define CAN_ALLOC_P(required) \
|
||||||
|
(((size_t)MALLOC_LIMIT - (size_t) __malloc_end \
|
||||||
|
- MALLOC_MINIMUM_GAP) >= (required))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* real_size is the size we actually have to allocate, allowing for
|
||||||
|
overhead and alignment. */
|
||||||
|
#define REAL_SIZE(sz) \
|
||||||
|
((sz) < sizeof (struct freelist_entry) - sizeof (size_t) \
|
||||||
|
? sizeof (struct freelist_entry) \
|
||||||
|
: sz + sizeof (size_t) + M_ALIGN(sz, sizeof (size_t)))
|
||||||
|
|
||||||
|
#ifdef DEFINE_MALLOC
|
||||||
|
|
||||||
|
void * __malloc_end = &__malloc_start;
|
||||||
|
fle __malloc_freelist;
|
||||||
|
|
||||||
|
void *
|
||||||
|
tiny_malloc (size_t sz)
|
||||||
|
{
|
||||||
|
fle *nextfree;
|
||||||
|
fle block;
|
||||||
|
|
||||||
|
/* real_size is the size we actually have to allocate, allowing for
|
||||||
|
overhead and alignment. */
|
||||||
|
size_t real_size = REAL_SIZE (sz);
|
||||||
|
|
||||||
|
/* Look for the first block on the freelist that is large enough. */
|
||||||
|
for (nextfree = &__malloc_freelist;
|
||||||
|
*nextfree;
|
||||||
|
nextfree = &(*nextfree)->next)
|
||||||
|
{
|
||||||
|
block = *nextfree;
|
||||||
|
|
||||||
|
if (block->size >= real_size)
|
||||||
|
{
|
||||||
|
/* If the block found is just the right size, remove it from
|
||||||
|
the free list. Otherwise, split it. */
|
||||||
|
if (block->size < real_size + sizeof (struct freelist_entry))
|
||||||
|
{
|
||||||
|
*nextfree = block->next;
|
||||||
|
return (void *)&block->next;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
size_t newsize = block->size - real_size;
|
||||||
|
fle newnext = block->next;
|
||||||
|
*nextfree = (fle)((size_t)block + real_size);
|
||||||
|
(*nextfree)->size = newsize;
|
||||||
|
(*nextfree)->next = newnext;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this is the last block on the freelist, and it was too small,
|
||||||
|
enlarge it. */
|
||||||
|
if (! block->next
|
||||||
|
&& __malloc_end == (void *)((size_t)block + block->size))
|
||||||
|
{
|
||||||
|
size_t moresize = real_size - block->size;
|
||||||
|
if (! CAN_ALLOC_P (moresize))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
*nextfree = NULL;
|
||||||
|
if (MALLOC_DIRECTION < 0)
|
||||||
|
{
|
||||||
|
block = __malloc_end = (void *)((size_t)block - moresize);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
__malloc_end = (void *)((size_t)block + real_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* No free space at the end of the free list. Allocate new space
|
||||||
|
and use that. */
|
||||||
|
|
||||||
|
if (! CAN_ALLOC_P (real_size))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (MALLOC_DIRECTION > 0)
|
||||||
|
{
|
||||||
|
block = __malloc_end;
|
||||||
|
__malloc_end = (void *)((size_t)__malloc_end + real_size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
block = __malloc_end = (void *)((size_t)__malloc_end - real_size);
|
||||||
|
}
|
||||||
|
done:
|
||||||
|
block->size = real_size;
|
||||||
|
// TODO: return as bounds
|
||||||
|
return (void *)&block->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef DEFINE_FREE
|
||||||
|
|
||||||
|
void
|
||||||
|
tiny_free (void *block_p)
|
||||||
|
{
|
||||||
|
fle *nextfree;
|
||||||
|
fle block = (fle)((size_t) block_p - offsetof (struct freelist_entry, next));
|
||||||
|
|
||||||
|
if (block_p == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Look on the freelist to see if there's a free block just before
|
||||||
|
or just after this block. */
|
||||||
|
for (nextfree = &__malloc_freelist;
|
||||||
|
*nextfree;
|
||||||
|
nextfree = &(*nextfree)->next)
|
||||||
|
{
|
||||||
|
fle thisblock = *nextfree;
|
||||||
|
if ((size_t)thisblock + thisblock->size == (size_t) block)
|
||||||
|
{
|
||||||
|
thisblock->size += block->size;
|
||||||
|
if (MALLOC_DIRECTION > 0
|
||||||
|
&& thisblock->next
|
||||||
|
&& (size_t) block + block->size == (size_t) thisblock->next)
|
||||||
|
{
|
||||||
|
thisblock->size += thisblock->next->size;
|
||||||
|
thisblock->next = thisblock->next->next;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if ((size_t) thisblock == (size_t) block + block->size)
|
||||||
|
{
|
||||||
|
if (MALLOC_DIRECTION < 0
|
||||||
|
&& thisblock->next
|
||||||
|
&& (size_t) block == ((size_t) thisblock->next
|
||||||
|
+ thisblock->next->size))
|
||||||
|
{
|
||||||
|
*nextfree = thisblock->next;
|
||||||
|
thisblock->next->size += block->size + thisblock->size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
block->size += thisblock->size;
|
||||||
|
block->next = thisblock->next;
|
||||||
|
*nextfree = block;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if ((MALLOC_DIRECTION > 0
|
||||||
|
&& (size_t) thisblock > (size_t) block)
|
||||||
|
|| (MALLOC_DIRECTION < 0
|
||||||
|
&& (size_t) thisblock < (size_t) block))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
block->next = *nextfree;
|
||||||
|
*nextfree = block;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// #ifdef DEFINE_REALLOC
|
||||||
|
// void *
|
||||||
|
// realloc (void *block_p, size_t sz)
|
||||||
|
// {
|
||||||
|
// fle block = (fle)((size_t) block_p - offsetof (struct freelist_entry, next));
|
||||||
|
// size_t real_size = REAL_SIZE (sz);
|
||||||
|
// size_t old_real_size;
|
||||||
|
|
||||||
|
// if (block_p == NULL)
|
||||||
|
// return malloc (sz);
|
||||||
|
|
||||||
|
// old_real_size = block->size;
|
||||||
|
|
||||||
|
// /* Perhaps we need to allocate more space. */
|
||||||
|
// if (old_real_size < real_size)
|
||||||
|
// {
|
||||||
|
// void *result;
|
||||||
|
// size_t old_size = old_real_size - sizeof (size_t);
|
||||||
|
|
||||||
|
// /* Need to allocate, copy, and free. */
|
||||||
|
// result = malloc (sz);
|
||||||
|
// if (result == NULL)
|
||||||
|
// return NULL;
|
||||||
|
// memcpy (result, block_p, old_size < sz ? old_size : sz);
|
||||||
|
// free (block_p);
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
// /* Perhaps we can free some space. */
|
||||||
|
// if (old_real_size - real_size >= sizeof (struct freelist_entry))
|
||||||
|
// {
|
||||||
|
// fle newblock = (fle)((size_t)block + real_size);
|
||||||
|
// block->size = real_size;
|
||||||
|
// newblock->size = old_real_size - real_size;
|
||||||
|
// free (&newblock->next);
|
||||||
|
// }
|
||||||
|
// return block_p;
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef DEFINE_CALLOC
|
||||||
|
// void *
|
||||||
|
// calloc (size_t n, size_t elem_size)
|
||||||
|
// {
|
||||||
|
// void *result;
|
||||||
|
// size_t sz = n * elem_size;
|
||||||
|
// result = malloc (sz);
|
||||||
|
// if (result != NULL)
|
||||||
|
// memset (result, 0, sz);
|
||||||
|
// return result;
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef DEFINE_CFREE
|
||||||
|
// void
|
||||||
|
// cfree (void *p)
|
||||||
|
// {
|
||||||
|
// free (p);
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef DEFINE_MEMALIGN
|
||||||
|
// void *
|
||||||
|
// memalign (size_t align, size_t sz)
|
||||||
|
// {
|
||||||
|
// fle *nextfree;
|
||||||
|
// fle block;
|
||||||
|
|
||||||
|
// /* real_size is the size we actually have to allocate, allowing for
|
||||||
|
// overhead and alignment. */
|
||||||
|
// size_t real_size = REAL_SIZE (sz);
|
||||||
|
|
||||||
|
// /* Some sanity checking on 'align'. */
|
||||||
|
// if ((align & (align - 1)) != 0
|
||||||
|
// || align <= 0)
|
||||||
|
// return NULL;
|
||||||
|
|
||||||
|
// /* Look for the first block on the freelist that is large enough. */
|
||||||
|
// /* One tricky part is this: We want the result to be a valid pointer
|
||||||
|
// to free. That means that there has to be room for a size_t
|
||||||
|
// before the block. If there's additional space before the block,
|
||||||
|
// it should go on the freelist, or it'll be lost---we could add it
|
||||||
|
// to the size of the block before it in memory, but finding the
|
||||||
|
// previous block is expensive. */
|
||||||
|
// for (nextfree = &__malloc_freelist;
|
||||||
|
// ;
|
||||||
|
// nextfree = &(*nextfree)->next)
|
||||||
|
// {
|
||||||
|
// size_t before_size;
|
||||||
|
// size_t old_size;
|
||||||
|
|
||||||
|
// /* If we've run out of free blocks, allocate more space. */
|
||||||
|
// if (! *nextfree)
|
||||||
|
// {
|
||||||
|
// old_size = real_size;
|
||||||
|
// if (MALLOC_DIRECTION < 0)
|
||||||
|
// {
|
||||||
|
// old_size += M_ALIGN_SUB (((size_t)__malloc_end
|
||||||
|
// - old_size + sizeof (size_t)),
|
||||||
|
// align);
|
||||||
|
// if (! CAN_ALLOC_P (old_size))
|
||||||
|
// return NULL;
|
||||||
|
// block = __malloc_end = (void *)((size_t)__malloc_end - old_size);
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// block = __malloc_end;
|
||||||
|
// old_size += M_ALIGN ((size_t)__malloc_end + sizeof (size_t),
|
||||||
|
// align);
|
||||||
|
// if (! CAN_ALLOC_P (old_size))
|
||||||
|
// return NULL;
|
||||||
|
// __malloc_end = (void *)((size_t)__malloc_end + old_size);
|
||||||
|
// }
|
||||||
|
// *nextfree = block;
|
||||||
|
// block->size = old_size;
|
||||||
|
// block->next = NULL;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// block = *nextfree;
|
||||||
|
// old_size = block->size;
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// before_size = M_ALIGN (&block->next, align);
|
||||||
|
// if (before_size != 0)
|
||||||
|
// before_size = sizeof (*block) + M_ALIGN (&(block+1)->next, align);
|
||||||
|
|
||||||
|
// /* If this is the last block on the freelist, and it is too small,
|
||||||
|
// enlarge it. */
|
||||||
|
// if (! block->next
|
||||||
|
// && old_size < real_size + before_size
|
||||||
|
// && __malloc_end == (void *)((size_t)block + block->size))
|
||||||
|
// {
|
||||||
|
// if (MALLOC_DIRECTION < 0)
|
||||||
|
// {
|
||||||
|
// size_t moresize = real_size - block->size;
|
||||||
|
// moresize += M_ALIGN_SUB ((size_t)&block->next - moresize, align);
|
||||||
|
// if (! CAN_ALLOC_P (moresize))
|
||||||
|
// return NULL;
|
||||||
|
// block = __malloc_end = (void *)((size_t)block - moresize);
|
||||||
|
// block->next = NULL;
|
||||||
|
// block->size = old_size = old_size + moresize;
|
||||||
|
// before_size = 0;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// if (! CAN_ALLOC_P (before_size + real_size - block->size))
|
||||||
|
// return NULL;
|
||||||
|
// __malloc_end = (void *)((size_t)block + before_size + real_size);
|
||||||
|
// block->size = old_size = before_size + real_size;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// /* Two out of the four cases below will now be possible; which
|
||||||
|
// two depends on MALLOC_DIRECTION. */
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (old_size >= real_size + before_size)
|
||||||
|
// {
|
||||||
|
// /* This block will do. If there needs to be space before it,
|
||||||
|
// split the block. */
|
||||||
|
// if (before_size != 0)
|
||||||
|
// {
|
||||||
|
// fle old_block = block;
|
||||||
|
|
||||||
|
// old_block->size = before_size;
|
||||||
|
// block = (fle)((size_t)block + before_size);
|
||||||
|
|
||||||
|
// /* If there's no space after the block, we're now nearly
|
||||||
|
// done; just make a note of the size required.
|
||||||
|
// Otherwise, we need to create a new free space block. */
|
||||||
|
// if (old_size - before_size
|
||||||
|
// <= real_size + sizeof (struct freelist_entry))
|
||||||
|
// {
|
||||||
|
// block->size = old_size - before_size;
|
||||||
|
// return (void *)&block->next;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// fle new_block;
|
||||||
|
// new_block = (fle)((size_t)block + real_size);
|
||||||
|
// new_block->size = old_size - before_size - real_size;
|
||||||
|
// if (MALLOC_DIRECTION > 0)
|
||||||
|
// {
|
||||||
|
// new_block->next = old_block->next;
|
||||||
|
// old_block->next = new_block;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// new_block->next = old_block;
|
||||||
|
// *nextfree = new_block;
|
||||||
|
// }
|
||||||
|
// goto done;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// /* If the block found is just the right size, remove it from
|
||||||
|
// the free list. Otherwise, split it. */
|
||||||
|
// if (old_size <= real_size + sizeof (struct freelist_entry))
|
||||||
|
// {
|
||||||
|
// *nextfree = block->next;
|
||||||
|
// return (void *)&block->next;
|
||||||
|
// }
|
||||||
|
// else
|
||||||
|
// {
|
||||||
|
// size_t newsize = old_size - real_size;
|
||||||
|
// fle newnext = block->next;
|
||||||
|
// *nextfree = (fle)((size_t)block + real_size);
|
||||||
|
// (*nextfree)->size = newsize;
|
||||||
|
// (*nextfree)->next = newnext;
|
||||||
|
// goto done;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// done:
|
||||||
|
// block->size = real_size;
|
||||||
|
// return (void *)&block->next;
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef DEFINE_VALLOC
|
||||||
|
// void *
|
||||||
|
// valloc (size_t sz)
|
||||||
|
// {
|
||||||
|
// return memalign (128, sz);
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
// #ifdef DEFINE_PVALLOC
|
||||||
|
// void *
|
||||||
|
// pvalloc (size_t sz)
|
||||||
|
// {
|
||||||
|
// return memalign (128, sz + M_ALIGN (sz, 128));
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef DEFINE_MALLINFO
|
||||||
|
// #include "malloc.h"
|
||||||
|
|
||||||
|
// struct mallinfo
|
||||||
|
// mallinfo (void)
|
||||||
|
// {
|
||||||
|
// struct mallinfo r;
|
||||||
|
// fle fr;
|
||||||
|
// size_t free_size;
|
||||||
|
// size_t total_size;
|
||||||
|
// size_t free_blocks;
|
||||||
|
|
||||||
|
// memset (&r, 0, sizeof (r));
|
||||||
|
|
||||||
|
// free_size = 0;
|
||||||
|
// free_blocks = 0;
|
||||||
|
// for (fr = __malloc_freelist; fr; fr = fr->next)
|
||||||
|
// {
|
||||||
|
// free_size += fr->size;
|
||||||
|
// free_blocks++;
|
||||||
|
// if (! fr->next)
|
||||||
|
// {
|
||||||
|
// int atend;
|
||||||
|
// if (MALLOC_DIRECTION > 0)
|
||||||
|
// atend = (void *)((size_t)fr + fr->size) == __malloc_end;
|
||||||
|
// else
|
||||||
|
// atend = (void *)fr == __malloc_end;
|
||||||
|
// if (atend)
|
||||||
|
// r.keepcost = fr->size;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (MALLOC_DIRECTION > 0)
|
||||||
|
// total_size = (char *)__malloc_end - (char *)&__malloc_start;
|
||||||
|
// else
|
||||||
|
// total_size = (char *)&__malloc_start - (char *)__malloc_end;
|
||||||
|
|
||||||
|
// #ifdef DEBUG
|
||||||
|
// /* Fixme: should walk through all the in-use blocks and see if
|
||||||
|
// they're valid. */
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// r.arena = total_size;
|
||||||
|
// r.fordblks = free_size;
|
||||||
|
// r.uordblks = total_size - free_size;
|
||||||
|
// r.ordblks = free_blocks;
|
||||||
|
// return r;
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef DEFINE_MALLOC_STATS
|
||||||
|
// #include "malloc.h"
|
||||||
|
// #include <stdio.h>
|
||||||
|
|
||||||
|
// void
|
||||||
|
// malloc_stats(void)
|
||||||
|
// {
|
||||||
|
// struct mallinfo i;
|
||||||
|
// FILE *fp;
|
||||||
|
|
||||||
|
// fp = stderr;
|
||||||
|
// i = mallinfo();
|
||||||
|
// fprintf (fp, "malloc has reserved %u bytes between %p and %p\n",
|
||||||
|
// i.arena, &__malloc_start, __malloc_end);
|
||||||
|
// fprintf (fp, "there are %u bytes free in %u chunks\n",
|
||||||
|
// i.fordblks, i.ordblks);
|
||||||
|
// fprintf (fp, "of which %u bytes are at the end of the reserved space\n",
|
||||||
|
// i.keepcost);
|
||||||
|
// fprintf (fp, "and %u bytes are in use.\n", i.uordblks);
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef DEFINE_MALLOC_USABLE_SIZE
|
||||||
|
// size_t
|
||||||
|
// malloc_usable_size (void *block_p)
|
||||||
|
// {
|
||||||
|
// fle block = (fle)((size_t) block_p - offsetof (struct freelist_entry, next));
|
||||||
|
// return block->size - sizeof (size_t);
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
|
|
||||||
|
// #ifdef DEFINE_MALLOPT
|
||||||
|
// int
|
||||||
|
// mallopt (int n, int v)
|
||||||
|
// {
|
||||||
|
// (void)n; (void)v;
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
// #endif
|
||||||
BIN
Tests/isa/testC
BIN
Tests/isa/testC
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user