ترجمة رمز باستخدام المؤشر ، إلى التجميع في Pascal - Delphi
سؤال
لدي هذا الرمز أدناه ، وأريد ترجمته إلى ASM ، لاستخدامه في Delphi أيضًا.
var
FunctionAddressList: Array of Integer;
type TFunction = function(parameter: Integer): Integer; cdecl;
function Function(parameter: Integer): Integer;
var
ExternFunction: TFunction;
begin
ExternFunction := TFunction(FunctionAddressList[5]);
Result := ExternFunction(parameter);
end;
إنه يعمل بشكل طبيعي ، لكن عندما أجرب نسخة التجميع:
function Function(parameter: Integer): Integer; cdecl;
asm
mov eax, FunctionAddressList
jmp dword ptr [eax + 5 * 4]
end;
من المفترض أن تعمل ، لأنه في C ++ يعمل في كلا الاتجاهين:
void *FunctionAddressList;
_declspec(naked) int Function(int parameter)
{
_asm mov eax, FunctionAddressList;
_asm jmp dword ptr [eax + 5 * 4];
}
typedef int (*TFunction)(int parameter);
int Function(int parameter)
{
TFunction ExternFunction = ((TFunction *)FunctionAddressList)[5];
return ExternFunction(parameter);
}
لكنه لا يعمل في دلفي.
في إصدار التجميع ، يضاعف الصفيف إلى 4 ، لأنه حجم الإزاحة بين كل عنصر من عناصر الصفيف ، وبالتالي فإن كلا الإصدارين متكافئان.
لذلك ، أريد أن أعرف لماذا لا يعمل مع دلفي. في دلفي ، يختلف حجم الإزاحة بين قيم عدد صحيح في صفيف عن C ++؟
لقد جربت بالفعل العديد من التعويضات ، مثل 1 ، 2 ، 4 ، 6 ، 8 ، وما إلى ذلك ، وأنواع كثيرة من الصفيف (مجموعة من المؤشر ؛ مؤشر فقط ؛ مجموعة من عدد صحيح ، إلخ) ، وحاولت العديد من اتفاقيات الاتصال ، وكان CDECL هو الوحيد الذي عمل مع الإصدار غير ASM ، ولكن مع ASM ، لم تنجح جميع الاختبارات.
شكرًا.
المحلول
أول تطبيق اختبار لإعادة إنتاج الخطأ:
var
FunctionAddressList: Array of Integer;
function Bar(parameter: Integer): Integer; cdecl;
begin
ShowMessage('Bar '+IntToStr(parameter));
end;
function Foo(parameter: Integer): Integer; cdecl;
asm
mov eax, FunctionAddressList
jmp dword ptr [eax + 5 * 4]
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SetLength(FunctionAddressList, 6);
FunctionAddressList[5]:= Integer(@Bar);
Foo(25);
end;
يتم تعريف عنوان الشريط بشكل صحيح ، ولكن المشكلة هي أن برنامج التحويل البرمجي Delphi يولد مقدمة و epilog لـ Foo ، لذا فإن رمز FOO الحقيقي هو
0046CD30 55 push ebp
0046CD31 8BEC mov ebp,esp
Unit1.pas.46: mov eax, FunctionAddressList
Unit1.pas.47: jmp dword ptr [eax + 5 * 4]
0046CD3B 5D pop ebp
0046CD3C C3 ret
نتيجةً لذلك ، تالف المكدس ، والمعلمة خاطئة وعنوان الإرجاع الشريطي خاطئ. إذا كنت لا تزال ترغب في القيام بالخدعة ، فاستخدم
function Foo(parameter: Integer): Integer; cdecl;
asm
pop ebp
mov eax, FunctionAddressList
jmp dword ptr [eax + 5 * 4]
end;
نصائح أخرى
Array of Integer
ليس ما تعتقد أنه. إنها صفيف ديناميكي يديره تلقائيًا.
يجب أن تجرب نفس الشيء باستخدام FunctionAddressList: ^Pointer;
- لاحظ أنه سيتعين عليك القيام بتخصيص يدوي وتخصيص.