2011-08-21 8 views
5

Estoy tratando de comprender algunas cosas sobre el ensamblador en línea en Linux. Estoy utilizando la función siguiente:ASM duda en línea

void test_func(Word32 *var){ 
    asm(" addl %0, %%eax" : : "m"(var)); 
    return; 
} 

Genera siguiente código ensamblador:

.globl test_func 
.type test_func, @function 
test_func: 
     pushl %ebp 
     movl %esp, %ebp 
#APP 
# 336 "opers.c" 1 
     addl 8(%ebp), %eax 
# 0 "" 2 
#NO_APP 
     popl %ebp 
     ret 
     .size test_func, .-test_func 

Resume var dirección de memoria para registro EAX valor en lugar de valor var.

¿Hay alguna manera de decirle a la instrucción addl que use var value en lugar de var mem address sin copiar var mem address en un registro?

Saludos

+0

Su asm en línea no define lo que se supone que está en EAX, así que gcc podría poner nada allí ... ¿qué estás realmente tratando de hacer? – servn

Respuesta

3

Suma la dirección de var mem a eax valor de registro en lugar de valor var.

Sí, la sintaxis del ensamblaje en línea de gcc es bastante arcana. Parafraseando desde la sección correspondiente en el GCC Inline Assembly HOWTO"m" aproximadamente le da la ubicación de la memoria de la variable C.

Es lo que usarías cuando solo quieres una dirección desde la que puedas escribir o leer. Observe que dije la ubicación de la variable C, por lo que %0 se establece en la dirección de Word32 *var - tiene un puntero a un puntero. Una traducción C del bloque de ensamblaje en línea podría parecerse a EAX += *(&var) porque puede decir que la restricción "m" toma implícitamente la dirección de la variable C y le da una expresión de dirección, que luego agrega al %eax.

¿Hay alguna forma de decirle a la instrucción addl que use var value en lugar de var mem address sin copiar var mem address en un registro?

Eso depende de lo que signifique. Que necesita para obtener var de la pila, por lo que alguien tiene que eliminar la referencia de la memoria (ver @Bo Perssons respuesta), pero no tiene que hacerlo en ensamblador en línea

La restricción es necesario que haya "m"(*var) (como se sugirió @fazo) Esto le dará la ubicación de memoria del valor var apuntando a, en lugar de una ubicación de memoria que apunta a él.

El código generado es ahora:

test_func: 
    pushl %ebp 
    movl %esp, %ebp 
    movl 8(%ebp), %eax 
#APP 
# 2 "test.c" 1 
    addl (%eax), %eax 
# 0 "" 2 
#NO_APP 
    popl %ebp 
    ret 

que es un poco sospechoso, pero eso es comprensible, ya que se olvidó de decirle a gcc que Demolí (modificada sin tener en la lista de entrada/salida) %eax. La fijación que genera asm("addl %0, %%eax" : : "m"(*var) : "%eax"):

movl 8(%ebp), %edx 
    addl (%edx), %eax 

Lo cual no es mejor o más correcto en este caso, pero siempre es una buena práctica para recordar. Consulte la sección en el clobber list y preste especial atención al "memory" clobber para el uso avanzado del ensamblaje en línea.

Aunque no desee (explícitamente) cargar la dirección de memoria en un registro, la cubriré brevemente. Cambio de la restricción "m"-"r" casi parece funcionar, las secciones pertinentes se cambia a (si incluimos %eax en la lista clobber):

movl 8(%ebp), %edx 
    addl %edx, %eax 

que es casi correcta, hemos cargado el valor del puntero var en un registro, pero ahora tenemos que especificarnos que estamos cargando desde la memoria. Cambiar el código para que coincida con la restricción (por lo general indeseable, sólo estoy mostrando que esté completa):

asm("addl (%0), %%eax" : : "r"(var) : "%eax"); 

Da:

movl 8(%ebp), %edx 
addl (%edx), %eax 

El mismo que con "m".

3

sí, porque le das var que es la dirección. dale * var.

gustan:

void test_func(Word32 *var){ 
    asm(" addl %0, %%eax" : : "m"(*var)); 
    return; 
} 

no recuerdo exactamente, pero se debe reemplazar "m" con "r"?

El operando de memoria no significa que tomará valor de esa dirección. es solo un puntero

+0

Haciendo eso, sobrescribirá el valor de% eax con la dirección var para obtener el valor de var. – LooPer

1

No, no hay modo de direccionamiento para procesadores x86 que tenga dos niveles indirectos.

Primero debe cargar el puntero desde una dirección de memoria y luego cargarlo indirectamente desde el puntero.

0

Trate

void test_func(Word32 *var){ 
    asm(" mov %0, %%edx; \ 
    addl (%%edx), %%eax" : : "m"(var));  

    return; 
}