Вопрос про cdecl, varargs

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Вопрос про cdecl, varargs

Сообщение ricochet » 13.10.2008 22:53:23

Всем привет!

В исходниках Python for Delphi есть такой код:

Код: Выделить всё
type
  TPythonInterface=class(TDynamicDll)
  private
    {...}
    DLL_PyArg_ParseTuple:
                     function( args: PPyObject; format: PChar {;...}):
                     Integer; cdecl; varargs;
    {...}
    function PyArg_ParseTuple( args: PPyObject; format: PChar;
                               argp: array of Pointer): Integer; cdecl;
  {...}
  end;
  {...}
function TPythonInterface.PyArg_ParseTuple ( args: PPyObject; format: PChar;
                            argp: array of Pointer): Integer; cdecl;
begin
{$IFDEF DELPHI6_OR_HIGHER}
{...}
{$ELSE}
{***} Result := DLL_PyArg_ParseTuple( args, format ); {***}
{$ENDIF}
end;


Почему выделенное звёздочками работает в Delphi (т.е. корректно передает аргументы, которые в argp) и не работает в freepascal?
FreePascal версии 2.2.0, ключ -Mdelphi используется.
Не работает следующим образом: исключение Access Violation, причем не внутри DLL_PyArg_ParseTuple, а где-то после, при вызовах других функций (портится стек?). Если вызов PythonInterface.PyArg_ParseTuple заменить непосредственно на PythonInterface.DLL_PyArg_ParseTuple c соответствующим изменением прототипа (либо добавление модификатора varargs и убирание квадратных скобок в вызывающем коде, либо добавление array of const в список аргументов), то все работает как надо. Одинаковое поведение и на Windows, и на Linux.
ricochet
незнакомец
 
Сообщения: 2
Зарегистрирован: 13.10.2008 22:29:55

Re: Вопрос про cdecl, varargs

Сообщение Sergei I. Gorelkin » 14.10.2008 00:47:28

Выделенное звездочками, как можно понять из $ifdef, относится к Дельфи младше шестой версии, который в принципе не умел вызывать cdecl ф-ции с переменным кол-вом аргументов. Работает, видимо, потому что при такой конструкции аргументы каким-то чудом оказываются расположены на стеке так как требуется.
Для FPC эти извращения не нужны, он нормально понимает как array of const, так и varargs. В данном случае должно быть достаточно откомпилить, определив символ DELPHI6_OR_HIGHER.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград

Re: Вопрос про cdecl, varargs

Сообщение ricochet » 14.10.2008 09:44:51

Sergei I. Gorelkin писал(а):В данном случае должно быть достаточно откомпилить, определив символ DELPHI6_OR_HIGHER.


Полностью функция выглядит вот так:
Код: Выделить всё
function TPythonInterface.PyArg_ParseTuple ( args: PPyObject; format: PChar;
                            argp: array of Pointer): Integer; cdecl;
begin
{$IFDEF DELPHI6_OR_HIGHER}
  Result := 0;
  { Do not optimize this to a "pure" assembler routine, because such
    a routine does not copy the array arguments in the prologue code }
  asm
    lea edx, format
    push [edx]

    sub edx, TYPE PChar
    push [edx]

    mov eax, Self
    mov eax, [eax].DLL_PyArg_ParseTuple
    call eax

    pop edx
    pop edx
    mov Result, eax
  end;
{$ELSE}
  Result := DLL_PyArg_ParseTuple( args, format );
{$ENDIF}
end;


Пробовал оставлять блок для DELPHI6, и это тоже падает с Access Violation. Может падает и по другому и починить не сложно, но в любом случае извращения с ассемблером хотелось бы использовать в последнюю очередь.
Я так понимаю, сложность в передаче всех аргументов одной cdecl-функции в другую в том, что неизвестно их количество. В принципе, форматная строка простая, и узнать количество несложно. Как тогда можно это сделать в freepascal?
ricochet
незнакомец
 
Сообщения: 2
Зарегистрирован: 13.10.2008 22:29:55

Re: Вопрос про cdecl, varargs

Сообщение Sergei I. Gorelkin » 14.10.2008 15:35:48

Ага. Я-то сначала подумал, что в ветке DELPHI6_OR_HIGHER написано нечто более адекватное, а там все еще хуже...

Ну, тогда, наверное, имеет смысл поступить так, как сам и предложил:
ricochet писал(а):Если вызов PythonInterface.PyArg_ParseTuple заменить непосредственно на PythonInterface.DLL_PyArg_ParseTuple c соответствующим изменением прототипа (либо добавление модификатора varargs и убирание квадратных скобок в вызывающем коде, либо добавление array of const в список аргументов), то все работает как надо


Немного подробнее: для FPC два объявления совершенно одинаковы, Дельфи же первый вариант не понимает (точнее понимает, но совсем не так как нужно):
Код: Выделить всё
function foo(arg1: whatever; args: array of const): integer; cdecl;
function foo(arg1: whatever): integer; cdecl; varargs;

При вызове первой ф-ции придется "переменные" аргументы заключать в квадратные скобки, при вызове второй - скобки не нужны.
Аватара пользователя
Sergei I. Gorelkin
энтузиаст
 
Сообщения: 1407
Зарегистрирован: 24.07.2005 14:40:41
Откуда: Зеленоград


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 9

Рейтинг@Mail.ru