代码之家  ›  专栏  ›  技术社区  ›  Lasse V. Karlsen

jcldotnet和一些使用汇编程序的奇怪调用模式

  •  1
  • Lasse V. Karlsen  · 技术社区  · 16 年前

    我们有自己的粘合层代码thingamajig,它允许我们在win32 delphi程序中托管.NET运行时。这使我们能够随着时间的推移逐步过渡到.NET。

    但是,我们经常会遇到一些问题,昨天我在这里看到了一个关于JCL的.NET主机实现的答案,所以我想看看是否有明显的区别。

    原来是有的,但我不明白它做了什么,为什么,以及我是否需要这样做。我当然会尝试它,但我非常希望其他人能够理解这个奇怪代码背后的原因,告诉我它的作用。

    随着时间的推移,我们可能会切换到使用JCL实现,但是由于我们即将发布一个版本,除非为了解决当前的问题是绝对必要的,否则在这一级别的代码进行大的修改是不合理的,所以请不要仅仅建议我们切换。

    不管怎样,区别在于它们如何调用.NET函数来加载和绑定到.NET运行时,基本上是如何从.NET dll调用导出的函数。

    以下是我的代码:

    type
      TCorBindToRuntimeEx = function(pwszVersion: PWideChar;
        pwszBuildFlavor: PWideChar;
        startupFlags: DWord; rclsid, riid: PGUID;
        out ppv: IUnknown): Integer; stdcall;
    ...
    var
      CorBindToRuntimeEx  : TCorBindtoRuntimeEx = nil;
    ...
    CorBindToRuntimeEx := GetProcAddress(Runtimehandle, 'CorBindToRuntimeEx');
    ...
    clsid := CLASS_CorRuntimeHost;
    iid := IID_ICorRuntimeHost;
    rc := CorBindToRuntimeEx('v2.0.50727', 'wks', 0, @clsid,
        @iid, UnkRuntimeEngine);
    

    现在,我只需使用getprocaddress将导出函数的地址加载到变量中,输入为 stdcall 函数指针,然后我调用它。这是可行的,差不多。正如我所说,在一些情况下,一些奇怪的错误消息会出现问题。

    好的,这是它们的代码,请特别注意汇编程序代码的功能。

    function CorBindToRuntimeEx(pwszVersion, pwszBuildFlavor: PWideChar;
      startupFlags: DWORD; const rclsid: TCLSID; const riid: TIID;
      out pv): HRESULT; stdcall;
    {$EXTERNALSYM CorBindToRuntimeEx}
    ...
    var
      _CorBindToRuntimeEx: Pointer = nil;
    
    function CorBindToRuntimeEx;
    begin
      GetProcedureAddress(_CorBindToRuntimeEx, mscoree_dll,
        'CorBindToRuntimeEx');
      asm
        mov esp, ebp
        pop ebp
        jmp [_CorBindToRuntimeEx]
      end;
    end;
    ...
    OleCheck(CorBindToRuntimeEx(PWideCharOrNil(ClrVer),
      PWideChar(ClrHostFlavorNames[Flavor]), Flags,
      CLASS_CorRuntimeHost, IID_ICorRuntimeHost,
      FDefaultInterface));
    

    请注意,我已经对代码进行了轻微的重新格式化,以避免出现水平滚动条,但是只添加了一些换行符和一些缩进,代码就是这样的。

    最后一个调用可能与此无关,它基本上会传递与我们相同的参数(请注意,我们将0作为选项值传递,但我们也使用了JCL代码使用的相同的特定参数,但问题仍然存在)。

    所以,我的问题是,汇编程序代码是做什么的?我知道它在技术上做什么,我以前一直在编程汇编,所以它操纵堆栈指针。

    问题是为什么必须这样做。我就是不明白。

    可能堆栈帧不是 相当地 调用约定 毕竟?

    今天请教我点东西。


    编辑 :好的,相应地更改了我的代码,但问题仍然存在,所以不是这样。看来我要做一些windbg挖掘第三方代码。

    1 回复  |  直到 16 年前
        1
  •  5
  •   Andreas Hausladen    16 年前

    汇编程序代码删除corbindtoruntimeex的stackframe。 如果调用corbindtoruntimeex,所有参数都将推送到堆栈(=gt;stdcall)。然后,该函数调用getprocedureaddress来初始化全局的corbindtoruntimeex变量,该变量现在指向“corbindtoruntimeex”函数。

    GetProceduredAddress返回后,必须调用_corbindtoruntimeex函数。但这里有个问题。Delphi自动在代码中添加了“push ebp;mov ebp,esp”(“begin”)。为了移除该堆栈框架,使用“mov esp,ebp;pop ebp”。“jmp[_corbindtoruntimeex]”然后将执行指针设置为_corbindtoruntimeex函数,该函数随后使用corbindtoruntimeex函数的返回地址。