2009-08-13 38 views
8

Tôi đã xem đoạn mã này và cần phải hiểu nó đang làm gì. Có vẻ như nó đang khai báo hai byte và sau đó không làm gì cả ...Lắp ráp nội tuyến x86 này là gì?

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

Cảm ơn!

+0

Thú vị. Đã quá lâu kể từ khi tôi xem xét bất kỳ điều này, tôi không chắc chắn. Bạn có thể chỉ định những gì bạn đang sử dụng assembler. Tôi không biết nếu điều này là thiết lập nội dung, địa chỉ, hoặc cả hai (!) Của "x". Nó sẽ không làm tôi ngạc nhiên nếu x điểm tại một cổng được ánh xạ bộ nhớ, được cập nhật bởi một thiết bị không đồng bộ, và do đó từ khóa "dễ bay hơi". Ai đó thực sự làm công cụ này sẽ sớm xuất hiện, tôi cho là vậy. – Roboprog

+2

Đặt cược bạn muốn người lập trình ban đầu sử dụng bình luận! –

+0

Cách dễ nhất: chỉ cần biên dịch nó và sau đó tháo rời nó. –

Trả lời

11

Điều này tạo ra hai byte (0F 31) trực tiếp vào luồng mã. Đây là một lệnh RDTSC, đọc bộ đếm thời gian vào EDX: EAX, sau đó sẽ được sao chép vào biến 'x' bằng ràng buộc đầu ra "= A" (x)

+0

Ah ok !! Và cú pháp "= A" (x) (Tôi đang sử dụng gcc4.1) để sử dụng% eax và% edx cùng nhau - nó có hoạt động trên kiến ​​trúc x86_64 không? Tôi nghĩ vậy nhưng tôi không biết nhiều về lắp ráp. –

+0

Có - ràng buộc 'A' có nghĩa là giá trị 64 bit trong EDX: cặp đăng ký EAX trong cả hai mô tả máy i386 và x86_64 gcc –

+0

@MK. và Chris: Không, trong mã 64 bit, một 'uint64_t' cho ràng buộc' "= A" 'thực sự sẽ chỉ chọn một trong' rax' hoặc 'rdx', giống như nếu bạn sử dụng' "= ad" '. Nó không chia các giá trị thành hai nửa bằng nhau cho bạn: ([Phiên bản này HOẶC cùng một nửa thấp và cao] (https://godbolt.org/g/nQfz7O) biên dịch thành mã tối ưu cho -m32 và -m64, bởi vì trong mã 32 bit OR tối ưu hóa đi –

4

0F 31 là mã x86 cho lệnh RDTSC (đọc tem thời gian); nó đặt giá trị được đọc vào thanh ghi EDX và EAX.

Chỉ thị _ _ asm__ không chỉ khai báo hai byte, nó đặt lắp ráp nội tuyến vào mã C. Có lẽ, chương trình có cách sử dụng giá trị trong các thanh ghi đó ngay sau đó.

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

2

Nó chèn một opcode 0F 31, mà theo this site là:

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

Sau đó, nó được lưu trữ kết quả trong x biến

0

Đó là inline asm for rdtsc, với mã hóa máy-mã được viết ra để hỗ trợ những người lắp ráp thực sự cũ mà không biết sự ghi nhớ.

Thật không may, nó chỉ hoạt động chính xác trong mã 32 bit vì "=A" không chia các toán hạng 64 bit bằng một nửa trong mã 64 bit. (Các gcc manual even uses rdtsc an an example to illustrate this)

Cách an toàn để viết những dòng này, mà biên dịch mã tối ưu với gcc -m32 hoặc -m64, là:

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

Trong mã 32bit, nó chỉ là rdtsc/ret, nhưng trong 64bit mã nó chuyển đổi cần thiết/hoặc để có được cả hai nửa thành rax cho giá trị trả lại.

Xem trên Godbolt compiler explorer.

Các vấn đề liên quan