Первые шаги на Assembler – Hello World для DOS
Автор: parrot 19.07.2017 09:49
Эту статью я вынужден начать с оправдания т.к. многие программисты считают ассемблер мертвым языком. Но так ли это на самом деле? И на сколько полезен ассемблер? Каковы его возможности? И в каких областях разработки ПО он применяется?
Что же такое assembler?
Ассемблер - (от англ. assembler - сборщик) - компьютерная программа, компилятор исходного текста программы, написанной на языке ассемблера, в программу на машинном языке (подробнее...).
По сути дела ассемблер является самым первым компилятором, позволявшим переводить понятный человеку код на языке ассемблер в понятный машине двоичный код.
Язык ассемблер - это низкоуровневый язык, слово низкоуровневый не значит то, что у ассемблера мало возможностей. Скорее наоборот, возможностей у него больше чем у других языков программирования, но что бы их реализовать нужно потратить большое количество времени, ведь программирование на низкоуровневом языке максимально приближает вас к написанию программ в машинных кодах, что безусловно дает большую гибкость, но и маленькую скорость разработки программного обеспечения. Хотя современные компиляторы языка ассемблер (самые известные masm, fasm, nasm. Как заметил один из людей на форуме, почти на каждую букву английского алфавита есть свой ассемблер.) дают возможности для программирования на ассемблере почти с такой же легкостью как и на языках высокого уровня, тенденция такова что мир идет к объектно-ориентированному программированию и кроссплатформенности чего ассемблер обеспечить на должном уровне не может.
Для чего нужен ассемблер?
Абсолютно бесполезных технологий не бывает, а если такие и создаются они быстро исчезают. Ассемблер до сих пор жив, а значит, его, где то применяют. Например, для написание драйверов, ядра таких операционных систем как windows, linux. Зачем там ассемблер? Ведь все это работало бы и без использования низкоуровневых языков. На сегодняшний день ассемблер обладает одним бесспорным преимуществом, программы написанные на нем работают в разы быстрей, чем подобные написанные на языках высокого уровня. Именно поэтому ассемблер подходит для написания критически важных участков кода, в которых необходимо серьезное быстродействие.
Но только ли для обеспечения быстродействия в программах нужен ассемблер? Нет, на мой взгляд, любой уважающий себя программист должен знать язык ассемблер, т.к. знание ассемблера и современных отладчиков очень часто помогают найти трудноуловимые ошибки в коде. Так же ассемблер серьезно помогает в понимании самой сути работы языков программирования, т.к. даже самые сложные действия складываются из маленьких кирпичиков, разобрать которые мы можем только благодаря ассемблеру.
У хакеров ассемблер всегда служил незаменимым инструментом для написания вирусов, руткитов, эксплойтов, шеллов, кряков, нахождение уязвимостей в ПО и т.д.
Приступим…
Написание своей первой программы на ассемблер мы будем под DOS. Почему именно под DOS?
Написание программ под DOS максимально раскрывает возможности ассемблера, т.к. DOS по сути получает все ресурсы компьютера она может на прямую работать со всеми устройствам и портами ввода/вывода как посредством функций BIOS, так и функций самой DOS (На самом деле если DOS программа запускается в среде ОС Windows, все ресурсов она не получает, Windows эмулирует все нужные для работы таких программ прерывания, таким образом, защищая себя от краха).
Написание программ под Windows в случае ассемблера легче, чем под DOS. Windows - это ОС в которой вся работа выполняется с помощью так называемых api. Api операционной системы это ни что иное как функции находящиеся в динамических библиотеках (.dll), передавая определенные данные этим функциям сама ОС выполняет всю рутинную работу, облегчая тем самым жизнь программистам.
Что нам нужно?
-
Для полноценной работы на ассемблере вам понадобится компилятор, выбрать можете один из трех:
-
MASM - http://masm32.com/
http://ru.wikipedia.org/wiki/MASM
-
NASM – http://nasm.us/
http://ru.wikipedia.org/wiki/NASM
-
FASM - http://flatassembler.net/
http://ru.wikipedia.org/wiki/Fasm
У каждого из компиляторов есть свои качества и недостатки, о которых вы можете почитать на страницах wiki. На официальных сайтах вы можете скачать сам компилятор и посмотреть более подробную документацию.
Так же вам понадобится отладчик, к сожалению, такие отладчики как IDA Pro и SoftICE стоят не малых денег, хотя их крякнутые версии можно найти в интернете. Я же рекомендую бесплатный отладчик OllyDbg, скачать который вы можете на официальном сайте OllyDbg.
Первая программа на ассемблере
.model tiny ;модель памяти .code ;начало сегмента кода org 100h ;отступ для PSP блока Begin: ;метка начала программы mov ah, 9 ;загружаем в регистр ah значение 9 mov dx, offset message ; в регистре dx указываем адрес (смешение) сообщения int 21h ;вызываем прерывание DOS 21 ret ; возврашаем управление message db «Hello World!», 0Dh, 0Ah, ‘$’ ;само сообщение end Begin;конец программы
Как скомпилировать?
Для того что бы скомпилировать программу типа COM в TASM вам надо набрать следующие две строки в командном интерпретаторе (cmd):
tasm hello.asm tlink /t /x hello.obj
Для того что бы скомпилировать программу типа COM в MASM вам надо набрать следующие три строки в командном интерпретаторе:
ml ./c hello.asm link hello.obj,,NUL,,, exe2bin hello.exe hello.com
В силу ограниченности данной статьи я не могу привести здесь все возможные примеры компиляции программ и обсудить все возможные ключи, это отдельная и очень большая тема. При желании вы всегда можете обратиться к справочному руководству конкретного ассемблера или одной из известных поисковых систем.
В каждом из приведенных примеров мы сначала получаем объектный файл (.obj), форматы объектных файлов у большинства ассемблеров одинаковые, так что можно спокойно пользоваться ассемблером из одного компилятора и компоновщиком из другого.
Разбор кода
Код программы на языке ассемблер для непосвященных выглядит ужасно, но не все так страшно.
Директива .tiny сообщает компилятору о том, что мы собрались использовать плоскую модель памяти, где код, данные и стек расположены в одном и том же сегменте размером 64кб, так же существуют и другие модели памяти, где код, стек и данные находятся в разных сегментах. Еще нужно упомянуть о модель памяти FLAT, она идентична TINY, за тем исключением, что в ней максимальный размер сегмента 4гб, т.к. используются 32-битные сегменты.
Директива .code говорит о том, что с этого момента начинается сегмент кода, на самом деле существуют так же и другие сегменты, например сегмент данных .data и сегмент стека .stack, с которыми вы познакомитесь в следующих статьях. В нашем же случае данные (сообщение) хранится в сегменте кода.
org 100h отодвигает начала программы на 256 байт (100h = 256 байт). Нужно это для того что бы программа разместила на месте первых свободных 256 байт так называемый PSP блок данных. В PSP программы могут получить количество доступной для приложения памяти, параметры командной строки и еще много полезной информации. На самом деле отодвигать можно не только начало программы с той же легкостью можно поставить эту строку кода в середине и в конце программы. Часто именно эта строчка кода говорит нам о том, что это COM программа. Программы под Windows в этом плане сложнее, PSP блока в них нет.
Метка Begin указывает начало первой команды и используется в директиве end. Директива end выполняет двоякую функцию говоря ассемблеру что в этом месте кончается код программы и тут же указывает с метки начинать выполнять эту программу. Вы можете сделать начала программы в середине листика если захотите, ассемблер вас поймет. Так же можете назвать метку не Begin, а Start или Adlfkjx не имеет значения, ассемблер все равно вас поймет.
Команда mov ah, 9 помешает в регистра ah номер функции DOS. Эта функция отвечает за вывод строки в STDOUT (стандартный вывод). Команда mov пожалуй одна из самых часто используемых команд в ассемблере, на сколько вы поняли она равносильна команде присваивания в языках высокого уровня (в Pascal`е и Delphi`и ah := 9; в С подобных языках ah = 9;). Но если в языках высокого уровня присваивать можно в любые переменные и массивы (области памяти) которые вы создали, то в ассемблере это не всегда так! В ассемблере есть регистры, вы можете расценивать их как переменные в языках высокого уровня (на самом деле это не так, регистры это специально выделенная «быстрая» область памяти в процессоре), вот в эти регистры вы и должны перемешать все те данные, с которыми вы будете работать. Опять же и в этом правиле много исключений, который мы с вами рассмотрим в следующих статьях.
Команда mov dx, offset message помешает в регистр dx смешение сообщения. Что такое смешение? В нашем конкретном примере можете рассматривать его как адрес сообщения. Почему именно адрес, а не само сообщение мы помешаем в регистр dx? Все просто, в регистр dx мы можем поместить только 16 бит (проще говоря, только 2 буквы в ANSI кодировке, подробнее про регистры и их назначение можно почитать на Википедии). Само сообщение хранится у нас так же в сегменте кода, выше я уже говорил, что есть так же и другие сегменты и обычно все статические данных хранят в сегменте данных, но в силу простоты нашей программы мы пока что храним данные в сегменте кода, выглядит это так:
message db «Hello World!», 0Dh, 0Ah, ‘$’
Эта строка заполняет данными 14 байт, ровно столько, сколько занимает сообщение «Hello World!» и два спец символа 0Dh и 0Ah, эти спец символы не что иное как перевод строки и возврат каретки (в C подобных языках /r/n, в Pascal подобных языках используются такие команды как WriteLn(); ). Знак доллара указывает ассемблеру что здесь строка заканчивается. Далее указатель на первую букву помешает в переменную message.
Нужен ли нам ассемблер?
Ответ на этот вопрос каждый найдет для себя сам. С одной стороны программистам на интерпретируемых языках (php, perl, python и т.д.) он как таковой не нужен, разве что для более детального понимания происходящих процессов. С другой стороны без понимания этих процессов можно ли назвать таких людей программистами?
Программистам же на компилируемых языках высокого уровня ассемблер бесспорно нужен, но можно обойтись и без него. Пусть каждый сам для себя решит, какой уровень овладения искусством программирования ему нужен…