将 Turbo Pascal 内联代码转换为 Object Pascal

Eng*_*aum 4 assembly pascal inline turbo-pascal x86-16

在将旧的 Turbo Pascal 单位转换为现代 Object Pascal 时,我遇到了以下问题:

function Less (var a, b; Relation : POINTER) : boolean;
    inline($5B/$59/$0E/$E8/$00/$00/$58/$05/$08/$00/$50/$51/$53/$CB);
Run Code Online (Sandbox Code Playgroud)

代码应该调用 an external function {$F+} function VariableLess(var a, b : Index) : boolean; {$F-},收集结果并将其传递给调用函数。该函数用于为无类型数据提供二叉树的单元中

procedure InsVarBBTree(var B: BBTree; var E; S: word; A: pointer; var ok: boolean);
{ puts variable E of size S into tree B. The order relation address is A. }
Run Code Online (Sandbox Code Playgroud)

因此,单元本身不能提供比较功能,即定义有效载荷的单元的工作。

使用在线反汇编器,我发现这对应于:

{$ASMMODE intel}
function Less (var a, b; Relation : POINTER) : boolean; assembler;

asm
  pop  bx
  pop  cx
  push cs
  call 6
  pop  ax
  add  ax, 8
  push ax
  push cx
  push bx
  retf
end;
Run Code Online (Sandbox Code Playgroud)

但是,编译器不喜欢该push语句。我应该怎么做才能让它在现代 64 位机器上工作?我意识到代码是 16 位的。

Mar*_*nau 7

我刚刚inline在 Turbo Pascal 5 上为 MS-DOS编译了一些函数来检查 Turbo Pascal 如何生成代码:

对于非inline函数调用,Turbo Pascal 将所有函数参数压入堆栈。第一个被首先推送(因此SS:SP指向最后一个函数参数)。然后执行a ( far) call。函数返回 using retf n,这意味着调用的函数从堆栈中删除所有参数。

在一个inline功能,只需给定的原始字节替换call指令。这意味着SS:SP指向参数,而不是返回地址。内联机器语言代码必须pop来自堆栈的参数。并且它不能返回 usingret而只是在代码之后的指令处继续代码执行inline

有了这些知识,可以分析汇编代码:

使用给出的汇编代码,您可以通过编写具有与要调用的函数相同的参数以及指向的附加参数的辅助函数(在您的情况下:)间接调用任何 functionprocedure任何参数(在您的情况下VariableLess:)Less实际功能。

代码等同于以下DelphiFreePascal代码:

type
    TMyCompare = function(var a, b) : boolean;

function Less (var a, b; Relation : TMyCompare) : boolean;
begin
    Less := Relation(a, b);
end;
Run Code Online (Sandbox Code Playgroud)

如果您的编译器支持函数指针 ( type TMyCompare = function ...),您可以这样做。

或者你甚至可以Less(x,y,z)z(x,y). 这甚至会更有效率。

当然,如果你这样做,指向函数(VariableLess)的指针不应该有类型,pointer而应该有类型TMyCompare

如果您的编译器不支持函数指针(Turbo Pascal 显然不支持),您可能需要汇编。

但在那种情况下,不同的编译器将需要不同的汇编代码!

因此,如果不了解编译器的内部结构,就无法翻译汇编代码。

编辑

我不确定您的编译器究竟是如何工作的。但是,如果我的原始代码不起作用,则以下代码可能起作用:

function Less (var a, b; Relation : Pointer) : boolean;
type
    TMyCompare = function(var a, b) : boolean;
var
    Relation2 : TMyCompare;
begin
    Relation2 := TMyCompare(Relation);
    Less := Relation2(a, b);
end;
Run Code Online (Sandbox Code Playgroud)