打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Inline Assembler in Delphi (VI) Calling external procedures

Inline Assembler in Delphi (VI) Calling external procedures

 

Inline Assembler in Delphi (VI)
Calling external procedures


By Ernesto De Spirito <edspirito@latiumsoftware.com>

API functions and the Stdcall calling convention



API functions are called transparently from inline assembler with the CALL statement. However, we must take into account that passing parameters to API functions is different since they normally use the Stdcall calling convention, instead of the Register calling convention, which is the one we've seen so far since it is the default convention.

In the Stdcall calling convention, all parameters are passed on the stack, from right to left, i.e. the last (rightmost) parameter is pushed first, and the first (leftmost) parameter is pushed last, so it'll the one on top of the stack. Here is an example of a procedure that calls an API function:

  procedure HideForm(Handle: THandle);
  // Windows.ShowWindow(Handle, SW_HIDE);
  asm
    push SW_HIDE               // push 0    // Pass second parameter
    push Handle                // push eax  // Pass first parameter
    call Windows.ShowWindow    // Call the API ShowWindow
  end;

If we have to call a method that uses the stdcall convention, remember that the Self pointer is an invisible first parameter, so it'll be pushed last on the stack.

If we have to write functions that use the stdcall convention, there's nothing special we should worry about. The compiler will always create a stack frame and references to parameter names will be converted into addresses relative to the base pointer:

  function AddAndMultiply(i1, i2, i3: integer): integer; stdcall;
  asm  // ==> push ebp; mov ebp, esp
    // Result := (i1 + i2) * i3;
    mov eax, i1   // mov eax, [ebp+8]
    add eax, i2   // add eax, [ebp+12]
    imul i3       // imul [ebp+16]
  end; // ==> pop ebp; ret 12

This is a sample call for the function:

  asm
    // a := AddAndMultiply(1, 2, 3); // result should be 9
    push 3
    push 2
    push 1
    call AddAndMultiply
    mov a, eax
  end;

After entering the function, the stack would look like this:

  |                |
  +----------------+
  |    Old EBP     |  [EBP], [ESP]
  +----------------+
  | Return Address |  [EBP+4]
  +----------------+
  |     i1 = 1     |  [EBP+8]
  +----------------+
  |     i2 = 2     |  [EBP+12]
  +----------------+
  |     i3 = 3     |  [EBP+16]
  +----------------+
  |                |


C/C++ libraries and the Cdecl calling convention



Sometimes we need to access functions in object files (.OBJ), static libraries (.LIB) or dynamic libraries (.DLL) written in C or C++, and quite frequently these functions use the Cdecl calling convention. It is very much like the Stdcall convention, but the stack should be cleaned by the caller, i.e., the caller should pop the parameters it pushed, or -better- increment the stack pointer.

  function AddAndMultiply(i1, i2, i3: integer): integer; cdecl;
  asm  // ==> push ebp; mov ebp, esp
    // Result := (i1 + i2) * i3;
    mov eax, i1   // mov eax, [ebp+8]
    add eax, i2   // add eax, [ebp+12]
    imul i3       // imul [ebp+16]
  end; // ==> pop ebp; ret

Notice in the comment for the last line that the function doesn't move the stack pointer as it did in the previous example that used the Stdcall convention, so the caller is the one who is responsible for that. This is a sample call for the function:

  asm
    // a := AddAndMultiply(1, 2, 3); // should be 9
    push 3
    push 2
    push 1
    call AddAndMultiply
    add esp, 12           // clean the stack
    mov a, eax
  end;

Notice that if the parameters were of type Byte instead of Integer, we should still move the stack pointer by 12 bytes since each parameter would take 32 bits (4 bytes) anyway.


The Pascal calling convention



Many C/C++ programmers prefer the Pascal calling convention over the Cdecl calling convention because it is more compact and also faster since the called function clears the stack in the RET statement, as it happens in the Stdcall convention. The Pascal convention is like the Stdcall convention, but parameters are passed left-to-right instead of right-to-left, i.e. the first (leftmost) parameter is pushed first, and the last (rightmost) parameter is pushed last:

  function AddAndMultiply(i1, i2, i3: integer): integer; pascal;
  asm  // ==> push ebp; mov ebp, esp
    // Result := (i1 + i2) * i3;
    mov eax, i1   // mov eax, [ebp+16]
    add eax, i2   // add eax, [ebp+12]
    imul i3       // imul [ebp+8]
  end; // ==> pop ebp; ret 12

Notice how the addresses of the parameters are translated different than in the previous examples.

This is a sample call for the function:

  asm
    // a := AddAndMultiply(1, 2, 3); // should be 9
    push 1
    push 2
    push 3
    call AddAndMultiply
    mov a, eax
  end;

After entering the function, the stack would look like this:

  |                |
  +----------------+
  |      EBP       |  [EBP], [ESP]
  +----------------+
  | Return Address |  [EBP+4]
  +----------------+
  |     i3 = 3     |  [EBP+8]
  +----------------+
  |     i2 = 2     |  [EBP+12]
  +----------------+
  |     i1 = 1     |  [EBP+16]
  +----------------+
  |                |




Previous: Inline Assembler in Delphi (V) - Objects
Next: Inline Assembler in Delphi (VII) - 128-bit integer arithmetic


分类: BASM Delphi
0
0
(请您对文章做出评价)
博主上一篇:Inline Assembler in Delphi (V) An Introdunction to Objects
博主下一篇:Inline Assembler in Delphi (II) ANSI strings
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
Debug Tutorial Part 2: The Stack
The details of C function stack (and heap) operation when function call is made (caller) and returne
论函数调用约定
DLL中调用约定和名称修饰(一)
函数调用方式介绍
函数调用约定和堆栈
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服