Solved

Register use when calling Delphi procedure inside asm statement

Posted on 2004-08-23
11
844 Views
Last Modified: 2011-09-20
Delphi help for register use inside asm...end statements says:
"An asm statement must preserve the EDI, ESI, ESP, EBP, and EBX registers, but can freely modify the EAX, ECX, and EDX registers."
It's easy at the first blush, but what happens when there is another procedure/function call inside asm...end bracket, e.g. as following:

procedure tobject1.method1;

  procedure nestedfunction1(argument1: integer);
  begin
    ...
  end;

  procedure inlineassembly1;
  asm
    mov eax, something // argument1
    call nestedfunction1
  end;

begin
  ...
end;

Although I do not modify any registers but eax in inlineassembly1 procedure, I cannot be sure whether nestedfunction1 inside inlineassembly1 so does or not. In this case, in order to be sure about "preserving the EDI, ESI, ESP, EBP, and EBX registers" inlineassembly1 has to look like this:

  procedure inlineassembly1;
  asm
    pushad
    mov eax, something // argument1
    call nestedfunction1
    popad
  end;
 
Since assembly routines usually are time critical solutions, the above shovn one isn't a convenient solution at all.
Moreover, I cannot see such pushad...popad brackets when disassembling compiled delphi code in CPU window. Does it mean that I needn't care of register use of Delphi procedures called inside asm...end bracket?
0
Comment
Question by:zoltan082098
  • 3
  • 3
  • 2
11 Comments
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 11874784
I've checked... pushad and popad are visible in my own CPU window (Delphi 7) then I just add a piece of code like:

asm
  pushad
  popad
end;

And true, if something is very time-critical you might not want to call it through Assembler this way. You might want to implement this in standard Delphi code then. But in my experience asm won't give you that much increase in speed since Delphi compiles to reasonable fast binaries anyway. Only small, often-called functions do gain a performance speed through assembler...
0
 

Author Comment

by:zoltan082098
ID: 11875290
I mean "I cannot see such pushad...popad brackets when disassembling compiled delphi code in CPU window" that Delphi itself never saves the registers by pushad before calling a procedure, that is, you won't see pushad/popad pairs bracketing a procedure in a compiled delphy binary UNLESS you place them in asm...end explicitly.

BTW please trust me regarding the speed increasing in my assembler routines, they are called about several million times during the data processing. I only want to avoid the following solutions:

  asm
    ... // some assembly code here
  end;
  nestedfunction1($1234)
  asm
    ... // continuing the assembly code
  end;

Since I can better use following:

  asm
    ...
    mov eax, $1234
    call nestedfunction1
    ....
  end;

The only problem regarding this solution is:
Do I have to take care about saving and restoring all the registers before and after calling nestedfunction1? If not, which are the registers to save in this situation?

Regards,
ZOltan
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 11881041
pushad/popad would be faster in my opinion than just pushing/popping specific registers.

You must make sure EDI, ESI, ESP, EBP, and EBX don't change after calling the procedure from your ASM code but I don't think a Delphi procedure will change them. This rule would apply to ALL procedures in Delphi, not just assembler procedures. Furthermore, you must preserve those registers that you need to remember for yourself. Thus if you store some pointer in EAX, you need to push/pop it before/after calling the procedure. All other registers are those you don't need and Delphi doesn't care about them.

If a register doesn't contain any valuable info then why store it? Whatever function is calling your assembler routine, it cannot assume all registers stay unchanged. Only EDI, ESI, ESP, EBP, and EBX must be kept. All others are not important. (Unless you're returning a value, of course. Then some registers are pointing to this data.)

Advise: Just try your code without pushing/popping anything... If the code breaks, you'll have to push some registers.
0
 
LVL 1

Expert Comment

by:aruana
ID: 11889897
Delphi assumes that nobody is suppose to play with the registers, so it need not bother to push/pop it in every call.  Imagine the overhead it will cause if need to.
Thus exist the rule,
"An asm statement must preserve the EDI, ESI, ESP, EBP, and EBX registers,..."

It means that if you are going to play with these registers, you must preserve it and pop it back upon return.  If you are sure you do not use them. Don't bother.  And you are free to play with the rest of the registers.

Now, looking back at your code,

    mov eax, something // argument1
    call nestedfunction1

following the same rule, nestedfucntion1 will not preserve EAX for you. so when it comes back, you cannot rely on its value also.
0
What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

 

Author Comment

by:zoltan082098
ID: 11890237
Guys,
it may be about my poor English but I suspect You still not really understand what's the problem here.
My code looks like this:

asm
   
    // section 1
    ...
    // end of section 1  
   
    // section 2
    mov eax, $1234
    call nestedfunction1
    // end of section 2

    // section 3
    ...
    // end of section 3
 
end;

"An asm statement must preserve the EDI, ESI, ESP, EBP, and EBX registers,...", that is, the state of these registers must be the same BEFORE section1 and AFTER section3 respectively.

Let' say that both section1 and section3 use just eax, ecx and edx registers. Can I be sure that the EDI, ESI, ESP, EBP, and EBX registers has been preserved in this asm statement?

Of course not, because of the section2, which contains the call to nestedfunction1, and I have no clue whether a call to an ARBITRARY Delphi function/procedure applies the same rule or not, that is, to preserve the above mentioned registers.

So, there is the big question:

Do I have to save/restore these registers before/after calling an arbitrary Delphi procedure inside an asm statement or not (or, think about the worst case, wnen such Delphi procedures does contain calls to WIN32 API functions)? If so, please show me some guidelines how can I decide eaxctly WHICH registers have to be saved befor calling Delphi functions?

Regards,
Zoltan
0
 
LVL 1

Accepted Solution

by:
aruana earned 500 total points
ID: 11899473
Delphi created the rule didn't they? They must follow the same rule.
If you do not play with those registers in section 1 and 3, you are considered as preserving them.
Then if you do not have any of your own code in nestedfunction1 that plays with the registers, you are considered as preserving them.
Any code unknown to you that does not follow this rule will screw the OS. If that happens, there is a posibility that the call would not even return back to your code.  And there is nothing you could do about it.  
So just play your part in rule and not play with the registers. Or preserve them if you do use them.
0
 
LVL 17

Expert Comment

by:Wim ten Brink
ID: 11941853
Aruana is correct. Delphi will preserve the same registers as the ones you're supposed to preserve. Delphi needs them internally. And actually, when you call nestedfunction1 those registers must contain correct values, the values they had when your routine was called. It will not mess up the OS, though, since the OS will just kick any bad-behaving application to the Bad-Application-Hell. (In other words: your application crashes.)

Thus, preserve those registers.
0
 
LVL 1

Expert Comment

by:aruana
ID: 11960739
"It will not mess up the OS, though, since the OS will just kick any bad-behaving application to the Bad-Application-Hell."
Well Alex, no offence, only with Windows XP, maybe.  But I still would not bet my money on it.  :-)
No offence to Microsoft either.  But that is how it is.
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now