Verwendung des Basiszeigerregisters in C++ Inline asm

Lesezeit: 4 Minuten

Verwendung des Basiszeigerregisters in C Inline asm
Kiefer

Ich möchte das Basiszeigerregister verwenden können (%rbp) innerhalb von Inline-asm. Ein Spielzeugbeispiel dafür ist wie folgt:

void Foo(int &x)
{
    asm volatile ("pushq %%rbp;"         // 'prologue'
                  "movq %%rsp, %%rbp;"   // 'prologue'
                  "subq $12, %%rsp;"     // make room

                  "movl $5, -12(%%rbp);" // some asm instruction

                  "movq %%rbp, %%rsp;"  // 'epilogue'
                  "popq %%rbp;"         // 'epilogue'
                  : : : );
    x = 5;
}

int main() 
{
    int x;
    Foo(x);
    return 0;
}

Ich hatte das gehofft, da ich die übliche Prolog-/Epilog-Funktionsaufrufmethode verwende, um das Alte zu pushen und zu poppen %rbp, das wäre ok. Es zeigt jedoch Fehler an, wenn ich versuche, darauf zuzugreifen x nach dem Inline-Asm.

Der von GCC generierte Assemblercode (leicht abgespeckt) lautet:

_Foo:
    pushq   %rbp
    movq    %rsp, %rbp
    movq    %rdi, -8(%rbp)

    # INLINEASM
    pushq %rbp;          // prologue
    movq %rsp, %rbp;     // prologue
    subq $12, %rsp;      // make room
    movl $5, -12(%rbp);  // some asm instruction
    movq %rbp, %rsp;     // epilogue
    popq %rbp;           // epilogue
    # /INLINEASM

    movq    -8(%rbp), %rax
    movl    $5, (%rax)      // x=5;
    popq    %rbp
    ret

main:
    pushq   %rbp
    movq    %rsp, %rbp
    subq    $16, %rsp
    leaq    -4(%rbp), %rax
    movq    %rax, %rdi
    call    _Foo
    movl    $0, %eax
    leave
    ret

Kann mir jemand sagen, warum dieses Segment fehlerhaft ist? Es scheint, dass ich irgendwie beschädigt %rbp aber ich sehe nicht wie. Vielen Dank im Voraus.

Ich verwende GCC 4.8.4 auf 64-Bit-Ubuntu 14.04.

  • Fügen Sie keine Tags nicht verwandter Sprachen hinzu.

    – zu ehrlich für diese Seite

    29. Dezember 2015 um 22:22 Uhr

  • Für den Assembler-Code: Verwenden Sie die Assembler-Argumente, um C-seitige Variablen anzugeben; Verlassen Sie sich nicht auf ein bestimmtes Registerlayout im Assemblercode. Und geben Sie immer Clobbers an.

    – zu ehrlich für diese Seite

    29. Dezember 2015 um 22:24 Uhr

  • movq %rdi, -8(%rbp) platziert RDI im Rotbereich. Das tust du dann pushq %rbp; was dekrementiert UVP durch 8 und setzt den Wert ein RBP dort. Leider seit RSP=RBP Sie haben gerade den Wert überschrieben, den GCC dort gespeichert hat (was vermutlich RDI). Nachdem Ihr Inline-Assembler fertig war, versuchte er es movq -8(%rbp), %rax. Nun, wir haben gerade erfahren, dass Sie die Daten am Speicherort vernichtet haben -8(%rbp) Daher enthält es jetzt einen falschen Wert, und dann versuchen wir, ihn damit zu dereferenzieren movl $5, (%rax). Diese Anweisung ist wahrscheinlich segfaults, weil RAX hat keinen gültigen Zeiger mehr.

    – Michael Petsch

    30. Dezember 2015 um 4:26 Uhr


  • Wenn Sie C/C++-Variablen innerhalb von Inline-Assembler verwenden möchten, müssen Sie wirklich damit beginnen, Eingabe- (und ggf. Ausgabe-)Einschränkungen zu verwenden, damit Daten ein- (und/oder ausgegeben) werden können.

    – Michael Petsch

    30. Dezember 2015 um 4:32 Uhr


  • Vielen Dank für diese ausführliche und informative Antwort. Was meinen Sie mit „die ganze Funktion in asm schreiben“ – wie würde ich sie dann in C/C++-Code integrieren? Oder meinst du das ganze Programm in asm schreiben?

    – Kiefer

    30. Dezember 2015 um 14:12 Uhr

  • Tolle Antwort Peter! Aber in Ihren Links sind Sie zweimal auf denselben Link gelangt.

    – Z-Boson

    30. Dezember 2015 um 18:43 Uhr


  • @jaw: Schreiben Sie den Prototyp in C und schreiben Sie die Funktion separat .S (GNU-Syntax) bzw .asm (NASM/YASM-Syntax). gcc -Wall -O3 main.c myfunc.S -o myprog. Siehe stackoverflow.com/questions/13901261/…. Wenn Sie NASM/YASM verwenden, führen Sie es aus yasm -felf64 myfunc.asm ein … machen .o die Sie mit C verknüpfen können. Stellen Sie sicher, dass Ihre Funktion der ABI folgt (welche Registrierungen beibehalten werden sollen und wo ihre Argumente zu finden sind), sonst wird sie beim gcc-Code beschädigt callsitzen. IIRC, Agner Fogs Optimizing Assembly Guide verbringt einige Zeit damit, wie dies zu tun ist. (Links im x86-Tag-Wiki)

    – Peter Cordes

    30. Dezember 2015 um 19:14 Uhr


  • @Zboson: Ich glaube, ich erinnerte mich an die anderen Links, die ich haben wollte, anstelle des Duplikats: die frühe Clobber-Diskussion. Und auch die Frage nach Operandengrößenmodifikatoren.

    – Peter Cordes

    30. Dezember 2015 um 19:51 Uhr

  • Tolle Verbindungen. In Bezug auf die Antwort von Stephen Canon hatte sie ursprünglich keinen Clobber-Modifikator. Ich folgte seiner Antwort, aber für 256-Bit-Hinzufügen, und ich konnte die richtige Antwort nicht erhalten, bis ich herausfand, dass ich einen Clobber-Modifikator verwenden musste. Ich hatte nie ein Problem mit seinem 128-Bit-Add ohne den Clobber-Modifikator. Das Problem trat nach dem dritten Hinzufügen auf. Aber das ist wohl nur Zufall. Deshalb habe ich einen Kommentar in seiner Antwort hinterlassen.

    – Z-Boson

    30. Dezember 2015 um 20:01 Uhr


  • Entschuldigung, mein Fehler: Es scheint das Problem nicht wirklich gelöst zu haben. Es ist immer noch Seg-Faulting. Irgendwelche anderen Ideen?

    – Kiefer

    29. Dezember 2015 um 23:09 Uhr

  • Tatsächlich schlägt es auch ohne die Anweisung “// einige asm-Anweisungen” fehl. Warum vermasselt Pushing und Popping $rbp?

    – Kiefer

    29. Dezember 2015 um 23:15 Uhr

  • Wo genau ist es segfaulting? Auf welche Adresse greift es zu und auf welche Anweisung befindet es sich?

    – Mats Petersson

    29. Dezember 2015 um 23:15 Uhr

  • Die Ausgabe von gdb sieht so aus (sie seg-Fehler ein paar Zeilen nach dem asm): Zeile 11: Foo (x=@0x7fffffffe034: 32767): ” : : : );” , Zeile 12: Foo (x=@0x7fffffffe020: -8128): “x = 5”, Zeile 13: “}”: Zugriff auf Speicher an Adresse 0x7fff0000000d nicht möglich. Programmempfangssignal SIGSEGV, Segmentierungsfehler.”

    – Kiefer

    29. Dezember 2015 um 23:27 Uhr


  • Bearbeiten Sie die Frage mit disass foo und info reg nach dem Absturz.

    – Mats Petersson

    29. Dezember 2015 um 23:35 Uhr

995820cookie-checkVerwendung des Basiszeigerregisters in C++ Inline asm

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy