I come across a problem while porting Delphi BASM32 code to FPC:
program MulTest;
{$IFDEF FPC}
{$mode delphi}
{$asmmode intel}
{$ELSE}
{$APPTYPE CONSOLE}
{$ENDIF}
function Mul(A, B: LongWord): LongWord;
asm
MUL EAX,EDX
end;
begin
Writeln(Mul(10,20));
Readln;
end.
The above code compiles in Delphi XE and works as expected; FPC outputs compile-time error on MUL EAX,EDX line:
Error: Asm: [mul reg32,reg32] invalid combination of opcode and operands
I am using Lazarus 1.4.4/FPC2.6.4 for Win32 (the current stable version)
Any workaround or fix for the problem?
FreePascal is correct. There are only 3 forms of
MUL:In other words, the first operand (used for both input and output) is specified in
AL/AX/EAX, and the second input operand is explicitly specified as either a general-purpose register or a memory address.So,
MUL EAX,EDXis indeed an invalid assembly instruction.If you compile this code in Delphi and use the debugger to look at the generated assembly, you would see that the call to
Mul(10,20)generates the following assembly code:So, as you can see, Delphi is actual parsing your source code, sees that the first operand is
EAXand strips it off for you, thus producing the correct assembly. FreePascal is not doing that step for you.The workaround? Write proper assembly code to begin with. Don't rely on the compiler to re-interpret your code for you.
Or, you could simply not write assembly code directly, let the compiler do the work for you. It knows how to multiple two
LongWordvalues together:Though Delphi does use
IMULinstead ofMULin this case. From Delphi's documentation:It also uses some unsightly bloated assembly unless stackframes are disabled and optimizations are enabled. By configuring those two options, it is possible to get
Mul()to generate a singleIMUL EDXinstruction (plus theRETinstruction, of course). If you don't want to change the options project-wide, you can isolate them to justMul()by using the{$STACKFRAMES OFF}/{$W-}and{$OPTIMIZATION ON}/{$O+}compiler instructions.Generates: