; Listing6-1.asm ; ; A program that demonstrates classes in MASM. option casemap:none include aoaTypes.inc include aoaMacros.inc include aoaClasses.inc include aoalib.inc includelib aoalib.lib .const ; Program title: align word ttlStr byte "Listing 6-1", 0 ; Class names for to the class objects: myClassName byte "myClass", 0 myClass2Name byte "myClass2", 0 ; Sample class type declarations: ; ; myClass is a base class (not derived ; from any other class). class myClass onHeap byte ? className qword ? virtual myFunc virtual myFunc2 endc myClass ; The "this" pointer for myClass: myClass@ textequ <(myClass ptr [rsi])> ; myClass2 is derived from myClass. ; ; It adds a new data field ("c"). ; It adds a new virtual method ("myFunc3") ; It overrides the myFunc2 method in the ; base class (replacing it with myFunc2a). class myClass2, inherits(myClass) c byte ? virtual myFunc3 override myFunc2, myClass2$myFunc2 endc myClass2 ; The "this" pointer for myClass2: myClass2@ textequ <(myClass2 ptr [rsi])> .data ; Allocate storage for two objects of the ; two class types above: mc1 myClass {} mc2 myClass2 {} mc3 qword ? ;Ptr to myClass2 .const ; Emit the VMTs for these classes. emitVMT myClass emitVMT myClass2 .code ; Here are the four methods for the two classes: ; myClass$myFunc: myClass$myFunc proc push rdx mov rdx, myClass@.className call print byte "In %s:myClass$myFunc", nl, 0 pop rdx ret myClass$myFunc endp ; myClass$myFunc2: myClass$myFunc2 proc push rdx mov rdx, myClass@.className call print byte "In %s:myClass$myFunc2", nl, 0 pop rdx ret myClass$myFunc2 endp ; myClass2$myFunc2 -- override2 myClass$myFunc2: myClass2$myFunc2 proc push rdx mov rdx, myClass2@.className call print byte "In %s:myClass2$myFunc2(ovr)", nl byte "Calling super->myFunc2", nl, 0 ; Demonstrate how to call the "super" myFunc2 ; function (myClass$myFunc2) from within this method. ; RSI points at the current object (which is fine) ; but we have to use the VMT for myClass (the parent, ; or super, class) when calling myFunc2 inv myClass2, myFunc2, rsi, super pop rdx ret myClass2$myFunc2 endp ; myClass2.myFunc3: myClass2$myFunc3 proc push rdx mov rdx, myClass2@.className call print byte "In %s:myClass2$myFunc3", nl, 0 pop rdx ret myClass2$myFunc3 endp ; Constructor for myClass: ; ; On entry: ; ; RSI- Pointer to object to initialize, or ; NULL (0) if this constructor is to ; allocate storage on the heap for the ; object. ; RCX- Point to string containing the name ; of the class. myClass$create proc push rcx push rsi ;To NULL check mov ecx, sizeof myClass lea rdi, vmtAdrs(myClass) call generic$Class$Constructor pop rcx ;Original RSI value test rsi, rsi ;Did allocation fail? jz failure ; Check to see if object was allocated on heap. Set the ; onHeap field to true if it was: test rcx, rcx setz cl mov myClass@.onHeap, cl ; Initialize pointer to field name: lea rcx, myClassName mov myClass@.className, rcx failure: pop rcx ret myClass$create endp ; Constructor for myClass2: myClass2$create proc push rcx push rsi mov ecx, sizeof myClass2 lea rdi, vmtAdrs(myClass2) call generic$Class$Constructor pop rcx ;Original RSI value test rsi, rsi ;Did allocation fail? jz failure ; Check to see if object was allocated on heap. Set the ; onHeap field to true if it was: test rcx, rcx setz cl mov myClass2@.onHeap, cl ; Initialize pointer to field name: lea rcx, myClass2Name mov myClass2@.className, rcx ; Set up the VMT pointer: lea rdi, vmtAdrs(myClass2) mov myClass2@.VMT, rdi failure: pop rcx ret myClass2$create endp ;-------------------------------------------------- ; ; Here is the main assembly language function. public asmMain asmMain proc saveRBX textequ <[rbp-8]> saveRSI textequ <[rbp-16]> saveRDI textequ <[rbp-24]> push rbp mov rbp, rsp sub rsp, 128 and rsp, -16 mov saveRBX, rbx mov saveRSI, rsi mov saveRDI, rdi ; Initialize the mc1 object by calling ; myClass$create (the constructor): lea rsi, mc1 call myClass$create ; Demonstrate accessing fields and calling ; virtual methods: mov rdx, mc1.className call print byte nl byte "------------------------------", nl byte "mc1 class=%s", nl, 0 call print byte "------------------------------", nl byte "Calling myFunc and myFunc2 via", nl byte "the mc1 object:", nl, 0 call print byte nl byte "inv mc1->myClass, myFunc:", nl, 0 inv myClass, myFunc call print byte nl byte "inv mc1->myClass, myFunc2:", nl, 0 inv myClass, myFunc2, rsi ; Initialize the mc2 object by calling ; myClass2$create (the constructor): lea rsi, mc2 call myClass2$create ; Access the inherited data field: mov rdx, mc2.className call print byte nl byte "------------------------------", nl byte "mc2 class=%s", nl, 0 call print byte "------------------------------" byte nl, nl, 0 ; Demonstrate various calls to the myClass2 object: call print byte "inv mc2->myClass2, _myClass2(myFunc), " byte "rsi, rdi:", nl, 0 inv myClass2, myFunc, rsi, rdi ; This call treats the pointer in RSI as a generic ; object of type myClass. Because myFunc2 was ; overridden, this actually winds up calling ; myFunc2a rather than myClass.myFunc2. call print byte nl byte "inv mc2->myClass, _myClass(myFunc2):", nl, 0 inv myClass, myFunc2 ; We can also call myFunc2 directly: call print byte nl byte "inv mc2->myClass2, _myClass2(myFunc2):", nl, 0 inv myClass2, myFunc2 ; Call the virtual function that is specific ; to myClass2: call print byte nl byte "inv mc2->myClass2, _myClass2(myFunc3):", nl, 0 inv myClass2, myFunc3 call print byte nl byte "-------------------------------", nl byte "Demonstrate loading the address", nl byte "of the mc1 object into RSI:" byte nl, 0 ; Demonstrate loading RSI with the address ; of an object using the "@" operator: call print byte nl byte "inv mc1->myClass, myFunc, @mc1:", nl, 0 inv myClass, myFunc, @mc1 call print byte nl, nl byte "-------------------------------", nl byte "Creating a new object on the", nl byte "heap (calling myClass2$create", nl byte "with RSI=0)", nl, 0 xor rsi, rsi call myClass2$create mov mc3, rsi call print byte "inv mc3->myClass2, _myClass2(myFunc), " byte "rsi, rdi:", nl, 0 inv myClass2, myFunc, rsi, rdi call print byte nl byte "inv mc3->myClass, _myClass2(myFunc2):", nl, 0 inv myClass, myFunc2 call print byte nl byte "inv mc3->myClass3, _myClass2(myFunc3):", nl, 0 inv myClass2, myFunc3 mov rbx, saveRBX mov rsi, saveRSI mov rdi, saveRDI leave ret ;Returns to caller asmMain endp end