Я пытаюсь изучить встроенную сборку GCC в Linux (x86), и мой первый эксперимент состоял в том, чтобы попытаться реализовать целочисленное обнаружение переполнения для умножения.Это кажется достаточно простым, но у него есть побочные эффекты, которых я не понимаю.
Итак, здесь я хочу умножить два беззнаковых 8-битных целых числа и посмотреть, не переполняется ли результат.В основном я просто загружаю первый операнд в регистр AL, а другой операнд в регистр BL, а затем использую инструкцию mul
.Результат сохраняется как 16-битное значение в регистре AX.Поэтому я затем копирую значение в регистре AX в мою переменную C b
, если оно не переполнено.Если он переполняется, я устанавливаю c
в 1.
uint8_t a = 10;
uint8_t b = 25;
uint8_t c = 0; // carry flag
__asm__
(
"clc;" // Clear carry flag
"movb %3, %%al;" // Load b into %al
"movb %2, %%bl;" // Load a into %bl
"mul %%bl;" // Multiply a * b (result is stored in %ax)
"movw %%ax, %0;" // Load result into b
"jnc out;" // Jump to 'out' if the carry flag is not set
"movb $1, %1;" // Set 'c' to 1 to indicate an overflow
"out:"
:"=m"(b), "=m"(c) // Output list
:"ir"(a), "m"(b) // Input list
:"%al", "%bl" // Clobbered registers (not sure about this)
);
Кажется, это работает нормально.Если я printf
значение 'b', я получаю 250, что является правильным.Кроме того, если я изменяю начальное значение 'b' на 26, то после умножения c
устанавливается в 1, что указывает на переполнение из-за курса (10 * 26> ~ uint8_t (0)).Проблема, которую я вижу, состоит в том, что переменная C a
установлена в 0 после умножения (или 1 в случае переполнения). Я не понимаю, почему a
будет изменено вообще чем-либо, что я делаю здесь,Его даже нет в списке выходных переменных, так почему моя процедура сборки влияет на значение a
?
Кроме того, я не уверен насчет списка засоренных регистров.Этот список должен информировать GCC о любых регистрах, которые использовались во время процедуры сборки, чтобы GCC не пытался использовать их неправильно.Я думаю, что мне нужно сообщить GCC, что я использовал регистры AL и BL, но как насчет регистра AX?Он неявно используется для хранения произведения двух 8-битных целых чисел, поэтому мне нужно включить его в список засоренных регистров?