Page 1 of 1

Object Oriented Programming in Assembly

#1 Martyn.Rae  Icon User is offline

  • The programming dinosaur
  • member icon

Reputation: 540
  • View blog
  • Posts: 1,406
  • Joined: 22-August 09

Posted 28 February 2011 - 10:57 PM

*
POPULAR

Object Oriented Programming in Assembly

Introduction

This tutorial explains how to write an assembler program that is based on the object oriented paradigm. To achieve this goal, I will use the Microsoft C++ class implementation and demonstrate what is required to write such classes in masm.

Class Structures

Let's start with a simple class called foo. This class has one member variable called m_foo_counter and two member functions get_counter and set_counter. In C++, this would be written as:-

class foo {
    private:
        int m_counter;
    public:
        int get_counter() { return m_counter; };
        void set_counter(int counter) { m_counter = counter; };
};



The same code can be written in C as follows:

    struct foo {
        int m_counter;
    };

    int foo_get_counter(foo * _THIS) { return _THIS->m_counter; };
    void foo_set_counter(foo * _THIS, int counter) { _THIS->m_counter = counter; };



Notice I have prepended get_counter and set_counter with foo_. This is to ensure that we know that these routines are 'members' of the class foo. This is for code documentation and serves no other purpose.

We can now convert this into MASM as follows:

foo                   struct
    m_counter         dd        ?
foo                   ends

                     .code
foo_get_counter       proc      object:DWORD
                      mov       ebx, object
                      mov       eax, foo.m_counter[ebx]
                      ret
foo_get_counter       endp

foo_set_counter       proc      object:DWORD, counter:DWORD
                      mov       ebx, object
                      mov       eax, counter
                      mov       foo.m_counter[ebx], eax
                      ret
foo_set_counter       endp



Hopefully, the example provided above was self-explanatory.

Virtual Functions

Let's extend our class foo defined above and provide it with a virtual function called check_counter. So we would have:

class foo {
    private:
        int m_counter;
    public:
        int get_counter() { return m_counter; };
        void set_counter(int counter) { m_counter = counter; };
        virtual bool check_counter(int minimum, int maximum) {
            if ( m_counter < minimum || m_counter > maximum ) return false;
            return true;
        }
};



Now, we have a different kettle of fish altogether, as the class now has to implement what is known as a vtable. The vtable is a table that contains a list of function pointers that could be overridden by a derived class.

The vtable pointer in Microsoft C++ is held as an invisible member variable, and precedes any other member variable.

Obviously, only functions defined with the virtual keyword in the class definition appear in the vtable, and the vtable of a derived class cannot contain less than the number of function pointers as it's base class(es). Any virtual functions declared in the derived class will appear after the functions of it's base class(es). Finally, the order of the virtual function declarations in the base class(es) and therefore the function pointers in the vtable is matched in derived classes. So, the fourth vtable function in the base class e.g foobar, will be the either the base vtable function pointer or the function pointer to the overridden foobar in a derived class.

Let's see how this is implemented in 'C'.

    struct foo;
    typedef bool (*check_counter)(foo * _THIS, int minimum, int maximum);

    struct foo_vtable {
        check_counter foo_check_counter;
    };

    struct foo {
        foo_vtable * m_vtable;
        int m_counter;
    };

    int foo_get_counter(foo * _THIS) { return _THIS->m_counter; };
    void foo_set_counter(foo * _THIS, int counter) { _THIS->m_counter = counter; };
    bool foo_check_counter(foo * _THIS, int minimum, int maximum) {
        if ( _THIS->m_counter < minimum || _THIS->m_counter > maximum ) return false;
        return true;
    }

    foo_vtable vt_foo = { foo_check_counter };




To use the code above, here is a code snippet.

    int main(int argc, char *argv[]) {
        foo * foo_instance = (foo *)malloc(sizeof(foo));
        foo_instance->m_vtable = &vt_foo;
        foo_set_counter(foo_instance, 11);
        bool result = foo_instance->m_vtable->foo_check_counter(foo_instance, 0, 10);
        free(foo_instance);
    }



Converting the 'C' code to MASM we get:

foo                   struct
    m_vtable          dd        ?
    m_counter         dd        ?
foo                   ends

                      .const
foo_vtable            dd        foo_check_counter

                      .data
foo_instance          foo       <foo_vtable, 0>

                      .code
foo_get_counter       proc      object:DWORD
                      mov       ebx, object
                      mov       eax, foo.m_counter[ebx]
                      ret
foo_get_counter       endp

foo_set_counter       proc      object:DWORD, counter:DWORD
                      mov       ebx, object
                      mov       eax, counter
                      mov       foo.m_counter[ebx], eax
                      ret
foo_set_counter       endp

foo_check_counter     proc      object:DWORD, minimum:DWORD, maximum:DWORD
                      mov       ebx, object
                      xor       eax, eax
                      mov       ecx, foo.m_counter[ebx]
                      cmp       ecx, minimum
                      jb        foo_check_counter_1
                      cmp       ecx, maximum
                      ja        foo_check_counter_1
                      inc       eax
foo_check_counter_1:  ret
foo_check_counter     endp



Here is the code to use the check_counter routine.

                      push      10
                      push      0
                      lea       eax, foo_instance
                      push      eax
                      mov       ebx, foo.m_vtable[eax]
                      mov       ecx, DWORD PTR [ebx]
                      call      DWORD PTR [ebx]  



The final stage of this journey is to derive a class from foo. I will call this class oof.

Here is the C++ code.

class foo {
    private:
        int m_counter;
    public:
        int get_counter() { return m_counter; };
        void set_counter(int counter) { m_counter = counter; };
        virtual bool check_counter(int minimum, int maximum) {
            if ( m_counter < minimum || m_counter > maximum ) return false;
            return true;
        }
};

class oof : public foo {
   public:
       bool check_counter(int minimum, int maximum) {
           if ( m_counter < minimum || m_counter > maximum ) return false;
           return true;
       }
}



The defined class code written in 'C'.

    struct foo;
    typedef bool (*check_counter)(foo * _THIS, int minimum, int maximum);

    struct foo_vtable {
        check_counter foo_check_counter;
    };

    struct foo {
        foo_vtable * m_vtable;
        int m_counter;
    };

    struct oof {
        foo_vtable * m_vtable;
        int m_counter;
    };

    int foo_get_counter(foo * _THIS) { return _THIS->m_counter; };
    void foo_set_counter(foo * _THIS, int counter) { _THIS->m_counter = counter; };
    bool foo_check_counter(foo * _THIS, int minimum, int maximum) {
        if ( _THIS->m_counter < minimum || _THIS->m_counter > maximum ) return false;
        return true;
    }
    bool oof_check_counter(foo * _THIS, int minimum, int maximum) {
        if ( _THIS->m_counter < minimum || _THIS->m_counter > maximum ) return false;
        return true;
    }

    foo_vtable vt_foo = { foo_check_counter };
    foo_vtable vt_oof = { oof_check_counter };




Finally, the MASM implementation

foo                   struct
    m_vtable          dd        ?
    m_counter         dd        ?
foo                   ends

                      .const
foo_vtable            dd        foo_check_counter
oof_vtable            dd        oof_check_counter

                      .data
foo_instance          foo       <foo_vtable, 0>

                      .code
foo_get_counter       proc      object:DWORD
                      mov       ebx, object
                      mov       eax, foo.m_counter[ebx]
                      ret
foo_get_counter       endp

foo_set_counter       proc      object:DWORD, counter:DWORD
                      mov       ebx, object
                      mov       eax, counter
                      mov       foo.m_counter[ebx], eax
                      ret
foo_set_counter       endp

foo_check_counter     proc      object:DWORD, minimum:DWORD, maximum:DWORD
                      mov       ebx, object
                      xor       eax, eax
                      mov       ecx, foo.m_counter[ebx]
                      cmp       ecx, minimum
                      jb        foo_check_counter_1
                      cmp       ecx, maximum
                      ja        foo_check_counter_1
                      inc       eax
foo_check_counter_1:  ret
foo_check_counter     endp

oof_check_counter     proc      object:DWORD, minimum:DWORD, maximum:DWORD
                      mov       ebx, object
                      xor       eax, eax
                      mov       ecx, foo.m_counter[ebx]
                      cmp       ecx, minimum
                      jb        oof_check_counter_1
                      cmp       ecx, maximum
                      ja        oof_check_counter_1
                      inc       eax
oof_check_counter_1:  ret
oof_check_counter     endp



Conclusion

I hope that you have understood this tutorial, as it is the way to interface COM and DCOM objects from assembler. Alternately, you could search for an assembler such as HLA that supports object oriented programming.

Is This A Good Question/Topic? 9
  • +

Page 1 of 1