Assembly Directives

The built-in assembler supports three assembly define directives: DB (define byte), DW (define word), and DD (define double word). Each generates data corresponding to the comma-separated operands that follow the directive.

The DB directive generates a sequence of bytes. Each operand can be a constant expression with a value between 128 and 255, or a character string of any length. Constant expressions generate one byte of code, and strings generate a sequence of bytes with values corresponding to the ASCII code of each character.

The DW directive generates a sequence of words. Each operand can be a constant expression with a value between 32,768 and 65,535, or an address expression. For an address expression, the built-in assembler generates a near pointer, a word that contains the offset part of the address.

The DD directive generates a sequence of double words. Each operand can be a constant expression with a value between 2,147,483,648 and 4,294,967,295, or an address expression. For an address expression, the built-in assembler generates a far pointer, a word that contains the offset part of the address, followed by a word that contains the segment part of the address.

The DQ directive defines a quad word for Int64 values.

The data generated by the DB, DW, and DD directives is always stored in the code segment, just like the code generated by other built-in assembly statements. To generate uninitialized or initialized data in the data segment, you should use Delphi var or const declarations.

Some examples of DB, DW, and DD directives follow.

0,99

DB DB

'string' style string }

DW 0FFFFH { One word }

  • One byte } { Two bytes }
  • Ord('A') } 'Hello world...',0DH,0AH 12,
  • String followed by CR/LF }

{ Delphi

DW 0,9999

MyVar

DW MyProc

0FFFFFFFFH { One double-word } DD

0,999999999 { Two double-words } DD

MyVar

{ Pointer to MyVar }

DD MyProc

When an identifier precedes a DB, DW , or DD directive, it causes the declaration of a byte-, word-, or double-word-sized variable at the location of the directive. For example, the assembler allows the following:

ByteVar DB

WordVar DW

IntVar DD

MOV MOV MOV

AL,ByteVar BX,WordVar

ECX,IntVar

The built-in assembler doesn't support such variable declarations. The only kind of symbol that can be defined in an inline assembly statement is a label. All variables must be declared using Delphi syntax; the preceding construction can be replaced by var

ByteVar: Byte; WordVar: Word; IntVar: Integer;

MOV AL,ByteVar MOV BX,WordVar MOV ECX,IntVar end;

SMALL and LARGE can be used determine the width of a displacement:

This instruction generates a 'normal' move with a 32-bit displacement ($00001234).

The second instruction will generate a move with an address size override prefix and a 16-bit displacement ($1234).

SMALL can be used to save space. The following example generates an address size override and a 2-byte address (in total three bytes)

MOV EAX, [SMALL 123] as opposed to

which will generate no address size override and a 4-byte address (in total four bytes).

Two additional directives allow assembly code to access dynamic and virtual methods: VMTOFFSET and DMTINDEX.

VMTOFFSET retrieves the offset in bytes of the virtual method pointer table entry of the virtual method argument from the beginning of the virtual method table (VMT). This directive needs a fully specified class name with a method name as a parameter (for example, TExample.VirtualMethod), or an interface name and an interface method name.

DMTINDEX retrieves the dynamic method table index of the passed dynamic method. This directive also needs a fully specified class name with a method name as a parameter, for example, TExample.

DynamicMethod. To invoke the dynamic method, call [email protected] with the (E)SI register containing the value obtained from DMTINDEX.

Note: Methods with the message directive are implemented as dynamic methods and can also be called using the DMTINDEX technique. For example:

TMyClass = class procedure x; message MYMESSAGE; end;

The following example uses both DMTINDEX and VMTOFFSET to access dynamic and virtual methods:

program Project2; type

TExample = class procedure DynamicMethod; dynamic;

procedure VirtualMethod; virtual;

end;

procedure TExample.DynamicMethod;

begin end;

procedure TExample.VirtualMethod;

begin end;

procedure CallDynamicMethod(e: TExample);

  • Save ESI register PUSH ESI
  • Instance pointer needs to be in EAX

MOV EAX, e

  • DMT entry index needs to be in (E)SI MOV ESI, DMTINDEX TExample.DynamicMethod
  • Now call the method CALL [email protected]
  • Restore ESI register

POP ESI

end;

procedure CallVirtualMethod(e: TExample);

  • Instance pointer needs to be in EAX MOV EAX, e
  • Retrieve VMT table entry MOV EDX, [EAX]
  • Now call the method at offset VMTOFFSET CALL DWORD PTR [EDX + VMTOFFSET TExample.VirtualMethod]

end;

var e: TExample; begin e := TExample.Create; try

CallDynamicMethod(e); CallVirtualMethod(e); finally e.Free;

Project Management Made Easy

Project Management Made Easy

What you need to know about… Project Management Made Easy! Project management consists of more than just a large building project and can encompass small projects as well. No matter what the size of your project, you need to have some sort of project management. How you manage your project has everything to do with its outcome.

Get My Free Ebook


Post a comment