[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 948
  • Last Modified:

Register use when calling Delphi procedure inside asm statement

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
zoltan082098
Asked:
zoltan082098
  • 3
  • 3
  • 2
1 Solution
 
Wim ten BrinkCommented:
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
 
zoltan082098Author Commented:
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
 
Wim ten BrinkCommented:
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
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
aruanaCommented:
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
 
zoltan082098Author Commented:
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
 
aruanaCommented:
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
 
Wim ten BrinkCommented:
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
 
aruanaCommented:
"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

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

  • 3
  • 3
  • 2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now