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!
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!
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)
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. –
Tak - ograniczenie "A" oznacza 64-bitową wartość w grupie rekordów EDX: EAX w opisach maszyn g3C i386 i x86_64: –
@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. –
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.
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
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.
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
Założę się, że oryginalny programista używał komentarzy! –
Najprostszy sposób: po prostu skompiluj go, a następnie zdemontuj. –