Tengo dificultades para entender las restricciones de función en el ensamblaje en línea de GCC (x86). Tengo read the manual, lo que explica exactamente lo que hace cada restricción. El problema es que, aunque entiendo lo que hace cada restricción, entiendo muy poco por qué usarías una restricción sobre otra, o cuáles podrían ser las implicaciones.Ensamblaje en línea de GCC: restricciones
Me doy cuenta de que este es un tema muy amplio, por lo que un pequeño ejemplo debería ayudar a reducir el enfoque. La siguiente es una rutina de asm simple que solo agrega dos números. Si se produce un desbordamiento de enteros, escribe un valor de 1
en una variable C de salida.
int32_t a = 10, b = 5;
int32_t c = 0; // overflow flag
__asm__
(
"addl %2,%3;" // Do a + b (the result goes into b)
"jno 0f;" // Jump ahead if an overflow occurred
"movl $1, %1;" // Copy 1 into c
"0:" // We're done.
:"=r"(b), "=m"(c) // Output list
:"r"(a), "0"(b) // Input list
);
Ahora bien, esto funciona bien, excepto que tenía que jugar de forma arbitraria con las restricciones hasta que llegué que funcione correctamente. Originalmente, he utilizado las siguientes limitaciones:
:"=r"(b), "=m"(c) // Output list
:"r"(a), "m"(b) // Input list
Tenga en cuenta que en lugar de un "0", que utilizo una restricción "m" para b
. Esto tuvo un extraño efecto secundario en el que si compilé con indicadores de optimización y llamé a la función dos veces, por alguna razón el resultado de la operación de adición también se almacenará en c
. Eventualmente leí sobre "matching constraints", que le permite especificar que una variable se utilizará como un operando de entrada y salida. Cuando cambié "m"(b)
a "0"(b)
funcionó.
Pero realmente no entiendo por qué usaría una restricción sobre otra. Quiero decir, sí, entiendo que "r" significa que la variable debe estar en un registro y "m" significa que debe estar en la memoria, pero no Realmente entiendo cuáles son las implicaciones de elegir una sobre otra, o por qué la operación de adición no funciona correctamente si elijo una determinada combinación de restricciones.
Preguntas: 1) En el código de ejemplo anterior, ¿por qué la restricción "m" en b
causa que se escriba c
? 2) ¿Hay algún tutorial o recurso en línea que entre en más detalles sobre las restricciones?
Gracias, esta es una respuesta excelente. Solo una aclaración: ¿por qué el modificador de restricción '=' (solo escritura) le da al compilador el derecho de reutilizar la misma ubicación de memoria, a pesar de que 'b' y' c' son variables diferentes con diferentes ubicaciones en la memoria? – Channel72
@ Channel72: "aunque' b' y 'c' son variables diferentes con diferentes ubicaciones en la memoria" --- en realidad es una suposición importante, una que a menudo no se aplica. Si 'b' y' c' son variables locales, es probable que ambos estén respaldados por registros, en lugar de una ubicación de memoria. En ese caso, la ubicación de la memoria es simplemente un lugar de espera temporal que está configurado exclusivamente para acomodar su restricción 'm' --- en cuyo caso,' b' y 'c' podrían usar la misma ubicación temporal. –
Ahora, si 'b' y' c' estuvieran realmente respaldados por ubicaciones de memoria, entonces estaríamos acertados ya que normalmente no deberían superponerse en absoluto. Y, si uno está respaldado por memoria y el otro respaldado por registro ... entonces cualquiera de esos escenarios es posible. –