2009-08-13 13 views
8

Encontré este código y necesito entender qué está haciendo. Simplemente parece declarar dos bytes y luego no hacer nada ...¿Qué está haciendo este ensamblaje en línea x86?

uint64_t x; 
__asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (x)); 

¡Gracias!

+0

Interesante. Ha pasado tanto tiempo desde que miré esto, no estoy seguro. Puede especificar qué ensamblador está utilizando. No sé si esto es establecer el contenido, la dirección o ambos (!) De "x". No me sorprendería si x apunta a un puerto mapeado en memoria, actualizado por un dispositivo de forma asíncrona y, por lo tanto, a la palabra clave "volátil". Alguien que realmente haga esto aparecerá pronto, supongo. – Roboprog

+2

¡Apuesto a que deseas que el programador original haya utilizado los comentarios! –

+0

La manera más fácil: compílala y luego desmóntala. –

Respuesta

11

Esto genera dos bytes (0F 31) directamente en la secuencia de código. Esta es una instrucción RDTSC, que lee el contador de marca de tiempo en EDX: EAX, que luego se copiará a la variable 'x' mediante la restricción de salida "= A" (x)

+0

¡Ah vale! Y la sintaxis "= A" (x) (estoy usando gcc4.1) para usar% eax y% edx juntos - ¿funcionará en x86_64 arch? Creo que sí, pero no sé mucho sobre ensamblaje. –

+0

Sí - la restricción 'A' significa un valor de 64 bits en el par de registros EDX: EAX en las descripciones de máquinas i386 y x86_64 gcc –

+0

@MK. y Chris: No, en el código de 64 bits un 'uint64_t' dada una restricción' "= A" 'simplemente elegirá uno de' rax' o 'rdx', como si hubiera usado' "= ad" '. No divide los valores en dos mitades iguales para ti :([Esta versión que las OR juntas en la mitad baja y alta] (https://godbolt.org/g/nQfz7O) se compila en el código óptimo para -m32 y -m64, porque en el código de 32 bits, el OR optimiza. –

4

0F 31 es el código de operación x86 para la instrucción RDTSC (contador de tiempo de lectura); coloca el valor leído en los registros EDX y EAX.

La directiva _ _ asm__ no solo declara dos bytes, sino que coloca el ensamblaje en línea en el código C. Presumiblemente, el programa tiene una forma de usar el valor en esos registros inmediatamente después.

http://en.wikipedia.org/wiki/Time_Stamp_Counter

2

Es la inserción de un 0F 31 opcode, que según this site es:

0F 31 P1+ f2 RDTSC EAX EDX IA32_T...  Read Time-Stamp Counter 

Entonces se está almacenando el resultado en el x variable de

0

Es asm inline for rdtsc, con el código de máquina escrito para admitir ensambladores realmente antiguos que no conocen el mnemónico.

Desafortunadamente, solo funciona correctamente en el código de 32 bits porque "=A" no divide los operandos de 64 bits a la mitad en el código de 64 bits. (El gcc manual even uses rdtsc an an example to illustrate this)

La manera segura de escribir esto, que compila a código óptimo con gcc -m32 o -m64, es decir:

#include <stdint.h> 
uint64_t timestamp_safe(void) 
{ 
    unsigned long tsc_low, tsc_high; // not uint32_t: saves a zero-extend for -m64 (but not x32 :/) 
    asm volatile("rdtsc" : "=d"(tsc_high), "=a" (tsc_low)); 
    return ((uint64_t)tsc_high << 32) | tsc_low; 
} 

En el código de 32 bits, es sólo rdtsc/ret, pero en 64 bits el código hace el cambio necesario/o para obtener ambas mitades en rax para el valor de retorno.

Véa en el Godbolt compiler explorer.

Cuestiones relacionadas