2009-08-13 20 views
8

Mi sono imbattuto in questo codice e ho bisogno di capire cosa sta facendo. Sembra solo dichiarare due byte e quindi non fare nulla ...Cosa sta facendo questo assembly in linea x86?

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

Grazie!

+0

Interessante. È da tanto che non guardo nulla di questo, non ne sono sicuro. È possibile specificare quale assemblatore si sta utilizzando. Non so se questo è l'impostazione del contenuto, l'indirizzo, o entrambi (!) Di "x". Non mi sorprenderebbe se x punti in una porta mappata in memoria, aggiornata da un dispositivo in modo asincrono, e quindi la parola chiave "volatile". Immagino che qualcuno che in realtà fa queste cose si presenterà presto. – Roboprog

+2

Scommetti che desideri che il programmatore originale abbia usato commenti! –

+0

Il modo più semplice: basta compilarlo e quindi smontarlo. –

risposta

11

Questo sta generando due byte (0F 31) direttamente nel flusso di codice. Questa è un'istruzione RDTSC, che legge il contatore di data e ora in EDX: EAX, che verrà quindi copiato nella variabile 'x' dal vincolo di uscita "= A" (x)

+0

Ah ok !! E la sintassi "= A" (x) (sto usando gcc4.1) per usare% eax e% edx insieme - funzionerà su x86_64 arch? Penso di sì ma non so molto del montaggio. –

+0

Sì: il vincolo "A" indica un valore a 64 bit nell'EDX: coppia di registri EAX in entrambe le descrizioni della macchina gcc i386 e x86_64 –

+0

@MK. e Chris: No, nel codice a 64bit un 'uint64_t' dato un' "= A" 'il vincolo in realtà sceglierà solo uno tra' rax' o 'rdx', come se tu avessi usato' "= annuncio" '. Non divide i valori in due metà uguali per te :([Questa versione che ORs insieme alla metà alta e bassa] (https://godbolt.org/g/nQfz7O) compila in codice ottimale per -m32 e -m64, perché nel codice a 32 bit l'OR si ottimizza. –

4

0F 31 è l'opcode x86 per l'istruzione RDTSC (lettura indicatore data/ora); posiziona il valore letto nei registri EDX ed EAX.

La direttiva _ _ asm__ non sta solo dichiarando due byte, sta posizionando l'assembly inline nel codice C. Presumibilmente, il programma ha un modo di usare il valore in quei registri immediatamente dopo.

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

2

È inserendo un 0F 31 codice operativo, che secondo this site è:

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

Poi memorizza il risultato nella x variabile

0

È asm linea for rdtsc, con la codifica del codice macchina scritta per supportare vecchi assemblatori che non conoscono il codice mnemonico.

Sfortunatamente, funziona solo correttamente in codice a 32 bit perché "=A" non divide gli operandi a 64 bit a metà nel codice a 64 bit. (Il gcc manual even uses rdtsc an an example to illustrate this)

Il modo sicuro per scrivere questo, che viene compilato in codice ottimale con gcc -m32 o -m64, è:

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

Nel codice a 32 bit, è solo rdtsc/ret, ma in 64bit codice esegue lo spostamento necessario/o per ottenere entrambe le metà in rax per il valore restituito.

Vedere su Godbolt compiler explorer.

Problemi correlati