Wie greife ich von Inline-Asm auf C struct / variables zu?

Betrachten Sie den folgenden Code:

    int bn_div(bn_t *bn1, bn_t *bn2, bn_t *bnr)
  {
    uint32 q, m;        /* Division Result */
    uint32 i;           /* Loop Counter */
    uint32 j;           /* Loop Counter */

    /* Check Input */
    if (bn1 == NULL) return(EFAULT);
    if (bn1->dat == NULL) return(EFAULT);
    if (bn2 == NULL) return(EFAULT);
    if (bn2->dat == NULL) return(EFAULT);
    if (bnr == NULL) return(EFAULT);
    if (bnr->dat == NULL) return(EFAULT);


    #if defined(__i386__) || defined(__amd64__)
    __asm__ (".intel_syntax noprefix");
    __asm__ ("pushl %eax");
    __asm__ ("pushl %edx");
    __asm__ ("pushf");
    __asm__ ("movl %eax, (bn1->dat[i])");
    __asm__ ("xorl %edx, %edx");
    __asm__ ("divl (bn2->dat[j])");
    __asm__ ("movl (q), %eax");
    __asm__ ("movl (m), %edx");
    __asm__ ("popf");
    __asm__ ("popl %edx");
    __asm__ ("popl %eax");
    #else
    q = bn->dat[i] / bn->dat[j];
    m = bn->dat[i] % bn->dat[j];
    #endif
    /* Return */
    return(0);
  }

Die Datentypen uint32 sind grundsätzlich vorzeichenlose lange Ganzzahlen oder vorzeichenlose 32-Bit-Ganzzahlen. Der Typ bnint ist entweder ein vorzeichenloses kurzes int (uint16_t) oder ein uint32_t, je nachdem, ob 64-Bit-Datentypen verfügbar sind oder nicht. Wenn 64-Bit verfügbar ist, ist bnint ein uint32, andernfalls ein uint16. Dies wurde durchgeführt, um Übertrag / Überlauf in anderen Teilen des Codes zu erfassen. Die Struktur bn_t ist wie folgt definiert:

typedef struct bn_data_t bn_t;
struct bn_data_t
  {
    uint32 sz1;         /* Bit Size */
    uint32 sz8;         /* Byte Size */
    uint32 szw;         /* Word Count */
    bnint *dat;         /* Data Array */
    uint32 flags;       /* Operational Flags */
  };

Die Funktion startet in Zeile 300 in meinem Quellcode. Wenn ich versuche, es zu kompilieren / zu machen, erhalte ich die folgenden Fehler:

system:/home/user/c/m3/bn 1036 $$ ->make
clang -I. -I/home/user/c/m3/bn/.. -I/home/user/c/m3/bn/../include  -std=c99 -pedantic -Wall -Wextra -Wshadow -Wpointer-arith -Wcast-align -Wstrict-prototypes  -Wmissing-prototypes -Wnested-externs -Wwrite-strings -Wfloat-equal  -Winline -Wunknown-pragmas -Wundef -Wendif-labels  -c /home/user/c/m3/bn/bn.c
/home/user/c/m3/bn/bn.c:302:12: warning: unused variable 'q' [-Wunused-variable]
    uint32 q, m;        /* Division Result */
           ^
/home/user/c/m3/bn/bn.c:302:15: warning: unused variable 'm' [-Wunused-variable]
    uint32 q, m;        /* Division Result */
              ^
/home/user/c/m3/bn/bn.c:303:12: warning: unused variable 'i' [-Wunused-variable]
    uint32 i;           /* Loop Counter */
           ^
/home/user/c/m3/bn/bn.c:304:12: warning: unused variable 'j' [-Wunused-variable]
    uint32 j;           /* Loop Counter */
           ^
/home/user/c/m3/bn/bn.c:320:14: error: unknown token in expression
    __asm__ ("movl %eax, (bn1->dat[i])");
             ^
<inline asm>:1:18: note: instantiated into assembly here
        movl %eax, (bn1->dat[i])
                        ^
/home/user/c/m3/bn/bn.c:322:14: error: unknown token in expression
    __asm__ ("divl (bn2->dat[j])");
             ^
<inline asm>:1:12: note: instantiated into assembly here
        divl (bn2->dat[j])
                  ^
4 warnings and 2 errors generated.
*** [bn.o] Error code 1

Stop in /home/user/c/m3/bn.
system:/home/user/c/m3/bn 1037 $$ ->

Was ich weiß

Ich betrachte mich als ziemlich versiert in x86-Assembler (wie aus dem Code hervorgeht, den ich oben geschrieben habe). Das letzte Mal, dass ich eine höhere Programmiersprache und einen Assembler mischte, verwendete Borland Pascal vor etwa 15 bis 20 Jahren, als ich Grafiktreiber für Spiele schrieb (Ära vor Windows 95). Ich bin mit der Intel-Syntax vertraut.

Was ich nicht weiß:

Wie greife ich von asm auf Mitglieder von bn_t (insbesondere * dat) zu? Da * dat ein Zeiger auf uint32 ist, greife ich auf die Elemente als Array zu (zB bn1-> dat [i]).

Wie greife ich auf lokale Variablen zu, die auf dem Stack deklariert sind?

Ich verwende push / pop, um überladene Register auf ihre vorherigen Werte zurückzusetzen, um den Compiler nicht zu verärgern. Muss ich jedoch auch das Schlüsselwort volatile in die lokalen Variablen aufnehmen?

Oder, gibt es einen besseren Weg, den ich nicht kenne? Ich möchte dies nicht in einen separaten Funktionsaufruf einfügen, da der Aufwand für den Aufruf so hoch ist, dass diese Funktion leistungskritisch ist.

Zusätzlich

Right jetzt fange ich gerade an, diese Funktion zu schreiben, also ist sie nirgends vollständig. Es fehlen Loops und andere solche Support / Glue-Codes. Das Hauptaugenmerk liegt jedoch auf dem Zugriff auf lokale Variablen / Strukturelemente.

EDIT 1:

Die Syntax, die ich verwende, scheint die einzige zu sein, die Clang unterstützt. Ich habe den folgenden Code ausprobiert und Clang gab mir alle möglichen Fehler:

__asm__ ("pushl %%eax",
    "pushl %%edx",
    "pushf",
    "movl (bn1->dat[i]), %%eax",
    "xorl %%edx, %%edx",
    "divl ($0x0c + bn2 + j)",
    "movl %%eax, (q)",
    "movl %%edx, (m)",
    "popf",
    "popl %%edx",
    "popl %%eax"
    );

Er möchte, dass ich in die erste Zeile eine schließende Klammer setze, die das Komma ersetzt. Ich habe %% anstelle von% verwendet, weil ich irgendwo gelesen habe, dass für Inline-Assembly %% erforderlich ist, um CPU-Register zu kennzeichnen, und Clang hat mir mitgeteilt, dass ich eine ungültige Escape-Sequenz verwende.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage