C Language
Inline-Montage
Suche…
Bemerkungen
Bei der Inline-Assembly werden in der Mitte des C-Quellcodes Assembly-Anweisungen hinzugefügt. Kein ISO-C-Standard erfordert die Unterstützung der Inline-Montage. Da dies nicht erforderlich ist, variiert die Syntax für die Inline-Assembly von Compiler zu Compiler. Obwohl es normalerweise unterstützt wird, gibt es sehr wenige Gründe für die Inline-Montage und viele Gründe, warum dies nicht der Fall ist.
Pros
- Leistung Durch das Schreiben der spezifischen Assembly-Anweisungen für eine Operation können Sie eine bessere Leistung als der vom Compiler generierte Assembly-Code erzielen. Beachten Sie, dass diese Leistungssteigerungen selten sind. In den meisten Fällen können Sie bessere Leistungssteigerungen erzielen, indem Sie den C-Code so umstellen, dass der Optimierer seine Arbeit erledigen kann.
- Hardwareschnittstelle Gerätetreiber oder Prozessor-Startcode benötigen möglicherweise einen Assembler-Code, um auf die richtigen Register zuzugreifen und um sicherzustellen, dass bestimmte Operationen in einer bestimmten Reihenfolge mit einer bestimmten Verzögerung zwischen den Operationen ausgeführt werden.
Cons
- Die Compiler-Portabilitätssyntax für die Inline-Assembly ist von einem Compiler zu einem anderen nicht garantiert. Wenn Sie Code mit Inline-Assembly schreiben, der von verschiedenen Compilern unterstützt werden soll, verwenden Sie Präprozessor-Makros (
#ifdef
), um zu prüfen, welcher Compiler verwendet wird. Schreiben Sie dann für jeden unterstützten Compiler einen separaten Inline-Assembly-Abschnitt. - Prozessorportabilität Sie können keine Inline-Assembly für einen x86-Prozessor schreiben und davon ausgehen, dass sie mit einem ARM-Prozessor funktioniert. Inline-Assembly soll für einen bestimmten Prozessor oder eine bestimmte Prozessorfamilie geschrieben werden. Wenn Sie eine Inline-Assembly haben, die auf verschiedenen Prozessoren unterstützt werden soll, überprüfen Sie mithilfe von Präprozessor-Makros, für welchen Prozessor der Code kompiliert wird, und wählen Sie den entsprechenden Assemblycode-Abschnitt aus.
- Zukünftige Leistungsänderungen Inline-Assembly kann mit Verzögerungen basierend auf einer bestimmten Prozessortaktrate geschrieben werden. Wenn das Programm für einen Prozessor mit einer schnelleren Uhr kompiliert wird, funktioniert der Assemblercode möglicherweise nicht wie erwartet.
gcc Basic ASM-Unterstützung
Grundlegende Assemblierungsunterstützung mit gcc hat die folgende Syntax:
asm [ volatile ] ( AssemblerInstructions )
Dabei ist AssemblerInstructions
der direkte Assemblycode für den angegebenen Prozessor. Das volatile-Schlüsselwort ist optional und hat keine Auswirkung, da gcc den Code in einer einfachen asm-Anweisung nicht optimiert. AssemblerInstructions
können mehrere Montageanweisungen enthalten. Eine grundlegende asm-Anweisung wird verwendet, wenn Sie eine asm-Routine haben, die außerhalb einer C-Funktion vorhanden sein muss. Das folgende Beispiel stammt aus dem GCC-Handbuch:
/* Note that this code will not compile with -masm=intel */
#define DebugBreak() asm("int $3")
In diesem Beispiel könnten Sie dann DebugBreak()
an anderen Stellen in Ihrem Code verwenden und es wird die Assemblyanweisung int $3
. Obwohl gcc keinen Code in einer einfachen asm-Anweisung ändert, kann das Optimierungsprogramm dennoch aufeinanderfolgende asm-Anweisungen verschieben. Wenn Sie mehrere Assembly-Anweisungen haben, die in einer bestimmten Reihenfolge vorkommen müssen, fügen Sie sie in einer asm-Anweisung ein.
gcc Extended ASM-Unterstützung
Erweiterte ASM-Unterstützung in gcc hat die folgende Syntax:
asm [volatile] ( AssemblerTemplate
: OutputOperands
[ : InputOperands
[ : Clobbers ] ])
asm [volatile] goto ( AssemblerTemplate
:
: InputOperands
: Clobbers
: GotoLabels)
wo AssemblerTemplate
die Vorlage für die Assembler - Befehl ist, OutputOperands
irgendwelche C - Variablen , die durch die Assemblercode modifiziert werden kann, InputOperands
irgendwelche C Variablen als Eingangsparameter verwendet, Clobbers
sind eine Liste oder Register , die durch den Assembler - Code modifiziert sind, und GotoLabels
sind alle goto-Anweisungsetiketten, die im Assemblycode verwendet werden können.
Das erweiterte Format wird innerhalb von C-Funktionen verwendet und ist die typischere Verwendung von Inline-Baugruppen. Im Folgenden finden Sie ein Beispiel aus dem Linux-Kernel für den Byte-Austausch von 16-Bit- und 32-Bit-Nummern für einen ARM-Prozessor:
/* From arch/arm/include/asm/swab.h in Linux kernel version 4.6.4 */
#if __LINUX_ARM_ARCH__ >= 6
static inline __attribute_const__ __u32 __arch_swahb32(__u32 x)
{
__asm__ ("rev16 %0, %1" : "=r" (x) : "r" (x));
return x;
}
#define __arch_swahb32 __arch_swahb32
#define __arch_swab16(x) ((__u16)__arch_swahb32(x))
static inline __attribute_const__ __u32 __arch_swab32(__u32 x)
{
__asm__ ("rev %0, %1" : "=r" (x) : "r" (x));
return x;
}
#define __arch_swab32 __arch_swab32
#endif
Jeder asm-Abschnitt verwendet die Variable x
als Eingabe- und Ausgabeparameter. Die C-Funktion gibt dann das manipulierte Ergebnis zurück.
Mit dem erweiterten asm-Format kann gcc die Assembly-Anweisungen in einem asm-Block nach denselben Regeln optimieren, die es für die Optimierung von C-Code verwendet. Wenn Sie möchten, dass Ihr ASM-Abschnitt unberührt bleibt, verwenden Sie das volatile
Schlüsselwort für den ASM-Abschnitt.
gcc Inline-Montage in Makros
Wir können Montageanweisungen in ein Makro einfügen und das Makro so verwenden, als würden Sie eine Funktion aufrufen.
#define mov(x,y) \
{ \
__asm__ ("l.cmov %0,%1,%2" : "=r" (x) : "r" (y), "r" (0x0000000F)); \
}
/// some definition and assignment
unsigned char sbox[size][size];
unsigned char sbox[size][size];
///Using
mov(state[0][1], sbox[si][sj]);
Die Verwendung von Inline-Assembly-Anweisungen, die in C-Code eingebettet sind, kann die Laufzeit eines Programms verbessern. Dies ist in zeitkritischen Situationen wie kryptografischen Algorithmen wie AES sehr hilfreich. Für einen einfachen Verschiebevorgang, der im AES-Algorithmus erforderlich ist, können Sie beispielsweise eine direkte Anweisung für die Rotate Right
durch den C-Verschiebungsoperator >>
ersetzen.
In einer Implementierung von 'AES256' haben wir in der Funktion 'AddRoundKey ()' einige Anweisungen wie diese:
unsigned int w; // 32-bit
unsigned char subkey[4]; // 8-bit, 4*8 = 32
subkey[0] = w >> 24; // hold 8 bit, MSB, leftmost group of 8-bits
subkey[1] = w >> 16; // hold 8 bit, second group of 8-bit from left
subkey[2] = w >> 8; // hold 8 bit, second group of 8-bit from right
subkey[3] = w; // hold 8 bit, LSB, rightmost group of 8-bits
/// subkey <- w
Sie weisen einfach den Bitwert von w
dem subkey
.
Wir können drei Verschiebungs-, Zuweisungs- und einen Zuweisungs-C-Ausdruck mit nur einer Baugruppe Rotate Right
Operation ändern.
__asm__ ("l.ror %0,%1,%2" : "=r" (* (unsigned int *) subkey) : "r" (w), "r" (0x10));
Das Endergebnis ist genau das gleiche.