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.





MultiQuote


|