Writing a Simple Operating System — from Scratch

(Jeff_L) #1

CHAPTER 5. WRITING, BUILDING, AND LOADING YOUR


KERNEL 49


void my_function () {
char* my_string = "Hello";
}

As before, we can disassemble to give something like that in Figure XXX.

00000000 55 push ebp
00000001 89E5 mov ebp ,esp
00000003 83EC10 sub esp ,byte +0x10
00000006 C745FA48656C6C mov dword [ebp -0x6],0x6c6c6548
0000000D 66 C745FE6F00 mov word [ebp -0x2],0x6f
00000013 C9 leave
00000014 C3 ret

Firstly, to get our bearings we look for theretinstruction, that marks the end of the
function. We see that the first two instructions of the function set the stack frame up,
as usual. The next instruction, which we have also seen before,sub esp,byte +0x10,
allocates 16 bytes on the stack to store our local variable. Now, the next instruction,
mov dword [ebp-0x4],0xf, should have a familiar form, since it stores a value in our
variable; but why does it store the number0xf--- we didn’t tell it to do that, did we?
After storing this suspicious value, we see the function politley revert the stack to the
callers stack frame (leave) then return (ret). But look, there are five more instructions
after the end of the function! What do you think the instructiondec eaxis doing?
Perhaps it decreases the value ofeaxby 1, but why? And what about the rest of the
instructions?
At times like this we need to do a sanity check, and remember that: the disasembler
cannot distinguish between code and data; and somewhere in that code must be data
for the string we defined. Now, we know that our function consists of the first half of
the code, since these instructions made sense to us, and they ended withret. If we now
assume that the rest of the code is in fact our data, then the suspicious value,0xf, that
was stored in our variable makes sense, because it is the offset from the start of the code
to where the data begins: our pointer variable is being set the the address of the data.
To reassure our instincts, if we looked up in an ASCII table the character values of our
string‘‘Hello’’, we would find them to be0x48,0x65,0x6c,0x6c, and0x6f. Now it
is becoming clear, because if we look at the middle column of the disasembler output we
see that these are the machine code bytes for those strange instructions that didn’t seem
to make sense; we see also that the very last byte is0x0, which C adds automatically to
the end of strings, so that, like in our assembly routineprintstring, during processing
we can easily determine when we reach the end of the string.


5.2 Executing our Kernel Code


Enough of the theory, let’s boot and execute the simplest of kernels written in C. This step
will use all we have learnt so far, and will pave the way to faster progress in developing
our operating system’s features.

Free download pdf