Ассемблер для Windows используя Visual Studio

Многие из нас изучали ассемблер в университете, но почти всегда это ограничивалось простыми алгоритмами под DOS. При разработке программ для Windows может возникнуть необходимость написать часть кода на ассемблер, в этой статье я хочу рассказать вам, как использовать ассемблер в ваших программах под Visual Studio 2005.

image

Создание проекта


В статье мы рассмотрим как вызывать ассемблер из С++ кода и обратно, передавать данные, а также использовать отладчик встроенный в Visual Studio 2005 для отладки кода на ассемблер.

Для начала нам нужно создать проект. Включаем Visual Studio, выбираем File > New > Project. В Visual Studio нет языка ассемблер в окне выбора типа проекта, поэтому создаем С++ Win32 проект. В окне настроек нового проекта выбираем «Empty Project».

image

По умолчанию Visual Studio не распознает файлы с кодом на ассемблер. Для того чтобы включить поддержку ассемблер нам необходимо настроить в проекте условия сборки указав какой программой необходимо компилировать файлы *.asm. Для этого выбираем пункт меню «Custom Build Rules...».

image

В открывшемся окне мы можем указать специальные правила компиляции для различных файлов, Visual Studio 2005 уже имеет готовое правило для файлов *.asm, нам необходимо лишь включить его, установив напротив правила «Microsoft Macro Assembler» галочку.

image

Добавление исходного кода


Перейдем к написанию исходного кода нашего проекта. Начнем с добавления исходного кода на c++. Добавим новый файл в папку Source Files. В качестве Template выбираем C++ File и вводим желаемое имя файла, например main.cpp. Напишем функцию, которая будет считывать имя введенное пользователем, оформив это в виде функции readName() которая будет возвращать ссылку на считанное имя. Мы получим примерно следующее содержимое файла:

#include <stdio.h>
 
void main ()
{
    printf("Hello, what is your name?\n");
}

void* readName()
{
    char name[255];        
    scanf("%s", &name);
    return &name;
}


Теперь, когда мы знаем имя пользователя мы можем вывести приветствие, его будет выводить функция sayHello() которую мы напишем на ассемблер, чтобы использовать эту функцию сначала мы должны указать что она будет определена в другом файле, для этого добавим блок к main.cpp:

extern "C"
{
    void sayHello();
}


Этот блок говорит компилятору, что функция sayHello() будет объявлена в другом файле и будет иметь правила вызова «C». Компилятор C++ искажает имена функций так, что указание правил вызова обязательно. Кроме того мы хотим использовать функцию readName() из функции sayHello(), для этого необходимо добавить extern «C» перед определением функции readName(), это позволит вызывать эту функцию из других файлов используя правила вызова «C».

Пришло время добавить код на ассемблер, для этого добавим в Source Folder новый файл. Выбираем тип Text File (.txt) и в поле название заменяем .txt на .asm, назовем наш файл hello.asm. Объявим функцию sayHello() и укажем внешние функции, которые мы хотим использовать. Получим следующий код:

.686
.MODEL FLAT, C
.STACK

.DATA
    helloFormat BYTE "Hello %s!",10,13,0
    
.CODE
readName PROTO C
printf PROTO arg1:Ptr Byte, printlist: VARARG
sayHello PROC
    invoke readName
    invoke printf, ADDR helloFormat, eax
    ret
sayHello ENDP
END


Теперь мы можем запустить проект, для этого просто выбираем Debug > Start Without Debugging или нажимаем комбинацию Ctrl-F5. Если все сделано верно, вы увидите окно программы:

image

Немного усложним задачу, попробуем написать на ассемблер функцию принимающую параметр и возвращающую значение. Для примера напишем функцию calcSumm() которая будет принимать целое число и возвращать сумму его цифр. Изменим наш код на С++ добавив в него информацию о функции calcSumm, ввод числа и собственно вызов функции. Добавим функцию в файл hello.asm, возвращаемое значение помещается в eax, параметры объявляются после ключевого слова PROC. Все параметры можно использовать в коде процедуры, они автоматически извлекутся из стека. Также в процедурах можно использовать локальные переменные. Вы не можете использовать эти переменные вне процедуры. Они сохранены в стеке и удаляются при возврате из процедуры:

.686              
.MODEL FLAT, C
.STACK
.DATA
    helloFormat	BYTE	"Hello %s!",10,13,0
	
.CODE
readName	PROTO	C
printf		PROTO	arg1:Ptr Byte, printlist: VARARG

sayHello PROC	
    invoke readName			
    invoke printf, ADDR helloFormat, eax
    ret	
sayHello ENDP 

calcSumm PROC a:DWORD	
    xor esi, esi
    mov eax, a
    mov	bx, 10
@div:
    xor	edx, edx
    div	bx
    add	esi, edx	
    cmp	ax, 0
    jne	@div
    mov eax, esi
    ret
calcSumm ENDP

END 


Запустив проект мы увидим следующий результат выполнения:

image

Отладка


Конечно в данной задаче нет ничего сложного и она вовсе не требует использования ассемблер. Более интересным будет рассмотреть, а что же нам дает Visual Studio для разработки на ассемблер. Попробуем включить режим отладки и установим точку остановки в hello.asm, запустим проект, мы увидим следующее:

image

Окно Disassembly (Debug > Windows > Disassembly) показываем команды ассемблер для данного объектного файла. Код который мы написали на С++ показывается черным цветом. Disassembled code показывается серым после соответствующего ему кода на C++/ассемблер. Окно Disassembly позволяет отлаживать код и осуществлять stepping по нему.

Окно регистров (Debug > Windows > Registers) позволяет посмотреть значение регистров.

Окно памяти (Debug > Windows > Memory) позволяет посмотреть дамп памяти, слева мы видим шестнадцатеричные адрес, справа шеснадцатеричные значения соответствующих ячеек памяти, можно перемещаться, вводя адрес в соответствующее поле в верху окна.
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 31

    +3
    А зачем столько сложностей с прописыванием компиляторов и т.д. Чем не подходит Inline Assembler?
    msdn.microsoft.com/en-us/library/4ks26t93.aspx
      +7
      Inline Assembler отлично подходит, описанный в статье метод может пригодиться например если есть уже готовый код на ассемблер, мы можем просто добавить .asm файл и вызывать его напрямую.

      Кроме того мы можем создать проект используя только .asm файлы (без С++), добавив метод main:
      .CODE
      main PROC
      invoke printf, ADDR helloWorld
      ret
      main ENDP
        +2
          0
          Кстати, да. Как-то даже не думал, что с этим проблемы могут быть. В качестве некоторой замены, правда есть x64 Intrinsics
            0
            Честно говоря, чем думать как уложиться в intrinsics и во что оно перейдет при компиляции — порой проще на ассемблере написать. Вот для использования SIMD-инструкций порой действительно хватает их intristic эквивалентов.
        +3
        >создать проект используя только .asm файлы (без С++)
        Тогда может не создавать С++ проект в VS, а использовать для этого другие инструменты?)
          0
          В студии уже есть готовый и очень неплохой отладчик. Плюс привычка. Для кого-то это может быть определяющим фактором. Как вариант возможно, что имеется несколько проектов, один из которых — библиотека на ассемблере. Такой метод позволит всё держать в одном месте.
          Ну и последний тезис «за» — вставки ассемлера ограничены в возможностях — емнип, нельзя объявлять данные, что приведёт к мешанине двух языков в пределах одной функции.
          Правда в Visual Studio нет подсветки синтаксиса для Asm (хотя где-то помнится пробегала инструкция по допиливанию подсветки, может даже на хабре).
            0
            А чем SoftICE плох? В своё время написаное на MASM'e да и не только отлаживалось именно им, хотя конечно, у всех свои предпочтения)
            • UFO just landed and posted this here
              • UFO just landed and posted this here
                0
                Я не говорю, что плох (хотя, имхо, большинство его плюсов для исследования программы или уровня ядра, где студия вообще не даст развернуться, ну разве что 2 компа и COM порт :) или в этом плане уже что-то улучшилось?). Просто если уже есть студия с неплохим отладчиком — то почему её не использовать?
                  0
                  2 компа не нужно. достаточно виртуальной машины
                  0
                  Айс больше заточен под отладку драйверов. Дебажить им обычные программы неудобно.
              +1
              В статье есть борьба с искажением имён компилятором C++. Но C++ кода нет. Может, использовать в качестве основного файла main.c, чтобы проблемы не возникало?
                0
                Насколько я понял, это просто пример. В реальном C++ приложении так обойтись не получится:)
                0
                Интересная статья!
                Я у себя в Колледже и вправду учил только асм на консольке. Теперь буду пробовать переходить под Win.
                Спасибо!
                • UFO just landed and posted this here
                    +18
                    void* readName()
                    {
                    char name[255];
                    scanf("%s", &name);
                    return &name;
                    }

                    Возвращение указателя на локальные данные процедуры это так брутально…
                      +4
                      Вообще-то, слово «ассемблер» легко склоняется:

                      И. ассемблер
                      Р. ассемблера
                      Д. ассемблеру
                      В. ассемблер
                      Т. ассемблером
                      П. ассемблере

                      Или у вас старая болезнь переводчиков, связанная с боязнью склонять иностранные слова? Раньше вот «Интернет» не склоняли.

                      • UFO just landed and posted this here
                        +2
                        Может, стоило бы упомянуть, что возврат адреса локальной переменной в других случаях чревато осложнениями?
                          +2
                          Кстати, здесь можно найти информацию о том, как добавить поддержку асма и для 2010 вижлы, и как прикрутить к ней же подсветку синтаксиса асма, а так же там море другой интересной информации.
                            –1
                            При разработке программ для Windows может возникнуть необходимость написать часть кода на ассемблер.


                            Программ? Нда…
                            Необходимость написать часть кода на ассемблере может возникнуть (а может и не возникать) при разработке драйверов специфичных устройств, но никак не программ.
                              0
                              Помнится, как-то оптимизируя программу заменил кусочек кода на вставку ASM размером всего десяток строк. Получил прирост скорости итераций в сотни раз.
                              Вместо нескольких минут результат выдавался через доли секунд.
                                +2
                                Ахахах. Это не означает, что того же самого нельзя было добиться без использования ассемблера.

                                Если Вас не затруднит, приведите, пожалуйста, пример high-level кода и, соответственно, low-level кода которым Вы его заменили, получив прирост в сотни раз — будет очень любопытно посмотреть этот парадоксальный пример — возможно, научусь чему-нибудь.
                                  0
                                  High-level уже нету. за 10 лет потерялся (только заново писать). а asm попробую завтра найти. Это на PC.

                                  Я сейчас с сигнальными процессорами связан. Так вот любая быстрая цифровая обработка сигналов немыслима без asma.
                                  А вот драйверы отлично пишутся на C/C++, т.к. там примитивные команды управления и никакие специфические инструкции процессора не требуются.
                                0
                                Вы занимаетесь коммерческой разработкой на С++? Я признаюсь на С++/ASM писал только для себя, поэтому не могу ничего утверждать. Но ведь есть множество вещей вроде MMX/SSE, декодирования видео и т.п. и даже если есть обертки на С++ для их использования, эти обертки ведь тоже кто-то писал?

                                В целом не берусь утверждать, но думаю тут работает «никогда не говори никогда». У меня например была необходимость написать часть кода на ассемблер, пусть и в учебных целях, но необходимость.

                                Специально сейчас скачал исходники mplayer, минимум 15 файлов полностью на ассемблере, чем это не программа?
                                  0
                                  Занимался.

                                  Эти 15 файлов, я думаю, отвечают за декодирование видео используя очень низкоуровневые методики (перечисленные Вами SIMD, а также, CUDA и т.д.).

                                  У меня, наверное, какой-то неправильный подход, но я никогда (да, да, никогда) не возьмусь за реализацию декодирования видео, кроме случая, если вся моя задача будет состоять в написании декодера видео. Точно также, как Вы не будете писать драйвер мыши при разработке GUI.

                                  Опять же, наверняка, я какие-то неправильные программы пишу, если у меня никогда не встречается интенсивных вычислительных задач. Я имею ввиду настолько интенсивных, чтобы их можно было бы ощутимо улучшить при помощи низкоуровневых хаков (давайте не будем забывать, что это именно хаки). Из практики могу вспомнить всего два проекта с интенсивными вычислениями. В одном использовался С++ только потому, что аналогов такой удобной геометрической библиотеки, как CGAL для .NET я не нашёл (там ещё потянулись большие числа GMP, MPFR, так что о .NET можно было сразу позабыть, если не хотелось изобретать аналоги драйверам мыши, только в мире математических алгоритмов). Во втором проекте на ура был использован C#. Я не хочу здесь втягиваться в холивар C# vs C++ (сам фанат C++, но помимо фанатизма есть ещё реальная жизнь — C# объективно позволяет реализовывать проекты на порядки быстрее).
                                –3
                                При разработке программ для Windows может возникнуть необходимость написать часть кода на ассемблере.

                                Я просто оставлю это без комментария.
                                  0
                                  >По умолчанию Visual Studio не распознает файлы с кодом на ассемблер.

                                  Это действительно так. По-моему, это связано с тем, что при создании файла из студии нет выбора типа .asm — можно создать текстовый файл и сменить расширение.

                                  Но, если вы вдруг забыли, где настраивается Custom build rules, можно просто исключить файл .asm из проекта и добавить его снова — в этом случае система подхватит его правильно и предложит диалоговое окошко, в котором уже есть соответствующее правило.

                                    0
                                    Многие из нас изучали ассемблер в университете, но почти всегда это ограничивалось простыми алгоритмами под DOS.

                                    У нас, к сожалению, было ещё хуже — даже до ввода-вывода чего-то в консоль под DOS дело не дошло.

                                    Полезная статья!

                                    Only users with full accounts can post comments. Log in, please.