Ассемблер из 32 bit в 64

Есть код ассемблер, который я использую в 32 битном Делфи.

function RotateRightBits(const Value:LongWord; const Bits:Byte):LongWord;register;assembler;
asm
 MOV CL,DL
 ROR EAX,CL
end;

Я переписываю программу в 64 битном FreePascal и столкнулся со сложностью перевода этого кода. Так как он возвращает совсем не то число что в 32 битном.

Аналог кода на Делфи работает в 10 раз дольше, по этому меня он не устраивает.

function RotateRightBits(const Value:LongWord;const Bits:Byte):LongWord;
var I,B:integer;
begin
 Result := Value;
 if Bits >= 32 then B := Bits mod 32
 else B := Bits;
 for I := 1 to B do
  if Result and 1 = 0 then Result := Result shr 1
  else Result := (Result shr 1) or $80000000;
 end;

Сильно сложно переписать 32 битный код ассемблера под 64 битные регистры, чтоб он работал идентично?


Ответы (1 шт):

Автор решения: Anton Shchyrov

В x32 параметры в функцию передаются через регистры eax, edx, ecx, а возвращаемый результат передается через регистр eax.

В x64 параметры в функцию передаются через регистры rcx, rdx, r8, r9, а возвращаемый результат передается через регистр rax.

Поэтому функцию нужно написать вот так

function RotateRightBits(Value: LongWord; Bits: Byte): LongWord; register; assembler;
asm
  {$IFDEF CPUx64}
  mov rax, rcx
  {$ENDIF}
  mov cl, dl
  ror eax, cl
end;

Если же 64 битная функция должна работать с 64 битными значениями, то нужно написать так

// Тип NativeUInt имеет различный размер в зависимости от платформы
function RotateRightBits(Value: NativeUInt; Bits: Byte): NativeUInt; register; assembler;
asm
  {$IFDEF CPUx32}
  mov cl, dl
  ror eax, cl
  {$ELSE}
  mov rax, rcx
  mov cl, dl
  ror rax, cl
  {$ENDIF}
end;
→ Ссылка