Was ist der Unterschied zwischen "asm", "asm" und "asm"?
Soweit ich das beurteilen kann, der einzige Unterschied zwischen __asm { ... };
und __asm__("...");
ist, dass die erste verwendet mov eax, var
und die zweite verwendet movl %0, %%eax
mit :"=r" (var)
am Ende. Welche weiteren Unterschiede gibt es? Und was ist nur asm
?
Kommentar zu dem Problem
@kennytm _asm ist ein synonym für die __asm, nach hier: msdn.microsoft.com/en-us/library/45yd4tzz(v=vs. 120).aspx
sollten Sie wählte die Antwort des Petrus ist, ist es weit überlegen.
InformationsquelleAutor der Frage Adrian | 2010-07-24
Du musst angemeldet sein, um einen Kommentar abzugeben.
Welche Sie verwenden, hängt von Ihrem compiler. Dies ist nicht standard, wie der C-Sprache.
InformationsquelleAutor der Antwort Ben Voigt
Es gibt einen massiven Unterschied zwischen MSVC inline-Assembler und GNU-C inline-asm. GCC-syntax entworfen für optimale Leistung, ohne verschwendet Anweisungen für die Verpackung einer einzelnen Anweisung oder so etwas. MSVC syntax ist entworfen, um zu sein, ziemlich einfach, aber AFAICT es ist unmöglich zu verwenden, ohne die Wartezeit und zusätzliche Anweisungen von einer Rundreise durch Speicher für Ihre ein-und Ausgänge.
Wenn Sie mit den inline asm aus performance-Gründen, diese macht MSVC inline-asm nur lebensfähig, wenn Sie schreiben, eine ganze Schleife komplett in asm, nicht für die Verpackung kurze Sequenzen, die in eine inline-Funktion. Das Beispiel unten (Verpackung
idiv
mit einer Funktion) ist die Art von Sache, die MSVC ist schlecht: ~8 extra store - /load-Anweisungen.MSVC inline-asm (mit MSVC und wahrscheinlich icc, vielleicht auch in einigen kommerziellen Compilern):
mov ecx, shift_count
zum Beispiel. So mit einer einzigen asm-Anweisung, die der compiler nicht generiert für Sie beinhaltet eine Rundfahrt durch Speicher-auf dem Weg in und auf dem Weg nach draußen.GNU-C-inline-asm ist nicht ein guter Weg, um zu lernen, asm. Sie haben, um zu verstehen, asm sehr gut, so dass Sie sagen kann der compiler über den code. Und Sie haben zu verstehen, was der Compiler wissen muss. Diese Antwort hat auch links zu anderen inline-asm-guides und Q&As. Die x86 - tag wiki hat viele gute Sachen für asm im Allgemeinen, sondern nur links auf, die für GNU inline-asm. (Die Sachen, die in diese Antwort gilt für GNU inline-asm auf nicht-x86-Plattformen, auch.)
GNU-C-inline-asm-syntax von gcc, clang, icc -, und vielleicht einigen kommerziellen Compilern, die für die Einführung GNU C:
"c" (shift_count)
erhalten den compiler, dieshift_count
variable inecx
bevor Sie Ihre inline-asm führt.extra klobig für große code-Blöcke, weil die asm hat innerhalb einer string-Konstante. In der Regel benötigen Sie
sehr nachtragend /härter, sondern ermöglicht geringere overhead-esp. zum Verpacken von einzelnen Anweisungen. (Verpackung einzelne Anweisungen war die ursprüngliche design-Absicht, die ist, warum haben Sie speziell zu sagen, der compiler über die frühe clobbers um ihn zu stoppen, verwenden die gleichen register für input-und output-ob das ein problem.)
Beispiel: full-width integer-division (
div
)Auf einem 32-bit-CPU, die Aufteilung einer 64-bit-integer durch einen 32bit integer oder wenn Sie eine full-multiplizieren (32x32->64), profitieren von inline-asm. gcc und clang nicht nutzen
idiv
für(int64_t)a /(int32_t)b
, wahrscheinlich, weil die Anleitung Fehler, wenn das Ergebnis passt nicht in ein 32bit-register. Also im Gegensatz zu dieses Q&A über die erste quotient und Rest von einemdiv
, ist dies ein Fall für die inline-asm. (Es sei denn, es gibt einen Weg, um zu informieren den compiler, dass das Ergebnis passt, also idiv nicht Schuld.)Verwenden wir Aufrufkonventionen, dass einige Argumente in Registern (mit
hi
auch in der Recht registrieren), um zu zeigen, eine situation, die näher zu dem, was Sie sehen würden, wenn inlining eine kleine Funktion wie diese.MSVC
Vorsichtig sein mit der register-arg Aufrufkonventionen bei der Verwendung von inline-asm. Anscheinend ist der inline-asm-support ist so schlecht entworfen/implementiert, dass der compiler kann nicht speichern/wiederherstellen arg Register rund um das inline-asm, wenn diese Argumente nicht verwendet werden, die in die inline-asm. Danke @RossRidge für den Hinweis.
Update: anscheinend verlassen ein Wert in
eax
oderedx:eax
und dann fallen aus dem Ende einer nicht-void-Funktion (ohnereturn
) unterstützt wird, auch beim inlining. Ich nehme an, das funktioniert nur, wenn es kein code nach derasm
- Anweisung. Dies vermeidet das speichern/reload für die Leistung (zumindest fürquotient
), aber wir können nichts über die Eingänge. In einer nicht-inline-Funktion mit stack args, werden Sie im Speicher schon, aber in diesen Fall schreiben wir eine kleine Funktion, die sinnvollerweise inline.Kompiliert mit MSVC 19.00.23026
/O2
auf rextester (mit einemmain()
findet sich das Verzeichnis der exe-Datei und dumps der compiler asm-Ausgabe auf stdout).Es gibt eine Tonne von extra-mov-Anweisungen, und der compiler nicht einmal nahe kommen, um die Optimierung jedes von ihm entfernt. Ich dachte, vielleicht würden Sie es sehen und verstehen, das
mov tmp, edx
im inneren des inline asm, und machen, dass ein Geschäft zupremainder
. Das würde aber erfordern das ladenpremainder
vom stack in ein register, bevor die inline-asm-block, denke ich.Diese Funktion ist eigentlich schlimmer mit
_vectorcall
als mit dem normalen alles-auf-den-stack-ABI. Mit zwei Eingängen in einem Register, es speichert Sie in den Speicher, so dass die inline-asm-laden können Sie aus den benannten Variablen. Wenn dies eingebettet, mehr noch der Parameter, die möglicherweise in die regs, und es wäre speichern Sie Sie alle, so der asm hätte speicheroperanden! Also im Gegensatz zu gcc, brauchen wir nicht viel zu gewinnen von inlining.Tun
*premainder = tmp
innerhalb der asm-block bedeutet mehr code geschrieben in asm, aber nicht vermeiden, die völlig braindead speichern - /laden - /Speicher-Pfad für den Rest. Dies reduziert die Anweisung count von 2 insgesamt 11 (nicht einschließlich dieret
).Ich versuche, den bestmöglichen code aus der MSVC, nicht auf "verwenden Sie es falsch", und erstellen Sie ein Stroh-Mann argument. Aber AFAICT es ist schrecklich für die Verpackung sehr kurze Sequenzen. Vermutlich gibt es eine systeminterne Funktion für 64/32 -> 32-Sparte, kann der compiler guten code zu generieren, der für diesen speziellen Fall, so dass die gesamte Prämisse der Verwendung von inline-asm für MSVC könnte ein Stroh-Mann argument. Aber es zeigt Ihnen, dass Interna viel besser als inline-asm für MSVC.
GNU C (gcc/clang/icc)
Gcc nicht sogar besser als die Leistung, die hier gezeigt beim inlining div64, denn es können in der Regel arrangieren für den vorangehenden code zu generieren, der 64-bit-Ganzzahl in edx:eax in den ersten Platz.
Kann ich nicht bekommen gcc zum kompilieren für die 32bit vectorcall ABI. Clang kann, aber es nervt beim inline asm mit
"rm"
Einschränkungen (versuchen Sie es auf die godbolt link: es prallt Funktion arg durch den Speicher statt mit der register-option in der Toolbar). Die 64-bit-MS-Aufrufkonvention ist in der Nähe der 32bit vectorcall, die ersten beiden Parameter edx, ecx. Der Unterschied ist, dass 2 weitere Parameter gehen in regs vor, den stack verwenden (und, dass der angerufene nicht pop die Argumente aus dem stack, das ist, was dieret 8
war etwa in der MSVC-Ausgabe.)kompilieren mit
gcc -m64 -O3 -mabi=ms -fverbose-asm
. Mit -m32 bekommst du nur 3 Lasten, idiv, und einen Speicher, wie Sie sehen können, ändern Sachen, die godbolt link.32bit vectorcall, gcc möchte etwas tun, wie
MSVC-Verwendung 13 Anleitung (nicht einschließlich der ret), im Vergleich zu gcc 4. Mit inlining, wie ich sagte, möglicherweise kompiliert nur eine, während MSVC würde immer noch verwenden, wahrscheinlich 9. (Sie brauchen nicht zu reservieren stack-Speicher oder laden
premainder
; ich nehme an, es hat noch zu speichern, zu 2 der 3 Eingänge. Dann lädt es Sie im inneren des asm, läuftidiv
, speichert zwei Ausgänge, und lädt Sie auch außerhalb der asm. So, die 4 lädt/speichert, für die Eingabe, und die anderen 4 für die Ausgabe.)InformationsquelleAutor der Antwort Peter Cordes
Mit gcc-compiler, es ist kein großer Unterschied.
asm
oder__asm
oder__asm__
sind die gleichen, die Sie gerade verwenden, um Konflikte zu vermeiden namespace Zweck (es gibt benutzerdefinierte Funktion, die Namen asm, usw.)InformationsquelleAutor der Antwort oDisPo
asm
vs__asm__
asm
funktioniert nicht mit-std=c99
, haben Sie zwei alternativen:__asm__
-std=gnu99
Mehr details: Fehler: 'asm' schwarzarbeit (erste Benutzung in dieser Funktion)
InformationsquelleAutor der Antwort Ciro Santilli 包子露宪 六四事件 法轮功