Accessing to arrays in inline asm block

I need to access a dynamic array through an inline assembler code block.

//------------------------------
var
  LUT : Array of DWORD;
  A,B,
  I   : DWORD;
 

Begin
  Setlength(LUT, 2048)
  For I:=0 to 2047 do
    LUT[I] := Random(High(DWORD));

  A := LUT[5];  // this works ok
 
  asm
     push bx
     pusha
 
     mov eax, LUT[5] // this causes a protection fault    
 
  End;
End;

//------------------------------

The assembler code that the compiler generates varies completly if the LUT variable is defined inside the procedure with the asm block and if it's defined as a class variable.

also I would like to access a varying index inside the array thru the asm block. Like this:

  mov eax, LUT[esi]

Can I do it? This generates wrong results as well.

What am I doing wrong?
idokAsked:
Who is Participating?
 
compeagerConnect With a Mentor Commented:
ok, thats the code for dynamic array located in private section of your object, but the code should be written in the method of your object...


Lets say this code was done before...
  SetLength(LUT, 3);
  LUT[0] := $50;
  LUT[1] := $60;
  ...

and this is your assembler code:
  index := 1;
  asm
    push     edi
    mov      eax,4
    mul      index
    mov      edi,self
    mov      edi,[edi + offset LUT]

    mov      eax,[edi + eax] // here

    pop      edi
  end;

  you can use edi in future accesses. mov eax,[edi+4] locates second element,
mov eax,[edi+ebx] locates ebx'th byte so on...
  if you need only one element, this code is more efficient
  asm
    mov      eax,self
    mov      eax,[eax + offset LUT]
    mov      eax,[eax + $0004]
  end;

what does that code?

    mov      eax,self
gets the address of current object

    mov      eax,[eax + offset LUT]
gets the address where LUT points, eax + offset LUT points where LUT pointer located, taking it into parantesis gets LUT's value which points the memory your array located...
    mov eax,[eax + $0004]
gets eax + xxxx'th dword so on...

is this your need?
0
 
idokAuthor Commented:
I meant "it makes a page fault" (EAccessViolation).

Also add popa, pop ebx at the end of the asm block...

(I was in a hurry... :-)
0
 
compeagerCommented:
try that

asm
  mov eax, some_index_value
  mov ebx, dword ptr LUT[eax]
end

or, I'm not sure but this one may be correct:

asm
  mov eax, dword ptr LUT[some_index_value]
end


be carefull choosing the value of eax. It's not the index of the n'th dword in your array but n'th byte in the order of your array. You should multiply index with size of dword or whatever the array consists of...
0
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
idokAuthor Commented:
Thanks for your answer.
Indeed it works when I multiply the value of the index in the sizeof the array element, BUT - it works only with static arrays.

When I try to get a value from a dynamic array (SetLength(LUT, 2048)) I get wrong values.

Do you think I should use native pointers? If yes, how can I increment the dereference ptr inside the asm?
0
 
idokAuthor Commented:
I am sorry, I discovered another problem - it doesn't work no matter if the array is static or dynamic if it's not defined in the same function that contains the asm block -- for example, my function is a class member function and if I define the array as a class variable (in the private area), when I try to access it through the asm block I get access violations (even with the dword ptr directive). Help!
0
 
jecksomCommented:
Hello idok!

procedure TForm1.Button1Click(Sender: TObject);
var
  TB: Array of longint;
  id,gid:dword;
begin
randomize;
setlength(TB, 2048);
For Id:=0 to 2047 do
TB[Id] :=random(DWORD(-1));
id:=random(2047);
showmessage(format('index %d = %d',[id,tb[id]]));
asm
pushad
mov  ebx,TB       // let say ebx = base address of TB
mov  esi,id       // esi - index
mov  eax,[ebx+esi*4] // array dword (4 bytes) ,
                     // so 4 bytes one element
mov  gid,eax         // get previous value
mov  eax,1111
mov  [ebx+esi*4],eax // set new value to make sure we
                     // working with correct element
popad             // restore values in set of dword registers
end;
showmessage(format('index %d = %d, prev value = %d',
            [id,tb[id],gid]));
end;

I guess you've asked about this ?

Jecksom

PS : showmessages for testing o'coz.
0
 
denizcanCommented:
jecjsom: LOL, what's the difference between your code and what I wrote???

0
 
denizcanCommented:
I = compeager
0
 
idokAuthor Commented:
This indeed works with dynamic/static arrays that are declared in the same function. Review my question - part of the problem is when I have a class variable and I wanna change it in the asm block of the same class member function.

Check my code out - it's a variant on jecksom's code moving the array and index vars to the class.

Two problems are created - I commented the problems in the asm block.

Here goes the problematic code: :-)

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    TB: Array of longint;
    id,gid:dword;

  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
  i : longint;
begin
    randomize;
    setlength(TB, 2048);
    For I:=0 to 2047 do
        TB[I] :=random(DWORD(-1));
    id:=random(2047);
    showmessage(format('index %d = %d',[id,tb[id]]));
    asm
    pushad
    mov  ebx,TB       // let say ebx = base address of TB
    mov  esi,id       // esi - index
    mov  eax,[ebx+esi*4] // <== ACCESS VIOLATION
                         // so 4 bytes one element
//    mov  gid,eax  // <== COMPILATION ERROR
    mov  eax,1111
    mov  [ebx+esi*4],eax // set new value to make sure we
                         // working with correct element
    popad             // restore values in set of dword registers
    end;
    showmessage(format('index %d = %d, prev value = %d',
                [id,tb[id],gid]));
end;

end.

//---------------------------------

HELP!
0
 
jecksomCommented:
Hi compeager,idok!

compeager : LUT in your comment is actually [bp-param]
so you can't do 'mov reg/mem,[bp-param+index*4]' in
asm, check CPU view.

idok: ok , sorry for so long answer , but it was night here,
at least i've understand your problem, will check it asap.

Jecksom
0
 
compeagerCommented:
one addition, Index is an Integer variable, I add it to show how to use an index value to reach the n'th element of array, if you didn't define it in your var block, compiler will give error...

var
  Index: Integer;

I though, you would catch but it was worth to remind...
0
 
jecksomCommented:
Idok:

this is it:

pushad
mov ebx,form1           // form1 base    --> ebx
mov esi,[ebx+TB]       // form1.TB base --> esi
mov edi,[ebx+id]        // form1.id base --> edi
mov eax,[esi+edi*4]   // form1.TB[id]  --> eax
mov [ebx+gid],eax     // eax           --> form1.gid
mov eax,1111            // check value   --> eax
mov [esi+edi*4],eax   // 1111          --> form1.TB[id]
popad

compeager: value *4 is 'shl value,2' ;)
0
 
idokAuthor Commented:
Ok, guys, thanks a million.
Gimme some time to evaluate the answers.

Jecksom: It's ok, I prefer long answers than short ones. :-)
0
 
idokAuthor Commented:
Why does the code for accessing static and dynamic arrays from asm has to be different?

The code you posted works only for dynamic arrays. How can I use static arrays as well?

If I define a pointer and do:
p := @LUT;

mov edi, [edi + offset LUT]

the p and edi contents are not the same, why?

0
 
compeagerCommented:
It's different because, the system works different. Compiler uses the static array variable as a base reference, but it uses dynamic array variable as a pointer. You can see the difference with cpu view window...

If you want to use same code, you should put the code in a sepearate procedure and call that procedure with referencing the array variable as a pointer... Like MyProc(@MyStaticArray) or, MyProc(MyDynamicArray). I didn't try this one, but it should work...
0
 
idokAuthor Commented:
Thanks for everything, guys.
You were both as helpful but compeager posted a working code first, and I am not aware of a way to divide the points you both deserve. :-)
0
All Courses

From novice to tech pro — start learning today.