Удаление пролога функции, написанной в чистом виде - PullRequest
7 голосов
/ 27 марта 2011

Я использую Delphi 2010. Можно ли сказать, что Delphi не генерирует пролог для функции? Я пишу некоторые чистые ассемблерные функции, такие как:

procedure SomeAssembly; stdcall;
begin
    asm
        ...
    end;
end;

и я бы хотел сказать Delphi не создавать пролог и эпилог для этой функции, например, функцию C100 __declspec(naked).

И поэтому никто не тратит впустую свое время, мне не нужна помощь, чтобы эти функции работали с прологом; Я уже могу это сделать. Это просто большое неудобство и сделает техническое обслуживание огромной проблемой. Мне придется вручную проверять прологи, сгенерированные компилятором, чтобы увидеть их длину, и если это изменится, моя программа потерпит крах.

Я также знаю, что могу написать функцию в виде серии байтов в байтовом массиве, но это было бы еще хуже, чем поиск длины пролога Delphi.

Ответы [ 3 ]

19 голосов
/ 27 марта 2011

Delphi не генерирует прологи или эпилоги для функций, имеющих без аргументов и объявленных с регистром соглашения о вызовах. Если вам нужны функции без прологов, объявите их как функции с нулевым аргументом, функции регистрации вызовов. Также пропустите блок begin - end и перейдите прямо к сборке.

procedure SomeAssembly; // register; (implied)
asm
  // ...
end;

Поскольку вы фактически лжете о природе функций, вызывать их может быть сложно. Если вы реализовали функцию так, как будто она получила параметры и использовали другое соглашение о вызовах, то вам нужно убедиться, что компилятор знает об этом на сайте вызовов. Для этого объявите указатель на функцию, который отражает «реальный» тип вашей функции вместо объявленного типа. Например, если ваша функция действительно является функцией stdcall с двумя аргументами, объявите что-то вроде этого:

type
  TSomeAssemblyFunc = function (Arg1: Integer; Arg2: PAnsiChar): Boolean; stdcall;
var
  SomeAssemblyProc: TSomeAssemblyProc;

Теперь назначьте эту переменную так, чтобы она указывала на вашу функцию:

SomeAssemblyProc := TSomeAssemblyProc(@SomeAssembly);
if SomeAssembly(2, 'foo') then ...

Помимо пропуска пролога и эпилога, компилятор сгенерирует неверную инструкцию RET для этой функции (из-за разного соглашения о вызовах), поэтому вам нужно будет убедиться, что вы произнесете ret 8 в своем коде вместо того, чтобы дать команду компилятора по умолчанию ret.


Найти длину пролога Delphi тривиально, если у вас есть работающий отладчик:

  1. Установить точку останова в начале функции.
  2. Вызовите функцию.
  3. Когда отладчик останавливается в точке останова, переключитесь в представление CPU.
  4. Посмотрите на инструкции, из которых состоит пролог.
  5. Подсчитать количество байтов, отображаемых рядом с этими инструкциями.
1 голос
/ 27 марта 2011

Согласно этой embarcadero docwiki вы можете пропустить окружающие begin и end, и компилятор пропустит некоторые из его вещей.Но если вам действительно нужен чистый ассемблер, почему бы не поместить свою функцию в отдельный файл ассемблера, соберите его с помощью tasm (exe-файл с именем tasm32) и создайте ссылку на него.Затем вы будете использовать директиву assembler в коде delphi.

0 голосов
/ 27 марта 2011

Разве

procedure SomeAssembly; stdcall;
asm
    ...
end;

не справились?

...