Skip to content

Instantly share code, notes, and snippets.

@ChrisMoney
Created March 1, 2012 02:27
Show Gist options
  • Save ChrisMoney/49652f3ce8d18e444e62 to your computer and use it in GitHub Desktop.
Save ChrisMoney/49652f3ce8d18e444e62 to your computer and use it in GitHub Desktop.
Assembly - Program manages memory usage
#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