преобразование ассемблерной функции в Delphi, которая выполняется на windows, в delphi / c ++ для выполнения на Linux - PullRequest
3 голосов
/ 21 апреля 2020

У меня есть эта функция ассемблера в моем приложении, написанная в delphi, и она хорошо работает на windows. Но мое требование состоит в том, чтобы выполнить ее на Linux, так как я переношу свое приложение на Linux. И во время компиляции этой функции в Linux я получил ошибку: «Неподдерживаемая языковая функция:« ASM »».

Кто-нибудь может помочь или подсказать, как реализовать его в c ++ или delphi, чтобы она работала для Linux. делюсь своим кодом:

type 
  PVersionizedPointer = ^TVersionizedPointer; 
  TVersionizedPointer = packed record 
    Ver : NativeInt; 
    Ptr : Pointer; 
  end; 
  TVersionizedPointerStorage = array[0 .. 2 * sizeof(TVersionizedPointer) - 1] of byte; 

function GetVersionizedPointer(var PointerStorage : TVersionizedPointerStorage) : 
    PVersionizedPointer; assembler;
const
  vp_size = sizeof(TVersionizedPointer);  
      // Note: sizeof(any) inside asm is always $31
  asm
    {$ifdef CPUX86}
      add EAX, vp_size - 1
      and EAX, not(vp_size - 1)
    {$endif}
    {$ifdef CPUX64}
      mov RAX, RCX
      add RAX, vp_size - 1
      and RAX, not(vp_size - 1)
    {$endif}
  end;
end;

Ответы [ 2 ]

5 голосов
/ 21 апреля 2020

Вероятно, проще всего сосредоточиться на том, что делает версия x86:

function GetVersionizedPointer(var PointerStorage: TVersionizedPointerStorage): PVersionizedPointer;
const
  vp_size = sizeof(TVersionizedPointer);
asm
  add EAX, vp_size - 1
  and EAX, not(vp_size - 1)
end;

ABI x86 означает, что адрес PointerStorage передается в функцию в EAX. Возвращаемое значение, другой адрес, также возвращается в EAX. Это знание позволяет нам понять, что делает функция, и позволяет нам писать это так: Pascal:

function GetVersionizedPointer(var PointerStorage: TVersionizedPointerStorage): PVersionizedPointer;
var
  Address: NativeUInt;
begin
  Address := NativeUInt(@PointerStorage);
  Address := Address + (SizeOf(TVersionizedPointer) - 1);
  Address := Address and not (SizeOf(TVersionizedPointer) - 1);
  Result := PVersionizedPointer(Address);
end;

Я написал это довольно многословно, чтобы прояснить, что делает каждый шаг. Переменной адреса присваивается адрес PointerStorage, и поэтому он играет ту же роль, что и EAX в исходной версии.

Сделайте вашу жизнь проще в будущем, используя эту чистую версию Pascal, и потеря кода ассемблера.

3 голосов
/ 21 апреля 2020

Эта функция предназначена для выравнивания памяти в памяти. Это совершенно бессмысленно в современных процессорах Intel / AMD . Это могло иметь преимущество на процессоре 8086, но не больше. Окончательно звучит как неправильная / преждевременная оптимизация.

Этой подпрограммы выравнивания можно просто избежать: она сделает код чище и быстрее. Просто избавьтесь от TVersionizedPointerStorage и используйте только TVersionizedPointer.

Отклонение данных будет быстрее, так как вам не нужно больше вычислять выравнивание, и вы просто используете необходимую память, тогда как TVersionizedPointerStorage всегда использует вдвое больший размер, поэтому это загрязняет кэш CPU L1 бесполезен и добавляет ненужное выделение памяти.

...