montaż x86: Instrukcja INC i DEC oraz flaga przepełnienia

W Zestawie x86 znacznik przepełnienia jest ustawiany, gdy operacja add lub sub na sygnowanej liczbie całkowitej przepełnia się, a znacznik carry jest ustawiany, gdy operacja na niepodpisanej liczbie całkowitej przepełnia się.

Jednakże, jeśli chodzi o instrukcje inc i dec, sytuacja wydaje się nieco inna. Zgodnie z tą stroną Instrukcja inc w ogóle nie ma wpływu na flagę carry.

Ale nie mogę znaleźć żadnych informacji o tym, jak inc i dec wpływają na flaga przepełnienia, jeśli w ogóle.

Czy inc lub dec ustawić znacznik przepełnienia, gdy wystąpi przepełnienie całkowite? I czy to zachowanie jest takie samo zarówno dla podpisanych, jak i niepodpisanych liczb całkowitych?

============================= edytuj =============================

OK, więc zasadniczo konsensus jest taki, że INC i DEC powinny zachowywać się tak samo jak ADD i SUB, jeśli chodzi o ustawianie FLAG, z wyjątkiem flagi carry. Tak też jest napisane w Intelu Instrukcja obsługi.

Problem w tym, że nie mogę odtworzyć tego zachowania w praktyce, jeśli chodzi o niepodpisane liczby całkowite.

Rozważ następujący kod złożenia (używając wbudowanego zestawu GCC, aby ułatwić drukowanie wyników.)

int8_t ovf = 0;

__asm__
(
    "movb $-128, %%bh;"
    "decb %%bh;"
    "seto %b0;"
    : "=g"(ovf)
    :
    : "%bh"
);

printf("Overflow flag: %d\n", ovf);

Tutaj dekrementujemy podpisaną 8-bitową wartość -128. Ponieważ -128 jest najmniejszą możliwą wartością, przepełnienie jest nieuniknione. Zgodnie z oczekiwaniami, to drukuje: Overflow flag: 1

Ale gdy zrobimy to samo z niepodpisaną wartością, zachowanie nie jest takie jak oczekuję:

int8_t ovf = 0;

__asm__
(
    "movb $255, %%bh;"
    "incb %%bh;"
    "seto %b0;"
    : "=g"(ovf)
    :
    : "%bh"
);

printf("Overflow flag: %d\n", ovf);

Tutaj zwiększam unsigned 8-bit wartość 255. Ponieważ 255 jest największą możliwą wartością, przepełnienie jest nieuniknione. Jednak to drukuje: Overflow flag: 0.

Huh? Dlaczego w tym przypadku nie ustawiono flagi przepełnienia?

Author: Channel72, 2010-10-13

7 answers

Flaga przepełnienia jest ustawiana, gdy operacja spowoduje zmianę znaku. Twój kod jest bardzo bliski. Udało mi się ustawić flagę OF za pomocą następującego kodu (VC++):

char ovf = 0;

_asm {
    mov bh, 127
    inc bh
    seto ovf
}
cout << "ovf: " << int(ovf) << endl;

Gdy BH jest zwiększany, MSB zmienia się z 0 na 1, powodując ustawienie OF.

To również ustawia Z:

char ovf = 0;

_asm {
    mov bh, 128
    dec bh
    seto ovf
}
cout << "ovf: " << int(ovf) << endl;

Należy pamiętać, że procesor nie rozróżnia numerów podpisanych i niepodpisanych. Gdy używasz arytmetyki dopełniacza 2, możesz mieć jeden zestaw instrukcji, które obsługują jedno i drugie. Jeśli chcesz przetestować unsigned overflow, musisz użyć flagi carry. Ponieważ INC / DEC nie wpływa na flagę carry, musisz użyć ADD / SUB w tym przypadku.

 16
Author: Ferruccio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-13 17:25:11

Intel® 64 i IA-32 Architectures Software Developer ' s Manuals

Spójrz na odpowiedni podręcznik Instrukcja zestawu odniesienia, A-M . Każda instrukcja jest dokładnie udokumentowana.

Tutaj znajduje się sekcja INC dotycząca dotkniętych FLAG:

Flaga CF nie jest naruszona. Flagi OF, SZ, ZF, AZ i PF są ustawiane zgodnie z wynikiem.

 3
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-13 15:59:36

Spróbuj zmienić swój test, aby przejść w numerze, a nie na twardym kodzie, a następnie wykonaj pętlę, która próbuje wszystkich 256 liczb, aby znaleźć tę, która ma wpływ na flagę. Albo niech ASM wykona pętlę i zakończy działanie, gdy uderzy flagę i lub gdy zawija się do numeru, z którym się zaczęło (zacznij od czegoś innego niż 0x00, 0x7F, 0x80 lub 0xFF).

EDIT

.globl inc
inc:
    mov $33, %eax

top:
    inc %al
    jo done
    jmp top

done:
    ret

.globl dec
dec:
    mov $33, %eax

topx:
    dec %al
    jo donex
    jmp topx

donex:
    ret

Dodawanie przepełnia się, gdy przechodzi z 0x7F do 0x80. dec przepełnia się, gdy idzie z 0x80 do 0x7F, podejrzewam, że problem tkwi w sposobie, w jaki używasz wbudowanego asemblera.

 3
Author: old_timer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-13 17:32:38

Jak wiele innych odpowiedzi wskazało, INC i DEC nie wpływają na CF, podczas gdy ADD i SUB tak.

To, co jeszcze nie zostało powiedziane, jest jednak to, że może to zmienić wydajność. Nie, że zwykle przeszkadza ci to, chyba że próbujesz zoptymalizować rutynę, ale zasadniczo nie Ustawienie CF oznacza, że INC/DEC zapisuje się tylko do części rejestru flags, co może spowodować częściowy rejestr flags , Zobacz Intel 64 i IA-32 Architectures Optimization Reference Manual lub Agner Fog ' s optimization manuals .

 3
Author: PhiS,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-14 17:22:24

Z wyjątkiem flagi carry inc Ustawia flagi w taki sam sposób, jak polecenie Add 1.

Fakt, że inc nie wpływa na flagę carry jest bardzo ważny.

Http://oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter_6/CH06-2.html#HEADING2-117

 2
Author: Andrey,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-13 15:55:17

To, co robi procesor, to ustawianie odpowiednich FLAG dla wyników tych instrukcji (add, adc, dec, inc, SBB, sub) zarówno dla przypadków podpisanych, jak i niepodpisanych, tj. dwa różne wyniki flag dla każdego op. alternatywą byłoby posiadanie dwóch zestawów instrukcji, gdzie jeden Ustawia flagi związane z podpisem, a drugi niepodpisane. Jeśli kompilator wydający polecenie używa zmiennych niepodpisanych w operacji, to testuje carry i zero (jc, jnc, jb, jbe itp.), Jeśli signed testuje przepełnienie, sign i zero (jo, jno, jg, jng, jl, jle itp.).

 0
Author: Olof Forshell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-02-16 09:16:56

CPU / ALU jest w stanie obsłużyć tylko niepodpisane liczby binarne, a następnie używa, CF, AF, SF, ZF, itd., aby umożliwić Ci podjęcie decyzji, czy używać go jako numeru podpisanego (OF), numeru niepodpisanego (CF) czy numeru BCD (AF).



Jeśli chodzi o twój problem, pamiętaj, aby wziąć pod uwagę same liczby binarne, jako niepodpisane.

ponadto przepełnienie I OF wymagają 3 liczb: liczby wejściowej, drugiej liczby do użycia w arytmetyce i wyniku numer.

Przepełnienie jest aktywowane tylko wtedy, gdy pierwsza i druga liczba mają tę samą wartość dla bitu znaku (bit najbardziej znaczący), a wynik ma inny znak. jak w, dodanie 2 liczb ujemnych skutkowało liczbą dodatnią, lub dodanie 2 liczb dodatnich skutkowało liczbą ujemną:

if( (Sign_Num1==Sign_Num2) && (Sign_Result!=Sign_Num1) ) OF=1;
else OF=0;


W pierwszym problemie używasz -128 jako pierwszej liczby. Druga liczba to implicite -1, używana przez instrukcję DEC. Więc my naprawdę mają numery binarne 0x80 i 0xFF. Oba mają bit znakowy ustawiony na 1. Wynikiem jest 0x7F, która jest liczbą z bitem znaku ustawionym na 0. Mamy 2 liczby początkowe z tym samym znakiem, a wynik z innym znakiem, więc wskazujemy przepełnienie. -128-1 spowodowało 127 i dlatego flaga przepełnienia jest ustawiona tak, aby wskazywała nieprawidłowy wynik podpisu.





W drugim problemie używasz 255 jako pierwszej liczby. Druga liczba jest implicite 1, używany przez instrukcję INC. Więc naprawdę mamy liczby binarne 0xFF i 0x01. Oba mają inny bit znaku, więc nie jest możliwe uzyskanie przepełnienia (przepełnienie jest możliwe tylko wtedy, gdy zasadniczo dodajemy 2 liczby tego samego znaku, ale nigdy nie jest możliwe przepełnienie 2 liczbami innego znaku, ponieważ nigdy nie prowadzą do wyjścia poza możliwą wartość podpisaną). wynikiem jest 0x00 i nie ustawia znacznika przepełnienia, ponieważ 255+1, a dokładniej -1+1 daje 0, co jest oczywiście poprawne dla arytmetyki podpisanej.

Pamiętaj, że aby ustawić flagę przepełnienia, dodawane/odejmowane liczby muszą mieć bit znaku o tej samej wartości, a następnie wynik musi mieć bit znaku o innej wartości.

 0
Author: alt.126,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-04-25 06:43:32