Visit our Sponsor   Visit our Sponsor
delphi3000.com - the free delphi knowledge platform
delphi3000.com - the free delphi knowledge platform
496 Users Online NOW
Have a look at your member-status

connecting people's knowledge


  - Recent ArticlesRSS feed for Recent Articles on delphi3000.com
  - List of All Articles
  - Top Viewed Articles
  - Articles (+Attachem.)
  - Articles Of Interest
  - Categories
  - Top Uploader
  - Search
  - Index

  - My Home
  - Submit an Article
  - My Articles
  - My Personal Data
  - My Bookmarks
  - Activities
  - Login/Logout

  - Sign Up
  - Why Sign Up
  - Newsletter

  - Press
  - Advertise

  - Contact
  - Feedback





Community
Borland
ClubeDelphi
Dr. Bob
UK-BUG
Delphi Meetings
Planeta Delphi







Startblatt.de






Share this article with friendsShare this article with friends
Rate this articleRate this article - to keep the quality of delphi3000.com !
Comment this article or read through previous comments (0)


Inline Assembler in Delphi (V) - ObjectsComponent available for this articleFormat this article printer-friendly!Bookmark function is only available for registered users!
Accessing objects from inline assembler code
Product:
Delphi 3.x (or higher)
Category:
Object Pascal
Skill Level:
Scoring:
Last Update:
09/12/2003
Search Keys:
delphi delphi3000 article borland vcl code-snippet inline assembler asm objects object class data members member field fields method methods constructor constructors property properties VMT
Times Scored:
7
Visits:
5911
Uploader: Ernesto De Spirito
Company: Latium Software
Reference: Pascal Newsletter #41
Component Download: http://www.latiumsoftware.com/download/p0041.zip
 
Question/Problem/Abstract:
How to work with objects in inline assembler
Answer:



Inline Assembler in Delphi (V)
An Introdunction to Objects


By Ernesto De Spirito <edspirito@latiumsoftware.com>


Objects are records



From the assembler point of view, an object is like a record, whose fields are its own fields plus the fields of its ancestors, plus the pointer to the VMT (Virtual Methods Table). Let's see this with an example:

  type
    TClass1 = class
      FieldA: integer;
      FieldB: string;
    end;

    TClass2 = class(TClass1)
      FieldC: integer;
    end;

In the example, TClass2 is somehow like a record with four fields:

  TClass2 = record
    VMT: pointer;       // invisible field, always first
    FieldA: integer;    // inherited from TClass1
    FieldB: string;     // inherited from TClass1
    FieldC: integer;    // declared in TClass2
  end;


Object variables are pointers
=============================

An object variable is just a pointer to an object, i.e. a pointer to a record.

  var
    a, b: TClass2;
  begin
    a := TClass2.Create;
    b := a;                // just a pointer assignment
    a.Free;
  end;

A constructor allocates memory for an instance (object) of its class, initializes it, and returns a pointer to the allocated memory. Thus, after the call to TClass.Create the variable "a" points to the record (the object):

  +---+             +--------+
  | a | ----------> |   VMT  |
  +---+             +--------+
                    | FieldA |
                    +--------+
                    | FieldB |
                    +--------+
                    | FieldC |
                    +--------+

The assignment "b := a" doesn't create a new object, copy of the first, but actually makes both variables point to the same object:

  +---+             +--------+             +---+
  | a | ----------> |   VMT  | <---------- | b |
  +---+             +--------+             +---+
                    | FieldA |
                    +--------+
                    | FieldB |
                    +--------+
                    | FieldC |
                    +--------+


Assembler methods



Methods receive an invisible first parameter called Self, which is a pointer to the object upon which the method should operate.

  type
    TTest = class
      FCode: integer;
    public
      procedure SetCode(NewCode: integer);
    end;

  procedure TTest.SetCode(NewCode: integer);
  begin
    FCode := NewCode;
  end;

  var
    a: TTest;
  begin
    :
    a.SetCode(2);
    :
  end;

The above Object Pascal code is somehow translated to standard Pascal as follows:

  type
    TTest = record
      VMT: pointer;
      FCode: integer;
    end;

  procedure SetCode(Self: TTest; NewCode: integer);
  begin
    Self.FCode := NewCode;
  end;

  var
    a: ^TTest;
  begin
    :
    SetCode(a, 2);
    :
  end;

The example serves to explain that methods receive the Self pointer as their first parameter, i.e. they receive the Self pointer in the EAX register, and the first declared parameter is passed as a second parameter in EDX, and so on (the second declared parameter is passed as third in ECX, and the rest of the parameters are passed on the stack). The method SetCode can be written in assembler like this:

  procedure TTest.SetCode(NewCode: integer);
  asm
    // EAX = Self = Address of TTest instance
    // EDX = NewCode parameter

    // FCode := NewCode;
    mov TTest[eax].FCode, edx       // TTest(EAX)^.FCode := EDX;
  end;

As you can see, object fields are accessed in the same way as record fields.

NOTE: Properties are not fields, and they cannot be accessed directly from inline assembler.


Here's an example of a method calling another method:

  procedure TTest.Increment;
  asm
    // SetCode(Code+1);
    mov edx, TTest[eax].FCode       // ECX := TTest(EAX)^.FCode;
    inc edx
    call TTest.SetCode;
  end;

We didn't set the value of EAX before making the call since EAX already contains the desired value (Self), so the called method will operate on the same object.

NOTES:

  • Virtual methods can only be called statically, since a reference to the class is needed in the call statemet.
  • Overloaded methods cannot be distinguished in inline assembler.



Assembler constructors



Constructors are very special methods. Constructors can be called to create an instance of a class (i.e. to allocate the memory for the object and initialize it), or simply to reinitialize an already created object:

  a := TTest.Create;   // allocates memory
  a.Create;            // only reinitializes an existing object

To distinguish between these two situations, constructors are passed an invisible second parameter of byte type (i.e. in the DL register) which can be positive or negative respectively (the compiler uses 1 and -1 respectively).

If we have to call a constructor from assembler code with DL = $01 (to allocate memory for the object), we have to pass a reference to the class in EAX. Since there is no symbol to access it directly from assembler, we have to do something similar to what we did with the type information for records:

  var
    TTest_TypeInfo: pointer;

  :

  initialization
    TTest_TypeInfo := TTest;

Now that we have initialized a global variable with the reference to the class from our Pascal code, we can use it in our assembler code:

  var
    a: TTest;
  begin
    // a := TTest.Create(2);
    asm
      mov eax, TTest_TypeInfo
      mov dl, 1
      mov ecx, 2
      call TTest.Create
      mov a, eax
    end;
    :
  end;

Calling a constructor to reinitialize the object is simpler, since we don't need a reference to the class:

  var
    a: TTest;
  begin
    :
    // a.Create(2);
    asm
      mov eax, a
      mov dl, -1
      mov ecx, 2
      call TTest.Create
    end;
    :
  end;

We have nothing to worry about if we have to write an assembler constructor since Delphi handles the allocation thing for us upon entry to the constructor, and -after that- EAX will point to the object, as it happens with any other method, but what is relevant is that if the constructor has parameters, the first declared parameter will be internally passed third, i.e. in ECX (instead as second, i.e. in EDX, as it happens with other methods), and the rest of the parameters will be passed on the stack.

  constructor TTest.Create(NewCode: integer);
  asm
    // FCode := NewCode
    mov TTest[eax].FCode, ecx
  end;




Previous: Inline Assembler in Delphi (IV) - Records
Next: Inline Assembler in Delphi (VI) - Calling external procedures





Please rate this article!
Skill level:
BeginnerExpert

Useful:
No!Very!

Overall rating:
PoorExcellent



Comments to this article
Write a new comment













 
Sign up to consume product discounts for Bronze memberships !

read more


  Visit our Sponsor

 

  Community Ad of
L. Rosenstein
 
   














 







     
  Copyright © 2000 - 2007 delphi3000.com - All rights reserved. Terms of use. || Privacy
delphi3000.com is a service by bluestep.com IT-Services GmbH (Vienna)