diff options
| author | John Wilbert M. Villamor <lameguy64@gmail.com> | 2019-04-06 10:11:07 +0800 |
|---|---|---|
| committer | John Wilbert M. Villamor <lameguy64@gmail.com> | 2019-04-06 10:11:07 +0800 |
| commit | f3e040230772f978540a71aea43dfde200992922 (patch) | |
| tree | bd8ca31b72dd01e24980b073854e263589530f56 /libpsn00b/libc/malloc.s | |
| download | psn00bsdk-f3e040230772f978540a71aea43dfde200992922.tar.gz | |
First commit
Diffstat (limited to 'libpsn00b/libc/malloc.s')
| -rw-r--r-- | libpsn00b/libc/malloc.s | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/libpsn00b/libc/malloc.s b/libpsn00b/libc/malloc.s new file mode 100644 index 0000000..20e5371 --- /dev/null +++ b/libpsn00b/libc/malloc.s @@ -0,0 +1,216 @@ +# Custom first-fit malloc routines by Lameguy64 +# Part of the PSn00bSDK Project + +.set noreorder + +.set ND_PREV, 0 # Address to previous block (NULL if starting block) +.set ND_NEXT, 4 # Address to next block (NULL if end block) +.set ND_SIZE, 8 # Size of block +.set ND_HSIZ, 12 + +.section .text + + +# Stupid small function just to get bss end +# due to GCC insisting externs to be gp relative +.global GetBSSend +.type GetBSSend, @function +GetBSSend: + la $v0, _end + jr $ra + nop + + +# Initializes the heap for malloc +# a0 - Starting address of heap +# a1 - Size of memory heap +# +.global InitHeap +.type InitHeap, @function +InitHeap: + la $v0, _malloc_addr + sw $a0, 0($v0) + la $v0, _malloc_size + sw $a1, 0($v0) + + sw $0 , ND_PREV($a0) # Set heap header + sw $0 , ND_NEXT($a0) + jr $ra + sw $0 , ND_SIZE($a0) + + +# Allocates a block of memory in the heap +# a0 - Size of memory block to allocate. +# +.global malloc +.type malloc, @function +malloc: + addiu $a0, 3 # Round size to a multiple of 4 + srl $a0, 2 + + la $a2, _malloc_addr + lw $a2, 0($a2) + sll $a0, 2 + +.find_next: + + move $a1, $a2 + + lw $a2, ND_NEXT($a1) # Get block header + lw $v1, ND_SIZE($a1) + + subu $v0, $a2, $a1 # Compute space between current and next + + beqz $v1, .empty_block # Occupy empty block (if size = 0) + nop + + beqz $a2, .new_block # Allocate a new block (if no next) + nop + + addiu $v0, -(ND_HSIZ*2) # Compute remaining space of block + subu $v0, $v1 + + blt $v0, $a0, .find_next # Search for the next block if space is not big enough + nop + + # Perform a block split using remaining space of current block + + addiu $v0, $a1, ND_HSIZ # Compute address for new header + addu $v0, $v1 + + sw $a1, ND_PREV($v0) # Set the new block header + sw $a2, ND_NEXT($v0) + sw $a0, ND_SIZE($v0) + + sw $v0, ND_NEXT($a1) # Update previous and next blocks + sw $v0, ND_PREV($a2) + + jr $ra + addiu $v0, ND_HSIZ + +.empty_block: # Occupy an empty block + + beqz $a2, .no_next # Skip size calculation if there's no next + nop + + addiu $v0, -ND_HSIZ + blt $v0, $a0, .find_next + nop + + b .skip_space_check + nop + +.no_next: + + la $v1, _malloc_addr # Check if there's enough space for a block + lw $v1, 0($v1) + la $v0, _malloc_size + lw $v0, 0($v0) + + subu $v1, $a1, $v1 + addu $v1, $a0 + addiu $v1, ND_HSIZ + + bgt $v1, $v0, .no_space + nop + +.skip_space_check: + + sw $a0, ND_SIZE($a1) + jr $ra # Return address + addiu $v0, $a1, ND_HSIZ + +.new_block: # Create a new block + + addu $a2, $a1, $v1 # Compute address for new block + addiu $a2, ND_HSIZ + + la $v1, _malloc_addr + lw $v1, 0($v1) + la $v0, _malloc_size + lw $v0, 0($v0) + + subu $v1, $a2, $v1 + addu $v1, $a0 + addiu $v1, ND_HSIZ + + bgt $v1, $v0, .no_space # Reject if it exceeds specified size + nop + + sw $a1, ND_PREV($a2) + sw $0 , ND_NEXT($a2) + sw $a0, ND_SIZE($a2) + + sw $a2, ND_NEXT($a1) + + jr $ra # Return address + addiu $v0, $a2, ND_HSIZ + +.no_space: # Return a null if no space can be found + jr $ra + move $v0, $0 + + +# Allocates a block of memory in block units and zero fills the +# allocated block. +# a0 - Block size. +# a1 - Number of blocks to allocate +# +.global calloc +.type calloc, @function +calloc: + mult $a0, $a1 + addiu $sp, -4 + sw $ra, 0($sp) + + jal malloc + mflo $a0 + + move $a0, $v0 + mflo $a1 +.clear_loop: + sw $0 , 0($a0) + addi $a1, 4 + bgtz $a1, .clear_loop + addiu $a0, 4 + + lw $ra, 0($sp) + addiu $sp, 4 + jr $ra + nop + + +# Deallocates an allocated block +# a0 - An address returned by malloc to deallocate +# +.global free +.type free, @function +free: + + addiu $a0, -ND_HSIZ + lw $a1, ND_PREV($a0) + lw $a2, ND_NEXT($a0) + + beqz $a1, .is_start # Check if block is a starting block + nop + + beqz $a2, .is_end + nop + + # Unlink + + sw $a2, ND_NEXT($a1) + jr $ra + sw $a1, ND_PREV($a2) + +.is_end: # Unlinks the ending block + jr $ra + sw $0 , ND_NEXT($a1) +.is_start: # Simply set size to 0 if starting block + jr $ra + sw $0 , ND_SIZE($a0) + + +# Internal variables +.comm _malloc_addr, 4, 4 +.comm _malloc_size, 4, 4 |
