Как стать программистом Как устроен компьютер. Что такое программа. Как написать свою программу. И многое другое узнаете вы из этой книги. Получить бесплатно! |
Ассемблер в Dev-C++
Главная / Ассемблер / Ассемблер и языки высокого уровня /
Лучшие книги по Ассемблеру
Сделал подборку не новых, но проверенных книг по программированию на языке ассемблера. Если вы также как и я любите погружаться на низкий уровень, в те закоулки мира программирования, куда не всем путь открыт, то посмотрите. Возможно, что-то вам понравится. Подробнее... |
Давно хотел разобраться с этой темой. И вот наконец собрался.
Дело в том, что инструкции процессора Интел и синтаксис вставок ассемблерного кода в программы на Visual C++ не будут работать в Dev-C++.
Потому что Dev-C++ использует компилятор GCC (бесплатный компилятор языка С++). Этот компилятор имеет встроенный ассемблер, но это не MASM и не TASM с привычным набором команд. Это ассемблер AT&T, синтаксис которого очень сильно отличается от синтаксиса MASM/TASM и подобных.
Кроме того, если в Паскале или Visual C++ вы просто используете ключевые слова - операторные скобки (в Паскале это asm...end, в Visual C++ это __asm {...}), и между этими скобками пишите инструкции ассемблера как вы привыкли, то с компилятором GCC это не проканает.
Я сначала никак не мог понять, почему. Но когда немного познакомился с документацией, то понял.
Оказывается, в компиляторе GCC, как и в Паскале и в Visual C++, есть ключевые слова asm и __asm. Вот только это вовсе не операторные скобки!!!
По сути это функции, которые вызываются с определённым набором параметров. И в эти функции в качестве параметров передаются инструкции ассемблера!
Вот уж воистину - зачем просто, если можно сложно!
В общем, использование встроенного ассемблера GCC - это целая наука. Если интересно её освоить, то можете начать вот с этой статьи (это мой перевод английского оригинала).
А здесь я просто в самых общих чертах покажу, как можно использовать вставки на ассемблере в Dev-C++ (это будет также справедливо для других средств разработки, использующих компилятор GCC).
Ассемблер AT&T
Как я уже сказал, этот ассемблер сильно отличается от привычных нам инструкций процессора Интел. Здесь я не буду об этом говорить. Если кому интересно, то основные отличия описаны здесь.
Вставка на ассемблере в Dev-C++
Основной формат вставки кода ассемблера показан ниже:
asm("Здесь код на ассемблере");
Пример:
/* помещает содержимое ecx в eax */ asm("movl %ecx %eax"); /* помещает байт из bh в память, на которую указывает eax */ __asm__("movb %bh (%eax)");
Как вы могли заметить, здесь используются два варианта встраивания ассемблера: asm и __asm__. Оба варианта правильные. Следует использовать __asm__, если ключевое слово asm конфликтует с каким-либо участком вашей программы (например, в вашей программе есть переменная с именем asm).
Если встраивание кода на ассемблере содержит более одной инструкции, то мы пишем по одной инструкции в строке в двойных кавычках, а также суффикс ’\n’ и ’\t’ для каждой инструкции.
Пример
__asm__ ("movl %eax, %ebx\n\t" "movl $56, %esi\n\t" "movl %ecx, $label(%edx,%ebx,$4)\n\t" "movb %ah, (%ebx)");
Однако в большинстве случаев требуется обмен данными между кодом на ассемблере и переменными, которые объявлены в исходных кодах на языке высокого уровня.
Это тоже возможно. Общий формат ассемблерной вставки для компилятора GCC такой:
asm (assembler template : output operands /* не обязательно */ : input operands /* не обязательно */ : list of clobbered registers /* не обязательно */ );
Не буду здесь подробно всё это расписывать, так как это уже сделано здесь. Там же вы найдёте все подробности использования встроенного ассемблера компилятора GCC (ну хотя не все, а основные).
Я же здесь приведу пример, и на этом успокоюсь.
Для начала не очень хороший пример.
int x = 0, y = 0; cout << x << endl; __asm__("movl $1, %eax"); //mov eax, 1 __asm__("addl $10, %eax"); //add eax, 10 __asm__("movl %%eax, %0\n":"=b"(x)); //x = 11 cout << x << endl;
Не очень хороший он потому, что мы изменяем значения регистров, а потом получаем значение регистра eax в переменную х. Но при этом мы не заботимся о том, что состояние этих регистров может быть изменено где-то в другом месте. Так что это может привести к потенциальным неожиданностям.
Теперь попробуем сделать всё чуть более правильно (хотя и не идеально).
int y = 15, z = 10; cout << "y = " << y << ", z = " << z << endl; __asm__("addl %%ebx, %%eax" //eax = eax + ebx (eax = y + z) :"=a"(y) //Выход: из eax в y :"a"(y), "b"(z) //Вход: y будет в eax, z будет в ebx ); cout << "y + z = y = " << y << endl;
Здесь в ассемблерный код мы передаём значения переменных y и z. Значение у помещается в регистр еах (на это указывает буква “a”), а значение z помещается в регистр ebx (на это указывает буква “b”).
Сам ассемблерный код выполняет сложение значений регистров eax и ebx, и помещает результат в eax. А уже этот результат выводится в переменную y. То, что у - это выходная переменная, определяет модификатор “=”.
Ну вот как-то так. Это, конечно, в самых общих чертах. Если кого интересуют подробности, то см. здесь.
Вступить в группу "Основы программирования"
Подписаться на канал в РУТУБ Подписаться на рассылки по программированию |
Первые шаги в программирование
Главный вопрос начинающего программиста – с чего начать? Вроде бы есть желание, но иногда «не знаешь, как начать думать, чтобы до такого додуматься». У человека, который никогда не имел дело с информационными технологиями, даже простые вопросы могут вызвать большие трудности и отнять много времени на решение. Подробнее... |