将TurboPascal内联代码转换为ObjectPascal
在将旧的 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);
代码应该调用 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. }
因此,单元本身不能提供比较功能,即定义有效载荷的单元的工作。
使用在线反汇编器,我发现这对应于:
{$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;
但是,编译器不喜欢该push语句。我应该怎么做才能让它在现代 64 位机器上工作?我意识到代码是 16 位的。
回答
我刚刚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。
有了这些知识,可以分析汇编代码:
使用给出的汇编代码,您可以通过编写具有与要调用的函数相同的参数以及指向的附加参数的辅助函数(在您的情况下:)间接调用任何 function或procedure任何参数(在您的情况下VariableLess:)Less实际功能。
代码等同于以下Delphi或FreePascal代码:
type
TMyCompare = function(var a, b) : boolean;
function Less (var a, b; Relation : TMyCompare) : boolean;
begin
Less := Relation(a, b);
end;
如果您的编译器支持函数指针 ( 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;