Inline-Assembler mit GCC — Änderungen 6724 → 6726

Zeile 3: Zeile 3:
 
==AT&T-Syntax==
 
==AT&T-Syntax==
 
Viele Assembler-Programmierer sind die Intel-Syntax gewohnt. gcc (oder genauer gesagt gas, der GNU Assembler) benutzt stattdessen die AT&T-Syntax. Die Hauptmerkmale der AT&T-Syntax sind:
 
Viele Assembler-Programmierer sind die Intel-Syntax gewohnt. gcc (oder genauer gesagt gas, der GNU Assembler) benutzt stattdessen die AT&T-Syntax. Die Hauptmerkmale der AT&T-Syntax sind:
−
* Register bekommen ein % vorangestellt: <pre>xor %eax, %eax</pre>
+
* Register bekommen ein % vorangestellt: <asm>xor %eax, %eax</asm>
−
* Das Quellregister kommt zuerst, das Zielregister als zweites. Der folgende Befehl kopiert von eax nach ecx (nicht umgekehrt, wie man vermuten könnte, wenn man nur Intel-Syntax kennt!): <pre>mov %eax, %ecx</pre>
+
* Das Quellregister kommt zuerst, das Zielregister als zweites. Der folgende Befehl kopiert von eax nach ecx (nicht umgekehrt, wie man vermuten könnte, wenn man nur Intel-Syntax kennt!): <asm>mov %eax, %ecx</asm>
−
* Konstanten bekommen grundsätzlich ein $ vorangestellt, Hexadezimalzahlen werden durch 0x eingeleitet: <pre>mov $42, %eax</pre><pre>mov $0xBADC0FFE, %eax</pre>
+
* Konstanten bekommen grundsätzlich ein $ vorangestellt, Hexadezimalzahlen werden durch 0x eingeleitet: <asm>mov $42, %eax</asm><asm>mov $0xBADC0FFE, %eax</asm>
−
* Die Operandengrößen sind im Mnemonic enthalten. Wird die Größe nicht angegeben, versucht der Assembler sie anhand der Operanden festzustellen. <pre>movl $123, %eax</pre><pre>movw $123, %ax</pre><pre>movb $123, %al</pre>
+
* Die Operandengrößen sind im Mnemonic enthalten. Wird die Größe nicht angegeben, versucht der Assembler sie anhand der Operanden festzustellen. <asm>movl $123, %eax</asm><asm>movw $123, %ax</asm><asm>movb $123, %al</asm>
−
* Speicherzugriffe erfolgen im Format "segment:displacement(base, index, scale)", wobei das Displacement als auch Index und Scale optional sind: <pre>pushl (%eax)</pre><pre>mov %eax, 0x8(%ebp)</pre><pre>mov 0xfffffff8(%esp,%eax,1),%eax</pre>
+
* Speicherzugriffe erfolgen im Format "segment:displacement(base, index, scale)", wobei das Displacement als auch Index und Scale optional sind: <asm>pushl (%eax)</asm><asm>mov %eax, 0x8(%ebp)</asm><asm>mov 0xfffffff8(%esp,%eax,1),%eax</asm>
  
 
Wer sich überhaupt nicht mit der AT&T-Syntax anfreunden kann, für den bleibt immer noch die gcc-Kommandozeilenoption "-masm=intel", die die Intelsyntax aktiviert.
 
Wer sich überhaupt nicht mit der AT&T-Syntax anfreunden kann, für den bleibt immer noch die gcc-Kommandozeilenoption "-masm=intel", die die Intelsyntax aktiviert.
Zeile 13: Zeile 13:
 
==Einfache Befehle==
 
==Einfache Befehle==
 
Die Einbindung von Inline Assembler in den C-Code ist ganz einfach: Das Schlüsselwort asm (oder alternativ __asm__) in Verbindung mit dem Assemblercode als String muss in den C-Code eingebettet werden:
 
Die Einbindung von Inline Assembler in den C-Code ist ganz einfach: Das Schlüsselwort asm (oder alternativ __asm__) in Verbindung mit dem Assemblercode als String muss in den C-Code eingebettet werden:
−
<pre>asm("int $0x30")</pre>
+
<c>asm("int $0x30")</c>
  
 
Sollen mehrere Assemblerbefehle ausgeführt werden, gibt es nicht nur eine Möglichkeit, dies zu schreiben: Entweder Trennung durch Strichpunkt (Semikolon) oder durch einen Zeilenumbruch. Strings können dabei wie in C üblich getrennt werden, so daß nicht ein längeres Stück Assemblercode in einer Zeile C untergebracht werden muß:
 
Sollen mehrere Assemblerbefehle ausgeführt werden, gibt es nicht nur eine Möglichkeit, dies zu schreiben: Entweder Trennung durch Strichpunkt (Semikolon) oder durch einen Zeilenumbruch. Strings können dabei wie in C üblich getrennt werden, so daß nicht ein längeres Stück Assemblercode in einer Zeile C untergebracht werden muß:
−
<pre>asm("cli; hlt");
+
<c>asm("cli; hlt");
 
asm("cli\nhlt");
 
asm("cli\nhlt");
 
asm(
 
asm(
 
   "cli;"
 
   "cli;"
 
   "hlt;"
 
   "hlt;"
−
);</pre>
+
);</c>
  
 
==Ein- und Ausgabeparameter==
 
==Ein- und Ausgabeparameter==
 
gcc unterstützt darüber hinaus noch die Möglichkeit, im Assemblercode Werte zu verarbeiten, die nicht direkt im Assemblerstring stehen, sondern beispielsweise in C-Variablen gespeichert sind. Diese Möglichkeit macht zu einem großen Teil die Mächtigkeit des Inline-Assemblers von gcc aus. Das asm-Konstrukt wird dann folgendermaßen erweitert:
 
gcc unterstützt darüber hinaus noch die Möglichkeit, im Assemblercode Werte zu verarbeiten, die nicht direkt im Assemblerstring stehen, sondern beispielsweise in C-Variablen gespeichert sind. Diese Möglichkeit macht zu einem großen Teil die Mächtigkeit des Inline-Assemblers von gcc aus. Das asm-Konstrukt wird dann folgendermaßen erweitert:
−
<pre>
+
<c>
 
asm(code : ausgabe : eingabe)
 
asm(code : ausgabe : eingabe)
−
</pre>
+
</c>
  
 
===Übergabe in bestimmten Registern===
 
===Übergabe in bestimmten Registern===
 
Wenn die Übergabe von Variablen bzw. Werten in bestimmten Registern stattfinden soll (z.B. für in/out benötigt), können diese Register direkt angegeben werden:
 
Wenn die Übergabe von Variablen bzw. Werten in bestimmten Registern stattfinden soll (z.B. für in/out benötigt), können diese Register direkt angegeben werden:
−
<pre>asm ("inb %1, %0" : "=a" (result) : "d" (port));</pre>
+
<c>asm ("inb %1, %0" : "=a" (result) : "d" (port));</c>
  
 
* Die Ausgabe bzw. Eingabe wird durch ''"register" (wert)'' spezifiziert. ''result'' und ''port'' wären im Beispiel zwei C-Variablen.
 
* Die Ausgabe bzw. Eingabe wird durch ''"register" (wert)'' spezifiziert. ''result'' und ''port'' wären im Beispiel zwei C-Variablen.
Zeile 46: Zeile 46:
 
* "g" steht für "general". Der Compiler hat die freie Wahl, wie er den Befehl umsetzen will. Er wird dabei nicht immer eine funktionierende Variante wählen, deswegen ist es oft notwendig, direkt "r" oder "m" anzugeben.
 
* "g" steht für "general". Der Compiler hat die freie Wahl, wie er den Befehl umsetzen will. Er wird dabei nicht immer eine funktionierende Variante wählen, deswegen ist es oft notwendig, direkt "r" oder "m" anzugeben.
 
* "i" steht für einen Immediate-Wert, "N" steht für einen Immediate-Wert in Bytegröße. Dies funktioniert nur, wenn der Wert konstant und bereits beim Kompilieren bekannt ist.
 
* "i" steht für einen Immediate-Wert, "N" steht für einen Immediate-Wert in Bytegröße. Dies funktioniert nur, wenn der Wert konstant und bereits beim Kompilieren bekannt ist.
−
* Mehrere Buchstaben können aneinandergereiht werden, um mehrere Optionen zu ermöglichen. Die vorderste Option, die funktioniert, wird dann gewählt. Der obenstehende Code für inb ließe sich also folgendermaßen ergänzen: <pre>asm ("inb %1, %0" : "=a" (result) : "Nd" (port));</pre> Wird inb darüber inline deklariert, kann der Compiler dann einen Funktionsaufruf wie ''inb(0x60)'' direkt in eine einzige Assemblerzeile übersetzen und muß kein Register zur Zwischenspeicherung von 0x60 verwenden. Bei einem Aufruf wie ''inb(my_port_variable)'' würde die traditionelle Variante gewählt und das Register benutzt werden.
+
* Mehrere Buchstaben können aneinandergereiht werden, um mehrere Optionen zu ermöglichen. Die vorderste Option, die funktioniert, wird dann gewählt. Der obenstehende Code für inb ließe sich also folgendermaßen ergänzen: <c>asm ("inb %1, %0" : "=a" (result) : "Nd" (port));</c> Wird inb darüber inline deklariert, kann der Compiler dann einen Funktionsaufruf wie ''inb(0x60)'' direkt in eine einzige Assemblerzeile übersetzen und muß kein Register zur Zwischenspeicherung von 0x60 verwenden. Bei einem Aufruf wie ''inb(my_port_variable)'' würde die traditionelle Variante gewählt und das Register benutzt werden.
  
 
==Beispiele==
 
==Beispiele==
Zeile 52: Zeile 52:
  
 
Aufruf des sleep-Syscalls in LOST:  
 
Aufruf des sleep-Syscalls in LOST:  
−
<pre>
+
<c>
 
     asm(
 
     asm(
 
         "mov %0, %%eax;"
 
         "mov %0, %%eax;"
 
         "int $0x30;"
 
         "int $0x30;"
 
     : : "i" (SYSCALL_PM_SLEEP) : "eax");
 
     : : "i" (SYSCALL_PM_SLEEP) : "eax");
−
</pre>
+
</c>
  
 
Laden der GDT:
 
Laden der GDT:
−
<pre>
+
<c>
 
struct {
 
struct {
 
     word size;
 
     word size;
Zeile 69: Zeile 69:
 
};
 
};
 
asm("lgdtl %0" : : "m" (gdt_ptr));
 
asm("lgdtl %0" : : "m" (gdt_ptr));
−
</pre>
+
</c>
  
 
Senden einer IPC-Nachricht in LOST:  
 
Senden einer IPC-Nachricht in LOST:  
−
<pre>
+
<c>
 
void send_message(dword pid, dword function, dword correlation_id, dword len, char* data)
 
void send_message(dword pid, dword function, dword correlation_id, dword len, char* data)
 
{
 
{
Zeile 93: Zeile 93:
 
     : : "g" (pid), "g" (len+8), "g"(function), "g" (correlation_id), "g" (data) , "g" (len) : "eax", "ecx");
 
     : : "g" (pid), "g" (len+8), "g"(function), "g" (correlation_id), "g" (data) , "g" (len) : "eax", "ecx");
 
}
 
}
−
</pre>
+
</c>
  
  
Zeile 99: Zeile 99:
 
[http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Constraints.html gcc-Manual: Constraints]
 
[http://gcc.gnu.org/onlinedocs/gcc-4.3.0/gcc/Constraints.html gcc-Manual: Constraints]
  
−
[[Category:Tutorials]]
+
[[Kategorie:Tutorials]]