2017-02-16 12 views
0

Рассмотрим следующую программу:умножение инструкция в инлайн сборки

#include <stdio.h> 
int main(void) { 
     int foo = 10, bar = 15; 
     __asm__ __volatile__("add %%ebx,%%eax" 
          :"=a"(foo) 
          :"a"(foo), "b"(bar) 
          ); 
     printf("foo+bar=%d\n", foo); 
} 

Я знаю, что add инструкция используется для того, sub инструкция используется для вычитания & так далее. Но я не понимаю эти строки:

__asm__ __volatile__("add %%ebx,%%eax" 
          :"=a"(foo) 
          :"a"(foo), "b"(bar) 
          ); 

Что такое точное значение :"=a"(foo) :"a"(foo), "b"(bar));? Что оно делает ? И когда я пытаюсь использовать mul инструкции здесь я получаю следующее сообщение об ошибке для следующей программы:

#include <stdio.h> 
int main(void) { 
     int foo = 10, bar = 15; 
     __asm__ __volatile__("mul %%ebx,%%eax" 
          :"=a"(foo) 
          :"a"(foo), "b"(bar) 
          ); 
     printf("foo*bar=%d\n", foo); 
} 

Ошибка: количество рассогласования операндов для `мула»

Итак, почему я получаю эту ошибку? Как решить эту ошибку? Я искал в Google об этих, но я не мог найти решение моей проблемы. Я использую Windows 10 os & процессор - это ядро ​​i3.

ответ

4

What is the exact meaning of :"=a"(foo) :"a"(foo), "b"(bar));

Существует подробное описание того, как параметры передаются инструкции ассемблерного here. Короче говоря, это говорит о том, что bar переходит в регистр ebx, foo переходит в eax, а после выполнения asm eax будет содержать обновленное значение для foo.

Error: number of operands mismatch for `mul'

Да, это не тот синтаксис для mul. Возможно, вам стоит потратить некоторое время на справочное руководство ассемблера x86 (например, this).

Я также добавлю, что использование inline asm обычно bad idea.


Редактировать: Я не могу ответить на ваш вопрос в комментарии.

Я не совсем уверен, с чего начать. Эти вопросы, похоже, указывают на то, что вы не очень хорошо понимаете, как работает ассемблер. Попытка научить вас программированию asm в SO-ответе не очень практична.

Но я могу указать вам в правильном направлении.

Прежде всего, рассмотрим этот бит ассемблерный код:

movl $10, %eax 
movl $15, %ebx 
addl %ebx, %eax 

ли вы понимаете, что это значит? Что будет в eax, когда это закончится? Что будет в ebx? Теперь сравните это с этим:

int foo = 10, bar = 15; 
__asm__ __volatile__("add %%ebx,%%eax" 
        :"=a"(foo) 
        :"a"(foo), "b"(bar) 
        ); 

С помощью «а» ограничение, вы просите GCC, чтобы переместить значение foo в EAX. Используя ограничение «b», вы просите его переместить bar в ebx. Он делает это, затем выполняет инструкции для asm (то есть add). При выходе из asm новое значение для foo будет в eax. Возьми?

Теперь давайте посмотрим на mul. Согласно документам, к которым я привязал вас, мы знаем, что синтаксис равен mul value. Это кажется странным, не так ли? Как может быть только один параметр до mul?Что он многозначает значение с?

Но если вы продолжаете читать, вы видите «Всегда умножает EAX на значение». Ааа. Поэтому здесь всегда подразумевается регистр «eax». Так что, если бы вы писали mul %ebx, это было бы действительно mul ebx, eax, но так как всегда имеет, чтобы быть eax, нет реального смысла его писать.

Однако, это немного сложнее, чем это. ebx может содержать 32-битное значение. Поскольку мы используем ints (вместо unsigned ints), это означает, что ebx может иметь число, равное 2,147,483,647. Но подождите, что произойдет, если вы умножаете 2,147,483,647 * 10? Хорошо, так как 2,147,483,647 уже такой же большой, как вы можете хранить в реестре, результат слишком велик, чтобы вписаться в eax. Таким образом, умножение (всегда) использует 2 регистра для вывода результата из mul. Это то, что эта ссылка имела в виду, когда она ссылалась «сохраняет результат в EDX: EAX».

Таким образом, вы могли бы написать умножение так:

int foo = 10, bar = 15; 
int upper; 
__asm__ ("mul %%ebx" 
     :"=a"(foo), "=d"(upper) 
     :"a"(foo), "b"(bar) 
     :"cc" 
     ); 

Как и прежде, это ставит планку в EBX и обув в EAX, а затем выполняет команду умножения.

И после выполнения asm, eax будет содержать нижнюю часть результата, а edx будет содержать верхний. Если foo * bar < 2,147,483,647, то foo будет содержать нужный результат, а upper будет равен нулю. В противном случае все усложняется.

Но это насколько я хочу идти. Помимо этого, возьмите класс asm. Читать книгу.

PS Вы также можете посмотреть ответ this и следующие 3 комментария, которые показывают, почему даже ваш пример «добавить» является «неправильным».

PPS Если этот ответ разрешил ваш вопрос, не забудьте нажать галочку рядом с ним, чтобы я получил свои точки кармы.

+0

Что здесь обозначают "a" и "b"? – Destructor

+0

Если вы прочитали документы, к которым я привязан для asm, вы увидите, что цитируемые строки являются «ограничениями», которые описывают, как сопоставить переменные языка C с чем-то, что может понять asm (см. Раздел i386 [здесь] (https: // gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html)). «a» относится к регистру eax. «b» означает ebx. –

+0

ОК спасибо. Я понял. Но у меня все еще есть одна проблема. Я хочу умножить значения переменных foo & bar и сохранить результат в foo. Я посетил ссылку, которую вы предоставили о создании мула, но мне все еще трудно узнать, что именно я должен сделать, чтобы достичь этого? – Destructor