Created
March 1, 2012 02:27
-
-
Save ChrisMoney/49652f3ce8d18e444e62 to your computer and use it in GitHub Desktop.
Assembly - Program manages memory usage
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#PURPOSE: Program to manage memory usage - allocates and deallocates memory as required | |
#NOTES: The program using these routines will ask for a certain size of memory. | |
# We actually use more than that size, but we put it at the beginning, before the pointer we hand back. we add a size field and an AVAILABLE/UNAVAILABLE marker, so the memory looks like this | |
############################################################### | |
# Available Marker#Size of memory#Actual memory locations | |
############################################################## | |
# Return pointer; Pointer points here | |
# The pointer we return only points to the actual locations requested to make it easier for the calling program. it also allows us to change our structure without the calling program having to change at all. | |
.section .data | |
### GLOBAL VARIABLES ### | |
#This points to the beginning of the memory we are managing | |
heap_begin: | |
.long 0 | |
#This points to one location past the memory we are managing | |
current_break: | |
.long 0 | |
### STRUCTURE INFORMATION ### | |
.equ HEADER_SIZE, 8 | |
#Location of the "available" flag in the header | |
.equ HDR_AVAIL_OFFSET, 0 | |
#Location of the size field in the header | |
.equ HDR_SIZE_OFFSET, 4 | |
################ | |
.equ UNAVAILABLE, 0 #This is the number we will use to makr space that has been given out | |
.equ AVAILABLE, 1 #This is the number we will use to mark space that has been returned and | |
# is available for giving | |
.equ LINUX_SYSCALL, 0x80 #make system calls easer to read | |
### FUNCTIONS ### | |
##allocate_unit ## | |
#PURPOSE: call this function to initialize the functions (specifically, this sets heap_begin and #current_break). This has no parameters and no return value | |
.global allocate_init | |
.type allocate_init, @function | |
allocate_init: | |
pushl %ebp #standard function stuff | |
movl %esp, %ebp | |
#If the brk system call is called with 0 in %ebx, it returns the last valid usable address | |
movl $SYS_BRK, %eax #find out where the break is | |
movl $0, %ebx | |
int $LINUX_SYSCALL | |
incl %eax #%eax now has the last valid address and we want the memory location after that | |
movl %eax, current_break #store the current break | |
#store the current break as our first memory address. | |
movl %eax, heap_begin #to get more memory from Linux the first time it is run | |
movl %ebp, %esp | |
pop %ebp #Exit function | |
ret | |
### End of function ### | |
## allocate ## | |
#PURPOSE: This function is used to grab a section of memory. It checks to see if there are any free blocks | |
# and if not, it asks Linux for a new one | |
# PARAMETERS: This function has one parameter - the size of the memory block we want to allocate. | |
# RETURN VALUE: This function returns the address of the allocated memory in %eax. IF there is no memory | |
# availble, it will return 0 in %eax. | |
## PROCESSING ## | |
#VARIABLES USED: | |
# ecx = hold the size of the requested memory (first/only parameter) | |
# eax = current memory region being examined | |
# ebx = current break position | |
# edx = size of current memory region | |
# we can scan through each memory region starting with heap_begin. We look at the size of each one, and if it # has been allocated. If it's big enough for the requested size and its available, it grabs that one. If it $ # does not find a region large enough, it asks Linux for more memory. In that case it moves current_break up | |
.globl allocate | |
.type allocate, @function | |
.equ ST_MEM_SIZE, 8 #stack position of the memory size to allocate | |
allocate: | |
pushl %ebp | |
movl %esp, %ebp | |
movl ST_MEM_SIZE(%ebp), %ecx #ecx will hold the size we are looking for (which is the first & only parameter | |
movl heap_begin, %eax #%eax will hold the current search location | |
movl current_break, %ebx #ebx will hold the current break | |
alloc_loop_begin: #here we iterate through each memory region | |
cmpl %ebx, %eax #need more memory if these are equal | |
je move_break | |
#grab the size of this memory | |
movl HDR_SIZE_OFFSET(%eax), %edx | |
#If the space is unavailable, go to the | |
cmpl $UNAVAILABLE, HDR_AVAIL_OFFSET(%eax) | |
je next_location #next one | |
cmpl %edx, %ecx #If the space is available, compare the size of the needed size. | |
#If its big enough, go to allocate_here | |
jle allocate_here | |
next_location: | |
addl $HEADER_SIZE, %eax #The total size of the memory region is the sum of the size requested | |
#(currently stored in #edx). plus another 8 bytes for the header (4 for the AVAILABLE/UNAVAILABLE FLAG, | |
#(and 4 for the size of the region). so adding %edx and $8 to the #eax will get the address of the next memory region. | |
jmp alloc_loop_begin #go look at the next location | |
allocate_here: #if we've made it here, that means that the region header of the region to allocate is in #eax | |
#mark space as unvavailable | |
movl $UNVAVAILABLE, HDR_AVAIL_OFFSET(%eax) | |
addl $HEADER_SIZE, %eax #move %eax past the header to the usable memory (since that's what we return) | |
movl %ebp, %esp #return from function | |
pop %ebp | |
ret | |
move_break: #if we've made it here, that means that we have exhausted all addressable memory | |
#and we need to ask for more. #ebx holds the current | |
#endpoint of the data, and ecx hold its size | |
#we need to increase %ebx to where we_want_memory to end so add space for the headers structure | |
#add space to the break for the data requested. | |
pushl %eax #save needed registers | |
pushl %ecx | |
pushl %ebx | |
movl $SYS_BRK, %eax | |
#reset the break (%eax has the requested break point) | |
int $LINUX_SYSCALL | |
#under normal conditions, this should return the new break in %eax, which will be either 0 if it fails or it | |
#will be equal to or larger than we asked for. We don't care in this program where it actually sets the break, so as long as %eax isn't 0, we don't care what it is | |
cmpl $0, %eax #check for error conditions | |
je error | |
popl %ebx #restore saved registers | |
popl %ecx | |
popl %eax | |
#set this memory as unvavailable, since we're about to give it away. | |
movl $UNAVAILABLE, HDR_AVAIL_OFFSET(%eax) | |
#set the size of memory | |
movl %ecx, HDR_SIZE_OFFSET(%eax) | |
movl %ebx, current_break #save the new break | |
movl %ebp, %esp #return function | |
popl %ebp | |
ret | |
error: | |
movl $0, %eax #on error, we return zero | |
movl %ebp, %esp | |
popl %ebp | |
ret | |
### END OF FUNCTION ### | |
## DEALLOCATE ## | |
# PURPOSE:This function gives back a region of memory to the pool after we're done using it. | |
# PARAMETERS: The only parameter is the address of the memory as we want to return to the memory pool. | |
# Return Value: | |
# There is no return value | |
#Processing: | |
# If you remember we actually hand the program the start of the memory that we can use, | |
# which is 8 storage locations after the actual start of the memory region. all we have to do is go back 8 locations and mark memory as available, so that the allocate function knows it can used it. | |
.globl deallocate | |
.type deallocate, @function | |
#stack position of the memory region to free | |
.equ ST_MEMORY_SEG, 4 | |
deallocate: | |
#since the function is so simple, we don't need any fancy function | |
#get the address of the memory to free | |
#(normally this is 8($ebp), but since we didn't push %ebp or move %esp to %ebp, we can just do 4(%esp) | |
movl ST_MEMORY_SEG(%esp), %eax | |
#get the pointer to the real beginning of the memory | |
subl $HEADER_SIZE, %eax | |
#mark it as available | |
movl $AVAILABLE, HDR_AVAIL_OFFSET(%eax) | |
#return | |
ret | |
### END OF FUNCTION ## |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment