Delphi 实现C说话函数调用

    添加时间:2013-5-14 点击量:

    在X86下,C说话函数调用,使将参数从右到左压入客栈,栈指针减小,最后一个参数压入后,栈指针指向最后一个参数


    是以我们可以经由过程增长栈指针,读取所有的参数,X86CPU的客栈是4字节对齐,也就是说字节性或者字型参数都是压入4


    字节。


    type  
    
    TArgPtr
    =record
    private
    FArgPtr
    : PByte;classfunction 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;
    classfunction 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 doesnt 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.

     

    文艺不是炫耀,不是花哨空洞的文字堆砌,不是一张又一张的逆光照片,不是将旅行的意义转化为名牌包和明信片的物质展示;很多时候它甚至完全不美——它嘶吼、扭曲,它会痛苦地抽搐,它常常无言地沉默。——艾小柯《文艺是一种信仰》
    分享到: