Ассемблер программа: Простая программа на ассемблере x86: Решето Эратосфена / Хабр

Содержание

Простая программа на ассемблере 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 блоков, оформленных в виде подпрограмм:

  1. input_max_number — с помощью консоли запрашивает у пользователя максимальное число, до которого производится поиск простых; во избежание ошибок значение ограничено константами MIN_MAX_NUMBER и MAX_MAX_NUMBER
  2. allocate_flags_memory — запросить у ОС выделение памяти для массива пометок чисел (простое/составное) в куче; в случае успеха возвращает указатель на выделенную память через регистр eax
  3. find_primes_with_eratosthenes_sieve — отсеять составные числа с помощью классического решета Эратосфена;
  4. print_primes — вывести в консоль список простых чисел;
  5. 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 секунд с Решетом Эратосфена.

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

Полезные ссылки

  1. Список ресурсов для изучения ассемблера
  2. Организация памяти
  3. Решето Эратосфена
  4. Решето Аткина
  5. Стек
  6. Стековый кадр

Программирование на Ассемблере для начинающих с примерами программ

Многие считают, что 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

    • возвращает управление операционной системе

 

 

Соглашения о связях:

  1. При входе в программу на ассемблере R15 содержит адрес точка входа (т.е. начало программы). R15 может быть использован в качестве базы регистр.

  2. При входе в программу на ассемблере 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
 

Очень простая программа на ассемблере, установка кода возврата на ноль и возврат вызывающей стороне

Очень простая программа на ассемблере, установка кода возврата на ноль и возврат вызывающей стороне
Малая программа на ассемблере
Установить код возврата на ноль и вернуться
  Содержание v-16. 01.01 — asmr1401.htm
  Введение
  Член JCL
  Основная программа на ассемблере
  Резюме
  Соглашение о программном обеспечении и отказ от ответственности
  Загрузки и ссылки
  Текущий сервер или доступ в Интернет
  Требуется доступ в Интернет
  Глоссарий терминов
  комментариев или отзывов
  Обзор компании

Эта программа просто вычитает Регистр-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 году и является частной компанией. Мы специализируемся на создании и развертывании бизнес-приложений с использованием новых или существующих технологий и сервисов. У нас есть команда людей, которые разбираются в широком спектре технологий, используемых в современных условиях. Нашими клиентами являются как малые предприятия, использующие Интернет-технологии, так и корпорации, использующие очень большие системы мейнфреймов.

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

Оставить комментарий

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *