Link to home
Start Free TrialLog in
Avatar of tobjectpascal
tobjectpascal

asked on

Assembly Problem

procedure TForm1.Button2Click(Sender: TObject);
Var
 Str: String;
 Str2: String;
 P: Pointer;
begin
 Str2:='ABCDEF';
 Str:='abcdef';
 Asm
   push esi;
   push edi;

   mov edi,[Str]; //abcde
   Mov esi,[Str2];  //ABCDE

   mov al,[esi]; //al now = 65
   Mov [esi],al;  //make this char 65 (yes i know, but even this errors :| )

   pop edi;
   pop esi;
 End;
   showMessage(Str);
end;


why does that ERROR?! i'm going to give up at this rate.
Avatar of tobjectpascal
tobjectpascal

ASKER

var
 s: String;
begin
 SetLength(s,6);
  asm
    mov Esi,S;
    mov cx,65;
    mov [esi],cx;
  end;
 showMessage(S);

Is the solution, for some reason it does not like 8 bit registers going in.... odd

Var
 Str: String;
 Str2: String;
 P: Pointer;
begin
 Str2:='ABCDEF';
 Str:='abcdef';
 SetLength(Str,6);  //This fixes the code!, why? i'm not sure.
 Asm
   push esi;
   push edi;

   mov edi,[Str]; //abcde
   Mov esi,[Str2];  //ABCDE

   mov al,[esi]; //al now = 65
   Mov [edi],al;  //make this char 65 (yes i know, but even this errors :| )

   pop edi;
   pop esi;
 End;
   showMessage(Str);
// FillChar(Str[1],6,ord('?'));
// SetLength(Str,6);
// Str:=Str+'?';

Any of these Get the code working, my logical assumption is that the Compiler disregards Str because it's not used in my code... but if that were true it does not explain why you can extract from the string's array but not put it back.
asm
  Lea eax,Str;
  Mov edx,6;
  Call System.@LStrSetLength;
End;

sorts it though.
ASKER CERTIFIED SOLUTION
Avatar of Russell Libby
Russell Libby
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

     lea   eax, [Str]       // Load str address
     call  UniqueString       // Make unique

So i'm guessing that SetLength does the same as UniqueString ?
anyway, thanks rlibby for all your help, As you probably can tell i'm trying to Learn BASM, problem i'm having is when to Push and when to move from Right to Left and when to Push to EAX EDX and ECX in that order...

But i think i'm slowly getting there :)

Thanks again.
Both the SetLength and UniqueString calls end up in the same place, which is _NewAnsiString, which handles the problem that the Delphi docs mention:

>> Only in cases where an application casts a string to a PChar and then modifies the contents of the string must UniqueString be used.

which is in effect what you are doing with the asm code.

Anyways, best of luck on your BASM work... its not always easy, but its usually quite rewarding.

Russell

Well i know i'm not offering any points, but this is really confusing me?

lea   eax, [Str]

not the same as

mov eax,offset [str]
 or
mov eax,str

I understand that's there's segments and indexes, Seg:howfarinto the segment

But Windows does not seem the same as when i touched on DOS assembly...

Load Effective Address
mov eax,Adre;

it's not a problem, as i can jsut use Lea but how on earth do you know what needs Lea... ugh

I can option up another question just for finding out the difference lol... but thanks for the help.

LEA (load effective address) loads a 32 bit address with the *address* of the operand, vs. a MOV, which will set the 32 bit address with the *value* of the operand. Think of it like this:

Pointer(@Str) // This is like LEA
Pointer(Str)    // This is like MOV

The difference usually comes down to passing a param by value or by reference. Take for example the functions:

- LStrSetLength
- UniqueString

They are both defined as taking a "var String" parameter (by reference), thus the LEA would be use to setup the EAX register for the call to either of these. If you were calling a function that took a pchar / string constant, then the MOV would be used instead.

Russell
ahhh thank you very much :)

You are one of the few true experts in this forum :)
Rlibby...here's why i was confused (taken from my example above)

   mov al,[esi]; //al now = 65

Gives 65 (the data from the pointer, not the pointer address)

   mov al,esi; //al now = 65

Will not compile because it's passing the address to al, and the address is bigger than 8 bytes

   mov eax,[esi]; //passes the Data, not the Value
   mov eax,esi; //passes the Pointer to the data not the value

So if it passes the pointer...

why not
   Mov Eax,Str;  
instead of
  lea   eax, [Str]  

Technically they should both be the same result, but I've checked, it's not....

Which is why i got confused why not just Mov Eax, it's not passing the data but the pointer....

This is going to kill me... Rlibby, if you answer this i'll throw you my last remainig few points in a new thread just accept it when i created it :P




Yes, technically they are the same, therefore I can understand the confusion. The problem comes down to the inline compiler in Delphi. Take for instance the following asm code block within a procedure called Test:

procedure Test;
var X:     Integer;
begin

  asm
     mov   X, 100
     mov   eax, X
  end;
  ShowMessage(IntToStr(X));

end;

The variable X is pointer to the memory location at EBP-4 (this is KEY). If you perform the following:

   mov  eax, X

The inline assembler will turn your code into:

   mov eax, [ebp-4]

Which is exactly what we DONT want. (we don't want the value, we want the address). In fact, the inline compiler generates the same code for both usages:

   mov   eax [X]
   mov   eax, X

Its really not the compiler's fault either, as only LEA can be used to transfer a calculated addresss such as

  [ebp-4]

In order to do that with a MOV, you would have to do:

  mov eax, ebp-4

Which won't fly, thus the reason for LEA.....

------

Hopefully I didn't confuse you more. ;-)
Russell




wh

the EAX register will end up with the value 100. Keep in mind that variable X is nothing more than a pointer to 4 bytes of memory. It
>> wh
>>
>> the EAX register will end up with the value 100. Keep in mind that variable X is nothing more than a pointer to 4 bytes of memory. It


Please ignore my edits that I forget to cleanup before posting

Russell
ahhh interesting, thank you, i've got about 35 points remaming, you can have them :)
Dont' worry about it.

Russell
Serously.... I'm on to something here..

var
 s: String;
begin
 s:='hello world';
asm
  lea eax,s;
  call uniquestring;  //fine

  mov eax,s;
  call showmessage;  //fine
end;


var
 s: String;
begin
 s:='hello world';
asm
//  lea eax,s;
  mov eax,s;
  call uniquestring;  //boooooooom

 // mov eax,s;
  lea eax,s;
  call showmessage;  //booooooooom
end;

That's got to be Borland at fault.... not accepting the same method of getting the address twice, that can't be right i know.

The only rule i can see is, if it crashes, try the other way lol
Seriously, the rules are pretty straight forward.

1 - MOV cannot be used in Delphi's inline asm to transfer an address. LEA must be used to transfer an address.
2 - Functions that accept var Value will require a LEA to setup the register.
3 - Functions that accept (const) Value will require a MOV to setup the register.

The difference comes down to passing a param by value or by reference. UniqueString requires a var String (by reference). I already explained why MOV EAX, S isn't going to cut it for that. It generates a:

mov eax, [ebp-4]

which moves the VALUE not the address, so LEA *must* be used for var values. The ShowMessage routine on the other hand expects a string value, so MOV must be used to setup the eax register. If you use LEA, then its going to push the address and not the value, and the routine has no way of knowing the difference. And I'm sure you have probably read other articles on asm, which is why you are under the premise that:

MOV EAX, REG
and
LEA EAX, [REG]

are the same. But you have to understand that those docs are usually tailored to MASM / raw ASM development, and that it doesn't always apply to inline assemblers such as Delphi's. (Eg you can't use the EIP reg in the inline assembler, etc..). In this case MOV and LEA do NOT generate the same results.

Russell


Ok At Last... lol sorry to be a pain in the rear end russel, but i think i finally understand it, I managed to code a routine that works...  lol and yes thank you for your paitients, if the help file requires a return to a Pointer i use Lea, or i pass by Var, otherwise i use Mov and pass by value..

I think i'm starting to understand :D I do find it interesting that they Delphi has internal names for example LstrCat will cause an error and instead it requires LstrCat3 kinda odd but not a problem Mucho Gracias :)

procedure TForm1.Button1Click(Sender: TObject);
var
 Ret: Integer;
 ResString,Val,s,sub: String;
Const
 S2: String = 'Position: ';
begin
 s:='hello world';
 sub:='llo';
asm
  lea eax,s;
  call uniquestring;
  push eax;
 // call showmessage;
  mov eax,sub;
  pop edx;
  Call system.@lstrpos;
  mov ret,eax;
  lea edx,val;
  Call Inttostr;

  Lea Eax,ResString;
  Mov Ecx,Val;
  Mov Edx,S2;
  Call System.@LStrCat3;

  Mov Eax,ResString;
  call showmessage;
end;