¿Qué hace el asm volátil en C?


Busqué en algún código C de

Http://www.mcs.anl.gov / ~kazutomo/rdtsc.html

Usan cosas como " en línea", "asm " etc como el siguiente:

Code1:

static __inline__ tick gettick (void) {
    unsigned a, d;
    __asm__ __volatile__("rdtsc": "=a" (a), "=d" (d) );
    return (((tick)a) | (((tick)d) << 32));
}

Code2:

volatile int  __attribute__((noinline)) foo2 (int a0, int a1) {
    __asm__ __volatile__ ("");
}

Me preguntaba qué hacen el code1 y code2?

Author: Deduplicator, 2014-10-20

3 answers

El modificador __volatile__ en un bloque __asm__ fuerza al optimizador del compilador a ejecutar el código tal cual. Sin él, el optimizador puede pensar que puede ser eliminado directamente, o levantado de un bucle y almacenado en caché.

Esto es útil para la instrucción rdtsc así:

__asm__ __volatile__("rdtsc": "=a" (a), "=d" (d) )

Esto no toma dependencias, por lo que el compilador podría asumir que el valor se puede almacenar en caché. Volatile se usa para forzarlo a leer una nueva marca de tiempo.

Cuando se usa solo, así:{[18]]}

__asm__ __volatile__ ("")

It en realidad no ejecutará nada. Sin embargo, puede extender esto para obtener una barrera de memoria en tiempo de compilación que no permita reordenar ninguna instrucción de acceso a la memoria:

__asm__ __volatile__ ("":::"memory")

La instrucción rdtsc es un buen ejemplo para volatile. rdtsc se usa generalmente cuando necesita medir el tiempo que algunas instrucciones tardan en ejecutarse. Imagina un código como este, donde quieres cronometrar r1 y r2 la ejecución:

__asm__ ("rdtsc": "=a" (a0), "=d" (d0) )
r1 = x1 + y1;
__asm__ ("rdtsc": "=a" (a1), "=d" (d1) )
r2 = x2 + y2;
__asm__ ("rdtsc": "=a" (a2), "=d" (d2) )

Aquí se permite al compilador almacenar en caché la marca de tiempo, y la salida podría mostrar que cada línea tomó exactamente 0 relojes para ejecutarse. Obviamente esto no es lo que quieres, así que introduce __volatile__ para evitar el almacenamiento en caché:

__asm__ __volatile__("rdtsc": "=a" (a0), "=d" (d0))
r1 = x1 + y1;
__asm__ __volatile__("rdtsc": "=a" (a1), "=d" (d1))
r2 = x2 + y2;
__asm__ __volatile__("rdtsc": "=a" (a2), "=d" (d2))

Ahora obtendrá una nueva marca de tiempo cada vez, pero todavía tiene un problema que tanto el compilador como la CPU pueden reordenar todas estas instrucciones. Podría terminar ejecutando los bloques asm después de que r1 y r2 ya se hayan calculado. Para trabajar alrededor de esto, usted agregaría algunas barreras que fuerzan serialización:

__asm__ __volatile__("mfence;rdtsc": "=a" (a0), "=d" (d0) :: "memory")
r1 = x1 + y1;
__asm__ __volatile__("mfence;rdtsc": "=a" (a1), "=d" (d1) :: "memory")
r2 = x2 + y2;
__asm__ __volatile__("mfence;rdtsc": "=a" (a2), "=d" (d2) :: "memory")

Tenga en cuenta la instrucción mfence aquí, que impone una barrera del lado de la CPU, y el especificador de "memoria" en el bloque volátil que impone una barrera en tiempo de compilación. En las Cpu modernas, puede reemplazar mfence:rdtsc con rdtscp para algo más eficiente.

 51
Author: Cory Nelson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-12 16:25:17

asm es para incluir código ensamblador nativo en el código fuente de C. Por ejemplo,

int a = 2;
asm("mov a, 3");
printf("%i", a); // will print 3

Los compiladores tienen diferentes variantes de la misma. __asm__ debería ser sinónimo, tal vez con algunas diferencias específicas del compilador.

volatile significa que la variable puede ser modificada desde el exterior (también conocido como no por el programa C). Por ejemplo, cuando se programa un microcontrolador donde la dirección de memoria 0x0000x1234 se asigna a una interfaz específica del dispositivo (es decir, cuando se codifica para el GameBoy, los botones / pantalla / etc accedido por aquí.)

volatile std::uint8_t* const button1 = 0x00001111;

Este compilador deshabilita las optimizaciones que dependen de *button1 que no cambian a menos que sean cambiadas por el código.

También se utiliza en la programación multihilo (no se necesita más hoy en día?) donde una variable puede ser modificada por otro hilo.

inline es una sugerencia al compilador para que llame" inline " a una función.

inline int f(int a) {
    return a + 1
}

int a;
int b = f(a);

Esto no debe ser compilado en una llamada de función a f sino en int b = a + 1. Como si f donde una macro. Compilación principalmente hacer esta optimización automáticamente dependiendo del uso de la función / contenido. __inline__ en este ejemplo podría tener un significado más específico.

Similarmente __attribute__((noinline)) (sintaxis específica de GCC) evita que una función se inline.

 3
Author: tmlen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-10-19 23:37:53

El atributo __asm__ especifica el nombre que se utilizará en el código ensamblador para la función o variable.

El calificador __volatile__, generalmente utilizado en la Computación en Tiempo Real de sistemas embebidos, aborda un problema con las pruebas de compilador del status register para el bit ERROR o READY que causan problemas durante la optimización. __volatile__ se introdujo como una forma de decirle al compilador que el objeto está sujeto a cambios rápidos y forzar cada referencia del objeto a ser una referencia genuina.

 -1
Author: David C. Rankin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-24 23:23:28