Von C Werte an Assembler Funktion übergeben



  • Moin,
    weil rkhb meinte ich soll meine Frage nochmal am besten hier stellen mach ich das jetzt 🙂 :

    Ich möchte von C Werte an eine Assemblerfunktion geben, nur weiß ich nicht wie ich die Daten da dann verarbeiten kann.
    Ich nutze Win64 (Windows 8), mein Compiler ist GCC und ich nutze Intel-Syntax.

    LG





  • Übergabe und Rückgabe von Parametern richtet sich nach der Microsoft-x64-Calling Convention:

    http://msdn.microsoft.com/en-us/library/9b372w95.aspx
    http://en.wikipedia.org/wiki/X86_calling_conventions#Microsoft_x64_calling_convention

    Parameter werden in RCX, RDX, R8 und R9 übergeben, wobei die C-Deklaration dabei von links nach rechts gelesen wird, d.h. der erste Parameter kommt nach RCX, der zweite nach RDX usw.

    Die Rückgabe geschieht normalerweise in RAX.

    callee.s:

    .data
        msg1:   .asciz "EXTERN"
        result: .int 1
    
    .section .text
    .global test_intel, test_intel_with_puts
    .extern puts
    
    .intel_syntax noprefix
    
    test_intel:                         # kein Prolog und Epilog
        xor eax, eax                    # obere Bits von EAX löschen
        cmp rcx, '~'
        setz al
        ret
    
    test_intel_with_puts:               # Prolog, Epilog wg. Wine-C-Funktion
        push   rbp                      # Prolog
        mov    rbp,rsp
        sub rsp, 32                     # shadow space für puts
    
        cmp rcx, '~'
        setz [rbp+16]                   # im eigenen shadow space speichern, da RCX durch puts zerstört wird
    
        lea rcx, [rip + msg1]           # RIP-relative Adressierung
    #   mov rcx, OFFSET msg1            # absolute Adressierung
        call puts
    
        mov al, [rbp+16]                # passt scho: puts ist mit rax=13 zurückgekommen
    
        leave                           # Epilog
        ret
    

    Hier gibt es zwei Funktionen: test_intel und test_intel_with_puts . Das liegt vorrangig daran, dass vor dem Aufruf einer Funktion ein sogenannter "shadow space" reserviert werden muss, den die Funktion dann (vielleicht) nutzt. Mein Wine stürzt ab, wenn dieser Platz nicht reserviert wird. Der shadow space kann frei genutzt werden (macht GCC genauso). Beide Funktionen vergleichen die Übergabe mit dem Buchstaben '~' und geben entsprechende Wahrheitswerte zurück. Intel-Syntax musst Du extra mit der Instruktion ".intel_syntax noprefix" einstellen.

    caller.c:

    #include <stdio.h>
    
    extern int test_intel (int);
    extern int test_intel_with_puts (int);
    
    char msg0[] = "INTERN";
    
    int test_intern (char a)
    {
        puts (msg0);
        return (a == '~');
    }
    
    int main ( void )
    {
        unsigned char a = '~';
        int b = 99;
    
        puts ("Hallo Welt");
    
        b = test_intern (a);
        printf ("%i\n",b);
    
        b = test_intel (a);
        printf ("test_intel\n%i\n",b);
    
        b = test_intel_with_puts (a);
        printf ("%i\n",b);
    
        return 0;
    }
    

    Zu kompilieren mit:

    gcc -m64 -o caller.exe -xassembler callee.s -xc caller.c

    Du kannst auch getrennt assemblieren/kompilieren:

    `as --64 -o callee.obj callee.s

    gcc -m64 -o caller.exe -Wl,callee.obj caller_win64.c`

    Ich hoffe, das klappt bei Dir. Ich konnte hier nur mit Wine testen. Wenn Du gar ein 32-Bit-Programm auf Deinem 64-Bit-Betriebssystem herstellen willst, dann melde Dich nochmal und teile genau(!) mit, welchen Compiler Du benutzt: gcc --version.

    viele grüße
    ralph


Anmelden zum Antworten