How To: OOP in assembly language

This post is a response to forum question posted by modchip:

"Recently, I've seen a lot of stuff about doing OOP in assembly language. Most of the stuff I've seen almost fried my brain. So... does anybody have some simple (by simple, I mean very simple) examples to get n00bs like me started? What are the basic requirements? What are its advantages? I would definitely want to learn more about this."


Definition:


Objects in assembly is implemented only by using structure (which serves as the class definition), defined to have its first member as a pointer to the class's virtual table (vtable), something like this:

    Animal struc
        vtable dd 0
        m_kind db 32 dup (0)
    Animal ends


Instance methods on the other hand are written as normal procedure having the “instance of the class“ as the first argument, known as the `this’ pointer, see these two methods for the Animal class I’ve written:

    GetKind@Animal proc $this:dword

       mov eax, $this                 ; setup the $this argument to EAX
       add eax, offset Animal.m_kind  ; Add the offset of member variable m_kind
       ret                            ; Return it

    GetKind@Animal endp

    SetKind@Animal proc uses esi edi $this:dword, lpValue:dword

       invoke GetKind@Animal, $this   ; Get the address of the member variable 
       invoke szCopy, lpValue, eax    ; Set it  with different value

       xor eax, eax
       ret

    SetKind@Animal endp


As you can see, there’s nothing fancy about writing methods, all you need is a naming convention that will help you work with unique namings. I use $this as the name of the `this’ pointer, and for method name, I use method name + ‘@’ character + name of the class who owns the method, thus GetKind@Animal and SetKind@Animal. For overloaded methods, I just append '@' + size of arguments. Something like, if I overloaded GetKind@Animal with argument for catching the output, I'll be writing it as: GetKind@Animal@4 where @4 means 1 DWORD argument pass the $this pointer.

Inside each methods, all you need is knowledge of working with assembly structures to get around with the $this pointer. In my example, I simply added the offset of the member I’m interested in, with the $this pointer:

    mov eax, $this                    ; setup the $this argument to EAX
    add eax, offset Animal.m_kind     ; Add the offset of member variable m_kind
my_class struc
        vtable dd 0
    my_class ends


Note: you only need vtable if there are virtual members defined (members that can be overridden by derived classes). I'll get to that on my next post.

This structure also holds all instance variables for that class.
Let’s assume we have a class called Animal with instance variable m_kind as 32 bytes, then our structure will be written like this:

That’s how I set register to point to the correct member variable. The code above, EAX now holds the effective address of Instance.m_kind. Then we can return it, or perform whatever logic we desire to that member variable.


Instanciation:

Creating an instance of the class is simply declaring a variable of type structure we’ve defined earlier:

     .data
       AnimalInstance Animal <>

Then call the constructor as "the first thing" before using the instance (if you want). C++ calls the constructor automagically for you (even creating default constructor for you), but in assembly, it’s up to you whether you want to call the constructor or not (you can actually implement constructorless objects).

Ok, assuming we've declared a default constructor ctor@Animal, calling it is similar to calling assembly procedure, passing the instance as the first argument:

    push offset AnimalInstance
    call ctor@Animal

Similar to calling the constructor above, calling the method is no different. Let’s assume we want to set the animal’s kind to “Bird” by calling the methof SetKind@Animal, you can do it this way: 

    .data
        AnimalInstance Animal <>
        animalInstanceKind db "Bird", 0

    .code
        push offset animalInstanceKind
        push offset AnimalInstance
        call SetKind@Animal

 I suggest to define a prototype for the methods, so we can use the MASM’s invoke:

     SetKind@Animal proto :dword, :dword

   
.code
        invoke SetKind@Animal, addr AnimalInstance, addr animalInstanceKind


Benefits:

I can't think of any good benefits, really. Implementing OOP in a non-OOP compiler is simply a kind of workaround which introduces much work and maintenance than working with procedural which is what's available in assembly language.

Benefits probably will count if OOP is available built-in in an assembler. HLA is one of the 'compiler' that provides this "built-in" functionality; and also, there's ObjAsm32 too, implementing OOP using set of MASM macros (emulating OOP keywords).



Closing:

That’s basically pretty much of it, practice and enjoy OOP in assembly language.
Thanks for reading. I’ll cover Overloading, Inheritance, Static and Virtual members on my next post.

Until the next time, happy coding.  

 

 

Attachment: oopasm1.zip
Published 08-22-2008 9:29 AM by cvega
Filed under: ,

Comments

# re: How To: OOP in assembly language (part 1)

Sunday, August 24, 2008 9:33 PM by modchip

Great! Thanks!!!

# Recent Links Tagged With "communityserver" - JabberTags

Sunday, October 05, 2008 3:19 AM by Recent Links Tagged With "communityserver" - JabberTags

Pingback from  Recent Links Tagged With "communityserver" - JabberTags