Announcement

Collapse
No announcement yet.

ASM-Funktion per Inline-Assembler aufrufen.

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • ASM-Funktion per Inline-Assembler aufrufen.

    Ich möchte für meine Delphi-Programme ein par Assembler-Routinen schreiben aber bin dummerweise Assembler-Anfänger und die Delphi-Hilfe gibt in sachen Parameter übergabe nicht viel her. Hoffe ihr könnt mir hiermit helfen:<br>
    <br>
    function MachWas(x, y, z: Byte): Integer;<br>
    asm<br>
    ...<br>
    end;<br>
    <br>
    procedure MachWasAnderes;<br>
    asm<br>
    CALL MachWas;<br>
    ...<br>
    end;<br>
    <br>
    Soweit alles kein Problem aber wie übergebe ich jetzt die Parameter? Bzw. in welche Register (oder in den Stack?) gehören die Parameter? Da das ganze sicher vom Typ der Parameter abhängt, wo kann ich entsprechende Info's bekommen?
    Und wie sieht das ganze mit API-Calls aus? Ich weiss dass CreateSolidBrush das EAX nimmt aber wie sieht es z.b. mit CreateHatchBrush aus?

    Wo sich die "Rückgabewerte" (komme nicht auf das richtige wort) befinden ist wunderbar erklärt nur die Übergabe...

    HILFE, danke!

    mfg,
    bp

  • #2
    Die Reihenfolge (left-to-right, right-to-left), der Ort der Parameter (stack, register) und wer den Stack aufzur&auml;umen hat, h&auml;ngt von der Aufrufkonvention der Funktion ab.

    Hier ein Beispiel mit allen Aufrufkonventionen, die von Delphi unterst&uuml;tzt...

    <pre><p><b>program</b> Project1;
    <p>
    <b>uses</b>
    Windows;
    <p>
    <b>function</b> FooRegister(x, y, z: Byte): Integer; <font color='red'><b>register</b></font>;
    <b>asm</b>
    <font color='blue'><i>// Result = x</i></font>
    AND EAX, 0000000FFH
    <font color='blue'><i>// Result += y</i></font>
    AND EDX, 0000000FFH
    ADD EAX, EDX
    <font color='blue'><i>// Result += z</i></font>
    AND ECX, 0000000FFH
    ADD EAX, ECX
    <b>end</b>;
    <p>
    <b>function</b> FooPascal(x, y, z: Byte): Integer; <font color='red'><b>pascal</b></font>;
    <b>asm</b>
    <font color='blue'><i>// Result = x</i></font>
    XOR EAX, EAX
    MOV AL, BYTE PTR [EBP + 010H]
    <font color='blue'><i>// Result += y</i></font>
    XOR EDX, EDX
    MOV DL, BYTE PTR [EBP + 00CH]
    ADD EAX, EDX
    <font color='blue'><i>// Result += z</i></font>
    XOR EDX, EDX
    MOV DL, BYTE PTR [EBP + 008H]
    ADD EAX, EDX
    <b>end</b>;
    <p>
    <b>function</b> FooCDecl(x, y, z: Byte): Integer; <font color='red'><b>cdecl</b></font>;
    <b>asm</b>
    <font color='blue'><i>// Result = x</i></font>
    XOR EAX, EAX
    MOV AL, BYTE PTR [EBP + 008H]
    <font color='blue'><i>// Result += y</i></font>
    XOR EDX, EDX
    MOV DL, BYTE PTR [EBP + 00CH]
    ADD EAX, EDX
    <font color='blue'><i>// Result += z</i></font>
    XOR EDX, EDX
    MOV DL, BYTE PTR [EBP + 010H]
    ADD EAX, EDX
    <b>end</b>;
    <p>
    <b>function</b> FooStdCall(x, y, z: Byte): Integer; <font color='red'><b>stdcall</b></font>;
    <b>asm</b>
    <font color='blue'><i>// Result = x</i></font>
    XOR EAX, EAX
    MOV AL, BYTE PTR [EBP + 008H]
    <font color='blue'><i>// Result += y</i></font>
    XOR EDX, EDX
    MOV DL, BYTE PTR [EBP + 00CH]
    ADD EAX, EDX
    <font color='blue'><i>// Result += z</i></font>
    XOR EDX, EDX
    MOV DL, BYTE PTR [EBP + 010H]
    ADD EAX, EDX
    <b>end</b>;
    <p>
    <b>function</b> FooSafeCall(x, y, z: Byte): Integer; <font color='red'><b>safecall</b></font>;
    <b>asm</b>
    <font color='blue'><i>// temp = x</i></font>
    XOR EDX, EDX
    MOV DL, BYTE PTR [EBP + 008H]
    <font color='blue'><i>// temp += y</i></font>
    XOR ECX, ECX
    MOV CL, BYTE PTR [EBP + 00CH]
    ADD EDX, ECX
    <font color='blue'><i>// temp += z</i></font>
    XOR ECX, ECX
    ADD CL, BYTE PTR [EBP + 010H]
    ADD EDX, ECX
    <font color='blue'><i>// Result = temp</i></font>
    MOV EAX, DWORD PTR [EBP + 014H]
    MOV DWORD PTR [EAX], EDX
    <b>end</b>;<p></pre>

    ..

    Comment


    • #3
      <pre><p><font color='blue'><i>// Display MessageBox with Result</i></font>
      <b>procedure</b> FooDisplay(Value: Integer); <b>register</b>;
      <b>const</b>
      Format: PAnsiChar = <font color='green'>'%8.8X'</font>;
      <b>var</b>
      Buffer: <b>array</b> [0..8] <b>of</b> AnsiChar;
      <b>asm</b>
      PUSH Value
      MOV EAX, DWORD PTR [Format]
      PUSH EAX
      LEA EAX, DWORD PTR [Buffer]
      PUSH EAX
      CALL wsprintfA
      ADD ESP, 00000000CH
      PUSH 000000000H
      PUSH 000000000H
      LEA EAX, DWORD PTR [Buffer]
      PUSH EAX
      PUSH 000000000H
      CALL MessageBoxA
      <b>end</b>;
      <p>
      <b>procedure</b> Foo();
      <b>var</b>
      Return: Integer;
      <b>asm</b>
      <font color='blue'><i>// <font color='red'>Register</font></i></font>
      MOV AL, 001H <font color='blue'><i>// x</i></font>
      MOV DL, 002H <font color='blue'><i>// y</i></font>
      MOV CL, 003H <font color='blue'><i>// z</i></font>
      CALL FooRegister <font color='blue'><i>// Result in EAX</i></font>
      CALL FooDisplay
      <p>
      <font color='blue'><i>// <font color='red'>Pascal</font></i></font>
      PUSH 000000001H <font color='blue'><i>// x</i></font>
      PUSH 000000002H <font color='blue'><i>// y</i></font>
      PUSH 000000003H <font color='blue'><i>// z</i></font>
      CALL FooPascal <font color='blue'><i>// Result in EAX</i></font>
      CALL FooDisplay
      <p>
      <font color='blue'><i>// <font color='red'>CDecl</font></i></font>
      PUSH 000000003H <font color='blue'><i>// z</i></font>
      PUSH 000000002H <font color='blue'><i>// y</i></font>
      PUSH 000000001H <font color='blue'><i>// x</i></font>
      CALL FooCDecl <font color='blue'><i>// Result in EAX</i></font>
      ADD ESP, 00000000CH <font color='blue'><i>// Cleanup Stack</i></font>
      CALL FooDisplay
      <p>
      <font color='blue'><i>// <font color='red'>StdCall</font></i></font>
      PUSH 000000003H <font color='blue'><i>// z</i></font>
      PUSH 000000002H <font color='blue'><i>// y</i></font>
      PUSH 000000001H <font color='blue'><i>// x</i></font>
      CALL FooStdCall <font color='blue'><i>// Result in EAX</i></font>
      CALL FooDisplay
      <p>
      <font color='blue'><i>// <font color='red'>SafeCall</font></i></font>
      LEA EAX, DWORD PTR [Return]
      PUSH EAX <font color='blue'><i>// Offset of Return</i></font>
      PUSH 000000003H <font color='blue'><i>// z</i></font>
      PUSH 000000002H <font color='blue'><i>// y</i></font>
      PUSH 000000001H <font color='blue'><i>// x</i></font>
      CALL FooSafeCall <font color='blue'><i>// Result in Return</i></font>
      TEST EAX, EAX <font color='blue'><i>// Validate Call</i></font>
      JZ @@SafeCallOk
      MOV DWORD PTR [Return], 0FFFFFFFFH
      @@SafeCallOk:
      MOV EAX, DWORD PTR [Return]
      CALL FooDisplay
      <b>end</b>;
      <p>
      <b>begin</b>
      Foo();
      <b>end</b>.<p></pre>

      - nic

      Comment


      • #4
        Falls Du beim Kompilieren einen "Internal error Cxxxx" bei FooSafeCall bekommst (auch Compiler haben so ihre Probleme mit sich und der Welt, dann f&uuml;ge bei der Funktion begin/end hinzu.
        (nach dem erfolgreichen Kompilieren hat der Compiler pl&ouml;tzlich keine Probleme mehr ohne begin/end, tztztz)

        <pre><p><b>function</b> FooSafeCall(x, y, z: Byte): Integer; <b>safecall</b>;
        <b>begin</b>
        <b>asm</b>
        <font color='blue'><i>// ...</i></font>
        <b>end</b>;
        <b>end</b>;<p></pre>

        - nic

        Comment


        • #5
          Vielen Dank!
          Jetzt hab ich alles um DIE super schnellen Programme zu entwickeln.

          nochmal danke,
          b

          Comment


          • #6
            Ich habe die Erfahrung gemacht das es besser ist nur die "Endpunkte" eine Algos. in Assembler zu coden. D.h. die eigentlichen inline Assembler Functionen rufen keine weiteren Sub Functionen auf. Man kann zwar versuchen alles in asm zu coden, wird aber dadurch kaum noch Peformancegewinne erzielen. Normalerweise konstruiert man einen Algo. top-down, d.h. seine Komplexität nimmt nach unten ab. Nur die innersten Funktionen/Schleifen sollten in inline asm gecodet werden, mehr nicht. <br>
            Superschnelle Programme sind deshalb superschnell weil sie morderne und effiziente Algorithmen nutzen, nicht weil sie in handmade Assembler gecodet wurden. Natürlich würden diese noch schneller durch asm, aber eben nur zu einem Bruchteil schneller als wenn man den Algorithmus verbessert.

            Gruß Hagen

            PS: Ausnahmen bestätigen die Regel: Der Delphi Compiler ist sehr ineffizient wenn man nur "Dispatcher" Funktionen mit Parametern benötigt. D.h. eine Funktion die auf Grund der Parameter verschiedene andere Funktionen aufruft. In diesem Moment wird der durch den Compiler erzeugte Overhead des Sicherns der Parameter auf dem Stack eigentlich überflüssig und "bremst" aus

            Comment


            • #7
              Mein Beispiel-Code dient auch mehr als Anschauungsmaterial.<br>
              Dort wo DWORD PTR [EBP + ...] geschrieben wurde, würde man normalerweise DWORD PTR [x] schreiben.<br>
              <p>
              Die einzige Situation, die Assembler zum Aufruf einer Funktion erfordert, ist der Aufruf von __fastcall Funktionen (Microsoft spezifisch).<br>
              Da Delphi __fastcall nicht kennt. Aber mit ein wenig Tricks geht es auch ohne Assembler (siehe Beispiel)...
              <pre><p><b>program</b> FastCall;
              <p>
              <b>uses</b>
              Windows;
              <p>
              <font color='blue'><i>// This is an example of an exported __fastcall function (Microsoft Specific).
              // #pragma comment(linker, "/EXPORT:FooFastCall=@FooFastCall@12")
              // extern "C" signed int __fastcall FooFastCall(
              // unsigned char x, // ECX
              // unsigned char y, // EDX
              // unsigned char z // Stack
              // ); // return in EAX</i></font>
              <p>
              <font color='blue'><i>// Swap parameters to map from 'register' to '__fastcall'
              // CAVEAT: function declaration differs from original</i></font>
              <p>
              <b>function</b> FooFastCall_Swapped(_eax, y, x, z: Byte): Integer; <b>register</b>;
              <b>external</b> <font color='green'>'FastCall.dll'</font> name <font color='green'>'FooFastCall'</font>;
              <p>
              <font color='blue'><i>// Write an Wrapper to map from 'register' to '__fastcall'
              // CAVEAT: not as fast as in C because of wrapping</i></font>
              <p>
              <font color='blue'><i>// import (for use in ASM blocks only)</i></font>
              <b>procedure</b> _FooFastCall(); <b>register</b>;
              <b>external</b> <font color='green'>'FastCall.dll'</font> name <font color='green'>'FooFastCall'</font>;
              <p>
              <b>function</b> FooFastCall_Wrapped(x, y, z: Byte): Integer; <b>register</b>;
              <b>asm</b>
              PUSH ECX <font color='blue'><i>// push z</i></font>
              MOV ECX, EAX <font color='blue'><i>// x to ECX</i></font>
              <font color='blue'><i>// y already in EDX</i></font>
              CALL _FooFastCall
              <b>end</b>;
              <p>
              <b>var</b>
              Return: Integer;
              Buffer: <b>array</b> [0..$20] <b>of</b> AnsiChar;
              <b>begin</b>
              Return := FooFastCall_Swapped(0, 2, 1, 3);
              wvsprintfA(Buffer, <font color='green'>'FastCall(swapped): %8.8X'</font>, PAnsiChar(@Return));
              MessageBoxA(0, Buffer, <font color='green'>'FastCall'</font>, MB_OK);
              Return := FooFastCall_Wrapped(1, 2, 3);
              wvsprintfA(Buffer, <font color='green'>'FastCall(wrapped): %8.8X'</font>, PAnsiChar(@Return));
              MessageBoxA(0, Buffer, <font color='green'>'FastCall'</font>, MB_OK);
              <b>end</b>.<p></pre>

              - nic

              Comment

              Working...
              X