Różne wartośći eax

0

Witam.

Od paru dni siedzę nad takim problemem któreg nie mogę pojąć. Bawię się poleceniem cpuid w assemblerze z arugmentem eax=1.
I powinno to zwrócić w rejestrze eax wartość decymalną steppingu , modelu itp. Potem tą wartość konwertuje na binarną i mam gotowy wynik. Tylko z tym to sobie poradzę. A problem jest w tej wartości decymalnej. Dlaczeg program assemblerowy zwraca inną wartość niż w C++
Oto mój kod w assemblerze w składni masm.

.model small
.586

.data 
   tym dd ?    
   tablica dd 26 dup(?)  
.stack 100h
.code
  .startup
  mov eax,1
  cpuid
  mov tym,eax ;kopiuje zawartość rejestru eax
  
  push ds
  pop es
  lea di,tablica  ;kopiuje zawartość zmiennej tym do 26 elementowej tablicy 
  lea si,tym
  mov cx,26
  cld 
  rep movsb
  
  mov bx,0
  mov cx,26
  petla:
  mov edx,tablica[bx]
  add dl,dh  ;Dodaję niższy i wyższy stan żeby uzyskać zawartość 16 bitową rejestru dx
  add dl,'0'
  mov ah,02h
  int 21h
  inc bx
  loop petla
  
  
  
  .exit
end

I wynikiem tego programu jest:Ms_Dos.PNG

Przeszukałem dużo stron o tym poleceniu itp i znalazłem stronę która mi to wytłumaczyła w składni C++.
Oto ten program w C++:

#include<iostream>
using namespace std;
int binaryNum[26];
int a[4];
void decTobin(int n)
{
  int i=0;
  while(n>0)
  {
    binaryNum[i]=n%2;
    n=n/2;
    i++;
  }
}
int main()
{
__asm__("mov $0x1 , %eax\n\t");
__asm__("cpuid\n\t");
__asm__("mov %%eax, %0\n\t":"=r" (a[0])); //gives model and family
__asm__("mov %%ebx, %0\n\t":"=r" (a[1])); //gives additional feature info
__asm__("mov %%ecx, %0\n\t":"=r" (a[2])); //feature flags
__asm__("mov %%edx, %0\n\t":"=r" (a[3])); //feature flags

cout<<"Wartosc A[0]: "<<a[0]<<endl;
decTobin(a[0]);
cout<<"Stepping ID: "<<binaryNum[3]<<binaryNum[2]<<binaryNum[1]<<binaryNum[0]<<endl;
cout<<"Model: "<<binaryNum[7]<<binaryNum[6]<<binaryNum[5]<<binaryNum[4]<<endl;
cout<<"Family ID: "<<binaryNum[11]<<binaryNum[10]<<binaryNum[9]<<binaryNum[8]<<endl;
cout<<"Procesor Type: "<<binaryNum[13]<<binaryNum[12]<<endl;
}

I wynik tego programu jest taki:C++_cpuid.PNG

Dlaczego te dwie wartości są różne. Zweryfikowałem dane wyjściowe i program w C++ jest prawidłowy i wszystkie dane się zgadzają. Był bardzo zadowolony gdyby ktoś pomógł rozwiązać problem lub chociaż wskazać drogę oraz wytłumaczyć co jest źle.

Jak coś C++ znam. Assemblera znam na poziomie podstawowym i dalej się roziwjam czytając książki i pisząc programy.

Bardzo dziękuję za pomoc i życzę miłego dnia.

2
pestka12 napisał(a):
  lea di,tablica  ;kopiuje zawartość zmiennej tym do 26 elementowej tablicy 
  lea si,tym
  mov cx,26
  cld 
  rep movsb

Kopiujesz bajty ze zmiennej tym oraz kolejne z leżącej za nią zmiennej tablica. Powinno być obliczenie ciągu dwójkowego.

  mov bx,0
  mov cx,26
  petla:
  mov edx,tablica[bx]
  add dl,dh  ;Dodaję niższy i wyższy stan żeby uzyskać zawartość 16 bitową rejestru dx
  add dl,'0'
  mov ah,02h
  int 21h
  inc bx
  loop petla

Nie wiem po co jest add dl,dh, ale ta pętla nie ma co wypisać w związku z wcześniejszym.
Natomiast jeśli chcesz uzyskać ten sam wynik dla rejestru eax (wyniku cpuid), to potrzebujesz w programie asm skonwertować jego wartość do postaci dziesiętnej lub wypisać w obu programach w postaci szesnastkowej.

0

@overcq: Hmm czyli mam rozumieć że to kopiowanie jest bez sensu i można to usunąć z kodu ?

Hmm jak mam to przekonwertować do systemu dziesietengo jeśli podobno (chociaż to wyczytałem na internecie) że wartość zwraca w rejestrze eax w systemie dziesiętnym. To można wskazać w jakim systemie to chociaż wyświetla bo na pewno nie w systemie dwójkowym.

Już widzę logikę błędu. Lecz do końca nie rozumiem jak go rozwiązać ?

Bardzo przepraszam ale jak pisałem wyżej jestem osobą początkującą a bardzo mi zależy na rozwiązaniu tego problemu.

1

https://stackoverflow.com/questions/45904075/displaying-numbers-with-dos

A DOSBox może zwracać inne CPUID w swojej emulacji (na potrzeby programów DOSowych).

1

@pestka12: Zobacz w dokumentacji Intela (https://software.intel.com/content/dam/develop/external/us/en/documents-tps/325462-sdm-vol-1-2abcd-3abcd.pdf) dla instrukcji cpuid.
cpuid.png
Dlatego w programie C++ masz wybieranie poszczególnych bitów. Ale wystarczy przesunąc shr, zamaskować and i wypisać w postaci szesnastkowej.

0

@pikob: Czyli cpuidem na dosboxie nie ma co się bawić bo jest to zabawa bez sensu typu że nigdy nie odczytam prawidłowych danych ?

@overcq Czy można to wytłumaczyć na jakimś przykładzie czyli kodzie. Jestem wzrokowcem a do specjalisty to mi bardzo i to bardzo długo z assemblera
Np pokazać wywołanie cpuid z eax=1 i żeby pan pokazał kodowo co dalej. Bo obecnie siedzę i wyrywam ostatnie włosy z głowy :D.

Oczywiście ten kod nie musi być od razu napisany ale w wolnym czasie i jak pan będzie miał chęć to by było wspaniale.

Naprawdę dziękuję każdemu za pomoc.

0

Tu masz przykład w dialekcie AT&T (ponieważ innego nie używam) w Linuksie, a gotowca nie będę podawał. Ten kod kompiluje się tak jak ten w C++ przy użyciu gcc lub clang do programu wykonywalnego w systemie 64-bitowym.

.text
.code64
.globl main
main:
    mov     $1, %eax
    cpuid
    mov     %eax, Wynik_cpuid
# Wypisanie tytułu Stepping ID.
    mov     $Stepping_id, %rdi
    mov     stdout, %rsi
    call    fputs
# Pętla wypisywania bitów Stepping ID.
    movl    $1 << 3, Licznik
1:  mov     Licznik, %eax
    mov     $'0', %rdi
    testl   %eax, Wynik_cpuid
    jz      0f
    inc     %rdi
0:  call    putchar
    shrl    $1, Licznik
    jnz     1b
    mov     $'\n', %rdi
    call    putchar
# Przesunięcie bitów Model na początek.
    shrl    $4, Wynik_cpuid
# Wypisanie tytułu Model.
    mov     $Model, %rdi
    mov     stdout, %rsi
    call    fputs
# Pętla wypisywania bitów Model.
    movl    $1 << 3, Licznik
1:  mov     Licznik, %eax
    mov     $'0', %rdi
    testl   %eax, Wynik_cpuid
    jz      0f
    inc     %rdi
0:  call    putchar
    shrl    $1, Licznik
    jnz     1b
    mov     $'\n', %rdi
    call    putchar
    xor     %rax, %rax
    ret
.data
Wynik_cpuid:
    .4byte  0
Licznik:
    .4byte  0
Stepping_id:
    .asciz  "Stepping ID: "
Model:
    .asciz  "Model: "

Powyżej są przykładowe dwie pętle dla Stepping ID oraz Model, pozostałe (dla Family ID i Processor Type) łatwo dopisać.
Licznik maskuje kolejne bity, które są wypisywane jako 0 lub 1. Do drugiej pętli (Model) Wynik_cpuid jest przesuwany o 4 bity w prawo, tak by początek był na Model.
Konwencja wywołania funkcji fputs czy putchar na Linuksie stanowi, że pierwszy argument jest przekazywany w rdi, a drugi w rsi. Na Windowsie: pierwszy w rcx, drugi w rdx. Więc trzeba zamienić rejestry do testu na Windowsie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1