¿Cómo acceder a estructuras / variables de C desde asm en línea?

Considere el siguiente código:

    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);
  }

Los tipos de datos uint32 son básicamente un entero largo sin signo o un entero de 32 bits sin signo uint32_t. El tipo bnint es un int corto sin signo (uint16_t) o un uint32_t, dependiendo de si los tipos de datos de 64 bits están disponibles o no. Si 64 bits está disponible, entonces bnint es un uint32, de lo contrario es un uint16. Esto se hizo para capturar carry / overflow en otras partes del código. La estructura bn_t se define de la siguiente manera:

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 */
  };

La función comienza en la línea 300 en mi código fuente. Entonces, cuando intento compilarlo / hacerlo, obtengo los siguientes errores:

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 $$ ->

Lo que yo sé

Me considero bastante versado en el ensamblador x86 (como lo demuestra el código que escribí anteriormente). Sin embargo, la última vez que mezclé un lenguaje de alto nivel y un ensamblador estaba usando Borland Pascal hace unos 15-20 años cuando escribía controladores de gráficos para juegos (era anterior a Windows 95). Mi familiaridad es con la sintaxis de Intel.

Lo que no sé:

¿Cómo accedo a los miembros de bn_t (especialmente * dat) desde asm? Como * dat es un puntero a uint32, estoy accediendo a los elementos como una matriz (p. Ej. Bn1-> dat [i]).

¿Cómo accedo a las variables locales que se declaran en la pila?

Estoy usando push / pop para restaurar los registros clobbered a sus valores anteriores para no alterar el compilador. Sin embargo, ¿también necesito incluir la palabra clave volátil en las variables locales?

O, ¿hay alguna forma mejor de la que no tenga conocimiento? No quiero poner esto en una llamada de función separada debido a la sobrecarga de llamadas ya que esta función es crítica para el rendimiento.

Adicional

Ahora mismo, estoy empezando a escribir esta función, por lo que no está completa. Faltan bucles y otros códigos de soporte / pegamento. Pero, la esencia principal es acceder a variables locales / elementos de estructura.

EDIT 1:

La sintaxis que estoy usando parece ser la única que admite clang. Intenté el siguiente código y clang me dio todo tipo de errores:

__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"
    );

Quiere que ponga un paréntesis de cierre en la primera línea, reemplazando la coma. Cambié a usar %% en lugar de% porque leí en alguna parte que el ensamblaje en línea requiere %% para denotar registros de CPU, y clang me decía que estaba usando una secuencia de escape no válida.

Respuestas a la pregunta(1)

Su respuesta a la pregunta