P /呼び出しやC#のカスタム呼び出し規約
-
23-08-2019 - |
質問
私は、ビジネスケースを持っています。具体的には、私は非標準のABIを使用する従来のDLLを持っている、と私は各機能の呼び出し規約を指定することが可能にする必要があります。
は、例えば、このDLL内の1つの機能は、スタックを介して他の部分と、EAXとEBXを介してその最初の二つの引数を受け付けます。別の機能は、スタック上の残りの部分と、ECXを経由して一つの引数を受け入れます。私は、これらの機能の数百を持っており、これらの機能にアクセスするために、私自身の中間ブリッジDLLを書く避けたい。
私の他のオプションは、手でロールバックする明白な理由のために望ましくない独自のカスタムP /呼び出しを、となります。
すべてのヘルプは高く評価され、感謝、
解決
私は、カスタムP /呼び出しで何を意味するのか理解していないが、私はあなたがインラインアセンブリで非管理C ++せずに逃げることができるか見ることができません。ほとんどすべてが32ビット値として渡されるので、あなたは、機能ごとに一つに並置として、各関数のシグネチャのために一つだけのプロキシを書いて逃げるかもしれません。それとも、XMLからプロキシを生成するコードジェネレータを書くことができます。すべてのプロキシ機能は本当に簡単になりますので、私は、しかし、このバージョンは、あまりにも好ましくない見ることができません。
int RealFunction(int param1, const char * param2, char param 3);
int MyFunction(int param1, int param2, int param3) { // argument types do not matter as long as they are not doubles or structures
__asm {
mov eax, param1
mov ebx, param2
push param3
call RealFunction
; depending on calling convention, you might need to do add esp, 12 here
; if RealFunction does not return its result in eax, you will need to do mov eax, <wherever the return value is> here
}
}
他のヒント
私は別のDLLなしで何をしたい達成するための何の組み込み方法がないかなり確信しています。私は、ランタイムシステムがサポートしているもの以外呼び出し規約を指定する方法を見ていませんでした。
私はしばらく前に呼び出し規約についての学習と呼び出し規則を変換するために、いくつかのコードを書きました。コードは、ラッパーライブラリはリフレクションを使用して、特別なC#のラッパーから呼び出される特殊な裸のスタブメソッドのメソッドを呼び出す/新しいPを放出する(Marshal.getdelegateforfunctionpointerが働いて得ることができませんでした)を発します。これは、パラメータを修正してから、実際にメソッドを呼び出します。
ここでは、Cコードがあります。私は便利なC#の部分を持っていない:(私はコードが吸うかもしれないので、一度にあまりにもアセンブラを学んでいた:)
typedef struct
{
USHORT ParameterOneOffset; // The offset of the first parameter in dwords starting at one
USHORT ParameterTwoOffset; // The offset of the second parmaeter in dwords starting at one
} FastCallParameterInfo;
__declspec( naked,dllexport ) void __stdcall InvokeFast()
{
FastCallParameterInfo paramInfo;
int functionAddress;
int retAddress;
int paramOne, paramTwo;
__asm
{
// Pop the return address and parameter info. Store in memory.
pop retAddress;
pop paramInfo;
pop functionAddress;
// Check if any parameters should be stored in edx
movzx ecx, paramInfo.ParameterOneOffset;
cmp ecx,0;
je NoRegister;
// Calculate the offset for parameter one.
movzx ecx, paramInfo.ParameterOneOffset; // Move the parameter one offset to ecx
dec ecx; // Decrement by 1
mov eax, 4; // Put 4 in eax
mul ecx; // Multiple offset by 4
// Copy the value from the stack on to the register.
mov ecx, esp; // Move the stack pointer to ecx
add ecx, eax; // Subtract the offset.
mov eax, ecx; // Store in eax for later.
mov ecx, [ecx]; // Derefernce the value
mov paramOne, ecx; // Store the value in memory.
// Fix up stack
add esp,4; // Decrement the stack pointer
movzx edx, paramInfo.ParameterOneOffset; // Move the parameter one offset to edx
dec edx; // Decrement by 1
cmp edx,0; // Compare offset with zero
je ParamOneNoShift; // If first parameter then no shift.
ParamOneShiftLoop:
mov ecx, eax;
sub ecx, 4;
mov ecx, [ecx]
mov [eax], ecx; // Copy value over
sub eax, 4; // Go to next
dec edx; // decrement edx
jnz ParamOneShiftLoop; // Loop
ParamOneNoShift:
// Check if any parameters should be stored in edx
movzx ecx, paramInfo.ParameterTwoOffset;
cmp ecx,0;
je NoRegister;
movzx ecx, paramInfo.ParameterTwoOffset; // Move the parameter two offset to ecx
sub ecx, 2; // Increment the offset by two. One extra for since we already shifted for ecx
mov eax, 4; // Put 4 in eax
mul ecx; // Multiple by 4
// Copy the value from the stack on to the register.
mov ecx, esp; // Move the stack pointer to ecx
add ecx, eax; // Subtract the offset.
mov eax, ecx; // Store in eax for later.
mov ecx, [ecx]; // Derefernce the value
mov paramTwo, ecx; // Store the value in memory.
// Fix up stack
add esp,4; // Decrement the stack pointer
movzx edx, paramInfo.ParameterTwoOffset; // Move the parameter two offset to ecx
dec edx; // Decrement by 1
cmp edx,0; // Compare offset with zero
je NoRegister; // If first parameter then no shift.
ParamTwoShiftLoop:
mov ecx, eax;
sub ecx, 4;
mov ecx, [ecx]
mov [eax], ecx; // Copy value over
sub eax, 4; // Go to next
dec edx; // decrement edx
jnz ParamTwoShiftLoop; // Loop
NoRegister:
mov ecx, paramOne; // Copy value from memory to ecx register
mov edx, paramTwo; //
push retAddress;
jmp functionAddress;
}
}