Use assembly to implement OOP

zhaozj2021-02-16  49

Use assembly to implement OOP

TAOWEN

I have just got started in OOP, just have seen some good materials in this area, I have born my thoughts. I hope to play the role of pouring bricks, leading to the criticism and suggestions of experts.

The OOP and the course-oriented process are the idea of ​​programming. If academics are Paradigm. Some people have said that since CFRONT generates C code, you can implement OOP with C itself and even compilation, but too much thing needs to do itofer. It is indeed this, and the process has long been used in the assembly design. OOP has already had an intersection with the compilation (95 years ago, TASM introduced the concept of OOP). Just assembly implementation OOP is not form, unable to provide Strong-typed and other security guarantees such as C (such as access rights). The package is just a conceptual, consciously observed.

OOP has several key, according to my thickness of understanding: package, inheritance and polymorphism. The specific performance is to put the function of the data and operation data, and the data is placed in the object, providing the interface to implement access. Inheritance achieves semantic or implementation, while reflecting two aspects of the concept level and the code. The polymorphism is the use of Pointer or Reference to implement the polymorphism in different inlay classes using pointers.

OOP's object model has several implementations that have an extremely detailed narrative in "Inside C Object Model":

1. Only put the data in the object, and associate the Member-function with the Class through Name Mangling technology. 2. Single table model, put the Pointe of the Member Function into a separate table, put the entry address of the table into the object (a class corresponds to a table). This is manifested in C as VTBL and VPTR. This model realizes the dynamic flexibility of running, although there are more dereference. 3. Double table model, list the data and function in two tables, then put the portal address of the two tables in the object, so that a single object has a fixed size. 4. Simple model, this is a model used when compiling. That is, the object is saved in the object, and the function address is saved. Whether it is TASM or MASM, it is doing this.

In terms of efficiency, C practice is optimal. Compilation Use the fourth type is forced to have a simplicity of implementation. To a certain extent, it is contrary to the efficient spirit of compilation.

TASM is not commonly used, and its OOP approach and MASM approach is similar. Here mainly discusses MASM OOP practices. The author is Nan and Thomas Bleeker. Its implementation is to use macro definitions to achieve the behind-the-scenes work of the compiler. Among them, there are many skills. But the final use is quite simple. The definition of the macro is placed in an Objects.inc file, and the ASM file contains this INC to use this Object Model.

Although macro is very delicate, after all, MASM lacks the syntax characteristics of OOP, and there are troubles in many ways to use. For example, the virtual function that covers the base class must be completed manually. That is, all parent class or more of all parent classes in the hierarchy need to be done manually in subclasses. Although there is such a shortcoming, OOP has brought a lot of benefits to compilation. such as:

1. Compilation Better and COM, C is interactive in object-oriented domains. Examples of compilation OOP have been used to call COM. If you use assembly OOP to write COM will produce components suitable for high speed and small size. 2. Expand the scope of assembly to solve the problem, making assemblers easier management and cooperation. The author of this Object Model uses the assembly OOP a program based on a neural network, less than 200K (most of whom is the space occupied by the image file). use

Define a solution to a base class.

Prepare the function prototype

Shape_init proto: dword

Shap_Destructorpto typefedef proto: dword

Shap_getareapto type: DWORD

Shap_SetColorpto TypedEf Proto: DWORD,: DWORD

In fact, it is the definition of Struc.

Class Shape, Shap

CMethod Destructor

Cmethod getarea

CMethod setColor

COLOR DD?

Shape ends

.DATA

;initialization

Begin_init

DD Offset Shap_Destructor_funct

DD offset shap_getarea_funct

DD Offset Shap_SetColor_Funct

DD NULL

End_init

.code

Shape_init Proc Uses Edi ESI LPTHIS: DWORD

Dactic call initialization

SET_CLASS Shape

Put EDI Assmue as Shape Type

SetObject EDI, Shape

Additional DPRINT macro, no need to

Dprint "Shape Created (Code In Shape.asm"

Cancellation assmue

ReleaseObject EDI

RET

Shape_init ENDP

Shap_destructor_funct proc buy edi lpthis: dword

SetObject EDI, Shape

DPRINT "Shape Destroyed (Code in Shape.asm"

ReleaseObject EDI

RET

Shap_destructor_funct endp

Shap_SetColor_Funct Proc Uses Edi LPTHIS: DWORD, DATA: DWORD

SetObject EDI, Shape

Mov Eax, Data

MOV [EDI] .color, EAX

Dprint "Shape Color Set !! (Code in Shape.asm)

ReleaseObject EDI

RET

SHAP_SETCOLOR_FUNCT ENDP

SHAP_GETAREA_FUNCT Proc Uses Edi LPTHIS: DWORD

SetObject EDI, Shape

DPRINT ""

DPRINT "Superclassing !!!!! This allows code re-us if you use this method !!"

DPRINT "Shape's getarea method! (Code in shape.asm)

MOV EAX, [EDI] .color

DPRINT "Called from Shape.Getarea, (Code in Shape.asm)

Dprintvalh Eax, "This Objects Color Val IS" DPRINT ""

ReleaseObject EDI

RET

SHAP_GETAREA_FUNCT ENDP

Inherit this class

Include Shape.ASM; Inherited Class Info File

Circle_init proto: dword

Circ_Destructorpto type: DWORD

Circ_setRadiuspto Typedef Proto: DWORD,: DWORD

Circ_getareapto type: DWORD

Class Circle, CIRC

Inherit the original data and functions

Shape <>; inherited class

Cmethod setRadius

RADIUS DD?

Circle Ends

.DATA

Begin_init

DD Offset Circ_Destructor_funct

DD Offset Circ_setRadius_funct

DD NULL

End_init

.code

Circle_init Proc Uses Edi ESI LPTHIS: DWORD

Initialization and implement inheritance

Set_class circle inherits shape

SetObject EDI, CIRCLE

; Equivalent to the constructor reset VPTR

Override Getarea, CirleAreaproc

Dprint "Circle Created (Code In Circle.asm)

ReleaseObject EDI

RET

Circle_init ENDP

Circ_Destructor_funct proc buy edi lpthis: DWORD

SetObject EDI, CIRCLE

DPRINT "Circle Destroyed (Code In Circle.asm"

Implement the call to the base class function

Super Destructor

ReleaseObject EDI

RET

Circ_Destructor_funct endp

Circ_setRadius_funct Proc Uses Edi LPTHIS: DWORD, DATA: DWORD

SetObject EDI, CIRCLE

Mov Eax, Data

MOV [EDI] .radius, EAX

DPRINT "Circle Radius Set (Code In Circle.asm)

ReleaseObject EDI

RET

CIRC_SETRADIUS_FUNCT ENDP

CirleAreaProc Proc Uses Edi LPTHIS: DWORD

Local Temp

SetObject EDI, CIRCLE

Super getarea

Mov Eax, [EDI] .radius

Mov Temp, EAX

Finit

Fild Temp

FIMUL TEMP

FLDPI

Fmul

Fistp Temp

Mov Eax, Temp

DPRINT "Circle Area (Code In Circle.asm)

ReleaseObject EDI

RET

CirleAREAPROC ENDP

Generate objects according to classes and use

Debugc EQU 1

.586

.Model flat, stdcall

Option CaseMAP: NONE

INCLUDE /MASM32/INCLUDE/Windows.inc

INCLUDE /MASM32/INCLUDE /MASM32.INCINCLUDE /MASM32/INCLUDE / WANEL32.INC

INCLUDE /MASM32/INCLUDE/USER32.INC

INCLUDELIB /MASM32/LIB/kernel32.lib

INCLUDELIB /MASM32/LIB/USER32.LIB

INCLUDELIB /MASM32/LIB/MASM32.LIB

Include Dmacros.inc

INCLUDE OBJECTS.INC

INCLUDE CIRCLE.ASM

.DATA

.DATA?

Hcircle DD?

.code

Start:

Recuse all inherited constructors .. and do all inits

DPRINT ""

DPRINT ">>> main.asm <<< [Mov Hcircle, $ New (Circle)]"

Mov Hcircle, $ New (Circle)

DPRINT ""

DPRINT ">>> main.asm <<< [Method Hcircle, Circle, SetColor, 7]

Method Hcircle, Circle, SetColor, 7

DPRINT ""

DPRINT ">>> main.asm <<< [Method Hcircle, Circle, SetRadius, 2]

Method Hcircle, Circle, Setradius, 2

DPRINT ""

DPRINT "------------ Test Polymorphic Method Hcircle.Getarea -------------

DPRINT ""

DPRINT ">>> main.asm <<< [Dprintvald $ Eax (Hcircle, Circle, Getarea), 'Area of ​​Hcircle']

Dprintvald $ Eax (Hcircle, Circle, Getarea), "Area of ​​Hcircle"

DPRINT ""

DPRINT "------------ Test Polymorphic Method Hcircle.Getarea -------------

DPRINT ""

DPRINT ">>> main.asm <<< [Dprintvald $ Eax (Hcircle, Shape, Getarea), 'Area of ​​Hcircle']"

DPRINT "Typing Calling this Ojbect Instance As a Shape Type Only! This is the true value"

DPRINT "of polymorphism. We dont need to know its a circle object in order to get the" "

DPRINT "Proper Area of ​​this Instance Object," "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "" "

DPRINT ""

DprintVald $ Eax (Hcircle, Shape, Getarea), "Area of ​​Hcircle" Dprint ""

DPRINT ""

DPRINT ">>> main.asm <<< [destroy hcircle]"

Destroy Hcircle

DPRINT ""

DPRINT ""

DPRINT "NOTE: Superclassing Here, As Each Destructor Call's The Super Destructor"

DPRINT "To Properly Clean Up After Each Class. To see super classing in"

DPRINT "in the polymorphic getarea function. Uncomment the super code in"

DPRINT "CircleareAproc, And Re-Compile"

Call EXITPROCESS

End Start

It seems quite messy, it is still quite quite quarter. Composed of four parts.

The first part is a statement of each member function. Special must have a "class name _INIT" function, this function is the constructor of the class, the name is this, can not be changed. The second part is a function declared by the class-guided function, in fact, is a Struc, which is the structure. It is used to achieve the inheritance of the structure by the definition of the inherent class. (Inheritance in data is done in the constructor). The third part is the initialization sequence (begin_init, end_init) placed in .data. It is equivalent to C VTBL, but includes the initial value of the data of the object. The fourth part is the implementation of each member function. Particularly, the set_class to be called and the Override that may be called, completed the inheritance of the data and the rewrite of the virtual function.

In actual use, please refer to some existing examples, you can use it. It is really easy to bring great convenience.

principle

All mystery is in Object.inc, which defines the following macros.

; - ================================================ ====================================== -

Macro List Index:

; - ================================================ ============================================= -; NewObject creates new object entities

; Method calls in the entity

; Destroy Destroy Object (MUST)

SetObject puts the pointer in the register "considers" a pointer to a structure

ReleaseObject cancels this "think"

; Override rewrites the address of the function in the form, implement the polymorphism

; Set_class achieves initialization, if necessary, inheritance (MUST)

; SUPER calls the base class function support

;

; $ Eax () Accelerated Method, Returns in EAX

; $ EBX () Accelerated Method, Returns in EBX

; $ ESI () Accelerated Method, Returns in ESI

; $ EDI () Accelerated Method, Returns in EDI

; $ New () accelerated newobject, returns in eax

; $ Super () accelerated super, returns in eax

; $ Destroy () Accelerated Destroy, Returns in Eax

; $ invoke () Accelerated Invoke, Returns in EAX

;

; Begin_init is labeled in the data segment (MUST)

End_init Indicates the end of the tag (MUST)

;

; Class is Struct (MUST)

; Set_interface to declair abbreviated interface and abv name (MUST)

; CMethod declaration or interface function

;

; - ================================================ ===============================================================================================================================================================】 The compiler works behind the scenes. I only list the code before and after the macro expansion, and explain it. For the specific implementation of macros, due to many grammar and skills, it is not convenient for detailed explanation (in fact, I have just passed the checklette, a little read).

Let's take a look at Class first, this is a part of the entrance to the official.

In fact, it is very simple to change the class to Struc.

Class Shape, Shap

CMethod Destructor

Cmethod getarea

CMethod setColor

COLOR DD?

Shape ends

Replace it is

Shape strung

CMethod Destructor

Cmethod getarea

CMethod setColor

COLOR DD?

Shape ends

Very nature, see how cmethod is doing

CMethod Destructor

Becomes

DESTRUCTOR PTR CIRC_DESTRUCTORPTO?

The whole will be launched as:

Shape strung

DESTRUCTOR PTR CIRC_DESTRUCTORPTO?

Getarea PTR CIRC_GETAREAPTO?

SETCOLOR PTR CIRC_SETCOLOR?

COLOR DD?

Shape ends

^ _ ^, The structure is a function pointer and data. Then, the clue is broken. Light This definition is definitely not possible. So, start from the beginning of the object, how New is done.

NewObject Circle

->

Invoke getProcessHeap

Invoke Heapalloc, EAX, NULL, SIZEOF CIRCLE

Push EAX

Invoke Circle_init, EAX

POP EAX

Here, a significant defect is to be used under Win32 because Win32API is used. You can replace the API to an external function. Then put it on a different platform to use as long as you change this dynamic allocation memory.

The resulting code is very simple, that is, allocating memory, then calls the constructor of the object. Here, the constructor of the mandatory requirements should be in the form of "class name _init". Although it is not a big limit, it is not very cool. This is also reasonable. By writing the name on the writing, you can avoid the flexibility to achieve the Overhead in the flexibility, you can see the destructor's form of pointer, because this is because Virtual desturctor.

Ok, let's get into the constructor below, we look at how the constructor is written:

Shape_init Proc Uses Edi ESI LPTHIS: DWORD

SET_CLASS ShapeSetObject EDI, Shape

Dprint "Shape Created (Code In Shape.asm"

ReleaseObject EDI

RET

Shape_init ENDP

LPTHIS should not be unfamiliar, but point to the pointer to the object. An object here is a Sturct. The first line is the key, set_class is the most troublesome and skillful macro. Let's take a look at how to do it.

SET_CLASS Shape

->

PUSH ESI

Push EDI

CLD

Mov ESI, Offset @initvallabel

Mov EDI, LPTHIS

Mov ECX, @initvalsizelabel

SHR ECX, 2

REP MOVSD

Mov ECX, @initvalsizelabel

And ECX, 3

REP MOVSB

POP EDI

POP ESI

Push and POP are practical to save lives. And Mov ESI, Offset @initvallabel is related to Begin_init behind. Offset @initvallabel is also the address marked by Begin_init. This program does not actually do special things. That is to assign the initialization of begin_init and end_init to the object that just new New. LPTHIS is the address of this object. Since set_class always assumes that you call it in a constructor, LPTHIS is of course existing (as a parameter of constructor). CLD, REP MOVVSD, etc. are tips for rapidly moving data for assembly. Check if the manual will know what to do. That is to try to move as a DWORD movement, then move a Byte, until all moved.

If you bring inherit, you have to trouble.

Set_class circle inherits shape

->

PUSH ESI

Push EDI

CLD

Mov EDI, LPTHIS

Mov ESI, Offset @initvallabel

MOV EAX, [ESI]

MOV [EDI], EAX

Add ESI, 4

Add Edi, Inher

Mov ECX, (@initvalsizelabel - 4)

SHR ECX, 2

REP MOVSD

Mov ECX, (@initvalsizelabel - 4)

And ECX, 3

REP MOVSB

POP EDI

POP ESI

Due to inherit, the destructor is reset. Mov Eax, [ESI] and MOV [EDI], EAX did this. Since the address of the designer has changed, only the data members that can only be inherited include the pointer of the virtual function.

Next is the object's destroy

Destroy Hcircle

->

MOV Eax, Hcircle

Push EAX

Call dword ptr [hcircle]

Push EAX

Invoke getProcessHeap

Invoke Heapfree, Eax, Null, Hcircle

POP EAX

Since the address of the destructor is the first member of the object (structure), Call is called the destructor. After calling, use Win32API to release the memory of the application.

Next is the destructor

Circ_Destructor_funct proc buy edi lpthis: DWORD

SetObject EDI, CIRCLE

DPRINT "Circle Destroyed (Code In Circle.asm"

Super DestructorReleaseObject Edi

RET

Circ_Destructor_funct endp

This is the destructuring function of the inheritance class of Shape. There is a super super that implements a function in the invocation base class. Let's continue to see its implementation.

Super Destructor

->

Invoke Circ_Destructorpto Ptr [(Inher_Initdata Inher.MethodName)], LPTHIS

Circ_Destructorpto specifies what kind of function is of the type of this address. Inher is a global thing in the macro, indicating the base class name of this class. The structure of inher_initdata inher.methodName is the actual address in this class in the base class.

The rest is the actual use of functions (you are "unauthorized" operation objects, although it is conceptual. In fact, you can destroy the OOP idea that reflects here. Because the compilation does not provide this protection of).

Method Hcircle, Shape, Getarea

->

MOV EDX, Hcircle

Invoke (Shape PTR [EDX]). Getarea, EDX

The season of harvest. This sentence reflects the idea of ​​polymorphism. Hcircle points to a Circle class object, but interprets it as a Shape class when calling. Go to understand it. Where is the polymorphism.

My point of view

From the global look at this object model, we can find this.

Object data and virtual function pointers are placed in all functions in the same table are virtual inheritance class rewriting base class virtual functions need to be hand-completed after initialization data (in the constructor) only provides rewritten in the upper layer base class. The assignment of the virtual function access memory and releases Win32API

The support of the three features of OOP, as follows

Packaging: There is no special protection for the data (no private). Data and function pointer are placed in the same structure into an object. Access data is completely rely on the provided interface. Inheritance: The structure inheritance is completed by the nesting of structural definitions (including structures that have been defined). Complete the inheritance of the data in the data in SET_CLASS. All inheritance is public. Polymorphism: The narrow understanding of polymorphisms is a different behavior for the call to the same function. We observe the following observations, why this object model supports polymorphism (because it supports derived class for the base class function.).

Class Shape

{

Virtual float getarea ();

......

}

Class Cicle: Public Shape: PUBLIC SHAPE

{

Float getarea ();

......

}

When you call the virtual function in an object through an object pointer. In fact, you have specified the type of the pointer when you compile. such as:

Float Getarea (Shape * SHP)

{

Return SHP-> Getarea ();

}

Therefore, the compiler can determine the index position you call in the VTBL by querying the information of the compile time. Then this call will be queried by VTBL and then instead of Call. When running, the pointer SHP is not necessarily a shape type, but his inheritance type. This two types of VTBL content may not be the same (derived class overwritten some of some SLOT addresses). So, this can be achieved to call the fault class in the case where the derived class is not known. The mystery is that the derived class and base classes put their respective implementations in the same location of VTBL. The compile period determines that the content is determined when running.

And what about this appraisal version of Object Model? In fact, it is almost. Mov Edx, Hcircle and Invoke (Shape Ptr [EDX]). getarea, EDX is a polymorphic call. Hcircle actually points to a CIRCLE type (the object here) is also responsible for the task of VTBL. When the call is designed, this pointer is interpreted as a shape type. That is, in accordance with the index where getarea is located in the shape type. The same index index is different, and the polymorphism is generated. Possible improvement

About virtual function

In fact, this object mode is really very good, and the function of the macro has played the ultimate. However, it enforces that all classes have a Virtual Destructor and all functions of Virtual. Within the scope of the ability of the macro, it has been made as simple as possible, and it is true that it is true. However, I don't think it would not put all the functions in the object (ie, the mandatory as a virtual function), which will increase a certain amount of cost.

C regards the non-virtual member function as an ordinary function, put it outside the object. In fact, I think this object model can also be used. And existing mandatory will limit some member function prototype names as "type name _ function name PTO", it is better to provide a macro.

My suggestion, put some of the function into the object (that is, using cmethod to declare the class). And others are not placed, just written in the same file. When you call the object's Member-function when you call the object, it decides whether this Member-function is existing in the virtual function table (which is a series of function pointers stored by the object itself). If it is not called as a normal function. If so, follow this mode.

Method This macro is also written. In the macro in Super, the Method is verified whether the Method will appear in the base class (and also to test whether the test is the last layer instead of the multi-layer base class). Such a Method can also verify that the way the call is displayed in the Class, and then different function calls are used separately.

About Super

This model can only call the overwhelmed function of the previous layer (that is, the parent class), which cannot be sapphires for the over-lasting function. The obstacle is that it cannot know which type is in which type is in the first time. I would like to provide this class name manually, you can override the function of any hierarchy. like this:

Super getarea

Super Getarea, Shape

There is no specific class name, it is considered to be a layer of Super, otherwise use the specific class name to super. The mystery of Super is also the function of the "Type Name_INITData" in the .data section to reach the function of the "Recovery" to be rewritten.

Just talking about it, TABLE in TASM can make up for Override's defects, it is a better struc. However, that is the result of Borland enhances the grammar. No matter how Thomas is, it is quite powerful.

link

The origin of the Object Model mentioned herein

My personal homepage provides a basic tutorial for Win32ASM

转载请注明原文地址:https://www.9cbs.com/read-26604.html

New Post(0)