在将旧的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);
代码应该调用一个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位的。
我刚刚在MS-DOS的Turbo Pascal 5上编译了一些inline
函数来检查Turbo Pascal如何生成代码:
对于非inline
函数调用,Turbo Pascal将所有函数参数压入堆栈。第一个被先推送(所以SS:SP
指向最后一个)函数参数)。然后执行a (far
)call
。该函数使用retf n
返回,这意味着被调用的函数将从堆栈中删除所有参数。
在inline
函数中,简单地用替换给出的原始字节call
指令。这意味着SS:SP
指向参数,而不是返回地址。内联机器语言代码必须从堆栈中pop
参数。并且它不能使用ret
返回,而只是在inline
代码之后的指令继续执行代码。
有了这些知识,就可以分析汇编代码了:
使用给出的汇编代码,您可以调用任意通过编写一个辅助函数(在您的情况下:Less
)来间接地使用任何参数(在您的情况下:VariableLess
)function
或procedure
,该函数具有与要调用的函数相同的参数加上指向实际函数的附加参数。
代码等于下面的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;
解决方案如下:在单元内部处理动态类型定义
type
TMyCompare = function(var a, b) : boolean;
function Less (var a, b; Relation : TMyCompare) : boolean;
begin
Result := Relation(a, b);
end;
procedure InsVarBBTree(var B: BBTree; var E; S: word; A: TMyCompare;
var ok: boolean);
{ puts variable E of size S into tree B. The order relation address is A. }
从外部调用
{$F+} function VariableLess(var a, b : Index) : boolean; {$F-}
begin
...
end;
InsVarBBTree(Baum, TempStr, SizeOf(TempStr), TMyCompare(@VariableLess), OK)
感谢所有帮助过我的人
恩格尔伯特·
我想它将适用于Free Pascal 16位目标,但您可能对此不感兴趣。对于非16位目标,16位代码将需要重写,内存模型和ABI是不同的。您的反汇编是象征性的,并且常量并不真正反映源的含义,就像原始汇编程序源(.asm)一样。
这个过程特别麻烦,因为它似乎对ABI做了假设,所以它本质上是不可移植的。
此外,即使您成功了,结果也不是最优的,因为对象pascal编译器(Delphi, Free pascal)比TP更加优化。对短过程使用外部汇编器会阻碍编译器内联的能力。
我认为Peter Cordes是对的,这是一种对实际功能的思考后显示的程序。不,我想Martin更近。这有点不合逻辑,但是因为编译器不能真正内联(只能转储汇编块),所以参数调用保持不变,并且必须在不访问堆栈帧/局部变量的情况下撤消。TP不把值保存在寄存器中,所以这是相对安全的。
您也可以尝试反汇编它,但最好的方法可能是简单地尝试从文档中为它制定一个pascal替代品,并忘记所有的微优化。