2009-08-13 14 views
8

Natknąłem się na ten kod i muszę zrozumieć, co robi. Wydaje się, że po prostu deklaruje dwa bajty, a następnie nic nie robi ...Co robi ten wbudowany procesor x86?

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

Dzięki!

+0

Interesujące. Od dawna nie patrzę na to, nie jestem pewien. Możesz określić, z jakiego asemblera korzystasz. Nie wiem, czy to ustawienie zawartości, adresu lub obu (!) "X". Nie zdziwiłoby mnie, gdyby x punkty na porcie mapowanym w pamięci, asynchronicznie zaktualizowane przez urządzenie, a tym samym słowo kluczowe "volatile". Ktoś, kto rzeczywiście to robi, wkrótce się zjawi. – Roboprog

+2

Założę się, że oryginalny programista używał komentarzy! –

+0

Najprostszy sposób: po prostu skompiluj go, a następnie zdemontuj. –

Odpowiedz

11

Generuje to dwa bajty (0F 31) bezpośrednio do strumienia kodu. Jest to instrukcja RDTSC, która odczytuje licznik znacznika czasu do EDX: EAX, który następnie zostanie skopiowany do zmiennej "x" przez ograniczenie wyjściowe "= A" (x)

+0

Ah ok! A składnia "= A" (x) (używam gcc4.1) do jednoczesnego korzystania z% eax i% edx - czy będzie działać na architekturze x86_64? Tak myślę, ale nie wiem zbyt wiele na temat montażu. –

+0

Tak - ograniczenie "A" oznacza 64-bitową wartość w grupie rekordów EDX: EAX w opisach maszyn g3C i386 i x86_64: –

+0

@MK. i Chris: Nie, w 64-bitowym kodzie, 'uint64_t' z ograniczeniem' "= A" 'faktycznie po prostu wybierze jeden z' rax' lub 'rdx', jak gdyby użyłeś' "= reklamy" '. Nie dzieli wartości na dwie równe połowy dla ciebie :([Ta wersja, która łączy razem niską i wysoką połowę] (https://godbolt.org/g/nQfz7O) kompiluje się do optymalnego kodu dla -m32 i -m64, ponieważ w 32-bitowym kodzie OR optymalizuje się z. –

4

0F 31 to kod operacji x86 dla instrukcji RDTSC (odczyt licznika znaczników czasu); umieszcza wartość odczytaną w rejestrach EDX i EAX.

Dyrektywa _ _ asm__ to nie tylko deklarowanie dwóch bajtów, ale umieszczenie wbudowanego zestawu w kodzie C. Można przypuszczać, że program ma sposób natychmiastowego wykorzystania wartości w tych rejestrach.

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

2

To wstawienie 0F 31 kod operacji, które zgodnie z this site jest:

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

Następnie zapisuje wynik w x zmiennej

0

to'S rolki ASM for rdtsc, z kodowanie kodu maszynowego napisanego w celu obsługi naprawdę starych asemblerów, które nie znają mnemoników.

Niestety działa poprawnie tylko w kodzie 32-bitowym, ponieważ "=A" nie dzieli 64-bitowych operandów na pół w 64-bitowym kodzie. (The gcc manual even uses rdtsc an an example to illustrate this)

bezpieczny sposób napisać ten, który kompiluje kod do optymalnej z gcc -m32 lub -m64 jest:

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

W kodzie 32-bitowym, to tylko rdtsc/ret, ale w wersji 64-bitowej kod wykonuje niezbędne przesunięcie/lub, aby uzyskać obie połówki w rax dla zwracanej wartości.

Zobacz go na Godbolt compiler explorer.