2013-02-23 26 views
5

Tôi đã nhìn thấy các bài về lỗi tương tự nhưng tôi vẫn nhận được lỗi:asm trong C "quá nhiều tài liệu tham khảo bộ nhớ cho` mov "

too many memory references for `mov' 
junk `hCPUIDmov buffer' after expression 

... đây là đoạn code (mingw trình biên dịch/C :: B):


    #include iostream 

    using namespace std; 

    union aregister 
    { 
     int theint; 
     unsigned bits[32]; 
    }; 

    union tonibbles 
    { 
     int integer; 
     short parts[2]; 
    }; 

    void GetSerial() 
    { 
     int part1,part2,part3; 
     aregister issupported; 
     int buffer; 

     __asm(
      "mov %eax, 01h" 
      "CPUID" 
      "mov buffer, edx" 
     );//do the cpuid, move the edx (feature set register) to "buffer" 


     issupported.theint = buffer; 
     if(issupported.bits[18])//it is supported 
     { 
      __asm(
       "mov part1, eax" 
       "mov %eax, 03h" 
       "CPUID" 
      );//move the first part into "part1" and call cpuid with the next subfunction to get 
      //the next 64 bits 

      __asm(
       "mov part2, edx" 
       "mov part3, ecx" 
      );//now we have all the 96 bits of the serial number 


      tonibbles serial[3];//to split it up into two nibbles 

      serial[0].integer = part1;//first part 
      serial[1].integer = part2;//second 
      serial[2].integer = part3;//third 
     } 
    } 

+2

nên không được sử dụng '% 'cho tất cả các đăng ký của bạn truy cập? –

+4

Tôi nghĩ rằng bạn đã quên một số dấu hiệu% trước khi đăng ký tên. – fuz

+0

3 dòng ở cuối câu hỏi cho tôi biết rằng bài đăng của tôi chủ yếu là mã? –

Trả lời

8

Mã lắp ráp của bạn là not correctly formatted cho gcc.

Thứ nhất, gcc sử dụng AT & T cú pháp (EDIT: by default, thanks nrz), vì vậy nó cần một % thêm cho mỗi đăng ký tham khảo và một $ cho toán hạng ngay lập tức. Toán hạng đích luôn ở bên bên phải.

Thứ hai, bạn sẽ cần phải vượt qua dấu tách dòng (ví dụ: \n\t) cho một dòng mới. Vì gcc chuyển chuỗi của bạn thẳng đến assembly, nó yêu cầu một cú pháp cụ thể.

Bạn thường phải cố gắng hết sức để giảm thiểu trình lắp ráp vì nó có thể gây ra sự cố cho trình tối ưu hóa. Cách đơn giản nhất để giảm thiểu lắp ráp được yêu cầu có lẽ sẽ là để phá vỡ các lệnh cpuid ra thành một chức năng, và tái sử dụng đó.

void cpuid(int32_t *peax, int32_t *pebx, int32_t *pecx, int32_t *pedx) 
{ 
    __asm(
     "CPUID" 
      /* All outputs (eax, ebx, ecx, edx) */ 
     : "=a"(*peax), "=b"(*pebx), "=c"(*pecx), "=d"(*pedx) 
      /* All inputs (eax) */ 
     : "a"(*peax)           
    ); 
} 

Sau đó chỉ cần gọi điện bằng cách sử dụng;

int a=1, b, c, d; 

cpuid(&a, &b, &c, &d); 

Cách khác có thể thanh lịch hơn là do it using macros.

+0

Mã này cũng thiếu các ràng buộc đăng ký, vì vậy theo như tôi biết, nó hoàn toàn không an toàn/không có thật. Bạn phải nói với gcc những gì bạn đăng ký sẽ sử dụng/clobber và nơi đầu vào/đầu ra đi. –

+0

@R .. Vâng, xấu của tôi, tôi đã chọn một ví dụ xấu từ trang. Thay thế nó bằng một số liên kết đến thông tin và một ví dụ phù hợp hơn. –

4
  1. Do cách C hoạt động,

    __asm(
        "mov %eax, 01h" 
        "CPUID" 
        "mov buffer, edx" 
    ); 
    

    tương đương với

    __asm("mov %eax, 01h" "CPUID" "mov buffer, edx"); 
    

    tương đương với

    __asm("mov %eax, 01hCPUIDmov buffer, edx"); 
    

    mà không phải là những gì bạn muốn.

  2. AT & Cú pháp T (mặc định của GAS) đặt thanh ghi đích ở cuối.

  3. AT & Cú pháp T yêu cầu phải nhanh chóng được bắt đầu bằng $.

  4. Bạn không thể tham chiếu các biến cục bộ như vậy; bạn cần chuyển chúng thành toán hạng.

Wikipedia's article đưa ra ví dụ làm việc trả về eax.

Đoạn sau đây có thể bao gồm việc bạn sử dụng-ca (Tôi không phức tạp quen thuộc với lắp ráp GCC inline hoặc CPUID):

int eax, ebx, ecx, edx; 
eax = 1; 
__asm("cpuid" 
    : "+a" (eax), "+b" (ebx), "+c" (ecx), "+d" (edx)); 
buffer = edx 
Các vấn đề liên quan