While converting old Turbo Pascal units to modern Object Pascal, I ran into the following:
function Less (var a, b; Relation : POINTER) : boolean;
inline($5B/$59/$0E/$E8/$00/$00/$58/$05/$08/$00/$50/$51/$53/$CB);
The code is supposed to call an external function {$F+} function VariableLess(var a, b : Index) : boolean; {$F-}, collect the result and pass it to the calling function. The function is used in a unit that provides binary trees for untyped data
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. }
Therefore, the unit itself cannot provide a comparison function, that is the job of the unit that defines the payload.
Using an online disassembler I found out that this corresponds to:
{$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;
However, the compiler doesn't like the push statement. What should I do to get this to work on a modern 64-bit machine? I realise the code is 16-bit.
Afaik it will work for Free Pascal 16-bits targets, but you are probably not interested in that. For non 16-bit targets, 16-bit code will need rewrite, the memory model and ABI is different. Your disassembly is symbolic and the constants don't really reflect the meaning of the source like an original assembler source (.asm) would.
This procedure is particularly hairy since it seems to make assumptions on the ABI, so it is inherently unportable.
Moreover, even if you would succeed, then the result would be suboptimal, since the object pascal compilers (Delphi, Free Pascal) are way more optimizing than TP ever was. Using external assembler for short procedures stunts the ability of the compiler to inline.
I think Peter Cordes is right, and this is a kind of thunk to the real functionality after the shown procedure.Nope, I think Martin is closer. It is a bit unlogical but because the compiler can't really inline (only dump an assembler block) the parameter calling remains the same, and must be undone without access to a stack frame/local variables. TP doesn't keep values in registers, so this is relatively safe.You could try to disassemble that too, but the best is probably to simply try to formulate an pascal substitute for it from documentation, and forget about all the micro-optimizations.