Как создать файл asm

Обновлено: 16.05.2024

Объектный файл
Только что начал изучать Assembler и сразу же столкнулся с проблемой: не удаётся получить объектный.

не создается объектный файл в TASM
ЗАДАНИЕ: Имеется система трех уравнений и следующие данные: -строка десятичных байт X из двадцати.

Как создать COM-файл?
Здравствуйте. ; Programm Hello3 .MODEL SMALL .CODE org 100h begin: jmp start Hello DB.

  • под DOS
    D:\masm32\bin\ml /c /Cp D:\MYPROG\atest.asm
  • под Windows
    D:\masm32\bin\ml /c /Cp /Gz /ID:\masm32\include /coff /nologo D:\MYPROG\atest.asm

Что-то произошло, как бы малозаметное милькание. Под виндовс.

Добавлено через 2 минуты
Где его искать, объектный файл?

Добавлено через 1 час 7 минут
Не разобрался.

D:\masm32 это папка с подпапками ассемблера

D:\MYPROG\atest.asm это моя программа

Как создать обьектны файл в D:\MYPROG ?

Объектный файл будет создан в текущем каталоге (папке).

Перемещайся в каталог (папку) с твоей программой
cd D:\MYPROG
И будучи там запускай ассемблер, указав операционке где его брать :
D:\MASM32\BIN\ml ключи atest.asm
, это если у тебя MASM32 инсталлирован в папку D:\MASM32

Добавлено через 1 минуту
Ну да, инсталлирован в папку D:\MASM32

Добавлено через 16 минут
То есть так? cd D:\MYPROG D:\MASM32\BIN\ml

Так выходит ошибка, а так D:\MYPROG D:\MASM32\BIN\ml попадаю в папку D:\MYPROG

И так D:\MYPROG D:\masm32\topgun.exe попадаю в папку D:\MYPROG

>То есть так? cd D:\MYPROG D:\MASM32\BIN\ml
Да не в одну строчку. Это две отдельные команды. М-да. Позвольте начать с командной строки. как в ней двигаца назад?? Часто бывает ошибка , да и вообще.. Уже кучу разных клавиш наугад перепробовал.

В чистой командной строке мало средств редактирования. Ошибся, нажимаешь Backspace несколько раз, забивая набранное неправильно, потом вписываешь правильно. Ну и нажатие F3 вспоминает последнюю исполненную команду.

Очень удобно работать с командной строкой из под FAR. Ctrl-стрелка тогда перемещает курсор по кускам команды а строке. Ctrl-E вспоминает последнюю набранную команду. Alt-F8 выдает список уже набранных команд из которого можно выбрать. Можно вставлять в командную строку из буфера обмена по Shift-Ins.

Другой удобный способ - создать BAT-файл с командами командной строки и уже его запускать. BAT-файл можно редактировать как текстовый файл, например в блокноте.

Добавлено через 1 минуту
Наиболее удобный способ - работать с BAT-файлом сидя в FAR Manager-е

Добавлено через 5 минут
Те кто начинали в MS-DOS под Norton Commander-ом или Волков-коммандером или DOS-Navigator-ом типично сидят в FAR-е, поскольку для них интерфейс Виндоуз - это только время терять. Почти что угодно в FAR-е делается в несколько раз быстрее. У интерфейса Виндоуз только одно преимущество - он интуитивно понятен людям, которые компьютер видят первый раз.

Добавлено через 2 минуты
А чистой командной строкой, получаемой по cmd.exe, пользуются только мазохисты или на чужом компе, на котором FAR-а нет.

Решение

Dimka-novitsek,
я расскажу как использую один единственный бат-файл для работы с разными ассемблерами (tasm, masm, fasm, nasm, goasm) и при этом создаю разные типы файлов COM, EXE for DOS, EXE for Windows, SYS, DLL при желании можете продлить этот список самостоятельно.
Внутри нашего asm.bat вставим процедуру, которая по трем первым словам, разделенным пробелами или табуляцией составит метку, на которую передаст управление внутри asm.bat и там уже из нашего asm-файла сделают необходимый нам файл-результат

Первая программа на ассемблере.

Ещё мы знаем, что в указанном формате пишутся резидентные программы, драйверы и вирусы.

Для достижения нашей цели делаем следующее.

  • Скачиваем с нашего сайта архив (DOS-1.rar) с предустановленными DOSBox и программами. Запускаем DOSBox. Стартует эмулятор MS-DOS и Norton Commander пятой версии.
  • В папке D:\TASM.2_0\TASM\ находим текстовый файл PRG.ASM. Это обычный текстовый файл, который можно создать
    с помощью любого текстового редактора, с расширением ASM вместо TXT.
  • В файл вносим код:
;Строка, после точки с запятой является комментарием org 100h ; начальное значение смещения программы в памяти - 100h int 21h ; вызов т.н. "прерывания" - системной функции DOS message db "Hello, World!" , 0Dh , 0Ah , '$' ; строка для вывода

Чтобы посмотреть список всех возможных параметров с пояснениями для файлов tasm.exe и tlink.exe необходимо запустить эти программы без параметров. Если вы сделаете это, не выходя из оболочки NC, то, чтобы просмотреть чистое окно DOS нажмите Ctrl+O, чтобы вернуться в NC, нажмите сочетание клавиш повторно.

Батник COMPLEX.BAT предназначен для создания исполняемых файлов из двух файлов кода (названия обязательно должны быть prg.asm, prg1.asm).

Наша первая программа на ассемблере прекрасно работает!

Выше мы рассмотрели стандартный подход к программированию на TASM в системе MS-DOS. Указанным алгоритмом создания программ можно пользоваться и далее.

Можете попробывать TASMED в папке D:\UTILS\TASMED\. Программа уже настроена и готова к использованию.

Первая программа на ассемблере.

Первая программа на ассемблере в среде разработки TASMED.

  • подсветка ассемблерного синтаксиса;
  • возможность сохранения проектов под любым именем и в любой директории;
  • работа как с TASM, так и MASM.

Практические советы: группирование проектов, русский язык в MS-DOS.

Для того, чтобы в исходниках, которые вы будете просматривать в системе MS-DOS с использованием текстовых редакторов DOS и различных сред разработок нормально отображалась кириллица (например в комментариях к строкам кода) необходимо проделать следующие действия.

Конечно вопрос снимается сам собой, если комментарии писать на английском.

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

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

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

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

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

image

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

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

image

Отладка

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

image

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

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

Окно памяти (Debug > Windows > Memory) позволяет посмотреть дамп памяти, слева мы видим шестнадцатеричные адрес, справа шеснадцатеричные значения соответствующих ячеек памяти, можно перемещаться, вводя адрес в соответствующее поле в верху окна.


Файл – это совокупность данных, которая хранится на некотором внешнем носителе (флеш-накопитель, жесткий диск) и может загрузиться в ОЗУ по мере необходимости.

В настоящее время любая программа, будь то устаревшая или современная, использует файлы и работает с ними: файлы постоянно нужно открывать, закрывать, создавать, удалять, записывать, считывать. Программы чаще всего используют файлы в качестве хранилищ, в которые записываются произвольные данные: например, настройки программы, её данные. Они предоставляют возможность хранить данные даже после завершения работы программы, что может использоваться для передачи данных другим программам или различными запусками одной и той же программы. К тому же, данные, с которыми работает программа, могут быть очень большими и размера ОЗУ может не хватить, но файлы помогают решить эту проблему.

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

Файлы в основном бывают 2 видов: текстовые и бинарные. В данной статье рассматривается работа именно с текстовыми файлами.

Операции по работе с файлами

Создание файла осуществляется с помощью функции 3с H прерывания 21 h . В регистр DX должен лежать путь до файла в формате строки, которая заканчивается нулевым байтом (например,“ C :\путь\файл”,0). Важно замечание: если файл уже существует, то он будет полностью очищен. В регистр CX можно указать атрибуты файла, но не обязательно. При возникновении ошибки создания Carry Flag примет значение единицы, а в AX будет код ошибки. Если ошибки нет, то в регистре AX будет храниться дескриптор (идентификатор) файла.

Открытие файла осуществляется с помощью функции 3 dH прерывания 21 h . Как и при создании файла, путь до открываемого файла должен лежать в DX . В AL записывается режим открытия файла(0 – только чтение, 1-только запись, 2 – чтение и запись). Закрытие файла, дескриптор которого находится в BX , производится функцией 3 eH .

С помощью функции 40 h осуществляется запись данных в файл. В BX должен храниться дескриптор файла, в DX - адрес буфера, содержащего записываемые данные, в CX - число записываемых байт. После записи в регистре AL будет храниться число считанных байт.

Функция 3 FH отвечает за чтение данных из файла. Данные на вход аналогичны тем, что подаются для записи: в DX - адрес буфера для чтения данных, в CX – число считываемых байт. В результате в AX будет храниться число прочитанных байт.

Пример программы

Для демонстрации функций предположим, что имеется программа, которая позволяет работать с личными электроприборами. Пользователь вводит устройства: название, мощность, количество, время работы. Данные хранятся в оперативной памяти, и после выключение программы все данные исчезнут. Чтобы избежать этой проблемы, нужно хранить введенные пользователем устройства в файле. Рассмотрим программную реализацию ранее описанных операций с файлами в контексте данной программы:

data segment ;сегмент данных

device struc ;структура прибор

power dw ?;мощность прибора

num db ?;количество таких приборов

time db ?;время работы устройства в день

;необходимые данные для операции с файлами

handle dw ?;дескриптор файла

buffer dw ?;буфер для записи

code segment;сегмент кода

mov ax , data ;инициализация сегмента данных

mov dl,filename; названиефайла

mov cx ,0;без атрибутов

mov [ handle ], ax ;в handle хранится дескриптор созданного файла

;запись данных в файл

mov si , buffer ;запишем в файл

mov lamp . power , si ;мощность лампы

mov dx , buffer ;записываемые данные

mov bx ,[ handle ]; в bx дескриптор файла,в которой будем записывать данные

mov cx ,2;размер данных(мощность имеет тип dw -2 байта)

mov bx ,[ handle ];дескриптор закрываемого файла

mov dl , filename ;название файла

mov cx ,0;атрибутов нет

mov al ,0;режим открытия - только чтение

mov [ handle ], ax

mov bx ,[ handle ];дескриптор считываемого файла

mov dx , buffer ;буффер для данных

mov cx ,4;количество считываемых байт

mov ax , buffer ;считали мощность лампы

mov lamp.power,ax;из файла

;снова закроем файл

mov ax ,4 c 00 h ;выход из программы

Организацию работы с файлами на Ассемблере непросто освоить, ведь она гораздо сложнее, чем на языках высокого уровня . Однако оно того стоит, ведь это дает множество бесценных возможностей. Без использования файлов практически любая программа не имеет практического смысла. Практически все, что написано на ассемблере – драйвера, вирусы, антивирусы, элементы операционной системы - используют файлы для самых различных целей. Таким образом, любой программист, использующий язык Ассемблер для написания программ, должен владеть навыком работы с файлами.

От теоретического материала я уже немного устал. Решил попрактиковаться, а заодно и поэкспериментировать с сегментами. Для экспериментов выбрал программку из книги Феногенова, и чуток изменил ее (текст можно взять тут):


Она ассемблируется и TASM и MASM.

Ассемблеры, в процессе трансляции, позволяют создавать, так называемые, файлы листингов. Файл листинга содержит не только исходный текст, но и транслированный машинный код в шестнадцатеричном формате. Файлы листингов TASM и MASM немного различаются. Листинги TASM содержат еще и номера строк в самое левой колонке, после которой уже идут шестнадцатеричные адреса смещения команд и данных (в MASM колонка адресов первая) относительно начала сегмента . Затем показан ассемблированный машинный код в шестнадцатеричном формате и затем соответствующие ему команды ассемблера.
Итак, к практике! Для каждой программы я создаю отдельную папку и в ней две подпапки MASM и TASM. Чтобы ассемблировать программу я захожу в каждую из них FAR-ом и запускаю соответственно m.bat или t.bat (расширение .bat можно не указывать, просто m или t). И из открывшегося окна уже ассемблирую программу. Ассемблируем hello.asm TASM-ом с ключом получения листинга ( /l ). Вводим последовательно команды: tasm /l hello и затем tlink hello . Обратите внимание что для TASM расширение .asm указывать не обязательно. Смотрим скриншот:


В директории, помимо объектного файла и исполняемого, образовался файл листинга - hello.lst, и файл карты данных - hello.map. Смотрим hello.lst.


Команды имеют различную длину и располагаются в памяти вплотную друг к другу. Так, первая команда mov ax,data, начинается со смещения 0000 сегмента кода и занимает 3 байта. Соответственно вторая команда начинается со смещения 0003. Вторая команда имеет длину 2 байта, поэтому третья команда начинается с байта 0005 и т.д.
Предложения программы с директивами segment , assume , end не транслируются в какие-либо машинные коды (как это уже говорилось) и не находят отражения в памяти . Они нужны лишь для передачи транслятору служебной информации, управляющей ходом трансляции.
Транслятор не смог полностью определить код команды mov ax,data . В этой команде в AX засылается адрес сегмента data. Однако этот адрес станет известен лишь в процессе загрузки исполняемого файла программы в память . Поэтому в листинге на месте этого адреса стоят нули. Символ s указывает на то, что в дальнейшем вместо нулей сюда будет подставлен сегментный адрес.
Еще одна помеченная команда с кодом ВА 0000 располагается в строке 6 листинга. В этой команде в регистр DX заносится смещение поля с именем msg, расположенное в сегменте данных (ключевое слово offset, указанное перед именем поля, говорит о том, что речь идет не о содержимом ячейки msg, а об ее смещении). Поле msg расположено в самом начале сегмента данных, и его смещение от начала сегмента равно 0, что и указано в коде команды. Почему же эта команда помечена буквой r , являющейся сокращением слова relocatable - перемещаемый?
Чтобы ответить на этот вопрос, нам придется рассмотреть, как сегменты программы размещаются в памяти. Как уже говорилось, любой сегмент может располагаться в памяти только с адреса, кратного 16, т.е. на границе 16-байтового блока памяти (параграфа). Конкретный адрес программы в памяти зависит от конфигурации компьютера, - какой размер занимает DOS, сколько загружено резидентных программ и драйверов, а также в каком режиме запускается программа - в отладчике или без него. Предположим, что сегментный адрес сегмента команд оказался равным 1306h (а). В нашей программе сегмент команд имеет размер 11h байт (что указано в строке 10 и в разделе Groups & Segments листинга), т.е. занимает целый параграф плюс один байт. Сегмент данных имеет размер 14h байт (строка 15 листинга и раздел Groups & Segments) и тоже требует для своего размещения немного больше одного параграфа. Из-за того, что сегмент данных должен начаться на границе параграфа, ему будет назначен сегментный адрес 1308h и между сегментами образуется пустой промежуток размером 15 байт . По той же причине между сегментом данных и стека образуется пустой промежуток в 12 байт .
Потеря 27 байт из многомегабайтовой памяти, разумеется, не имеет никакого значения. Однако в некоторых случаях, например, при компоновке единой программы из большого количества модулей с небольшими по размеру подпрограммами, суммарная потеря памяти может оказаться значительной.


Для того, чтобы устранить потери памяти, можно сегмент данных объявить с выравниванием на байт:

что и видим в выводе команды DIR:


Образ программы в памяти начинается с сегмента префикса программы (Program Segment Prefics, PSP), образуемого и заполняемого системой . PSP всегда имеет размер 256 байт; он содержит таблицы и поля данных, используемые системой в процессе выполнения программы. Вслед за PSP располагаются сегменты программы в том порядке, как они объявлены в программе . Сегментные регистры автоматически инициализируются следующим образом: ES и DS указывают на начало PSP (что дает возможность, сохранив их содержимое, обращаться затем в программе к PSP), CS - на начало сегмента команд, a SS - на начало сегмента стека. В указатель команд IP загружается относительный адрес точки входа в программу ( из операнда директивы end ), а в указатель стека SP - величина, равная объявленному размеру стека, в результате чего указатель стека указывает на конец стека (точнее, на первое слово за его пределами ).
Таким образом, после загрузки программы в память адресуемыми оказываются все сегменты, кроме сегмента данных. Инициализация регистра DS в первых двух строках программы позволяет сделать адресуемым и этот сегмент.

Итак, первой исполняемой командой по адресу 144B мы видим:

144B:0000 B84D14 MOV AX,144D

Посмотрим внимательней на адресок 144D , который заносится в регистр AX. По идее это должен быть адрес сегмента данных, так как в тексте нашей программы этой строке соответствует команда mov ax,data . Код нашей программы (с учетом выравнивания на границу параграфа, 17 байт кода + 15 пустых байт) занимает 32 байта ( 20h байт), то есть два параграфа. Сегмент данных мы определили в нашей программе сразу за сегментом кода, то есть сегмент данных начинается через 20h байт от начала программы. Адрес в CS у нас равен 144B0 (не забываем про нолик). Прибавим 20h к 144B0h и получаем 144D0h. 144B0h+20h=144D0h . В листинге трансляции эта же команда определена как B8 0000s . Вспоминаем, что говорилось про буковку s . Этот адрес подставляется ОС в процессе загрузки программы в память . Кстати стоит еще заметить как выглядит код этой команды уже в памяти при исполнении - B84D14 . Как видим B8 осталась, а адрес записан сюда ОС с изменением очередности байт . Выполняем эту команду и смотрим состояние регистров. Затем выполняем вторую команду и смотрим состояние регистров и дамп сегмента кодов.


Еще стоит обратить внимание на изменение в регистре AX, после команды mov ah,09 . Изменился только старший байт, который принял занчение 09, а младший байт сохранил свое занчение 4D. А так же на то, что в регистр DX было помещено смещение (0000) от начала сегмента данных (в нашем случае выводимой на экран фразы).
Полный дам выполнения программы приведен ниже:

AX=144D BX=0000 CX=0140 DX=0000 SP=0100 BP=0000 SI=0000 DI=0000
DS=143B ES=143B SS=144F CS=144B IP=0003 NV UP EI PL NZ NA PO NC
144B:0003 8ED8 MOV DS,AX
-t

AX=144D BX=0000 CX=0140 DX=0000 SP=0100 BP=0000 SI=0000 DI=0000
DS=144D ES=143B SS=144F CS=144B IP=0005 NV UP EI PL NZ NA PO NC
144B:0005 B409 MOV AH,09
-d ds:0
144D:0000 2D 3D 2A 20 48 65 6C 6C-6F 20 57 6F 72 6C 64 20 -=* Hello World
144D:0010 2A 3D 2D 24 00 00 00 00-00 00 00 00 00 00 00 00 *=-$.
144D:0020 2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
144D:0030 2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
144D:0040 2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
144D:0050 2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
144D:0060 2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
144D:0070 2A 2A 2A 2A 2A 2A 2A 2A-2A 2A 2A 2A 2A 2A 2A 2A ****************
-t

AX=094D BX=0000 CX=0140 DX=0000 SP=0100 BP=0000 SI=0000 DI=0000
DS=144D ES=143B SS=144F CS=144B IP=0007 NV UP EI PL NZ NA PO NC
144B:0007 BA0000 MOV DX,0000
-t

AX=094D BX=0000 CX=0140 DX=0000 SP=0100 BP=0000 SI=0000 DI=0000
DS=144D ES=143B SS=144F CS=144B IP=000A NV UP EI PL NZ NA PO NC
144B:000A CD21 INT 21
-g 10d
-=* Hello World *=-
Программа завершилась нормально
-

Читайте также: