GCC inline assembly: ograniczenia

Mam trudności ze zrozumieniem ograniczeń roli w GCC inline assembly (x86). Przeczytałem instrukcję , która dokładnie wyjaśnia, co robi każde ograniczenie. Problem polega na tym, że chociaż rozumiem, co robi każde ograniczenie, mam bardzo mało zrozumienia, dlaczego można użyć jednego ograniczenia nad innym, lub jakie konsekwencje mogą być.

Zdaję sobie sprawę, że jest to bardzo szeroki temat, więc mały przykład powinien pomóc zawęzić ostrość. Poniżej znajduje się prosta procedura asm, która dodaje tylko dwie liczby. Jeśli wystąpi przepełnienie całkowite, zapisuje wartość 1 do wyjściowej zmiennej C.

 int32_t a = 10, b = 5;
 int32_t c = 0; // overflow flag

 __asm__
 (
  "addl %2,%3;"        // Do a + b (the result goes into b)
  "jno 0f;"            // Jump ahead if an overflow occurred
  "movl $1, %1;"       // Copy 1 into c
  "0:"                 // We're done.

  :"=r"(b), "=m"(c)    // Output list
  :"r"(a), "0"(b)     // Input list
 );

Teraz to działa dobrze, z tym, że musiałem arbitralnie majstrować z ograniczeniami, dopóki nie dostałem go do poprawnego działania. Początkowo używałem następujących ograniczeń:

  :"=r"(b), "=m"(c)    // Output list
  :"r"(a), "m"(b)     // Input list

Zauważ, że zamiast" 0", używam ograniczenia" m " dla b. To miało dziwny efekt uboczny, gdzie jeśli skompilowałem z flagami optymalizacji i wywołałem funkcję dwa razy, z jakiegoś powodu wynik operacji dodawania również zostanie zapisany w c. W końcu przeczytałem o " dopasowywanie ograniczeń ", które pozwala określić, że zmienna ma być używana zarówno jako operand wejściowy, jak i wyjściowy. Kiedy zmieniłem "m"(b) na "0"(b) zadziałało.

Ale naprawdę nie rozumiem, dlaczego używasz jednego ograniczenia nad innym. Rozumiem, że" r "oznacza, że zmienna powinna być w rejestrze, A" m " oznacza, że powinna być w pamięci - ale ja Nie naprawdę zrozumieć, jakie są konsekwencje wyboru jednego nad drugim, lub dlaczego operacja dodawania nie działa poprawnie, jeśli wybieram pewną kombinację ograniczeń.

Pytania: 1) w powyższym przykładowym kodzie, dlaczego ograniczenie " m " na b spowodowało, że c zostało napisane do? 2) Czy istnieje jakiś samouczek lub zasób online, który szczegółowo opisuje ograniczenia?

Author: Channel72, 2010-10-10

1 answers

Oto przykład, aby lepiej zilustrować, dlaczego powinieneś starannie wybierać ograniczenia (ta sama funkcja, co Twoja, ale być może napisana nieco zwięźle): {]}

bool add_and_check_overflow(int32_t& a, int32_t b)
{
    bool result;
    __asm__("addl %2, %1; seto %b0"
            : "=q" (result), "+g" (a)
            : "r" (b));
    return result;
}

Więc stosowane ograniczenia były: q, r, i g.

  • q oznacza tylko eax, ecx, edx, lub ebx można wybrać. Dzieje się tak dlatego, że instrukcje set* muszą zapisywać się do rejestru 8-bitowego(al, ah, ...). Użycie b w %b0 oznacza użycie najniższego 8-bitowego porcja (al, cl, ...).
  • dla większości instrukcji dwuoperandowych, przynajmniej jeden z operandów musi być rejestrem. Więc nie używaj m ani g dla obu; używaj r dla co najmniej jednego z operandów.
  • dla ostatniego operandu, nie ma znaczenia czy jest to rejestr czy pamięć, więc użyj g (ogólne).

W powyższym przykładzie zdecydowałem się użyć g (zamiast r) dla a, ponieważ odniesienia są zwykle implementowane jako wskaźniki pamięci, więc używając r constraint wymagałby najpierw skopiowania referenta do rejestru, a następnie skopiowania z powrotem. Używając g, referent może być aktualizowany bezpośrednio.


Co do tego, dlaczego Twoja Oryginalna wersja nadpisała c z wartością dodatku, to dlatego, że podałeś =m w gnieździe wyjściowym, a nie (powiedzmy) +m; to oznacza, że kompilator może ponownie użyć tego samego miejsca pamięci dla wejścia i wyjścia.

W Twoim przypadku oznacza to dwa wyniki (ponieważ ta sama pamięć lokalizacja została użyta dla b ic):

  • dodanie Nie przepełniło się: wtedy c zostało nadpisane wartością b (wynik dodania).
  • dodatek nie przepełnił się: wtedy c stał się 1 (i b może również stać się 1, w zależności od tego, jak kod został wygenerowany).
 13
Author: Chris Jester-Young,
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-10 02:33:23