Компиляция ассемблер кода в windows

В этой статье мы рассмотрим процессы компиляции и компоновки программ на языке ассемблер для для операционных систем DOS и Windows. Напомню что компиляция — это процесс перевода файлов программы в так называемые объектные файлы. Объектные файлы — это файлы, в которых находится почти готовая программа в виде разрозненных кусков кода, связанных некоторой служебной информацией. Чтобы превратить эти куски кода в готовую программу используется компоновщик. Он выстраивает код в исполняемом файле в нужном порядке и создает готовый файл заданного формата. Этот получившийся файл уже можно исполнять.

Начнем с компиляции под DOS

В DOS существовало два вида исполняемых файлов: *.com и *.exe. Файлы *.com характеризуются тем, что весь код программы, данные и место для стека содержится в одном сегменте памяти, причем код программы должен находиться в сегменте со смещением в 256 байт (100h). Файлы формата *.exe не имеют ограничений на количество используемых сегментов памяти.

Для компиляции под DOS я использую компилятор MASM версии 6.11 и TASM версии 5.3

Компиляция и компоновка файлов *.com с помощью TASM:

    \tasm32\bin\tasm53.exe test.asm, test.obj, test.lst /z /t /ml /m2 /l
    \tasm32\bin\tlink.exe test.obj /x /t /3

Компиляция и компоновка файлов *.exe с помощью TASM:

    \tasm32\bin\tasm53.exe test.asm, test.obj, test.lst /z /t /ml /m2 /l
    \tasm32\bin\tlink test.obj, test.exe /x /3

Описание всех параметров можно получить, выполнив в командной строке tasm53.exe /? и tlink.exe /?
 

Компилятор MASM позволяет выполнять компиляцию и компоновку через вызов своей программы-оболочки ml.exe

Компиляция файлов *.com с помощью MASM:

    \masm611\bin\ml.exe test.asm /AT /Fl /link

Компиляция файлов *.exe с помощью MASM:

    \masm611\bin\ml.exe test.asm /Fl /link

Компиляция под Windows

Для компиляции под Windows используются компилятор MASM32 и TASM32.

Компиляция и компоновка файлов *.exe с помощью TASM32:

    \tasm32\bin\tasm32.exe test.asm, test.obj, test.lst /zi /t /ml /m3 /q
    \tasm32\bin\tlink32 /x /Tpe /ap /c /V4.0 test.obj, test.exe, , user32.lib

Компиляция файлов *.exe с помощью MASM32:

   \masm32\bin\ml.exe /c /coff test.asm
   \masm32\bin\link.exe /SUBSYSTEM:WINDOWS test.obj

После компиляции

После компиляции и компоновки у вас должен получиться исполняемый файл *.exe или *.com формата, в зависимости от того, какие параметры вы задавали компилятору.

Последнее обновление: 01.07.2023

Установка MASM

Для работы с MASM надо установить для Visual Studio инструменты разработки для C/C++. Поэтому после загрузки программы установщика Visual Studio запустим ее и в окне устанавливаемых
опций выберем пункт Разработка классических приложений на C++:

Установка MASM 64 в Windows

Visual Studio включает как 32-разрядные, так и 64-разрядные версии MASM. 32-раздяная версия представляет файл ml.exe,
а 64-разрядная — файл ml64.exe. Точное расположение файлов может варьироваться от версии Visual Studio. Например, в моем случае это папка
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\bin\Hostx64\x64

Ассемблер MASM64 в Windows

Для использования MASM64 перейдем к меню Пуск и в списке программ найдем пункт Visual Studio и подпункт
x64 Native Tools Command Prompt for VS 2022

Build Tools for Visual Studio 2022 и MASM64 в Windows

Нам должна открыться консоль. Введем в нее ml64, и нам отобразится версия ассемблера и некоторая дополнительная информация:

**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.5.5
** Copyright (c) 2022 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

C:\Program Files\Microsoft Visual Studio\2022\Community>ml64
Microsoft (R) Macro Assembler (x64) Version 14.35.32217.1
Copyright (C) Microsoft Corporation.  All rights reserved.

usage: ML64 [ options ] filelist [ /link linkoptions]
Run "ML64 /help" or "ML64 /?" for more info

C:\Program Files\Microsoft Visual Studio\2022\Community>

Стоит отметить, что запуск этой этой утилиты фактически представляет запуск файла C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat —
он по сути вызывает другой файл — vcvarsall.bat, который собственно и настраивает окружение для выполнения ассемблера.

Структура программы на ассемблере MASM

Типичная программа на MASM содержит одну или несколько секций, которые определяют, как содержимое программы будет располагаться в памяти. Эти секции
начинаются с таких директив MASM, как .code или .data. Данные, используемые в программе, обычно определяются в секции .data.
Инструкции ассембра определяются в секции .code.

В общем случае программа на ассемблере MASM имеет следующий вид:

.code

main proc
 
  ret
main endp

end

Директива .code указывает MASM сгруппировать операторы, следующие за ней, в специальный раздел памяти, зарезервированный для машинных инструкций.

Ассемблер преобразует каждую машинную инструкцию в последовательность из одного или нескольких байт. CPU интерпретирует эти значения байт как машинные инструкции во
время выполнения программы.

Далее с помощью операторов main proc определяется процедура main. Операторы main endp указывают на конец функции main.
Между main proc и main endp располагаются выполняемые инструкции ассемблера. Причем в самом конце функции идет инструкция ret,
с помощью которой выполнение возвращается в окружение, в котором была вызвана даннуа процедура.

В конце файла кода идет инструкция end

Программа может содержать комментарии, которые располагаются после точки с запятой:

.code   ; начало секции с кодом программы

main proc   ; Функция main
 
 ret ; возвращаемся в вызывающий код
 
main endp ; окончание функции main

end ; конец файла кода

Комментарии на работу программы никак не влияют и при компиляции не учитываются.

Компиляция программы

Компиляция программы на MASM обычно происходит в командной строке. Например, воспользуемся кодом выше и напишем простейшую программу на ассемблере, которая ничего
не делает. Для этого определим на жестком диске папку для файлов с исходным кодом. Допустим, она будет называться
C:\asm. И в этой папке создадим новый файл, который назовем hello.asm и в котором определим следующий код:

.code   ; начало секции с кодом программы

main PROC   ; Функция main
 
 ret ; возвращаемся в вызывающий код
 
main ENDP

END ; конец файла кода

Откроем программу x64 Native Tools Command Prompt for VS 2022 и перейдем в ней к папке, где располагается файл hello.asm. Затем выполним следующую команду

ml64 hello.asm /link /entry:main

В данном случае вызываем приложение ml64.exe и передаем ему для компиляции файл hello.asm. А флаг /link указывает MASM
скомпоновать скомпилированный файл в файл приложения exe, а все дальнейшие параметры (в частности, параметр /entry:main) передаются компоновщику.
Параметр /entry:main передает компоновщику имя основной процедуры/функции, с которой начинается выполнение программы.
Компоновщик сохраняет этот адрес этой процедуры/функции в специальном месте исполняемого файла, чтобы Windows могла определить начальный адрес основной программы после загрузки исполняемого файла в память.

В результате ассемблер скомпилирует ряд файлов

**********************************************************************
** Visual Studio 2022 Developer Command Prompt v17.5.5
** Copyright (c) 2022 Microsoft Corporation
**********************************************************************
[vcvarsall.bat] Environment initialized for: 'x64'

C:\Program Files\Microsoft Visual Studio\2022\Community>cd c:\asm

c:\asm>ml64 hello.asm /link /entry:main
Microsoft (R) Macro Assembler (x64) Version 14.35.32217.1
Copyright (C) Microsoft Corporation.  All rights reserved.

 Assembling: hello.asm
Microsoft (R) Incremental Linker Version 14.35.32217.1
Copyright (C) Microsoft Corporation.  All rights reserved.

/OUT:hello.exe
hello.obj
/entry:main

c:\asm>

В итоге в каталоге программы будут сгенерированы объектный файл hello.obj и собственно файл программы — hello.exe.

Время на прочтение
4 мин

Количество просмотров 142K

Многие из нас изучали ассемблер в университете, но почти всегда это ограничивалось простыми алгоритмами под 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) позволяет посмотреть дамп памяти, слева мы видим шестнадцатеричные адрес, справа шеснадцатеричные значения соответствующих ячеек памяти, можно перемещаться, вводя адрес в соответствующее поле в верху окна.

In this guide you will learn how to compile a MASM assembly file into a Windows executable.

Prerequisites

Before we begin you’re going to need to install MASM32. I’ve written a guide on how to do that. MASM includes the required compiler ml.exe and the linker link.exe. The documentation for each are below.

  • Compiler: https://docs.microsoft.com/en-us/cpp/assembler/masm/ml-and-ml64-command-line-reference?view=vs-2017
  • Linker: https://docs.microsoft.com/en-us/cpp/build/reference/linker-options?view=vs-2017

Once you have MASM installed copy the sample code below and save it as program.asm:

.386
.model flat,stdcall
.stack 4096
.code
main PROC
nop
main ENDP
END main

Our executable will do absolutely nothing. It will be used to test compilation and linking. Let’s do that …

The Not So Easy Way

Some time in the past it was possible to run ml.exe and have it produce an executable. This method has never worked for me for reasons I will discuss in a moment:

ml.exe program.asm 

On my system this produces the following error:

LINK : warning LNK4044: unrecognized option "z2"; ignored

This error occurs because the compiler attempts to compile and link, but if your ml.exe and link.exe versions do not match you will run into this same problem.

The reason is because ml.exe is attempting to pass the /z2 option to link.exe, but the linker doesn’t recognize the option. This is discussed in a bit more detail here.

Fear not my friends, there is a solution!

The Other Way

Instead of expecting ml.exe to call link.exe you can instead compile the assembly into .obj file and call link.exe yourself. An equally simple solution.

You do that like so:

ml.exe /c /coff program.asm
link.exe /subsystem:windows program.obj

The first line compiles the MASM assembly file into an COFF (common object file format) file. The /c option tells ml.exe to not run link.exe. The /coff option is what tells the compiler to generates a COFF file.

The second line runs the linker. The /subsystem:windows option is required and tells the operating system how to run the executable.

Running the 2 commands will compile and link your MASM assembly to produce a Win32 executable. Note the above will not work if you’re using MASM64.

If you have any problems or questions please leave a comment below.

💡 Assembly Language Weekly Newsletter

Every week I publish a newsletter that contains tutorials, tips, tricks and resources related to assembly language. If you would like to receive this newsletter subscribe here: http://eepurl.com/ghximb

How do you compile assembly code using Visual Studio?

I want to compile and run an assembly source file in Visual Studio 2010.

I’ve created a Visual C++ project and inserted some assembly code in a file code.asm:

.586              ;Target processor.  Use instructions for Pentium class machines
.MODEL FLAT, C    ;Use the flat memory model. Use C calling conventions
.STACK            ;Define a stack segment of 1KB (Not required for this example)
.DATA             ;Create a near data segment.  Local variables are declared after
                  ;this directive (Not required for this example)
.CODE             ;Indicates the start of a code segment.

clear PROC
   xor eax, eax 
   xor ebx, ebx 
   ret 
clear ENDP 
END

However the problem is when you try and compile this, you get:

LINK : error LNK2001: unresolved external symbol _mainCRTStartup

I did go and enable the build customization masm.targets (right click project > Build Customizations..), but to no avail.

Peter Mortensen's user avatar

asked Dec 28, 2010 at 19:19

bobobobo's user avatar

2

Sounds to me like the custom build rules for .asm files isn’t enabled. Right-click the project, Custom Build Rules, tick «Microsoft Macro Assembler». With the «END clear» directive and disabling incremental linking I’m getting a clean build.

It’s different starting from VS2010:

  1. Right-click Project, Build customizations, tick «masm«.
  2. Right-click the .asm file, Properties, change Item Type to «Microsoft Macro Assembler«.

rustyx's user avatar

rustyx

81k26 gold badges200 silver badges268 bronze badges

answered Dec 28, 2010 at 21:41

Hans Passant's user avatar

Hans PassantHans Passant

924k146 gold badges1696 silver badges2536 bronze badges

2

Command line:

Compile the code with:

ml /c /Cx /coff code.asm

You get code.obj as the output.

Link with:

link code.obj /SUBSYSTEM:console /out:go.exe /entry:clear

You can now run go.exe.

Alternatively, do it all in one go with:

ml /Cx /coff code.asm /link /SUBSYSTEM:console /link /entry:clear

Visual Studio (not solved)

answered Dec 28, 2010 at 21:19

bobobobo's user avatar

bobobobobobobobo

65.1k62 gold badges259 silver badges363 bronze badges

2

Visual Studio includes the MASM macro assembler. Smaller fragments of assembler code are often written in inline assembly in a C or C++ program.

To integrate an assembler file in a Visual Studio project, create a regular C/C++ project (command line or GUI), and just add a file ending in .asm to the list of source files.

To specify clear as the entry point, follow these instructions:

  1. Open the project’s Property Pages
    dialog box. For details, see Setting
    Visual C++ Project Properties.

  2. Click the Linker folder.

  3. Click the Advanced property page.

  4. Modify the Entry Point property.

(It was taken from the Visual Studio documentation.)

I can confirm Hans Passant’s instruction. In addition, according to this article, if you first add the «build customizations» masm checkbox, and then add the file, it will automatically be recognized as an assembler file. Furthermore, not specifying the entry point name in the END directive, but instead specifying it in the project settings also works for me.

Peter Mortensen's user avatar

answered Dec 28, 2010 at 19:23

Martin v. Löwis's user avatar

Martin v. LöwisMartin v. Löwis

125k19 gold badges198 silver badges235 bronze badges

0

here is how to compile nasm assembly source code with vs20xx:

  1. «Excluded From Build» to «No»

  2. «Item Type» to «Custom Build Tool»

  3. Hit Apply

  4. Custom Build Tool -> General -> Command Line:

    c:\nasm\nasm -f win64 my_asm.asm

  5. Custom Build Tool -> General -> Outputs:

    my_asm.obj

  6. call the function like this:

    extern «C» int foo(void); // written in assembly!

https://www.cs.uaf.edu/2017/fall/cs301/reference/nasm_vs/

nasm tutorial:

http://cs.lmu.edu/~ray/notes/nasmtutorial/

answered Mar 20, 2019 at 6:43

sailfish009's user avatar

sailfish009sailfish009

2,5711 gold badge24 silver badges31 bronze badges

The problem is that your assembly code is just a function. To compile and link, you need to have a start procedure just like Main in C/C++. You can specify the start symbol by specifying in your END directive. Like:

END clear

Or if you want, you can link the .obj file generated with the C/C++ generated .obj one.

Peter Mortensen's user avatar

answered Dec 28, 2010 at 21:04

Madhur Ahuja's user avatar

Madhur AhujaMadhur Ahuja

22.2k14 gold badges71 silver badges124 bronze badges

3

  • Компиляция python в exe windows
  • Компьютер бесконечно перезагружается после установки windows
  • Компьютер выключается но вентиляторы работают windows 10
  • Компьютер выключается во время загрузки windows
  • Компоненты программного обеспечения windows 10