Team LiB
Previous Section Next Section

Using Our Allocator

The programs we do in this book aren't complicated enough to necessitate a memory manager. Therefore, we will just use our memory manager to allocate a buffer for one of our file reading/writing programs instead of assigning it in the .bss.

The program we will demonstrate this on is read-records.s from Chapter 6. This program uses a buffer named record_buffer to handle its input/output needs. We will simply change this from being a buffer defined in .bss to being a pointer to a dynamically-allocated buffer using our memory manager. You will need to have the code from that program handy as we will only be discussing the changes in this section.

The first change we need to make is in the declaration. Currently it looks like this:

 .section .bss
 .lcomm, record_buffer, RECORD_SIZE

It would be a misnomer to keep the same name, since we are switching it from being an actual buffer to being a pointer to a buffer. In addition, it now only needs to be one word big (enough to hold a pointer). The new declaration will stay in the .data section and look like this:

record_buffer_ptr:
 .long 0

Our next change is we need to initialize our memory manager immediately after we start our program. Therefore, right after the stack is set up, the following call needs to be added:

 call allocate_init

After that, the memory manager is ready to start servicing memory allocation requests. We need to allocate enough memory to hold these records that we are reading. Therefore, we will call allocate to allocate this memory, and then save the pointer it returns into record_buffer_ptr. Like this:

 pushl $RECORD_SIZE
 call  allocate
 movl  %eax, record_buffer_ptr

Now, when we make the call to read_record, it is expecting a pointer. In the old code, the pointer was the immediate-mode reference to record_buffer. Now, record_buffer_ptr just holds the pointer rather than the buffer itself. Therefore, we must do a direct mode load to get the value in record_buffer_ptr. We need to remove this line:

pushl $record_buffer

And put this line in its place:

pushl record_buffer_ptr

The next change comes when we are trying to find the address of the firstname field of our record. In the old code, it was $RECORD_FIRSTNAME + record_buffer. However, that only works because it is a constant offset from a constant address. In the new code, it is the offset of an address stored in record_buffer_ptr. To get that value, we will need to move the pointer into a register, and then add $RECORD_FIRSTNAME to it to get the pointer. So where we have the following code:

 pushl $RECORD_FIRSTNAME + record_buffer

We need to replace it with this:

 movl  record_buffer_ptr, %eax
 addl  $RECORD_FIRSTNAME, %eax
 pushl %eax

Similarly, we need to change the line that says

 movl  $RECORD_FIRSTNAME + record_buffer, %ecx

so that it reads like this:

 movl  record_buffer_ptr, %ecx
 addl  $RECORD_FIRSTNAME, %ecx

Finally, one change that we need to make is to deallocate the memory once we are done with it (in this program it's not necessary, but it's a good practice anyway). To do that, we just send record_buffer_ptr to the deallocate function right before exitting:

 pushl record_buffer_ptr
 call  deallocate

Now you can build your program with the following commands:

as read-records.s -o read-records.o
ld alloc.o read-record.o read-records.o write-newline.o count-
chars.o -o read-records

You can then run your program by doing ./read-records.

The uses of dynamic memory allocation may not be apparent to you at this point, but as you go from academic exercises to real-life programs you will use it continually.


Team LiB
Previous Section Next Section