Простая программа на ассемблере x86: Решето Эратосфена / Хабр
Вступительное слово
По своей профессии я не сталкиваюсь с низкоуровневым программированием: занимаюсь программированием на скриптовых языках. Но поскольку душа требует разнообразия, расширения горизонтов знаний или просто понимания, как работает машина на низком уровне, я занимаюсь программированием на языках, отличающихся от тех, с помощью которых зарабатываю деньги – такое у меня хобби.
И вот, я хотел бы поделиться опытом создания простой программы на языке ассемблера для процессоров семейства x86, с разбора которой можно начать свой путь в покорение низин уровней абстракции.
До ее написания я сформулировал такие требования к будущей программе:
- Моя программа не должна быть программой под DOS. Слишком много примеров ориентировано на нее в связи с простым API. Моя программа обязательно должна была запускаться на современных ОС.
- Программа должна использовать кучу – получать в свое распоряжение динамически распределяемую память.
- Чтобы не быть слишком сложной, программа должна работать с целыми беззнаковыми числами без использования переносов.
Задачей для своей программы я выбрал поиск простых чисел с помощью Решета Эратосфена. В качестве ассемблера я выбрал nasm.
Код я писал с упором больше на стиль и понятность, чем на скорость его выполнения. К примеру, обнуление регистра я проводил не с помощью xor eax, eax
, а с помощью mov eax, 0
в связи с более подходящей семантикой инструкции. Я решил, что поскольку программа преследует исключительно учебные цели, можно распоясаться и заниматься погоней за стилем кода в ассемблере.
Итак, посмотрим, что получилось.
С чего начать?
Пожалуй, самая сложная вещь, с которой сталкиваешься при переходе от высокоуровневых языков к ассемблеру, это организация памяти. К счастью, на эту тему на Хабре уже была хорошая статья.
Так же встает вопрос, каким образом на таком низком уровне реализуется обмен данными между внутренним миром программы и внешней средой. Тут на сцену выходит API операционной системы. В DOS, как уже было упомянуто, интерфейс был достаточно простой. К примеру, программа «Hello, world» выглядела так:
SECTION .text org 0x100 mov ah, 0x9 mov dx, hello int 0x21 mov ax, 0x4c00 int 0x21 SECTION .data hello: db "Hello, world!", 0xD, 0xA, '$'
В Windows же для этих целей используется Win32 API, соответственно, программа должна использовать методы соответствующих библиотек:
%include "win32n.inc" extern MessageBoxA import MessageBoxA user32.dll extern ExitProcess import ExitProcess kernel32.dll SECTION code use32 class=code ..start: push UINT MB_OK push LPCTSTR window_title push LPCTSTR banner push HWND NULL call [MessageBoxA] push UINT NULL call [ExitProcess] SECTION data use32 class=data banner: db "Hello, world!", 0xD, 0xA, 0 window_title: db "Hello", 0
Здесь используется файл win32n. inc, где определены макросы, сокращающие код для работы с Win32 API.
Я решил не использовать напрямую API ОС и выбрал путь использования функций из библиотеки Си. Так же это открыло возможность компиляции программы в Linux (и, скорее всего, в других ОС) – не слишком большое и нужное этой программе достижение, но приятное достижение.
Вызов подпрограмм
Потребность вызывать подпрограммы влечет за собой несколько тем для изучения: организация подпрограмм, передача аргументов, создание стекового кадра, работа с локальными переменными.
Подпрограммы представляют собой метку, по которой располагается код. Заканчивается подпрограмма инструкцией ret
. К примеру, вот такая подпрограмма в DOS выводит в консоль строку «Hello, world»:
print_hello: mov ah, 0x9 mov dx, hello int 0x21 ret
Для ее вызова нужно было бы использовать инструкцию call
:
call print_hello
Для себя я решил передавать аргументы подпрограммам через регистры и указывать в комментариях, в каких регистрах какие аргументы должны быть, но в языках высокого уровня аргументы передаются через стек. К примеру, вот так вызывается функция printf
из библиотеки Си:
push hello call _printf add esp, 4
Аргументы передаются справа налево, обязанность по очистке стека лежит на вызывающей стороне.
При входе в подпрограмму необходимо создать новый стековый кадр.
print_hello: push ebp ;сохраняем указатель начала стекового кадра на стеке mov ebp, esp ;теперь началом кадра является вершина предыдущего
Соответственно, перед выходом нужно восстановить прежнее состояние стека:
mov esp, ebp pop ebp ret
Для локальных переменных так же используется стек, на котором после создания нового кадра выделяется нужное количество байт:
print_hello: push ebp mov ebp, esp sub esp, 8 ;опускаем указатель вершины стека на 8 байт, чтобы выделить память
Так же архитектура x86 предоставляет специальные инструкции, с помощью которых можно более лаконично реализовать эти действия:
print_hello: enter 8, 0 ;создать новый кадр, выделить 8 байт для локальных переменных leave ;восстановить стек ret
Второй параметр инструкции enter
– уровень вложенности подпрограммы.
Непосредственно программа
Проект содержит такие файлы:
main.asm
– главный файл,functions.asm
– подпрограммы,string_constants.asm
– определения строковых констант,Makefile
– сценарий сборки
Рассмотрим код основного файла:
main.asm
%define SUCCESS 0 %define MIN_MAX_NUMBER 3 %define MAX_MAX_NUMBER 4294967294 global _main extern _printf extern _scanf extern _malloc extern _free SECTION .text _main: enter 0, 0 ;ввод максимального числа call input_max_number cmp edx, SUCCESS jne .custom_exit mov [max_number], eax ;выделяем память для массива флагов mov eax, [max_number] call allocate_flags_memory cmp edx, SUCCESS jne .custom_exit mov [primes_pointer], eax ;отсеять составные числа mov eax, [primes_pointer] mov ebx, [max_number] call find_primes_with_eratosthenes_sieve ;вывести числа mov eax, [primes_pointer] mov ebx, [max_number] call print_primes ;освободить память от массива флагов mov eax, [primes_pointer] call free_flags_memory ;выход .success: push str_exit_success call _printf jmp .return .custom_exit: push edx call _printf .return: mov eax, SUCCESS leave ret %include "functions.asm" SECTION .data max_number: dd 0 primes_pointer: dd 0 %include "string_constants.asm"
Видно, что программа поделена по смыслу на 5 блоков, оформленных в виде подпрограмм:
input_max_number
— с помощью консоли запрашивает у пользователя максимальное число, до которого производится поиск простых; во избежание ошибок значение ограничено константамиMIN_MAX_NUMBER
иMAX_MAX_NUMBER
allocate_flags_memory
— запросить у ОС выделение памяти для массива пометок чисел (простое/составное) в куче; в случае успеха возвращает указатель на выделенную память через регистрeax
find_primes_with_eratosthenes_sieve
— отсеять составные числа с помощью классического решета Эратосфена;print_primes
— вывести в консоль список простых чисел;free_flags_memory
— освободить память, выделенную для флагов
Для функций было условлено такое правило: значение возвращается через регистр eax
, регистр edx
содержит статус.
SUCCESS
, то есть, 0
, в случае неудачи — адрес строки с сообщением об ошибке, которое будет выведено пользователю.Файл string_constants.asm
содержит определение строковых переменных, значения которых, как намекает название файла, менять не предполагается. Только ради этих переменных было сделано исключение к правилу «не использовать глобальные переменные». Я так и не нашел более удобного способа доставлять строковые константы функциям ввода-вывода – подумывал даже записывать на стек непосредственно перед вызовами функций, но решил, что эта идея куда хуже идеи с глобальными переменными.
string_constants.asm
;подписи ввода-вывода, форматы str_max_number_label: db "Max number (>=3): ", 0 str_max_number_input_format: db "%u", 0 str_max_number_output_format: db "Using max number %u", 0xD, 0xA, 0 str_print_primes_label: db "Primes:", 0xD, 0xA, 0 str_prime: db "%u", 0x9, 0 str_cr_lf: db 0xD, 0xA, 0 ;сообщения выхода str_exit_success: db "Success!", 0xD, 0xA, 0 str_error_max_num_too_little: db "Max number is too little!", 0xD, 0xA, 0 str_error_max_num_too_big: db "Max number is too big!", 0xD, 0xA, 0 str_error_malloc_failed: db "Can't allocate memory!", 0xD, 0xA, 0
Для сборки применяется такой сценарий:
Makefile
ifdef SystemRoot format = win32 rm = del ext = . exe else format = elf rm = rm -f ext = endif all: primes.o gcc primes.o -o primes$(ext) $(rm) primes.o primes.o: nasm -f $(format) main.asm -o primes.o
Подпрограммы (функции)
input_max_number
Код подпрограммы
; Ввести максимальное число ; Результат: EAX - максимальное число input_max_number: ;создать стек-фрейм, ;4 байта для локальных переменных enter 4, 1 ;показываем подпись push str_max_number_label ;см. string_constants.asm call _printf add esp, 4 ;вызываем scanf mov eax, ebp sub eax, 4 push eax push str_max_number_input_format ;см. string_constants.asm call _scanf add esp, 8 mov eax, [ebp-4] ;проверка cmp eax, MIN_MAX_NUMBER jb .number_too_little cmp eax, MAX_MAX_NUMBER ja .number_too_big jmp .success ;выход .number_too_little: mov edx, str_error_max_num_too_little ;см. string_constants.asm jmp .return .number_too_big: mov edx, str_error_max_num_too_big ;см.string_constants.asm jmp .return .success: push eax push str_max_number_output_format ;см. string_constants.asm call _printf add esp, 4 pop eax mov edx, SUCCESS .return: leave ret
Подпрограмма призвана ввести в программу максимальное число, до которого будет производиться поиск простых. Ключевым моментов тут является вызов функции scanf
из библиотеки Си:
mov eax, ebp sub eax, 4 push eax push str_max_number_input_format ;см. string_constants.asm call _scanf add esp, 8 mov eax, [ebp-4]
Таким образом, сначала в eax
записывается адрес памяти на 4 байта ниже указателя базы стека. Это память, выделенная для локальных нужд подпрограммы. Указатель на эту память передается функции scanf
как цель для записи данных, введенных с клавиатуры.
После вызова функции, в eax
из памяти перемещается введенное значение.
allocate_flags_memory и free_flags_memory
Код подпрограмм
; Выделить память для массива флагов ; Аргумент: EAX - максимальное число ; Результат: EAX - указатель на память allocate_flags_memory: enter 8, 1 ;выделить EAX+1 байт inc eax mov [ebp-4], eax push eax call _malloc add esp, 4 ;проверка cmp eax, 0 je .fail mov [ebp-8], eax ;инициализация mov byte [eax], 0 cld mov edi, eax inc edi mov edx, [ebp-4] add edx, eax mov al, 1 .write_true: stosb cmp edi, edx jb .write_true ;выход mov eax, [ebp-8] jmp .success .fail: mov edx, str_error_malloc_failed ;см. string_constants.asm jmp .return .success: mov edx, SUCCESS .return: leave ret ; Освободить память от массива флагов ; Аргумент: EAX - указатель на память free_flags_memory: enter 0, 1 push eax call _free add esp, 4 leave ret
Ключевыми местами этих подпрограмм являются вызовы функций malloc
и free
из библиотеки Си.
malloc
в случае удачи возвращает через регистр eax
адрес выделенной памяти, в случае неудачи этот регистр содержит 0
. Это самое узкое место программы касательно максимального числа. 32 бит вполне достаточно для поиска простых чисел до 4 294 967 295, но выделить разом столько памяти не получится.
find_primes_with_eratosthenes_sieve
Код подпрограммы
;Найти простые числа с помощью решета Эратосфена ;Аргументы: EAX - указатель на массив флагов, EBX - максимальное число find_primes_with_eratosthenes_sieve: enter 8, 1 mov [ebp-4], eax add eax, ebx inc eax mov [ebp-8], eax ;вычеркиваем составные числа cld mov edx, 2 ;p = 2 mov ecx, 2 ;множитель с = 2 .strike_out_cycle: ;x = c*p mov eax, edx push edx mul ecx pop edx cmp eax, ebx jbe .strike_out_number jmp .increase_p .strike_out_number: mov edi, [ebp-4] add edi, eax mov byte [edi], 0 inc ecx ;c = c + 1 jmp . strike_out_cycle .increase_p: mov esi, [ebp-4] add esi, edx inc esi mov ecx, edx inc ecx .check_current_number: mov eax, ecx mul eax cmp eax, ebx ja .return lodsb inc ecx cmp al, 0 jne .new_p_found jmp .check_current_number .new_p_found: mov edx, ecx dec edx mov ecx, 2 jmp .strike_out_cycle .return: leave ret
Подпрограмма реализует классический алгоритм для вычеркивания составных чисел, решето Эратосфена, на языке ассемблера x86. Приятна тем, что не использует вызовы внешних функций и не требует обработки ошибок 🙂
print_primes
Код подпрограммы
; Вывести простые числа ; Параметры: EAX - указатель на массив флагов, EBX - максимальное число print_primes: enter 12, 1 mov [ebp-4], eax mov [ebp-8], ebx push str_print_primes_label call _printf add esp, 4 cld mov esi, [ebp-4] mov edx, esi add edx, [ebp-8] inc edx mov [ebp-12], edx mov ecx, 0 . print_cycle: lodsb cmp al, 0 jne .print jmp .check_finish .print: push esi push ecx push str_prime ;см. string_constants.asm call _printf add esp, 4 pop ecx pop esi mov edx, [ebp-12] .check_finish: inc ecx cmp esi, edx jb .print_cycle push str_cr_lf call _printf add esp, 4 leave ret
Подпрограмма выводит в консоль простые числа. Ключевым моментом тут является вызов функции printf
из библиотеки Си.
Заключение
Что ж, программа отвечает всем сформулированным требованиям и, кажется, проста для понимания. Хочется надеяться, кому-нибудь ее разбор поможет вникнуть в программирование на низком уровне и он получит от него такое же удовольствие, какое получил я.
Так же привожу полные исходники программы.
Могу так же привести интересный факт. Поскольку с детства нас учили, что программы на языке ассемблера выполняются быстрее, я решил сравнить скорость выполнения этой программы со скоростью программы на C++, которую я писал когда-то и которая искала простые числа с помощью Решета Аткина. Программа на С++, скомпилированная в Visual Studio с /O2
выполняла поиск до числа 230 примерно за 25 секунд на моей машине. Программа же на ассемблере показала 15 секунд с Решетом Эратосфена.
Это, конечно, скорее байка, чем научный факт, поскольку не было серьезного тестирования не было выяснения причин, но как интересный факт для завершения статьи подойдет, как мне кажется.
Полезные ссылки
- Список ресурсов для изучения ассемблера
- Организация памяти
- Решето Эратосфена
- Решето Аткина
- Стек
- Стековый кадр
Программирование на Ассемблере для начинающих с примерами программ
Многие считают, что Assembler – уже устаревший и нигде не используемый язык, однако в основном это молодые люди, которые не занимаются профессионально системным программированием. Разработка ПО, конечно, хорошо, но в отличие от высокоуровневых языков программирования, Ассемблер научит глубоко понимать работу компьютера, оптимизировать работку с аппаратными ресурсами, а также программировать любую технику, тем самым развиваясь в направлении машинного обучения. Для понимания этого древнего ЯП, для начала стоит попрактиковаться с простыми программами, которые лучше всего объясняют функционал Ассемблера.
IDE для Assembler
Первый вопрос: в какой среде разработки программировать на Ассемблере? Ответ однозначный – MASM32. Это стандартная программа, которую используют для данного ЯП. Скачать её можно на официальном сайте masm32.com в виде архива, который нужно будет распаковать и после запустить инсталлятор install.exe. Как альтернативу можно использовать FASM, однако для него код будет значительно отличаться.
Перед работой главное не забыть дописать в системную переменную PATH строчку:
С:\masm32\bin
Программа «Hello world» на ассемблере
Считается, что это базовая программа в программировании, которую начинающие при знакомстве с языком пишут в первую очередь. Возможно, такой подход не совсем верен, но так или иначе позволяет сразу же увидеть наглядный результат:
.386 . model flat, stdcall option casemap: none include /masm32/include/windows.inc include /masm32/include/user32.inc include /masm32/include/kernel32.inc includelib /masm32/lib/user32.lib includelib /masm32/lib/kernel32.lib .data msg_title db "Title", 0 msg_message db "Hello world", 0 .code start: invoke MessageBox, 0, addr msg_message, addr msg_title, MB_OK invoke ExitProcess, 0 end start
Для начала запускаем редактор qeditor.exe в папке с установленной MASM32, и в нём пишем код программы. После сохраняем его в виде файла с расширением «.asm», и билдим программу с помощью пункта меню «Project» → «Build all». Если в коде нет ошибок, программа успешно скомпилируется, и на выходе мы получим готовый exe-файл, который покажет окно Windows с надписью «Hello world».
Сложение двух чисел на assembler
В этом случае мы смотрим, равна ли сумма чисел нулю, или же нет. Если да, то на экране появляется соответствующее сообщение об этом, и, если же нет – появляется иное уведомление.
.486 .model flat, stdcall option casemap: none include /masm32/include/windows.inc include /masm32/include/user32.inc include /masm32/include/kernel32.inc includelib /masm32/lib/user32.lib includelib /masm32/lib/kernel32.lib include /masm32/macros/macros.asm uselib masm32, comctl32, ws2_32 .data .code start: mov eax, 123 mov ebx, -90 add eax, ebx test eax, eax jz zero invoke MessageBox, 0, chr$("В eax не 0!"), chr$("Info"), 0 jmp lexit zero: invoke MessageBox, 0, chr$("В eax 0!"), chr$("Info"), 0 lexit: invoke ExitProcess, 0 end start
Здесь мы используем так называемые метки и специальные команды с их использованием (jz, jmp, test). Разберём подробнее:
- test – используется для логического сравнения переменных (операндов) в виде байтов, слов, или двойных слов. Для сравнения команда использует логическое умножение, и смотрит на биты: если они равны 1, то и бит результата будет равен 1, в противном случае – 0. Если мы получили 0, ставятся флаги совместно с ZF (zero flag), которые будут равны 1. Далее результаты анализируются на основе ZF.
- jnz – в случае, если флаг ZF нигде не был поставлен, производится переход по данной метке. Зачастую эта команда применяется, если в программе есть операции сравнения, которые как-либо влияют на результат ZF. К таким как раз и относятся test и cmp.
- jz – если флаг ZF всё же был установлен, выполняется переход по метке.
- jmp – независимо от того, есть ZF, или же нет, производится переход по метке.
Программа суммы чисел на ассемблере
Примитивная программа, которая показывает процесс суммирования двух переменных:
.486 .model flat, stdcall option casemap: none include /masm32/include/windows.inc include /masm32/include/user32.inc include /masm32/include/kernel32.inc includelib /masm32/lib/user32.lib includelib /masm32/lib/kernel32.lib include /masm32/macros/macros. asm uselib masm32, comctl32, ws2_32 .data msg_title db "Title", 0 A DB 1h B DB 2h buffer db 128 dup(?) format db "%d",0 .code start: MOV AL, A ADD AL, B invoke wsprintf, addr buffer, addr format, eax invoke MessageBox, 0, addr buffer, addr msg_title, MB_OK invoke ExitProcess, 0 end start
В Ассемблере для того, чтобы вычислить сумму, потребуется провести немало действий, потому как язык программирования работает напрямую с системной памятью. Здесь мы по большей частью манипулируем ресурсами, и самостоятельно указываем, сколько выделить под переменную, в каком виде воспринимать числа, и куда их девать.
Получение значения из командной строки на ассемблере
Одно из важных основных действий в программировании – это получить данные из консоли для их дальнейшей обработки. В данном случае мы их получаем из командной строки и выводим в окне Windows:
.486 . model flat, stdcall option casemap: none include /masm32/include/windows.inc include /masm32/include/user32.inc include /masm32/include/kernel32.inc includelib /masm32/lib/user32.lib includelib /masm32/lib/kernel32.lib include /masm32/macros/macros.asm uselib masm32, comctl32, ws2_32 .data .code start: call GetCommandLine ; результат будет помещен в eax push 0 push chr$("Command Line") push eax ; текст для вывода берем из eax push 0 call MessageBox push 0 call ExitProcess end start
Также можно воспользоваться альтернативным методом:
.486 .model flat, stdcall option casemap: none include /masm32/include/windows.inc include /masm32/include/user32.inc include /masm32/include/kernel32.inc includelib /masm32/lib/user32.lib includelib /masm32/lib/kernel32.lib include /masm32/macros/macros. asm uselib masm32, comctl32, ws2_32 .data .code start: call GetCommandLine ; результат будет помещен в eax invoke GetCommandLine invoke MessageBox, 0, eax, chr$("Command Line"), 0 invoke ExitProcess, 0 push 0 call ExitProcess end start
Здесь используется invoke – специальный макрос, с помощью которого упрощается код программы. Во время компиляции макрос-команды преобразовываются в команды Ассемблера. Так или иначе, мы пользуемся стеком – примитивным способом хранения данных, но в тоже время очень удобным. По соглашению stdcall, во всех WinAPI-функциях переменные передаются через стек, только в обратном порядке, и помещаются в соответствующий регистр eax.
Циклы в ассемблере
Вариант использования:
.data msg_title db "Title", 0 A DB 1h buffer db 128 dup(?) format db "%d",0 .code start: mov AL, A .REPEAT inc AL . UNTIL AL==7 invoke wsprintf, addr buffer, addr format, AL invoke MessageBox, 0, addr buffer, addr msg_title, MB_OK invoke ExitProcess, 0 end start
.data msg_title db "Title", 0 buffer db 128 dup(?) format db "%d",0 .code start: mov eax, 1 mov edx, 1 .WHILE edx==1 inc eax .IF eax==7 .BREAK .ENDIF .ENDW invoke wsprintf, addr buffer, addr format, eax invoke MessageBox, 0, addr buffer, addr msg_title, MB_OK invoke ExitProcess, 0
Для создания цикла используется команда repeat. Далее с помощью inc увеличивается значение переменной на 1, независимо от того, находится она в оперативной памяти, или же в самом процессоре. Для того, чтобы прервать работу цикла, используется директива «.BREAK». Она может как останавливать цикл, так и продолжать его действие после «паузы». Также можно прервать выполнение кода программы и проверить условие repeat и while с помощью директивы «. CONTINUE».
Сумма элементов массива на assembler
Здесь мы суммируем значения переменных в массиве, используя цикл «for»:
.486 .model flat, stdcall option casemap: none include /masm32/include/windows.inc include /masm32/include/user32.inc include /masm32/include/kernel32.inc includelib /masm32/lib/user32.lib includelib /masm32/lib/kernel32.lib include /masm32/macros/macros.asm uselib masm32, comctl32, ws2_32 .data msg_title db "Title", 0 A DB 1h x dd 0,1,2,3,4,5,6,7,8,9,10,11 n dd 12 buffer db 128 dup(?) format db "%d",0 .code start: mov eax, 0 mov ecx, n mov ebx, 0 L: add eax, x[ebx] add ebx, type x dec ecx cmp ecx, 0 jne L invoke wsprintf, addr buffer, addr format, eax invoke MessageBox, 0, addr buffer, addr msg_title, MB_OK invoke ExitProcess, 0 end start
Команда dec, как и inc, меняет значение операнда на единицу, только в противоположную сторону, на -1. А вот cmp сравнивает переменные методом вычитания: отнимает одно значение из второго, и, в зависимости от результата ставит соответствующие флаги.
С помощью команды jne выполняется переход по метке, основываясь на результате сравнения переменных. Если он отрицательный – происходит переход, а если операнды не равняются друг другу, переход не осуществляется.
Ассемблер интересен своим представлением переменных, что позволяет делать с ними что угодно. Специалист, который разобрался во всех тонкостях данного языка программирования, владеет действительно ценными знаниями, которые имеют множество путей использования. Одна задачка может решаться самыми разными способами, поэтому путь будет тернист, но не менее увлекательным.
Post Views: 57 476
программных частей на АССЕМБЛЕРЕ
программных частей на АССЕМБЛЕРЕЧасти программы АССЕМБЛЕРА
Заявление CSECT
-
Оператор END
Формат: КОНЕЦ этикетки
Определяет конец того, что должно быть собрано.
Последняя строка программы на ассемблере.
Этикеткаобычно является этикеткой на основной или 1 st CSECT. Если указано, то именованная метка CSECT является точкой входа программы.
-
Последняя строка исполняемого кода:
БКР В1111,14
- возвращает управление операционной системе
Соглашения о связях:
При входе в программу на ассемблере R15 содержит адрес точка входа (т.е. начало программы). R15 может быть использован в качестве базы регистр.
При входе в программу на ассемблере R14 содержит адрес возврата , который является адресом в операционной системе для перехода, когда программа законченный.
Пример программы на АССЕМБЛЕРЕ:
Адрес Код для выполнения 000000 EXMPL1 CSECT 000000 л 5,24(,15) 000004 А 5,28(,15) 000008 СТ 5,36(,15) 00000С л 4,32(,15) 000010 СР 4,5 000012 СТ 4,40(,15) 000016 БКР Б1111,14 000018 NUM1 DC F15 00001C NUM2 DC F7 000020 NUM3 DC F8 000024 РЕЗУЛЬТАТ1 ДС Ф 000028 РЕЗУЛЬТАТ2 ДС Ф КОНЕЦ ПРИМЕР1
Было бы неплохо иметь возможность использовать метки NUM1, NUM2 и т. д.?
Неявная адресация
-
Неявный адрес адрес, который потребуется ассемблеру преобразовать в явный адрес
Используйте метку (обычно на DC или DS в хранилище), а не D(B) или Адрес D(X,B) при кодировании инструкции
Формат 1: этикетка
Формат 2: метка + n — где n — десятичное смещение
Формат 3: метка(R) — где R — номер индексного регистра
Формат 4: метка + n(R) — где n — десятичное смещение, R — индекс reg
Должен сначала установить адресность (снабдить ассемблер базовый адрес) с оператором USING.
Формат: USING label, R
-
Регистр R #, который содержит действительный базовый адрес
метка метка в программе, соответствующая базовому адресу в р
USING не занимает места.
Пересмотренный образец программы на АССЕМБЛЕРЕ:
Адрес Код для выполнения 000000 EXMPL1 CSECT 000000 ИСПОЛЬЗОВАНИЕ EXMPL1,15 000000 л 5, НОМЕР1 000004 А 5,ЧИСЛО2 000008 СТ 5, РЕЗУЛЬТАТ 1 00000C л 4,ЧИСЛО3 000010 СР 4,5 000012 СТ 4, РЕЗУЛЬТАТ 2 000016 БКР Б1111,14 000018 NUM1 DC F15 00001C NUM2 DC F7 000020 NUM3 DC F8 000024 РЕЗУЛЬТАТ1 ДС Ф 000028 РЕЗУЛЬТАТ2 ДС Ф КОНЕЦ ПРИМЕР1
Очень простая программа на ассемблере, установка кода возврата на ноль и возврат вызывающей стороне
Очень простая программа на ассемблере, установка кода возврата на ноль и возврат вызывающей стороне Малая программа на ассемблере Установить код возврата на ноль и вернуться |
|
Эта программа просто вычитает Регистр-15 из самого себя (т. е. устанавливает значение в ноль) и затем делает безусловный переход к адресу указанному в Регистре-14. Ассемблерная программа написана на IBM Mainframe Assembler, она будет компилироваться с использованием Assembler/H или HLASM. Участник JCL предоставляется для запуска задания в виде пакетного задания MVS на мейнфрейме IBM или в виде проекта с Micro Focus Mainframe Express (MFE), работающего в системе Windows.
Эта программа может служить учебным пособием для программистов, плохо знакомых с ассемблером 370, и справочником для опытных программистов.
Мы приложили значительные усилия, чтобы документы и программные технологии были правильными и точными. Мы оставляем за собой право вносить изменения без предварительного уведомления в любое время. Функция, представленная в этой версии, основана на запросах на усовершенствование от определенной группы пользователей. Цель состоит в том, чтобы вносить изменения по мере необходимости и в сроки, зависящие от наличия ресурсов.
Copyright © 1987-2023
Технологии и услуги SimoTime
Все права защищены
Ниже приведен JCL мейнфрейма (ASMR14J1.jcl), необходимый для запуска программы на ассемблере. Оператор JOB необходимо будет изменить для конкретных сред мэйнфреймов. Это также будет работать в системе Windows с использованием Mainframe Express, предоставляемого Micro Focus.
//ASMR14J1 ЗАДАНИЕ SIMOTIME,ACCOUNT,CLASS=1,MSGCLASS=O,NOTIFY=LRSP1 //* **************************************************** ******************** //* ASMR14J1.JCL — член JCL для пакетной обработки заданий * //* Этот член JCL предоставлен SimoTime Technologies * //* (С) Копирайт 1987-2019 Все права защищены * //* URL веб-сайта: http://www.simotime.com * //* электронная почта: [email protected] * //* **************************************************** ******************** //* //* Текст - ассемблер 370, возврат к вызывающей стороне с нулевым кодом возврата //* Автор - SimoTime Technologies //* Дата - 01 января 1997 г. //* //* **************************************************** ******************** //* Шаг 1 из 1. Это одноэтапное задание. //* // ASMWTOS1 EXEC PGM=ASMR14A1 //STEPLIB DD DSN=SIMOTIME.DEMO.LOADLIB1,DISP=SHR //*
Эта программа (ASMR14A1.mlc) соблюдает протокол вызова мейнфрейма и правила использования регистров. Регистр-15 используется для передачи кода возврата, а регистр-14 содержит адрес возврата для вызывающей программы. Эта программа просто вычитает Регистр-15 из самого себя (т.е. устанавливает значение в ноль) и затем делает безусловный переход к адресу, указанному в Регистре-14.
******************************************************* ********************* * ASMR14A1.MLC - это программа HLASM * * Предоставлено SimoTime Technologies * * (С) Авторское право 1987-2019 Все права защищены * * URL веб-сайта: http://www.simotime.com * * электронная почта: [email protected] * ******************************************************* ********************* * * * Создано: 1 июня 1974 г. , Симмонс * * Изменено: 01.06.1974, Симмонс, на сегодняшний день изменений нет... * * * ******************************************************* ********************* * * Установите код возврата на НОЛЬ и возврат к вызывающему абоненту. * ASMR14A1 CSECT SR 15,15 * Установить код возврата на ноль BR 14 * Возврат к вызывающему абоненту КОНЕЦ
Примечание. Программа выполняет ту же функцию, что и IEFBR14.
Это простая программа, которая устанавливает нулевой код возврата и возвращает в вызывающую программу. Этот документ может быть использован как руководство для новых программистов на ассемблере или как краткий справочник для опытных программистов. Образцы сосредоточены на методах кодирования отдельных инструкций. Как всегда, ответственность за тщательное тестирование всех программ лежит на программисте.
Разрешение на использование, копирование, изменение и распространение этого программного обеспечения, документации или учебных материалов в любых целях требует уплаты SimoTime Technologies платы. Как только оплата будет получена SimoTime, будет доставлена последняя версия программного обеспечения, документации или учебных материалов, а также будет предоставлена лицензия для использования на предприятии при условии, что уведомление об авторских правах SimoTime появится на всех копиях программного обеспечения. Название или логотип SimoTime не могут использоваться в какой-либо рекламе или публикациях, касающихся использования программного обеспечения, без письменного разрешения SimoTime Technologies.
SimoTime Technologies не дает никаких гарантий и не делает заявлений о пригодности программного обеспечения, документации или учебных материалов для каких-либо целей. Он предоставляется «КАК ЕСТЬ» без каких-либо явных или подразумеваемых гарантий, включая подразумеваемые гарантии товарного состояния, пригодности для определенной цели и ненарушения прав. SimoTime Technologies не несет ответственности за любые прямые, косвенные, фактические или косвенные убытки, возникшие в результате потери использования, данных или проектов, будь то в результате действия контракта или деликта, возникающие в результате или в связи с использованием или работой этого программного обеспечения. , документации или учебных материалов.
Соглашение об использовании программного обеспечения и отказ от ответственности
Разрешение на использование, копирование, изменение и распространение этого программного обеспечения, документации или учебных материалов в любых целях требует уплаты SimoTime Technologies платы. Как только оплата будет получена SimoTime, будет доставлена последняя версия программного обеспечения, документации или учебных материалов, а также будет предоставлена лицензия для использования на предприятии при условии, что уведомление об авторских правах SimoTime появится на всех копиях программного обеспечения. Название или логотип SimoTime не могут использоваться в какой-либо рекламе или публикациях, касающихся использования программного обеспечения, без письменного разрешения SimoTime Technologies.
SimoTime Technologies не дает никаких гарантий и не делает заявлений о пригодности программного обеспечения, документации или учебных материалов для каких-либо целей. Он предоставляется «КАК ЕСТЬ» без каких-либо явных или подразумеваемых гарантий, включая подразумеваемые гарантии товарного состояния, пригодности для определенной цели и ненарушения прав. SimoTime Technologies не несет ответственности за любые прямые, косвенные, фактические или косвенные убытки, возникшие в результате потери использования, данных или проектов, будь то в результате действия контракта или деликта, возникающие в результате или в связи с использованием или работой этого программного обеспечения. , документации или учебных материалов.
Загрузки и ссылки
Этот раздел содержит ссылки на документы с дополнительной информацией, выходящей за рамки и цели этого документа. Первая группа документов может быть доступна из локальной системы или через интернет-соединение, для второй группы документов потребуется интернет-соединение.
Примечание. Лицензия SimoTime требуется для того, чтобы элементы были доступны в локальной системе или на сервере.
Текущий сервер или доступ в Интернет
Следующие ссылки могут быть на текущий сервер или в Интернет.
Изучите Assembler Connection, чтобы найти дополнительные примеры методов программирования на ассемблере для мэйнфреймов и образцы кода.
Изучите таблицы перевода ASCII и EBCDIC. Эти таблицы предназначены для тех, кому необходимо лучше понять структуру битов и различия форматов кодирования.
Изучите коды возврата статуса файла, чтобы интерпретировать результаты доступа к наборам данных VSAM и/или файлам QSAM.
Требуется доступ в Интернет
Следующие ссылки требуют подключения к Интернету.
Этот набор программ и документации доступен для загрузки. Ссылка на оценочный вариант zPAK, который включает участников программы, документацию и контрольные файлы.
Хорошее место для начала Домашняя страница SimoTime для доступа к официальным документам, примерам программ и информации о продуктах. Эта ссылка требует подключения к Интернету
Исследовать Веб-сайт Micro Focus для получения дополнительной информации о продуктах (включая Micro Focus COBOL) и услугах, доступных от Micro Focus. Эта ссылка требует подключения к Интернету.
Словарь терминов
Изучите Глоссарий терминов, чтобы найти список терминов и определений, используемых в этом наборе документов и официальных документов.
Комментарии или отзывы
Этот документ был создан и поддерживается SimoTime Technologies. Если у вас есть какие-либо вопросы, предложения, комментарии или отзывы, пожалуйста, используйте следующую контактную информацию.
1. | Отправьте электронное письмо в нашу службу поддержки. |
2. | Наши телефоны следующие. |
2.1. | 1 415 763-9430 офис-справочная |
2.2. | 1 415 827-7045 моб. |
Мы ценим ваше мнение.
Обзор компании
SimoTime Technologies была основана в 1987 году и является частной компанией. Мы специализируемся на создании и развертывании бизнес-приложений с использованием новых или существующих технологий и сервисов. У нас есть команда людей, которые разбираются в широком спектре технологий, используемых в современных условиях. Нашими клиентами являются как малые предприятия, использующие Интернет-технологии, так и корпорации, использующие очень большие системы мейнфреймов.
Довольно часто для выхода на более крупные рынки или предоставления более высокого уровня обслуживания существующим клиентам требуется, чтобы новые интернет-технологии работали в дополнение к существующим корпоративным системам мейнфреймов.