una que pilas pila partes las funcionan funciona funcion electrica cual como delphi variadic-functions

delphi - que - ¿Cómo puede una función con ''varargs'' recuperar el contenido de la pila?



partes de una pila (3)

Normalmente, en Delphi uno declararía una función con un número variable de argumentos usando el método ''array of const''. Sin embargo, para la compatibilidad con el código escrito en C, hay una directiva ''varargs'' muy desconocida que se puede agregar a una declaración de función (lo aprendí mientras leía el excelente documento '' Pitfalls of convering '' de Rudy ).

Como ejemplo, uno podría tener una función en C, declarada así:

void printf(const char *fmt, ...)

En Delphi, esto se convertiría en:

procedure printf(const fmt: PChar); varargs;

Mi pregunta es: ¿cómo puedo acceder al contenido de la pila al implementar un método que se define con la directiva ''varargs''?

Esperaría que exista alguna herramienta para esto, como las traducciones de Dephi de las funciones va_start (), va_arg () y va_end (), pero no puedo encontrar esto en ninguna parte.

¡Por favor ayuda!

PD: Por favor, no se distraiga en las discusiones sobre la alternativa ''por qué'' o ''array of const'' - Necesito esto para escribir parches tipo C para las funciones dentro de los juegos de Xbox (vea el proyecto del emulador de Delphi Xbox ''Dxbx'' en sourceforge para detalles).


Delphi no te permite implementar una rutina varargs. Solo funciona para importar funciones cdecl externas que usan esto.

Como varargs se basa en la convención de llamadas cdecl, básicamente necesita volver a implementarlo en Delphi, utilizando el ensamblaje y / o varios tipos de manipulación de punteros.


De acuerdo, veo que la aclaración en su pregunta significa que debe implementar una importación de C en Delphi. En ese caso, debe implementar varargs usted mismo.

El conocimiento básico necesario es la convención de llamadas de C en el x86: la pila crece hacia abajo, y C empuja los argumentos de derecha a izquierda. Por lo tanto, un puntero al último argumento declarado, después de que se incrementa por el tamaño del último argumento declarado, apuntará a la lista de argumentos de la cola. A partir de entonces, es simplemente una cuestión de leer el argumento e incrementar el puntero en un tamaño apropiado para avanzar más en la pila. La pila x86 en el modo de 32 bits generalmente está alineada con 4 bytes, y esto también significa que los bytes y las palabras se pasan como enteros de 32 bits.

De todos modos, aquí hay un registro de ayuda en un programa de demostración que muestra cómo leer datos. Tenga en cuenta que Delphi parece estar pasando tipos Extendidos de una manera muy extraña; sin embargo, es probable que no tenga que preocuparse por eso, ya que los flotadores de 10 bytes generalmente no se usan ampliamente en C, y ni siquiera se implementan en el último MS C, IIRC.

{$apptype console} type TArgPtr = record private FArgPtr: PByte; class function Align(Ptr: Pointer; Align: Integer): Pointer; static; public constructor Create(LastArg: Pointer; Size: Integer); // Read bytes, signed words etc. using Int32 // Make an unsigned version if necessary. function ReadInt32: Integer; // Exact floating-point semantics depend on C compiler. // Delphi compiler passes Extended as 10-byte float; most C // compilers pass all floating-point values as 8-byte floats. function ReadDouble: Double; function ReadExtended: Extended; function ReadPChar: PChar; procedure ReadArg(var Arg; Size: Integer); end; constructor TArgPtr.Create(LastArg: Pointer; Size: Integer); begin FArgPtr := LastArg; // 32-bit x86 stack is generally 4-byte aligned FArgPtr := Align(FArgPtr + Size, 4); end; class function TArgPtr.Align(Ptr: Pointer; Align: Integer): Pointer; begin Integer(Result) := (Integer(Ptr) + Align - 1) and not (Align - 1); end; function TArgPtr.ReadInt32: Integer; begin ReadArg(Result, SizeOf(Integer)); end; function TArgPtr.ReadDouble: Double; begin ReadArg(Result, SizeOf(Double)); end; function TArgPtr.ReadExtended: Extended; begin ReadArg(Result, SizeOf(Extended)); end; function TArgPtr.ReadPChar: PChar; begin ReadArg(Result, SizeOf(PChar)); end; procedure TArgPtr.ReadArg(var Arg; Size: Integer); begin Move(FArgPtr^, Arg, Size); FArgPtr := Align(FArgPtr + Size, 4); end; procedure Dump(const types: string); cdecl; var ap: TArgPtr; cp: PChar; begin cp := PChar(types); ap := TArgPtr.Create(@types, SizeOf(string)); while True do begin case cp^ of #0: begin Writeln; Exit; end; ''i'': Write(ap.ReadInt32, '' ''); ''d'': Write(ap.ReadDouble, '' ''); ''e'': Write(ap.ReadExtended, '' ''); ''s'': Write(ap.ReadPChar, '' ''); else Writeln(''Unknown format''); Exit; end; Inc(cp); end; end; type PDump = procedure(const types: string) cdecl varargs; var MyDump: PDump; function AsDouble(e: Extended): Double; begin Result := e; end; function AsSingle(e: Extended): Single; begin Result := e; end; procedure Go; begin MyDump := @Dump; MyDump(''iii'', 10, 20, 30); MyDump(''sss'', ''foo'', ''bar'', ''baz''); // Looks like Delphi passes Extended in byte-aligned // stack offset, very strange; thus this doesn''t work. MyDump(''e'', 2.0); // These two are more reliable. MyDump(''d'', AsDouble(2)); // Singles passed as 8-byte floats. MyDump(''d'', AsSingle(2)); end; begin Go; end.


Encontré esto (de un hombre que conocemos :))

Para escribir esto correctamente, necesitará usar BASM, el ensamblador integrado de Delphi y codificar la secuencia de llamadas en asm. Espero que tengas una buena idea de lo que tienes que hacer. Quizás una publicación en el grupo .basm te ayudará si te quedas atascado.