Mam trudności ze zrozumieniem ograniczeń roli w GCC inline assembly (x86). Mam read the manual, który dokładnie wyjaśnia, co każde ograniczenie ma. Problem polega na tym, że chociaż rozumiem, co robi każde ograniczenie, bardzo niewiele rozumiem, dlaczego używałbyś jednego ograniczenia w stosunku do drugiego lub jakie mogą być tego konsekwencje.Montaż inline w GCC: ograniczenia
Zdaję sobie sprawę, że jest to bardzo szeroki temat, więc mały przykład powinien pomóc zawęzić nacisk. Poniżej przedstawiono prostą procedurę asm, która dodaje tylko dwie liczby. Jeśli wystąpi przepełnienie liczby całkowitej, zapisuje wartość 1
na wyjściową zmienną 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 dowolnie manipulować ograniczeniami, dopóki nie zacząłem działać poprawnie. Początkowo używałem następujące ograniczenia:
:"=r"(b), "=m"(c) // Output list
:"r"(a), "m"(b) // Input list
Zauważ, że zamiast „0”, używam „M” ograniczenie dla b
. Miało to dziwny skutek uboczny, gdy skompilowałem z flagami optymalizacyjnymi i dwukrotnie wywołałem funkcję, z jakiegoś powodu wynik operacji dodawania również zostałby zapisany w c
. W końcu przeczytałem o "matching constraints", który pozwala ci określić, że zmienna ma być używana jako operand wejściowy i wyjściowy. Po zmianie "m"(b)
na "0"(b)
zadziałało.
Ale tak naprawdę nie rozumiem, dlaczego używałbyś jednego ograniczenia zamiast drugiego. Chodzi mi o to, rozumiem, że "r" oznacza, że zmienna powinna znajdować się w rejestrze, a "m" oznacza, że powinna być w pamięci - ale ja nie rozumiem, co to jest wybór jednego z nich, ani dlaczego operacja dodawania nie działa poprawnie, jeśli wybiorę pewną kombinację ograniczeń.
Pytania: 1) W powyższym przykładzie kodu, dlaczego ograniczenie "m" na b
powoduje, że c
jest zapisywane? 2) Czy jest jakiś tutorial lub zasób online, który bardziej szczegółowo opisuje ograniczenia?
Dzięki - to doskonała odpowiedź. Tylko jedno wyjaśnienie: dlaczego modyfikator ograniczenia "=" (tylko do zapisu) daje kompilatorowi prawo do ponownego użycia tej samej lokalizacji pamięci, mimo że "b" i "c" to różne zmienne z różnymi lokalizacjami w pamięci? – Channel72
@ Channel72: "nawet jeśli" b "i" c "są różnymi zmiennymi z różnymi lokalizacjami w pamięci" --- to jest rzeczywiście główne założenie, które często nie ma zastosowania. Jeśli "b" i "c" są zmiennymi lokalnymi, są szanse, że oba są faktycznie wspierane przez rejestry, a nie jako miejsce w pamięci. W takim przypadku lokalizacja pamięci jest po prostu tymczasowym miejscem przechowywania ustawionym wyłącznie w celu uwzględnienia ograniczenia 'm' --- w takim przypadku' b' i 'c' mogą bardzo dobrze używać tej samej tymczasowej lokalizacji. –
Teraz, jeśli 'b' i' c' faktycznie były tak naprawdę wspierane przez lokalizacje w pamięci, to masz rację, że normalnie nie powinny się w ogóle pokrywać. A jeśli jeden jest wspierany przez pamięć, a drugi jest wspierany przez rejestr ... to jeden z tych scenariuszy jest możliwy. –