-
Notifications
You must be signed in to change notification settings - Fork 4
/
alloc.s
305 lines (247 loc) · 9.79 KB
/
alloc.s
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#PURPOSE: Program to manage memory usage - allocates
# and deallocates memory as requested
#
#NOTES: The programs 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#
# #########################################################
# ^--Returned 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####
#size of space for memory region header
.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
###########CONSTANTS###########
.equ UNAVAILABLE, 0 #This is the number we will use to mark
#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 SYS_BRK, 45 #system call number for the break
#system call
.equ LINUX_SYSCALL, 0x80 #make system calls easier to read
.section .text
##########FUNCTIONS############
##allocate_init##
#PURPOSE: call this function to initialize the
# functions (specifically, this sets heap_begin and
# current_break). This has no parameters and no
# return value.
.globl 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
movl %eax, heap_begin #store the current break as our
#first address. This will cause
#the allocate function to get
#more memory from Linux the
#first time it is run
movl %ebp, %esp #exit the function
popl %ebp
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 available, 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 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 #standard function stuff
movl %esp, %ebp
movl ST_MEM_SIZE(%ebp), %ecx #%ecx will hold the size
#we are looking for (which is the first
#and 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
jle allocate_here #the size to the needed size. If its
#big enough, go to allocate_here
next_location:
addl $HEADER_SIZE, %eax #The total size of the memory
addl %edx, %eax #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 %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 unavailable
movl $UNAVAILABLE, 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 the function
popl %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 holds its size
#we need to increase %ebx to
#where we _want_ memory
#to end, so we
addl $HEADER_SIZE, %ebx #add space for the headers
#structure
addl %ecx, %ebx #add space to the break for
#the data requested
#now its time to ask Linux
#for more memory
pushl %eax #save needed registers
pushl %ecx
pushl %ebx
movl $SYS_BRK, %eax #reset the break (%ebx 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 unavailable, since we're about to
#give it away
movl $UNAVAILABLE, HDR_AVAIL_OFFSET(%eax)
#set the size of the memory
movl %ecx, HDR_SIZE_OFFSET(%eax)
#move %eax to the actual start of usable memory.
#%eax now holds the return value
addl $HEADER_SIZE, %eax
movl %ebx, current_break #save the new break
movl %ebp, %esp #return the function
popl %ebp
ret
error:
movl $0, %eax #on error, we return zero
movl %ebp, %esp
popl %ebp
ret
########END OF FUNCTION########
##deallocate##
#PURPOSE:
# The purpose of this function is to give back
# a region of memory to the pool after we're done
# using it.
#
#PARAMETERS:
# The only parameter is the address of the memory
# 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 they 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 that memory as available,
# so that the allocate function knows it can use 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 of the fancy function stuff
#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##########