1 Востаннє редагувалося Дмитро-Чебурашка (24.03.2018 17:27:48)

Тема: "=a"(REG_EAX) і таке всяке

#include <stdio.h>
    
#define REG_EAX reg[0]
#define REG_EBX reg[1]
#define REG_ECX reg[3]
#define REG_EDX reg[2]

void cpuid(void);
void check_flag(int);

int reg[5];
char *vendor;

int main(int argc, char *argv[])
{
  reg[5] = 0;

  //Якщо виконати cpuid з EAX=0, то:
//EAX - максимальне значення, з яким можна виконувати cpuid
//EBX: EDX: ECX - рядок - 12-байтнвий іденфікатор виробника 

  REG_EAX = 0;
  cpuid();
  vendor = (char *) REG_EBX;
  printf("Vendor: %s\n", vendor);


  //Якщо в EAX=1, то cpuid встановит регістри відповідно 
  //з можливостями процесора. 

  REG_EAX = 1;
  cpuid();
  
  // В EAX знаходиться інформація про типи, моделі, сімействі
   // і модифікації процесора

  printf("Family: %i\n", (REG_EAX & 0xF00) >> 8); //EAX bits 11-8
  printf("Model: %i\n", (REG_EAX & 0xF0) >> 4); //EAX bits 7-4
  printf("Stepping: %i\n", REG_EAX & 0xF); //EAX bits 3-0
  
  printf("Type: ");

  switch ( (REG_EAX & 0x3000) >> 12 ) {
  case 0:
    printf("OEM\n");
    break;

  case 1:
    printf("Overdrive\n");
    break;

  case 2:
    printf("Dual\n");
    break;
  } 

  // Перевіряємо чи встановлені певні біти в регістрі EDX
   // від них залежить, чи присутні деякі можливості
   // процесора

  printf(" FPU                               : "); check_flag(0);
  printf(" VMode Extensions                  : "); check_flag(1);
  printf(" Debugging Extensions              : "); check_flag(2);
  printf(" 4-Megabyte Pages                  : "); check_flag(3);
  printf(" RDTSC Instruction                 : "); check_flag(4);
  printf(" Machine-Specific Registers        : "); check_flag(5);
  printf(" Extended Physical Addressing      : "); check_flag(6);
  printf(" Machine-Check Exception           : "); check_flag(7);
  printf(" CMPXCHG8B Instruction             : "); check_flag(8);
  printf(" APIC                              : "); check_flag(9);
  printf(" SYSENTER, SYSEXIT Instructions    : "); check_flag(10);
  printf(" Memory Type Range Registers (MTRR): "); check_flag(12);
  printf(" Global Pages                      : "); check_flag(13);
  printf(" Machine Check Architecture        : "); check_flag(14);
  printf(" CMOVcc, FCMOV Instructions        : "); check_flag(15);
  printf(" Page Attributes Table             : "); check_flag(16);
  printf(" MMX                               : "); check_flag(23);
  printf(" FXSAVE, FXRSTOR Instructions      : "); check_flag(24);
  printf(" SSE                               : "); check_flag(25);
  printf(" SSE2                              : "); check_flag(26);
}


//Функция перевіряє встановлен лі біт нумер flag в REG_EDX
void check_flag(int flag)
{
  int mask=1;
  mask <<= flag;
  
  if ( (REG_EDX & mask) != 0) {
    printf("found\n");
  } else {
    printf("NOT FOUND\n");
  }
}

//Функція виконує інструкцію CPUID, і зберігає після неї
//регістри в REG_EAX, REG_EBX, REG_ECX і REG_EDX
void cpuid()
{
  asm("cpuid":
      "=a"(REG_EAX),
      "=b"(REG_EBX),
      "=c"(REG_ECX),
      "=d"(REG_EDX):
      "a"(REG_EAX));

}

Доброго усім! Прога не моя. Ідея програми повністю зрозуміла, а ось реалізація її - ніфіга. Я її побачив, і відразу ж думаю, зрозуміло ж все, от щастя! Компілюю, запускаю. Програма падає й зникає, навить і не збуджуючи виключення або повідомлення, що я ніколи в житті ще не бачив.
Почав дивитися я код і не розумію. Дивлюся далі в усі очі і знову ж не розумію.

Давайте частинами.

REG_REG_EAX повинен бути регістр REG_EAX, вірю що так. "=a" це що??? ??  Як??

"=a"   "=b"  "=c"(   "=d"  це що за букви?  І "a" тоді що?

А, от, повідомлення віндовсу є. Ну не в цьому річ.

#define REG_EAX reg[0]
#define REG_EBX reg[1]
#define REG_ECX reg[3]
#define REG_EDX reg[2]
Тобто замість REG_EAX компілятор проставить reg[0].

int reg[5];    reg[4] і reg[5] про запас?

vendor = (char *) REG_EBX;  Чого ж ште в char * переводити?

А, от може тут його і зашкалює. Я вже напевно і зрозумів де тут помилка.

Подякували: Betterthanyou1

2 Востаннє редагувалося ReAl (25.03.2018 02:31:41)

Re: "=a"(REG_EAX) і таке всяке

По-перше, якщо

int reg[5];

то за

  reg[5] = 0;

вже треба розстрілювати через повішання. Треба

reg[4] = 0;

(а чому _треба_, стане зрозуміло нижче).
По друге, ясно ж написано: «//EBX: EDX: ECX - рядок - 12-байтнвий іденфікатор виробника»
Тобто у цих чотирьох 32-бітних регістрах знаходиться ідентифікатор виробника. Не вони всі вказують на ідентифікатор, а вони містять. Тому в масиві reg[] вже знаходиться ідентифікатор і треба

vendor = (char *) REG_EBX;

замінити на

vendor = (char *) &REG_EBX;

Цих двох змін достатньо, щоб програма запрацювала (тільки треба збирати у 32-бітному режимі).
Занесений у reg[4] нуль обмежує рядок, 12 символів якого розміщено у reg[1], reg[2], reg[3].

3

Re: "=a"(REG_EAX) і таке всяке

p.s. Література для додаткового читання:
https://uk.wikipedia.org/wiki/CPUID
https://uk.wikipedia.org/wiki/GCC_Inline_Assembly

4

Re: "=a"(REG_EAX) і таке всяке

О, справді цікава тема, я також цім цікавився...
Тут декілька посилань, можливо будуть корисні
gcc
https://gcc.gnu.org/onlinedocs/gcc/Usin … ith-C.html - How to Use Inline Assembly Language in C Code
https://gcc.gnu.org/onlinedocs/gcc-4.7. … d-Asm.html - Assembler Instructions with C Expression Operands
Microsoft C++
https://msdn.microsoft.com/uk-ua/library/4ks26t93.aspx - Inline Assembler
https://msdn.microsoft.com/uk-ua/library/45yd4tzz.aspx - __asm

Re: "=a"(REG_EAX) і таке всяке

Надзвичайно дякую!!