Введение в язык Assembler. Специфические особенности языка ассемблер

Эту идею мы вынашивали долго. Наверное, несколько лет мы штурмовали ее со всех сторон, и всякий раз нам что-нибудь мешало. С одной стороны, ассемблер - это круто настолько, насколько вообще может быть круто для нашего читателя-хакера (крякера, реверсера) умение общаться с компьютером на его языке. С другой стороны - актуальных руководств по асму, в том числе издания этого века, достаточно, а времена нынче либеральные, веб-хакеры и любители JS могут нас не понять и не одобрить. 🙂 Точку в споре физиков, лириков, старообрядцев, никониан, веб-хакеров и тру-крякеров поставил успех . Оказалось, что сейчас, в XXI веке, тру-крякеры все еще не сдали своих позиций и нашим читателям это интересно!

Но что такое программирование само по себе по своей сути, вне зависимости от какого-либо языка? Разнообразие ответов поражает. Наиболее часто можно услышать такое определение: программирование - это составление инструкций или команд для последовательного исполнения их машиной с целью решить ту или иную задачу. Такой ответ вполне справедлив, но, на мой взгляд, не отражает всей полноты, как если бы мы назвали литературу составлением из слов предложений для последовательного прочтения их читателем. Я склонен полагать, что программирование ближе к творчеству, к искусству. Как любой вид искусства - выражение творческой мысли, идеи, программирование представляет собой отражение человеческой мысли. Мысль же бывает и гениальная, и совершенно посредственная.

Но, каким бы видом программирования мы ни занимались, успех зависит от практических навыков вкупе со знанием фундаментальных основ и теории. Теория и практика, изучение и труд - вот краеугольные камни, на которых основывается успех.

В последнее время ассемблер незаслуженно находится в тени других языков. Обусловлено это глобальной коммерциализацией, направленной на то, чтобы в максимально короткие сроки получить как можно большую прибыль от продукта. Иными словами, массовость взяла верх над элитарностью. А ассемблер, по моему мнению, ближе к последнему. Гораздо выгоднее в сравнительно небольшие сроки поднатаскать ученика в таких, например, языках, как С++, С#, PHP, Java, JavaScript, Python, чтобы он был более-менее способен создавать ширпотребный софт, не задаваясь вопросами, зачем и почему он так делает, чем выпустить хорошего специалиста по ассемблеру. Примером тому служит обширнейший рынок всевозможных курсов по программированию на любом языке, за исключением ассемблера. Та же тенденция прослеживается как в преподавании в вузах, так и в учебной литературе. В обоих случаях вплоть до сегодняшнего дня большая часть материала базируется на ранних процессорах серии 8086, на так называемом «реальном» 16-битном режиме работы, операционной среде MS-DOS! Возможно, что одна из причин в том, что, с одной стороны, с появлением компьютеров IBM PC преподавателям пришлось перейти именно на эту платформу из-за недоступности других. А с другой стороны, по мере развития линейки 80х86 возможность запуска программ в режиме DOS сохранялась, что позволяло сэкономить деньги на приобретение новых учебных компьютеров и составление учебников для изучения архитектуры новых процессоров. Однако сейчас такой выбор платформы для изучения совершенно неприемлем. MS-DOS как среда выполнения программ безнадежно устарела уже к середине девяностых годов, а с переходом к 32-битным процессорам, начиная с процессора 80386, сама система команд стала намного более логичной. Так что бессмысленно тратить время на изучение и объяснение странностей архитектуры реального режима, которые заведомо никогда уже не появятся ни на одном процессоре.

Что касается выбора операционной среды для изучения ассемблера, то, если говорить о 32-битной системе команд, выбор сравнительно невелик. Это либо операционные системы Windows, либо представители семейства UNIX.

Также следует сказать несколько слов о том, какой именно ассемблер выбрать для той или другой операционной среды. Как известно, для работы с процессорами х86 используются два типа синтаксиса ассемблера - это синтаксис AT&T и синтаксис Intel. Эти синтаксисы представляют одни и те же команды совершенно по-разному. Например, команда в синтаксисе Intel выглядит так:

Mov eax,ebx

В синтаксисе же AT&T уже будет иной вид:

Movl %eax,%ebx

В среде ОС UNIX более популярен синтаксис типа AT&T, однако учебных пособий по нему нет, он описывается исключительно в справочной и технической литературе. Поэтому логично выбрать ассемблер на основе синтаксиса Intel. Для UNIX-систем есть два основных ассемблера - это NASM (Netwide Assembler) и FASM (Flat Assembler). Для линейки Windows популярностью пользуются FASM и MASM (Macro Assembler) от фирмы Microsoft, и также существовал еще TASM (Turbo Assembler) фирмы Borland, которая уже довольно давно отказалась от поддержки собственного детища.

В данном цикле статей изучение будем вести в среде Windows на основе языка ассемблера MASM (просто потому, что он мне нравится больше). Многие авторы на начальном этапе изучения ассемблера вписывают его в оболочку языка си, исходя из тех соображений, что перейти к практическим примерам в операционной среде якобы довольно трудно: нужно знать и основы программирования в ней, и команды процессора. Однако и такой подход требует хоть мало-мальских начатков знаний в языке си. Данный же цикл статей от самого своего начала будет сосредоточен только на самом ассемблере, не смущая читателя ничем иным, ему непонятным, хотя в дальнейшем и будет прослеживаться связь с другими языками.

Следует отметить, что при изучении основ программирования, и это касается не только программирования на ассемблере, крайне полезно иметь представление о культуре консольных приложений. И совершенно нежелательно начинать обучение сразу же с создания окошечек, кнопочек, то есть с оконных приложений. Бытует мнение, что консоль - архаичный пережиток прошлого. Однако это не так. Консольное приложение почти лишено всякой внешней зависимости от оконной оболочки и сосредоточено главным образом на выполнении конкретно поставленной задачи, что дает прекрасную возможность, не отвлекаясь ни на что другое, концентрировать внимание на изучении базовых основ как программирования, так и самого ассемблера, включая знакомство с алгоритмами и их разработку для решения практических задач. И к тому моменту, когда настанет время перейти к знакомству с оконными приложениями, за плечами уже будет внушительный запас знаний, ясное представление о работе процессора и, самое главное, осознание своих действий: как и что работает, зачем и почему.

Что такое ассемблер?

Само слово ассемблер (assembler) переводится с английского как «сборщик». На самом деле так называется программа-транслятор, принимающая на входе текст, содержащий условные обозначения машинных команд, удобные для человека, и переводящая эти обозначения в последовательность соответствующих кодов машинных команд, понятных процессору. В отличие от машинных команд, их условные обозначения, называемые также мнемониками , запомнить сравнительно легко, так как они представляют собой сокращения от английских слов. В дальнейшем мы будем для простоты именовать мнемоники ассемблерными командами. Язык условных обозначений и называется языком ассемблера .

На заре компьютерной эры первые ЭВМ занимали целые комнаты и весили не одну тонну, имея объем памяти с воробьиный мозг, а то и того меньше. Единственным способом программирования в те времена было вбивать программу в память компьютера непосредственно в цифровом виде, переключая тумблеры, проводки и кнопочки. Число таких переключений могло достигать нескольких сотен и росло по мере усложнения программ. Встал вопрос об экономии времени и денег. Поэтому следующим шагом в развитии стало появление в конце сороковых годов прошлого века первого транслятора-ассемблера, позволяющего удобно и просто писать машинные команды на человеческом языке и в результате автоматизировать весь процесс программирования, упростить, ускорить разработку программ и их отладку. Затем появились языки высокого уровня и компиляторы (более интеллектуальные генераторы кода с более понятного человеку языка) и интерпретаторы (исполнители написанной человеком программы на лету). Они совершенствовались, совершенствовались - и, наконец, дошло до того, что можно просто программировать мышкой.

Таким образом, ассемблер - это машинно ориентированный язык программирования, позволяющий работать с компьютером напрямую, один на один. Отсюда и его полная формулировка - язык программирования низкого уровня второго поколения (после машинного кода). Команды ассемблера один в один соответствуют командам процессора, но поскольку существуют различные модели процессоров со своим собственным набором команд, то, соответственно, существуют и разновидности, или диалекты, языка ассемблера. Поэтому использование термина «язык ассемблера» может вызвать ошибочное мнение о существовании единого языка низкого уровня или хотя бы стандарта на такие языки. Его не существует. Поэтому при именовании языка, на котором написана конкретная программа, необходимо уточнять, для какой архитектуры она предназначена и на каком диалекте языка написана. Поскольку ассемблер привязан к устройству процессора, а тип процессора жестко определяет набор доступных команд машинного языка, то программы на ассемблере не переносимы на иную компьютерную архитектуру.

Поскольку ассемблер всего лишь программа, написанная человеком, ничто не мешает другому программисту написать свой собственный ассемблер, что часто и происходит. На самом деле не так уж важно, язык какого именно ассемблера изучать. Главное - понять сам принцип работы на уровне команд процессора, и тогда не составит труда освоить не только другой ассемблер, но и любой другой процессор со своим набором команд.

Синтаксис

Общепринятого стандарта для синтаксиса языков ассемблера не существует. Однако большинство разработчиков языков ассемблера придерживаются общих традиционных подходов. Основные такие стандарты - Intel-синтаксис и AT&T-синтаксис .

Общий формат записи инструкций одинаков для обоих стандартов:

[метка:] опкод [операнды] [;комментарий]

Опкод - это и есть собственно ассемблерная команда, мнемоника инструкции процессору. К ней могут быть добавлены префиксы (например, повторения, изменения типа адресации). В качестве операндов могут выступать константы, названия регистров, адреса в оперативной памяти и так далее. Различия между стандартами Intel и AT&T касаются в основном порядка перечисления операндов и их синтаксиса при разных методах адресации.

Используемые команды обычно одинаковы для всех процессоров одной архитектуры или семейства архитектур (среди широко известных - команды процессоров и контроллеров Motorola, ARM, x86). Они описываются в спецификации процессоров.

Оригинал: Get started in assembly language. Part 1
Автор: Mike Saunders
Дата публикации: 30 октября 2015 г.
Перевод: А.Панин
Дата перевода: 10 ноября 2015 г.

Часть 1: Преодолеваем ограничения высокоуровневых языков программирования и разбираемся, как на самом деле работает центральный процессор.

Для чего это нужно?

  • Для понимания принципов работы компиляторов.
  • Для понимания инструкций центрального процессора.
  • Для оптимизации вашего кода в плане производительности.

Большинство людей считает, что язык ассемблера мало чем отличается от черной магии и является частью темного и страшного мира, в который рискует войти лишь 0.01% лучших разработчиков программного обеспечения. Но на самом деле это красивый и очень доступный язык программирования. Вам стоит изучить его основы хотя бы для того, чтобы лучше понимать механизм генерации кода компиляторами, принцип работы центральных процессоров, а также лучше представлять принцип работы компьютеров. Язык ассемблера по своей сути является текстовым представлением инструкций, которые исполняет центральный процессор, с некоторыми дополнительными возможностями, упрощающими процесс программирования.

На сегодняшний день никто в здравом уме не станет разрабатывать мощное приложение для настольного компьютера на языке ассемблера. Ведь код такого приложения будет слишком запутанным, процесс отладки приложения будет значительно усложнен, кроме того придется приложить колоссальные усилия, чтобы портировать это приложение для работы с другими архитектурами центральных процессоров. Но при этом язык ассемблера все же используется для различных целей: многие драйверы из состава ядра Linux содержат фрагменты кода на языке ассемблера, который используется как из-за того, что является лучшим языком программирования для непосредственного взаимодействия с аппаратным обеспечением, так и из соображения повышения скорости работы драйверов. Также в определенных случаях код, написанный вручную на языке ассемблера, может работать быстрее кода, сгенерированного компилятором.

В статьях данной серии мы будем подробно исследовать мир языка ассемблера. В данной статье мы рассмотрим лишь базовые приемы программирования, в статье из следующего номера журнала разберемся с более сложными вопросами, после чего закончим рассмотрение языка ассемблера написанием простой загружающейся операционной системы - она не сможет выполнять какой-либо полезной работы, но будет основываться на вашем коде и работать непосредственно с аппаратным обеспечением без необходимости загрузки каких-либо сторонних ОС. Звучит неплохо, не правда ли? Давайте начнем

Ваша первая программа на языке ассемблера

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

Некоторые текстовые редакторы, такие, как Vim, осуществляют подсветку синтаксиса языка ассемблера (попробуйте использовать команду set syn=nasm )

Скопируйте следующий код в в текстовое поле любого текстового редактора и сохраните его в файле с именем myfirst.asm в вашей домашней директории:

Section .text global _start _start: mov ecx, message mov edx, length mov ebx, 1 mov eax, 4 int 0x80 mov eax, 1 int 0x80 section .data message db "Assembly rules!", 10 length equ $ - message

(Примечание: для отступов в коде вы можете использовать как как символы пробелов, так и символы табуляции - это не имеет значения.) Данная программа просто выводит строку "Assembly rules!" на экран и завершает работу.

Инструмент, который мы будем использовать для преобразования данного кода языка ассемблера в исполняемый бинарный файл носит довольно забавное название "ассемблер". Существует много различных ассемблеров, но моим любимым ассемблером является NASM; он находится в репозитории пакетов программного обеспечения практически любого дистрибутива, поэтому вы можете установить его с помощью менеджера пакетов программного обеспечения с графическим интерфейсом, команды yum install nasm , apt-get install nasm или любой другой команды, актуальной для вашего дистрибутива.

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

Nasm -f elf -o myfirst.o myfirst.asm ld -m elf_i386 -o myfirst myfirst.o

Первая команда предназначена для генерации с помощью NASM (исполняемого) файла объектного кода с именем myfirst.o формата ELF (формат исполняемых файлов, используемый в Linux). Вы можете спросить: "Для чего генерируется файл объектного кода, ведь логичнее сгенерировать файл с инструкциями центрального процессора, которые он должен исполнять?" Ну, вы могли бы использовать исполняемый файл с инструкциями центрального процессора в операционных системах 80-х годов, но современные операционные системы предъявляют больше требований к исполняемым файлам. Бинарные файлы формата ELF включают информацию для отладки, они позволяют разделить код и данные благодаря наличию отдельных секций, что позволяет предотвратить переписывание данных в этих секциях.

Позднее в процессе рассмотрения методики написания кода для работы непосредственно с аппаратным обеспечением (для нашей минималистичной операционной системы) в рамках данной серии статей мы уделим внимание и таким бинарным файлам с инструкциями центрального процессора.

Взгляд в прошлое

На данный момент в нашем распоряжении имеется файл myfirst.o с исполняемым кодом нашей программы. При этом процесс сборки программы еще не завершен; с помощью линковщика ld мы должны связать код из этого файла со специальным системным кодом запуска программ (т.е., шаблонным кодом, который исполняется при запуске каждой программы) для генерации исполняемого файла с именем myfirst . (Параметр elf_i386 описывает тип бинарного формата - в данном случае это означает, что вы можете использовать 32-битный ассемблерный код даже если вы используете 64-битный дистрибутив.)

Если процесс сборки программы пройдет успешно, вы сможете выполнить вашу программу с помощью следующей команды:

В результате вы должны увидеть вывод: "Assembly rules!". Это означает, что вы добились своего - создали полноценную независимую программу для Linux, код которой написан полностью на языке ассемблера. Разумеется, данная программа не выполняет каких-либо полезных действий, но при этом она является отличным примером, демонстрирующим структуру программы на языке ассемблера и позволяющим проследить процесс преобразования исходного кода в бинарный файл.

Перед тем, как мы перейдем к углубленному изучению кода, было бы неплохо узнать размер бинарного файла нашей программы. После выполнения команды ls -l myfirst вы увидите, что размер бинарного файла равен примерно 670 байтам. Теперь оценим размер эквивалентной программы на языке C:

#include int main() { puts("Assembly rules!"); }

Если вы сохраните этот код в файле с именем test.c , скомпилируете его (gcc -o test test.c ) и рассмотрите параметры результирующего бинарного файла с именем test , вы обнаружите, что этот файл имеет гораздо больший размер - 8.4k. Вы можете удалить из этого файла отладочную информацию (strip -s test ), но и после этого его размер сократится незначительно, лишь до 6 k. Это объясняется тем, что компилятор GCC добавляет большой объем упомянутого выше кода для запуска и завершения работы приложения, а также связывает приложение с библиотекой языка программирования C большого размера. Благодаря данному примеру несложно сделать вывод о том, что язык ассемблера является лучшим языком программирования для разработки приложений, предназначенных для эксплуатации в условиях жесткого ограничения объема носителя данных.

Следует упомянуть о том, что многие разработчики, использующие язык ассемблера, получают отличные зарплаты за разработку кода для ограниченных в плане ресурсов встраиваемых устройств и именно поэтому язык ассемблера является единственным реальным вариантом для разработки игр для старых 8-битных консолей и домашних компьютеров.

Дизассемблирование кода

Разработка нового кода является увлекательным занятием, но еще более интересным занятием может оказаться исследования чужой работы. Благодаря инструменту под названием objdump (из пакета Binutils) вы можете "дизассемблировать" исполняемый файл, а именно, преобразовать инструкции центрального процессора в их текстовые эквиваленты. Попытайтесь использовать данный инструмент по отношению к бинарному файлу myfirst, над которым мы работали в данном руководстве, следующим образом:

Objdump -d -M intel myfirst

Вы увидите список инструкций из секции кода бинарного файла. Например, первая инструкция, с помощью которой мы поместили информацию о расположении нашей строки в регистр ecx, выглядит следующим образом:

Mov ecx,0x80490a0

В процессе ассемблирования NASM заменил метку строки "message" на числовое значение, соответствующее расположению этой строки в секции данных бинарного файла. Таким образом, результаты дизассемблирования бинарных файлов менее полезны, чем их оригинальный код, ведь в них отсутствуют такие вещи, как комментарии и строки, но они все же могут оказаться полезными для ознакомления с реализациями критичных к времени исполнения функций или взлома систем защиты приложений. Например, в 80-х и 90-х годах многие разработчики использовали инструменты для дизассемблирования программ с целью идентификации и нейтрализации систем защиты от копирования игр.

Вы также можете дизассемблировать программы, разработанные с использованием других языков программирования, но полученные при этом результаты дизассемблирования могут быть значительно усложнены. Например, вы можете выполнить приведенную выше команду objdump по отношению к бинарному файлу /bin/ls и самостоятельно оценить тысячи строк из секции кода, сгенерированные компилятором на основе оригинального исходного кода утилиты на языке C.

Анализ кода

А теперь давайте обсудим назначение каждой из строк кода нашей программы. Начнем с этих двух строк:

Section .text global _start

Это не инструкции центрального процессора, а директивы ассемблера NASM ; первая директива сообщает о том, что приведенный ниже код должен быть расположен в секции кода "text" финального исполняемого файла. Немного неочевидным является тот факт, что секция с названием "text" содержит не обычные текстовые данные (такие, как наша строка "Assembly rules!"), а исполняемый код, т.е., инструкции центрального процессора. Далее расположена директива global _start , сообщающая линковщику ld о том, с какой точки должно начаться исполнение кода из нашего файла. Эта директива может оказаться особенно полезной в том случае, если мы захотим начинать исполнение кода не с самого начала секции кода, а из какой-либо заданной точки. Параметр global позволяет читать данную директиву не только ассемблеру, но и другим инструментам, поэтому она обрабатывается линковщиком ld .

Как было сказано выше, исполнение кода должно начинаться с позиции _start . Ввиду этого мы явно указываем соответствующую позицию в нашем коде:

Отдельные слова с символами двоеточия в конце называются метками и предназначены для указания позиций в коде, к которым мы можем перейти (подробнее об этом в следующей статье серии). Таким образом, исполнение программы начинается с этой строки! Кроме того, мы наконец достигли первой реальной инструкции центрального процессора:

Mov ecx, message

Язык ассемблера является по своей сути набором мнемоник для инструкций центрального процессора (или машинного кода). В данном случае mov является одной из таких инструкций - она также может быть записана в понятном центральному процессору бинарном формате, как 10001011. Но работа с бинарными данными может превратиться в кошмар для нас, обычных людей, поэтому мы будем использовать эти более читаемые варианты. Ассемблер просто преобразует текстовые инструкции в их бинарные эквиваленты - хотя он и может выполнять дополнительную работу, о которой мы поговорим в следующих статьях серии.

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

В данный момент главным хранилищем для используемых центральным процессором данных являются ваши банки оперативной памяти. Но ввиду того, что оперативная память находится за пределами центрального процессора, на осуществление доступа к ней тратится много времени. Для ускорения и упрощения описанного процесса центральный процессор содержит свою собственную небольшую группу ячеек памяти, называемую регистрами. Инструкции центрального процессора могут использовать эти регистры напрямую, причем в рассматриваемой строке кода мы используем регистр с именем ecx .

Это 32-х битный регистр (следовательно, он может хранить числа из диапазона от 0 до 4,294,967,295). При рассмотрении следующих строк кода вы увидите, что мы также работаем с регистрами edx , ebx и eax - это регистры общего назначения, которые могут использоваться для выполнения любых задач, в отличие от специализированных регистров, с которыми мы познакомимся в следующем месяце. А это небольшое пояснение для тех, кому не терпится узнать о происхождении имен регистров: регистр ecx носил имя c во время выпуска 8-ми битных процессоров, после чего был переименован в сх для хранения 16-и битных значений и в ecx для хранения 32-х битных значений. Таким образом, несмотря на то, что имена регистров в настоящее время выглядят немного странно, во времена выпуска старых центральных процессоров разработчики использовали регистры общего назначения с отличными именами a , b , c и d .

После того, как вы начнете работу, вы не сможете остановиться

Одним из вопросов, которые мы будем рассматривать в следующем месяце, является вопрос использования стека, поэтому мы подготовим вас к его рассмотрению прямо сейчас. Стек является областью памяти, в которой могут храниться временные значения тогда, когда необходимо освободить регистры для других целей. Но наиболее важной возможностью стека является способ хранения данных в нем: вы будете "помещать" ("push") значения в стек и "извлекать" ("pop") их из него. В стеке используется принцип LIFO (last in, first out - первый вошел, последний вышел), следовательно, последнее добавленное в стек значение будет первым извлечено из него.

Представьте, что у вас есть, к примеру, пустая упаковка от чипсов Pringles и вы помещаете в нее вещи в следующей последовательности: двухслойный крекер, фишка с персонажем "Альф" и диск от приставки GameCube. Если вы начнете извлекать эти вещи, вы извлечете диск от приставки GameCube первым, затем фишку с персонажем "Альф" и так далее. При работе с языком ассембера стек используется следующим образом:

Push 2 push 5 push 10 pop eax pop ebx pop ecx

После исполнения этих шести инструкций регистр eax будет содержать значение 10, регистр ebx - значение 5 и регистр ecx - значение 2. Таким образом, использование стека является отличным способом временного освобождения регистров; если, к примеру, в регистрах eax и ebx имеются важные значения, но вам необходимо выполнить текущую работу перед их обработкой, вы можете поместить эти значения в стек, выполнить текущую работу и извлечь их из стека, вернувшись к предыдущему состоянию регистров.

Кроме того, стек используется при вызове подпрограмм для хранения адреса возврата к основному коду. По этой причине необходимо проявлять особую осторожность при работе со стеком - если вы перепишете хранящиеся в нем данные, вы не сможете вернуться к предыдущей позиции в основном коде приложения, отправившись в одну сторону навстречу аварийному завершению работы приложения!

Двигаемся дальше

Вернемся к коду: инструкция mov перемещает (на самом деле, копирует) число из одного места в другое, справа налево. Таким образом, в данном случае мы говорим: "следует поместить message в регистр ecx ". Но что такое "message"? Это не другой регистр, это указатель на расположение данных. Ближе концу кода в секции данных "data" вы можете обнаружить метку message , после которой следует параметр db , указывающий на то, что вместо метки message в коде должно быть размещено несколько байт. Это очень удобно, так как нам не придется выяснять точное расположение строки "Assembly rules!" в секции данных - мы можем просто сослаться на нее с помощью метки message . (Число 10 после нашей строки является всего лишь символом перехода на новую строку, аналогичным символу \n , добавляемому к строкам при работе с языком программирования C).

Таким образом, мы поместили данные о расположении строки в регистр ecx . Но то, что мы сделаем дальше является особенно интересным. Как упоминалось ранее, центральный процессор не имеет какой-либо реальной концепции аппаратных устройств - для вывода чего-либо на экран вам придется отправить данные видеокарте или переместить данные в оперативную память видеокарты. Но мы не имеем какой-либо информации о расположении этой оперативной памяти видеокарты, кроме того, все используют различные видеокарты, параметры сервера оконной системы X, оконные менеджеры и.т.д. Исходя из этого, непосредственный вывод чего-либо на экран с помощью небольшой по объему программы в нашем случае практически невозможен.

Поэтому мы попросим ядро ОС сделать это для нас. Ядро Linux предоставляет в распоряжение низкоуровневых приложений большое количество системных вызовов, с помощью которых приложения могут инициировать выполнение различных операций на уровне ядра. Один из этих системных вызовов предназначен для вывода текстовой строки. После использования этого системного вызова ядро ОС выполняет всю необходимую работу - и, разумеется, оно предоставляет даже более глубокий уровень абстракции, на котором строка может быть выведена с помощью обычного текстового терминала, эмулятора терминала оконной системы X или даже записана в открытый ранее файл.

Однако, перед тем, как сообщить ядру ОС о необходимости вывода текстовой строки, нам придется передать ему дополнительную информацию, помимо информации о расположении строки, уже находящейся в регистре ecx . Также нам придется сообщить ему о том, сколько символов нужно вывести для того, чтобы вывод строки не продолжался после ее окончания. Именно для этого используется строка из секции данных ближе к концу кода приложения:

Length equ $ - message

В данной строке используется другая метка length , но вместо параметра db для связывания этой метки с какими-либо данными, мы используем параметр equ для того, чтобы сообщить, что данная метка является эквивалентом чего-либо (это немного похоже на директиву препроцессора #define в языке программирования C). Символ доллара соответствует текущей позиции в коде, поэтому в данном случае мы говорим: "метка length должна быть эквивалентна текущей позиции в коде за вычетом расположения строки с меткой "message"".

Вернемся к секции кода приложения, в которой мы размещаем данное значение в регистре edx :

Mov edx, length

Все идет отлично: два регистра заполнены информацией о расположении строки и количестве символов строки для вывода. Но перед тем, как мы сообщим ядру ОС о необходимости выполнения его части работы, нам придется предоставить ему еще немного информации. Во-первых, мы должны сообщить ядру ОС о том, какой "дескриптор файла" следует использовать - другими словами, куда должен быть направлен вывод. Данная тема выходит за границы руководства по использованию языка ассемблера, поэтому скажем лишь, что нам нужно использовать стандартный поток вывода stdout , что означает: выводить строку на экран. Стандартный поток вывода использует фиксированный дескриптор 1, который мы помещаем в регистр ebx .

Теперь мы крайне близки к осуществлению системного вызова, но остался еще один регистр, который должен быть заполнен. Ядро ОС может выполнять большое количество различных операций, таких, как монтирование файловых систем, чтение данных из файлов, удаление файлов и других. Соответствующие механизмы активируются с помощью упомянутых системных вызовов и перед тем, как мы передадим управление ядру ОС, нам придется сообщить ему, какой из системных вызовов следует использовать. На странице вы можете ознакомиться с информацией о некоторых системных вызовах, доступных программам - в нашем случае необходим системный вызов sys_write ("запись данных в дескриптор файла") с номером 4. Поэтому мы разместим его номер в регистре eax :

И это все! Мы выполнили все необходимые приготовления для осуществления системного вызова, поэтому сейчас мы просто передадим управление ядру ОС следующим образом:

Инструкция int расшифровывается как "interrrupt" ("прерывание") и буквально прерывает поток исполнения данной программы, переходя в пространство ядра ОС. (В данном случае используется шестнадцатеричное значение 0x80 - пока вам не следует беспокоиться о нем.) Ядро ОС осуществит вывод строки, на которую указывает значение в регистре ecx , после чего вернет управление нашей программе.

Для завершения исполнения программы следует осуществить системный вызов sys_exit , который имеет номер 1. Поэтому мы размещаем данный номер в регистре eax , снова прерываем исполнение нашей программы, после чего ядро ОС аккуратно завершает исполнение нашей программы и мы возвращаемся к приветствию командной оболочки. Можно сказать, что вы выполнили поставленную задачу: реализовали завершенную (хотя и очень простую) программу на языке ассемблера, код которой разработан вручную без использования каких-либо объемных библиотек.

Мы рассмотрели достаточно много аспектов использования языка ассемблера в данном руководстве и, как упоминалось ранее, вместо этого мы могли бы сфокусироваться лишь на теоретической информации. Но я все же надеюсь, что реальный пример программы оказался полезным для вас, а в следующем номере журнала мы потратим больше времени на рассмотрение некоторых концепций, которые были затронуты в данном руководстве. Кроме того, мы усовершенствуем нашу программу, добавив в нее логику и подпрограммы - версии операторов if и goto языка ассемблера.

В процессе ознакомления с кодом данной программы вы можете попытаться самостоятельно модифицировать его для выполнения следующих операций:

  • Вывода отличной, более длинной строки.
  • Вывода двух строк, одна после другой.
  • Возврата измененного кода завершения работы приложения командной оболочке (для этого придется воспользоваться поисковой системой Google!).

Если вы столкнулись с трудностями и нуждаетесь в помощи, заходите на наш форум по адресу http://forums.linuxvoice.com - автор руководства будет рядом и с удовольствием направит вас по правильному пути. Удачного программирования!

Язык программирования

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

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

Директивы ассемблера позволяют включать в программу блоки данных (описанные явно или считанные из файла); повторить определённый фрагмент указанное число раз; компилировать фрагмент по условию; задавать адрес исполнения фрагмента, менять значения меток в процессе компиляции; использовать макроопределения с параметрами и др.

Каждая модель процессора, в принципе, имеет свой набор команд и соответствующий ему язык (или диалект) ассемблера.

Достоинства и недостатки

  • минимальное количество избыточного кода (использование меньшего количества команд и обращений в память). Как следствие - большая скорость и меньший размер программы
  • большие объемы кода, большое число дополнительных мелких задач
  • плохая читабельность кода, трудность поддержки (отладка, добавление возможностей)
  • трудность реализации парадигм программирования и любых других сколько-нибудь сложных конвенций, сложность совместной разработки
  • меньшее количество доступных библиотек, их малая совместимость
  • непосредственный доступ к аппаратуре: портам ввода-вывода, особым регистрам процессора
  • возможность написания самомодифицирующегося кода (т.е. метапрограммирования, причем без необходимости программного интерпретатора)
  • максимальная «подгонка» для нужной платформы (использование специальных инструкций, технических особенностей «железа»)
  • непереносимость на другие платформы (кроме двоично совместимых).

Синтаксис

Общепринятого стандарта для синтаксиса языков ассемблера не существует. Однако, существуют стандарты де-факто - традиционные подходы, которых придерживаются большинство разработчиков языков ассемблера. Основными такими стандартами являются Intel-синтаксис и AT&T-синтаксис.

Общий формат записи инструкций одинаков для обоих стандартов:

`[метка:] опкод [операнды] [;комментарий]`

Опкод - непосредственно мнемоника инструкции процессору. К ней могут быть добавлены префиксы (повторения, изменения типа адресации и пр.). В качестве операндов могут выступать константы, названия регистров, адреса в оперативной памяти и пр.. Различия между стандартами Intel и AT&T касаются, в основном, порядка перечисления операндов и их синтаксиса при различных методах адресации.

Используемые мнемоники обычно одинаковы для всех процессоров одной архитектуры или семейства архитектур (среди широко известных — мнемоники процессоров и контроллеров Motorola, ARM, x86). Они описываются в спецификации процессоров.

Например, процессор Zilog Z80 наследовал систему команд Intel i8080, расширил ее и поменял мнемоники (и обозначения регистров) на свой лад. Например, сменил интеловские mov на ld . Процессоры Motorola Fireball наследовали систему команд Z80, несколько её урезав. Вместе с тем, Motorola официально вернулась к мнемоникам Intel. и в данный момент половина ассемблеров для Fireball работает с интеловскими мнемониками, а половина с мнемониками Zilog.

Директивы

Кроме инструкций, программа может содержать директивы: команды, не переводящиеся непосредственно в машинные инструкции, а управляющие работой компилятора. Набор и синтаксис их значительно разнятся и зависят не от аппаратной платформы, а от используемого компилятора (порождая диалекты языков в пределах одного семейства архитектур). В качестве набора директив можно выделить:

  • определение данных (констант и переменных)
  • управление организацией программы в памяти и параметрами выходного файла
  • задание режима работы компилятора
  • всевозможные абстракции (т.е. элементы языков высокого уровня) - от оформления процедур и функций (для упрощения реализации парадигмы процедурного программирования) до условных конструкций и циклов (для парадигмы структурного программирования)
  • макросы

Происхождение и критика термина «язык ассемблера»

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

Язык ассемблера в русском языке часто называют «ассемблером» (а что-то связанное с ним - «ассемблерный»), что, согласно английскому переводу слова, неправильно, но вписывается в правила русского языка. Однако, сам ассемблер (программу) тоже называют просто «ассемблером», а не «компилятором языка ассемблера» и т. п.

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

Элементы синтаксиса:

Примеры:

Hello, World!:

Пример для версий Intel x86 (IA32)

mov ax , cs mov ds , ax mov ah , 9 mov dx , offset Hello int 21h xor ax , ax int 21h Hello : db "Hello World !", 13, 10, "$"

Hello, World!:

Пример для версий Amiga

move . l #DOS move . l 4. w , a6 jsr - $0198(a6 ) ; OldOpenLibrary move . l d0 , a6 beq . s . Out move . l #HelloWorld , d1 A ) moveq #13, d2 jsr - $03AE (a6 ) ; WriteChars B ) jsr - $03B4 ; PutStr move . l a6 , a1 move . l 4. w , a6 jsr - $019E (a6 ) ; CloseLibrary . Out rts DOS dc . b "dos.library" , 0 HelloWorld dc . b "Hello World!" , $A , 0

Hello, World!:

Пример для версий AtariST

move . l #helloworld , - (A7 ) move #9, - (A7 ) trap #1 addq . l #6, A7 move #0, - (A7 ) trap #1 helloworld : dc . b "Hello World !", $0d , $0a , 0

Hello, World!:

Пример для версий Intel x86 (IA32)

NASM Linux , используется Intel синтаксис. Компиляция и линковка:

  • nasm –f elf –o hello.o hello.asm
  • ld -o hello hello.o

SECTION . data msg db "Hello , world !", 0xa len equ $ - msg SECTION . text global _start _start : ; Точка входа в программу mov eax , 4 ; "write" системный вызов mov ebx , 1 mov ecx , msg ; Указатель на данные mov edx , len ; Количество данных int 0x80 ; Вызов ядра mov eax , 1 ; "_exit" системный вызов mov ebx , 0 ; Возвращаем 0 (все хорошо) int 0x80 ; Вызов ядра

Hello, World!:

Пример для версий PDP-8

/ — комментарии.

/ Hello World на ассемблере для DEC PDP - 8 * 200 hello , cla cll tls / tls устанавливает флаг печати. tad charac / создает индексный регистр dca ir1 / для получения символов tad m6 / настроить счетчик для dca count / ввода символов. next , tad i ir1 / получить символ. jms type / его тип. isz count / сделать что нибудь еще? jmp next / нет, ввести другой символ hlt type , 0 / подпрограмма type tsf jmp . - 1 tls cla jmp i type charac , . / используется в качестве начального значения ir1 . 310 / H 305 / E 314 / L 314 / L 317 / O 254 / , 240 / 327 / W 317 / O 322 / R 314 / L 304 / D 241 / ! m6 , - 15 count , 0 ir1 = 10 $

Hello, World!:

Пример для версий PDP-11

Программа написана на макроассемблере MACRO-11 Для компиляции и запуска этой программы в ОС RT-11 командуем:

MACRO HELLO

ERRORS DETECTED: 0

LINK HELLO -- Линкуем. RUN HELLO -- Запускаем

TITLE HELLO WORLD ; Название . MCALL . TTYOUT ,. EXIT HELLO :: MOV #MSG , R1 ; Начальный адрес строки 1$: MOVB (R1 ) + , R0 ; Получаем следующий символ BEQ DONE ; Если ноль, выходим из цикла . TTYOUT ; Иначе печатаем символ BR 1$ ; Повтор цикла DONE : . EXIT MSG : . ASCIZ / Hello , world !/ ; Строка Hello , world ! . END HELLO ; Конец программы HELLO

Hello, World!:

Пример для версий System/360 , System/370

IBM System/360/370/390 Basic Assembler Language .

// EXEC ASSEMBLY START MAIN BALR 2 , 0 USING * , 2 OPEN PRINT MVC BUF , HW PUT PRINT CLOSE PRINT EOJ HW DC CL132 " HELLO WORLD " BUF DS CL132 PRINT DTFPR IOAREA1 = BUF , DEVADDR = SYSLST , BLKSIZE = 132 , * DEVICE = 3203 , CONTROL = YES , PRINTOV = YES END MAIN /* // EXEC LNKEDT // EXEC /* /&

Hello, World!:

Пример для версий Apple II

* HELLO WORLD FOR 6502 APPLE ][ * ******************************** STROUT EQU $DB3A LDY #> HELLO LDA #< HELLO JMP STROUT HELLO ASC "HELLO WORLD !", 00

Hello, World!:

Пример для версий PDP-10

CHTTYO — весь ввод/вывод осуществляется с помощью каналов ввода/вывода. Лучше всего сделать символические имена для тех каналов, которые вы используете, и начинать их с CH. Определите эти имена с помощью MIDAS оператора == .

CALL — это символическое обозначение для вызова системного вызова. Его формат: .CALL .

OPEN открывает канал ввода/вывода для использования. Требует два параметра — номер канала и имя устройства в SIXBIT.

LOSE %LSFIL — системный вызов, который печатает сообщение об ошибке ввода/вывода, если вдруг она произошла.

IOT — системный вызов, который фактически занимается вводом/выводом. В качестве параметра нужно указать канал и адрес, содержащий код символа для вывода. Например, “H представляет H .

TITLE PRINTHELLO A = 1 CHTTYO == 1 ; Канал для вывода. START : ; Открытие TTY канала. . CALL [ SETZ ? SIXBIT / OPEN / [. UAO , CHTTYO ] ? [ SIXBIT / TTY / ] ((SETZ ))] . LOSE %LSFIL . IOT CHTTYO ,[ "H ] ; Печать HELLO WORLD посимвольно. . IOT CHTTYO ,[ "E ] . IOT CHTTYO ,[ "L ] . IOT CHTTYO ,[ "L ] . IOT CHTTYO ,[ "O ] . IOT CHTTYO ,[ ^M ] ; Символ новой строки . IOT CHTTYO ,[ "W ] . IOT CHTTYO ,[ "O ] . IOT CHTTYO ,[ "R ] . IOT CHTTYO ,[ "L ] . IOT CHTTYO ,[ "D ] . VALUE ; Программка, остановись :) END START

Числа Фибоначчи:

Пример для версий MIPS32

Эмулятор MARS. Вывод консоли MARS:

The Fibonacci numbers are: 1 1 2 3 5 8 13 21 34 55 89 144 -- program is finished running --

Программа выводит 15 чисел Фибоначчи. Количество чисел можно изменить в секции.data.

Data space: .asciiz " " head : .asciiz "The Fibonacci numbers are:\n" fib: .word 0 : 15 size : .word 15 .text main: la $t0 , fib la $t5 , size lw $t5 , 0 ($t5 ) li $t2 , 1 add.d $f0 , $f2 , $f4 sw $t2 , 0 ($t0 ) sw $t2 , 4 ($t0 ) addi $t1 , $t5 , - 2 loop : lw $t3 , 0 ($t0 ) lw $t4 , 4 ($t0 ) add $t2 , $t3 , $t4 sw $t2 , 8 ($t0 ) addi $t0 , $t0 , 4 addi $t1 , $t1 , - 1 bgtz $t1 , loop la $a0 , fib move $a1 , $t5 jal print li $v0 , 10 syscall print : add $t0 , $zero , $a0 add $t1 , $zero , $a1 la $a0 , head li $v0 , 4 syscall out : lw $a0 , 0 ($t0 ) li $v0 , 1 syscall la $a0 , space li $v0 , 4 syscall addi li $v0 , 1 la $a0 , ($t2 ) syscall la $a0 , string1 li $v0 , 4 syscall mult $t1 , $t2 mflo $t1 li $v0 , 1 la $a0 , ($t1 ) syscall la $a0 , string2 li $v0 , 4 syscall addiu $t2 , $t2 , 1 beq $t2 , 16 , endloop j loop endloop: li $v0 , 10 syscall



Государственное Бюджетно-Образовательное Учреждение

Предмет : информатика

Реферат

Тема: История языков программирования.

Ассемблер.

Выполнил : ученик 8 класса,

средней школы №1467

Сорокин Николай

Руководитель : Цветкова Оксана Михайловна

Введение

С увеличением объёма вычислений появился первый счётный переносной инструмент – “Счёты”.

В начале 17 века возникла необходимость в сложных вычислениях. потребовались счётные устройства, способные выполнять большой объём вычислений с высокой точностью. В 1642 г. французский математик Паскаль сконструировал первую механическую счётную машину – “Паскалину”.

В 1830 г. английский учёный Бэбидж предложил идею первой программируемой вычислительной машины (“аналитическая машина”). Она должна была приводиться в действие силой пара, а программы кодировались на перфокарты. Реализовать эту идею не удалось, так как было не возможно сделать некоторые детали машины.

Первый реализовал идею перфокарт Холлерит. Он изобрёл машину для обработки результатов переписи населения. В своей машине он впервые применил электричество для расчётов. В 1930 г. американский учёный Буш изобрел дифференциальный анализатор – первый в мире компьютер.

Большой толчок в развитии вычислительной техники дала вторая мировая война. Военным понадобился компьютер, которым стал “Марк-1” – первый в мире цифровой компьютер, изобретённый в 1944 г. профессором Айкнем. В нём использовалось сочетание электрических сигналов и механических приводов. Размеры: 15 X 2,5 м., 750000 деталей. Могла перемножить два 23-х разрядных числа за 4 с.

В 1946 г. группой инженеров по заказу военного ведомства США был создан первый электронный компьютер – “Эниак”. Быстродействие: 5000 операций сложения и 300 операций умножения в секунду. Размеры: 30 м. в длину, объём – 85 м3., вес – 30 тонн. Использовалось 18000 эл. ламп.

Первая машина с хронимой программой – ”Эдсак” – была создана в 1949 г., а в 1951 г. создали машину “

Юнивак” – первый серийный компьютер с хронимой программой. В этой машине впервые была использована магнитная лента для записи и хранения информации

Для чего нужен язык программирования?

Компьютеpы появились очень давно в нашем миpе, но только в последнее вpемя их начали так усиленно использовать во многих отpаслях человеческой жизни. Ещё десять лет назад было редкостью увидеть какой-нибудь персональный компьютер - они были, но были очень дорогие, и даже не каждая фирма могла иметь у себя в офисе компьютер. А теперь? Теперь в каждом третьем доме есть компьютер, который уже глубоко вошёл в жизнь самих обитателей дома.

Сама идея создания искусственного интеллекта появилась давным давно, но только в 20 столетии её начали приводить в исполнение. Сначала появились огромные компьютеры, которые были подчастую размером с огромный дом. Использование таких махин, как вы сами понимаете, было не очень удобно. Но что поделаешь? Но мир не стоял на одном месте эволюционного развития - менялись люди, менялась их Среда обитания, и вместе с ней менялись и сами технологии, всё больше совершенствуясь. И компьютеры становились всё меньше и меньше по своим размерам, пока не достигли сегодняшних размеров.

Но человеку ведь тоже надо как-нибудь общаться с машиной - ведь кому нужна неуправляемая машина? Сначала люди вели своё общение с компьютерам посредством перфокарт. Перфокарты - это небольшие карточки, на которые нанесены ряды цифр. У компьютера имелся “дисковод”, в который вставлялись сами карты и он при помощи маленьких иголочек ставил дырочки на цифрах. Такое общение мало кому доставляло удовольствие - ведь не очень удобно таскать с собой кучи перфокарт, которые после одного использования приходилось выбрасывать.

Но, как и другие технологии, процесс общения человека с искусственным интеллектом претерпел кое-какие изменения. Теперь человек проводит свою беседу с компьютером при помощи клавиатуры и мышки. Это довольно удобно и иногда даже доставляет удовольствие человеку.

Современные вычислительные машины представляют одно из самых значительных достижений человеческой мысли, влияние которого на развитие научно-технического прогресса трудно переоценить. Области применения ЭВМ непрерывно расширяются. Этому в значительной степени способствует распространение персональных ЭВМ, и особенно микроЭВМ.

За время, прошедшее с 50-х годов, цифровая ЭВМ превратилась из “волшебного”, но при этом дорогого, уникального и перегретого нагромождения электронных ламп, проводов и магнитных сердечников в небольшую по размерам машину – персональный компьютер – состоящий из миллионов крошечных полупроводниковых приборов, которые упакованы в небольшие пластмассовые коробочки.

В результате этого превращения компьютеры стали применяться повсюду. Они управляют работой кассовых аппаратов, следят за работой автомобильных систем зажигания, ведут учёт семейного бюджета, или просто используются в качестве развлекательного комплекса… Но это только малая часть возможностей современных компьютеров. Более того, бурный прогресс полупроводниковой микроэлектроники, представляющей собой базу вычислительной техники, свидетельствует о том, что сегодняшний уровень как самих компьютеров, так и областей их применения является лишь слабым подобием того, что наступит в будущем.

Компьютеры начинают затрагивать жизнь каждого человека. Если вы заболеете, и если вас направят в больницу, то попав туда, в окажетесь в мире, где от компьютеров зависят жизни людей (в части современных больниц вы даже встретите компьютеров больше, чем самих пациентов, и это соотношение будет со временем расти, перевешивая число больных). Постепенно изучение компьютерной техники пытаются вводить в программы школьного обучения как обязательный предмет, чтобы ребёнок смог уже с довольно раннего возраста знать строение и возможности компьютеров. А в самих школах (в основном на западе и в Америке) уже многие годы компьютеры применялись для ведения учебной документации, а теперь они используются при изучении многих учебных дисциплин, не имеющих прямого отношения к вычислительной технике. Даже в начальной школе компьютеры внедряются для изучения курсов элементарной математики и физики. Сами микропроцессоры получили не менее широкое распространение чем компьютеры - они встраиваются в кухонные плиты для приготовления пищи, посудомоечные машины и даже в часы.

Очень широкое распространение получили игры, построенные на основе микропроцессоров. Сегодня игровая индустрия занимает очень большую часть рынка, постепенно вытесняя с него другие развлечения детей. Но для детского организма очень вредно сидеть часами за монитором и отчаянно нажимать на клавиши, так как у ребёнка может развиться своеобразная болезнь - когда у него только одно на уме – компьютер, и больше ничего. Дети с такой болезнью обычно становятся агрессивными, если их начинают ограничивать в доступе к играм. У таких детей сразу пропадает какое-либо желание делать что-то, что не относится к компьютеру и что им не интересно - так они начинают забрасывать свою учёбу, что ведёт к не очень хорошим последствиям.

Уже сейчас компьютеры могут чётко произносить различные фразы, словосочетания, проигрывать музыку и.т.д. Человек теперь может сам записать какие-нибудь слова, предложения и даже музыкальные композиции на своём компьютере для того, чтобы потом компьютер мог их воспроизводить в любое назначенное время.

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

Но проблема распознавания речи является частью более широкой проблемы, называемой распознаванием образов. Если компьютеры смогут хорошо распознавать образы, они будут способны анализировать рентгенограммы и отпечатки пальцев, а также выполнять многие другие полезные функции (сортировкой писем они занимаются уже сейчас). Следует заметить, что человеческий мозг прекрасно справляется с распознаванием образов даже при наличии различных шумов и искажений, и исследования в этой области, направленные на приближение соответствующих возможностей компьютера к способностям человека, представляются весьма перспективными. Если компьютеры смогут достаточно качественно распознавать речь и отвечать на неё в словесной форме, то, по-видимому, станет возможным вводить в них в этой форме программы и данные. Это позволит в буквальном смысле слова говорить компьютеру, что он должен делать, и выслушивать его мнение по этому поводу при условии, конечно, что выдаваемые ей указания чёткие, не содержат противоречий и.т.д.

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

Мы часто жалуемся, что другие люди не понимают нас; но пока и сами персональные компьютеры не способны до конца понять нас, или понять, что мы хотим сказать с полуслова. И в течение какого-то периода времени нам придётся довольствоваться такими машинами, которые просто следуют нашим указаниям, исполняя их “с точностью до миллиметра”.

Для общения с компьютерами, ещё во времена перфокарт, тогдашние программисты использовали язык программирования, очень похожий на современный Ассемблер. Это такой язык, где все команды, поступающие к компьютеру пишутся подробно при помощи специальных слов и значков{?}.

В наше время усиленно используются языки программирования более высокого уровня, работать с которыми намного легче чем с Ассемблером, так как в них одно слово может заменять сразу несколько команд. И притом большинство языков программирования высокого уровня в названиях команд, используемых при общении с компьютером, используют эквиваленты, названные на английском языке, что, естественно, облегчает программирование. Но в них есть один минус по сравнению с языками, подобными Ассемблеру - в Ассемблере все команды, поступаемые из программы чётко распределяются в памяти компьютера, занимая свободные места, тем самым значительно выигрывая в скорости; а языки высокого уровня не умеют этого, соответственно теряя в скорости исполнения программы. А в нашем сегодняшнем мире всем известно, что: “Время - деньги”.

Хотя, пока компьютер уступает человеку с точки зрения творческой деятельности, потому что машина не наделена пока такими качествами, которые смогли бы ей помочь создать что-нибудь новое, что не введено в её память самим человеком.

Боьшинство людей, по-видимому, считают, что термины “вычислительная машина” и “вычислительная техника” синонимами и связывают их с физическим оборудованием, как, например, микропроцессором, дисплеем, дисками, принтерами и другими истройствами, привлекающими внимание людей, когда человек видит компьютер. Хотя эти устройства и важны, всё-таки они составляют только “верхушку айсберга”. На начальном этапе использованаия современного компьютера мы имеем дело не с самим компьютером, а с совокупностью правил, называемых языками программироваания, на которых указываются действия, которые должен выполнять компьютер. Важное значение языка программирования подчёркивается тем фактом, что сама вычислительная машина может рассматриваться как аппаратный интерпретатор какого-нибудь конкретного языка, который называется машинным языком. Для обеспечения эффективной работы машины разработаны машинные языки, использование которых представляет известные трудностидля человека. Большинство пользователей не чувствуют этих неудобств благодаря наличию одного или нескольких языков, созданных для улучшения связи человека с машиной. Гибкость вычислительной машины проявляется в том, что она может исполнять программы-трансляторы (в общем случае онм называются компиляторами или интерпретаторами) для преобразования программ с языков, ориентированных на пользователей, в программы на машинном языке. (В свою очередь даже сами программы, игры, системные оболочки являются ни чем иным, как довольно простая программа-транслятор, которая по мере работы, или игры обращается при помощи своих команд к “компьютерным внутренностям и наружностям”, транслиуя свои команды в машинные языки. И всё это происходит в реальном времени.)

Машинные языки, языки ассемблера и

языки высокого уровня

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

1. Машинные языки

2. Ассемблерные языки

3. Языки высокого уровня.

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

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

Одним из языко высокого уровня является язык программирования С.

История языка С

Язык с берет свое начало от двух языков, BCPL и B. В 1967 году Мартин Ричардс разработал BCPL как язык для написания системного программного обеспечения и компиляторов. В 1970 году Кен Томпсон использовал В для создания ранних версий операционной системы UNIX на компьютере DEC PDP-7. как в BCPL, так и в В переменные не разделялись на типы- каждое значение данных занимало одно слово в памяти и ответственность на различение, например, целых и действительных чисел целиком ложилась на плечи программиста.

Язык С был разработан (на основе В) Деннисом Ричи из Bell Laboratories и впервые был реализован в 1972 году на компьютере DEC PDP-11. Известность С получил в качестве языка ОС UNIX. Сегодня практически все основные операционные системы были написаны на С и/ или С++. По прошествии двух десятилетий С имеется в наличии на большинстве компьютеров. Он не зависит от аппаратной части.

В конце 70-х годов С превратился в то, что мы называем «традиционный С». В 1983 году Американским комитетом национальных стандартов в области компьютеров и обработке информации был учрежден единый стандарт этого языка.

Заключение

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

Список использованной литературы

1. Том Сван “Освоение Turbo Assembler”, Диалектика, Киев, 1996 г.

2. Березин Б.И., Березин С.Б. “Начальный курс программирования”, Диалог МИФИ, Москва, 1996 г.

3. Лекции Комлевой Нины Викторовны по предмету “Языки программирования и методы трансляции”

4.Х.М.Дейтел, Как программировать на С, Издательство Бином, Москва, 2000 г.

Ассе́мблер (asm, assembler); от англ. assemble - собирать, монтировать) - язык программирования низкого уровня, вспомогательная программа в составе операционной системы для автоматического перевода исходной программы, подлежащей выполнению на компьютере, на машинный язык; вид транслятора . Понятия ассемблера отражают архитектуру электронно-вычислительной машины. Ассемблер - символьная форма записи машинного языка, использование которой упрощает написание машинных программ. Для одного и того же компьютера могут быть разработаны разные языки ассемблера. В отличие от языков высокого уровня, в котором проблемы реализации алгоритмов скрыты от разработчиков, язык ассемблера тесно связан с системой команд компьютера. Ассемблер обеспечивает доступ к регистрам, указание методов адресации и описание операций в терминах команд процессора. Он может содержать средства более высокого уровня: встроенные и определяемые макрокоманды, соответствующие нескольким машинным командам, автоматический выбор команды в зависимости от типов операндов, средства описания структур данных.

Особенности ассемблера

Ассемблером называют также компилятор с языка ассемблера в команды машинного языка. Другое название такого компилятора - мнемокод. Он предназначен для представления в удобном (мнемоническом) виде машинных кодов команд, обеспечивает эффективное использование ресурсов системы (процессор, память, периферия). Мнемокод используется в местах, где требуется быстродействие, ограничен по размер оперативной памяти. Ассемблером также называют иногда систему команд центрального процессора.

Под каждую архитектуру процессора и под каждую операционную систему существует свой ассемблер. Кросс-ассемблеры позволяют на машинах с одной архитектурой ассемблировать программы для другой архитектуры или другой операционной системы. Ассемблер обеспечивает доступ к регистрам, указание методов адресации и описание операций в терминах команд процессора. Ассемблер может содержать средства высокого уровня: встроенные и определяемые макрокоманды, соответствующие нескольким машинным командам, автоматический выбор команды в зависимости от типов операндов, средства описания структур данных.

Команды языка ассемблера соответствуют командам процессора и представляют собой символьную форму записи команд и аргументов. Язык ассемблер обеспечивает связывание частей программы и данныx через метки, выполняемое при ассемблировании (для каждой метки высчитывается адрес, после чего каждое вхождение метки заменяется на этот адрес). Поскольку системы команд микропроцессоров различаются, каждый процессор имеет свой набор команд на языке ассемблера и свои компиляторы-ассемблеры.

Обычно программы или участки кода пишутся на языке ассемблера в случаях, когда разработчику нужно оптимизировать быстродействие (при создании драйверов), размер кода. Большинство компиляторов позволяют комбинировать в одной программе, код написанный на разных языках программирования. Это позволяет писать сложные программы используя высокоуровневый язык, не теряя быстродействия в критических ко времени задачах, используя для них части написанные на языке ассемблера. Комбинирование достигается вставкой фрагментов на языке ассемблера в текст программы (специальными директивами языка) или написанием процедур на языке ассемблера. Этот способ используется для несложных преобразований данных, но он неприменим в полноценном ассемблерном коде с данными и подпрограммами с множеством входов и выходов, не поддерживаемых высокоуровневыми языками.

В таком случае используют модульную компиляцию, когда каждый файл программы компилируется в объектный модуль, которые затем линкуются (связываются) в готовую программу. Объектные файлы представляют собой блоки машинного кода и данных, с неопределенными адресами ссылок на данные и процедуры в других объектных модулях, а также список своих процедур и данных. Линкер собирает код и данные каждого объектного модуля в программу, вычисляет и заполняет адреса перекрестных ссылок между модулями. В процессе линковки происходит связывание программы со статическими и динамическими библиотеками (являющихся архивами объектных файлов).При модульной компиляции каждый объектный модуль программы может быть написан на своем языке программирования и скомпилирован своим компилятором (ассемблером).