Вот Вам исходник с комментами для изучения вопроса о строках. Консольная программа на masm32.
пример программы по заданию чтобы начать постепенно разбиратся..
Ну зачем столько лишних слов? Так и пишите уж: "чтобы сдать и забыть ассемблер как страшный сон". Хотите разбираться — разбирайтесь с моим исходником. Не самый плохой пример работы со строками, если что.
быстрее всего помогают разобраться в этом разделе.
Запрещено отсылать пользователей из тематических разделов в разделы фриланса, а также рекламировать свои услуги или просить/требовать оплату за помощь, кроме разделов для платных услуг.
Вычисление длины строки на ассемблере, как одна из наиболее часто возникающих задач, занимала умы разработчиков еще на заре компьютерной эпохи 🙂 Однако впоследствии, с появлением и развитием операционных систем, и, соответственно, доступностью многочисленных встроенных сервисных функций работы со строками (в числе которых предоставляется и функция вычисления длины строки), подобные помысли практически перестали волновать умы представителей сообщества. С развитием высокоуровневых языков все меньше людей задумываются о том, "а как же там на низком уровне всё это реализовано", редко кого волнует оптимизация кода по быстродействию. Даже разработчики, что-либо пишущие на ассемблере, охотнее обращаются к встроенному функционалу, предоставляемому программным интерфейсом, нежели собственными наработкам, и их можно понять, поскольку производительности предоставляемых системой функций, да и языка в целом вполне хватает для того, что бы в большинстве задач не отвлекаться на пару сотен лишних тактов.
К вычислению/заданию длины строки в исходном коде применимы две основных стратегии:
- Статическая — когда длины строк известны заранее и задаются в исходном коде в виде констант;
- Динамическая — когда длины строк заранее неизвестны (данные, полученные в процессе работы) и вычисляются в ходе выполнения кода;
Со статическим определением длины строки всё довольно-таки просто, чаще всего подход реализуется следующим образом:
и впоследствии используется в коде как-то вот так:
А вот с динамическим определением длины строки не все так однозначно. Основная, доступная разработчикам системная функция, это lstrlen , экспортируемая (предоставляемая) библиотекой kernel32.dll . Исключительно из любопытства хотелось бы оценить качество кода встроенных функции Windows и посмотреть, так ли они хороши, как должны быть. Попробуем поизучать код функции lstrlen , так сказать, "под микроскопом", то есть в отладчике, отладив код любой типовой программы, использующей данную функцию. После передачи управления на библиотечную функцию я просто протрассировал её до блока вычисления длины строки и скопировал найденный код, вот что у меня получилось:
Вы знаете, результатом я был приятно удивлен, потому как, честно говоря рассчитывал на худшее. Оказывается, сам вложенный цикл прохода по строке (строки 9 — 12 ), на который должно тратиться основное процессорное время, достаточно хорошо оптимизирован как по байт-коду, так и по скорости выполнения. Он состоит из четырех "быстрых" команд (минимальное количество микроопераций (μops) и задержек (latency)): mov , inc , test , jne . Однако тут существует другая проблема, в той или иной мере свойственная всем системным функциям современных операционных систем — это "обвес" функции и "вложенные" вызовы. Все дело в том, что от момента, кода ваш код вызывает функцию lstrlen и до выполнения непосредственно блока сравнения, происходит N-ое количество операций: вызовы сторонних функций, выполняющих дополнительную работу, сохранение/восстановление многочисленных стековых фреймов, проверки различных локальных и глобальных переменных и далее по списку. Отсюда можно сделать вывод, что при однократном вызове функции lstrlen существенной "просадки" скорости выполнения не будет, однако при многочисленных циклических вызовах на этот "лишний" с точки зрения вашей программы код будет уходить уже существенное процессорное время. Тем не менее, с этим уже ничего не поделаешь, это реалии всех операционных систем, код системных библиотек которых взаимосвязан, и тем самым привязан к различным дополнительным алгоритмам.
Собственная реализация для ASCIIZ-строк
Откровенно говоря, поскольку идея собственной реализации вычисления длины строки на ассемблере является одной из базовых в творчестве каждого кодера, у меня она родилась достаточно давно, еще в те далекие времена, когда на нашем информационном пространстве свирепствовал MSDOS версии 3.30, а железо было представлено отечественными машинками ЕС-1840 и ЕС-1841. Причина была достаточно прозаична, требовались функции для реализации тех или иных частей приложений/загрузчиков/осей. К сожалению (а может и к счастью), вся эта масса кривого кода давно уже переместилась в информационный ад (при условии, что он существует), а те дискеты, на которых она когда-то размещалось, скорее всего догнивают под многометровым слоем цивилизационных отходов где-то на региональной мусорной свалке. Но кое-что память человеческая сумела сохранить.
16-битный код
Для тех, кто глубокими ночами, в зашторенной комнате с приглушенным светом и закрытой на ключ дверью, балуется 16-битным кодом реального режима, могу предложить такую вот реализацию функции:
Язык программирования ассемблер
Язык программирования ассемблер сейчас редко используется для решения прикладных задач, однако его изучение позволяет лучше понять принципы работы ЭВМ, операционных систем и трансляторов с языков высокого уровня. В разное время в большинстве ПЭВМ использовались и используются процессоры фирмы Intel (8086/8088, 80186, 80286, i386, i486, Celeron, Pentium и т.д., см. с. 23-25). Эти процессоры поддерживают преемственность на уровне машинных команд: программы, написанные для младших моделей процессоров, без всяких изменений могут быть выполнены на более старших моделях. При этом базовой является система команд процессора 8086. Язык ассемблера — это символьная форма записи машинного языка, его использование существенно упрощает написание машинных программ. Приведем перевод английских слов:
assemble:1. собирать, монтировать, 2. компоновать с помощью ассемблера, ассемблировать, транслировать с помощью ассемблера, транслировать программу с помощью ассемблера
assembling:1. сборка, монтаж, 2. компоновка, ассемблирование, трансляция программы с помощью ассемблера
Для ПЭВМ разработаны разные языки ассемблера. Наиболее распространены язык фирмы Microsoft, названный языком макроассемблера (сокращенно MASM) и язык Turbo Assembler фирмы Borland (сокращенно TASM). Для того, чтобы программы на ассемблере случайно не нанесли вред операционной системе и программному обеспечению, последующие задания рекомендуется выполнять в виртуальной машине.
Рассмотрим пример простейшей программы, выводящей на экран надпись Hello world (Здравствуй, мир, англ., greet — приветствие).
Программа | Выполняемые действия |
Data SEGMENT Greet DB ‘Hello world’,13,10, ‘$’ Data ENDS Assume CS: Code, DS:Data Code SEGMENT Start: mov ax, Data mov ds,ax; mov dx, OFFSET Greet mov ah,9 int 21h mov al,0 mov ah, 4ch int 21h Code ENDS Stack1 SEGMENT Stack DB 100h DUP(?) Stack1 ENDS END Start | Начало сегмента данных Конец сегмента данных Объявление, что регистры процессора CS и DS будут содержать номера сегментов с именами Code и Data Начало сегмента команд Метка Поместить в регистр АХ номер сегмента Data Переслать АХ в регистр DS (команды непосредственной загрузки регистра DS нет) В регистр dx помещается смещение надписи относительно DS В регистр ah помещается номер 9 функции DOS “выведи надпись” Прерывание (вывод надписи) Возвращение в систему: в регистр ah помещается номер функции “возврат в систему” Прерывание (окончание выполнения программы) Конец сегмента команд Начало сегмента стека Конец сегмента стека Директива END заканчивает текст программы и предписывает начинать ее с команды, снабженной меткой Start |
Программа на ассемблере – это последовательность предложений, каждое из которых записывается в отдельной строке. Комментарии начинаются с символа “;”. Общий синтаксис предложений-команд:
В квадратных скобках указаны необязательные части команды. Метка нужна для ссылок на команду из других мест программы. Разрешается указывать в строке только одну метку с двоеточием (например, Start: ) и больше ничего, тогда она метит следующую команду программы. Мнемокод (мнемонический код) – это служебное слово, указывающее в символьной форме операцию, которую должна выполнить команда. Примерами операндов являются числа и имена переменных. Если операндов несколько, они отделяются друг от друга запятыми. Операндами могут быть и выражения, составляемые из чисел, имен переменных и операторов. Основные операторы ассемблера приведены в табл. 2.1.
Категория | Operator | What it is (or does) |
() [ ] | Подвыражение (Subexpression) Ссылка на ячейку памяти (Memory reference) | |
. | Селектор структурных элементов (Structure member selector) | |
Унарные | + — | Унарный плюс (Unary plus) Унарный минус (Unary minus) |
: | Переопределение сегмента (Segment override) | |
OFFSET SEG TYPE PTR | Возвращает смещение (Returns offset part) Возвращает сегментную часть Returns segment part Возвращает тип (байтовый размер) Returns type (byte size) Приведение типа (Typecast) | |
* / MOD SHL SHR | Умножение (Multiplication) Целое деление (Integer division) Integer modulus (remainder) Логический сдвиг влево (Logical shift left) Логический сдвиг вправо (Logical shift right) | |
Аддитивные | + — | Двоичное сложение (Binary addition) Двоичное вычитание (Binary subtraction) |
Битовые | NOT AND OR XOR | Битовое НЕ Битовое И Битовое ИЛИ Битовое Исключающее ИЛИ |
В программе на ассемблере для описания переменных и их имен должны присутствовать предложения-директивы с общим синтаксисом:
Имя (например, Greet) – это, как правило, имя константы или переменной, описываемой данной директивой. Название директивы – это служебные слова. Директива DB (define byte – определить байт) определяет данные размером в байт. При ее выполнении ассемблер вычисляет операнды и записывает их значения в последовательные байты памяти, начиная с первого незанятого. Первому из байтов дается указанное имя, по которому на этот байт можно ссылаться из других мест программы. Когда ассемблер встретит в программе имя переменной, он заменит его на адрес, который принято называть значением имени. По описанию переменной запоминается также ее размер (тип). Например, директива Greet DB ‘Hello world’,13,10, ‘$’ записывает последовательные байты памяти коды символов, помещенных в кавычки, код 10 (перевод строки), код 13 (возврат каретки) устанавливающий курсор на начало текущей строки, код символа конца строки ‘$’. Директивы определения помещаются в начале программы до команд.
Задания:
1. Найдите в тексте программы директиву определения данных и команды. В командах найдите и выпишите мнемокоды и операции, которые им соответствуют.
2. Выполните в программе-оболочке Far следующие действия (рис. 3.42):
1) Создайте в Far файл Greet.ASM и наберите программу.
2) Cкомпилируйте с помощью команды tasm greet.
3) Скомпонуйте с помощью команды tlink greet.
Получив исполняемый файл Greet.EXE выполните программу, например, введя имя Greet в командную строку.
Рис. 2.12. Команды и результаты компиляции и компоновки программы
3. Выполните то же самое задание с помощью интегрированной среды TASM. Скопируйте папку ТА из папки Student_MUPK_NW:COMMONLANGV в папку C:Student, запустите файл ta.exe. Нажмите клавишу F10 для перехода в главное меню, выполните команду File-Load (Файл-Загрузить), нажмите Enter, выберите из списка нужный файл. Выполните настройку — отключите опцию создания com-файла (рис. 2.13) и сохраните ее командой Options-Save options.
Рис. 2.13. Изменение опций компоновщика с отключением опции создания
com-файла
Затем выполните команды Compile to OBJ (компиляция), Make EXE file(компоновка) (рис. 2.14). В случае успеха выполните команду Run-Run program, затем Run-User screen.
Рис. 2.14. Создание exe-файла
В рассмотренных здесь и ниже примерах использованы вывод и ввод символов, реализуемых при выполнении одной из группы команд прерывания с шестнадцатиричным номером 21h дисковой операционной системы MS DOS. Перед выполнением команды прерывания INT в регистр AH записывают номер нужной функции. Функции с номерами 4Сh, 2 и 9 выполняют возврат управления операционной системе для продолжения выполнения программы, вывод одного символа на экран и вывод строки. Символ с кодами 10 (перевод строки) перемещает курсор в следующую строку экрана, оставляя его в той же колонке. Символ 13 (возврат каретки) устанавливает курсор на начало текущей строки. Функция 0Ch прерывания 21h вводит с клавиатуры символы (с эхо-печатью их на экране) до тех пор, пока не будет нажата клавиша Enter, и записывает их в буфер размером 15 позиций. Пока не нажата клавиша Enter, набираемый текст можно редактировать клавишами Backspace (отмена последнего символа) и Esc (отмена всего набранного текста). Функции ввода 0Ah, 0Ch и другие считывают символы из начала буфера.
Изучение работы микропроцессора с помощью Турбо Отладчика (Borland Turbo Debugger)
Турбо Отладчик (входящий в состав среды Borland C++) позволяет прослеживать выполнение инструкций ассемблера, содержимое ячеек оперативной памяти и регистров процессора и математического сопроцессора [58]. Он также позволяет отлаживать программы на языках Си и Паскаль. Общий вид команды запуска отладчика
TD opt name args
где opt – опции, name – имя запускаемой программы, args – ее аргументы.
Не нашли то, что искали? Воспользуйтесь поиском:
Лучшие изречения: Сдача сессии и защита диплома — страшная бессонница, которая потом кажется страшным сном. 8913 — | 7222 — или читать все.
91.146.8.87 © studopedia.ru Не является автором материалов, которые размещены. Но предоставляет возможность бесплатного использования. Есть нарушение авторского права? Напишите нам | Обратная связь.
Отключите adBlock!
и обновите страницу (F5)
очень нужно