Приступаем к обучению asm. Для того, чтобы уже на первых программах можно было вводить данные и видеть результат, написаны файлы с макрокомандами (io.asm, ioprc.asm). Для нас, дебилов, также заготовлены .exe файлы, которые все это сами линкуют и дают результат. Однако, хочется делать все самому. Итак, есть три файла: job.asm - это моя задача, io.asm - файл с макрокомандами (он подключается в первом файле строкой include io.asm) и файл ioprc.asm где описаны процедуры ввода вывода. Предварительно готовиться ioprc.obj (что просто), а теперь надо бы линковать job.asm c учетом этого, но у меня не выходит. Вот как выглядит .bat файл у преподов (MASM 4.0): @echo off c:\masm\masm %1,%1,%1 /ic:\masm; if errorlevel 1 goto fin c:\masm\link %1+c:\masm\ioproc.obj,%1; if errorlevel 1 goto fin del %1.obj %1.exe :fin Но, по-моему, в masm32 команды типа c:\masm\link %1+c:\masm\ioproc.obj не пройдут? ЗЫ. Я не знаю пока ничего о структуре программ на ассемблере. Объясните, как правильно запустить (fac прочитан, но в данном вопросе не помог). И да прибудет с вами сила.
Я, наконец, разобрался что к чему и захотелось поделиться (если лишнее - удалите). Это пригодится всем тем, кто изучает базовый ассемблер, т.е. сам ассемблер, а не его взаимодействие с win32 API. С помощью макроопределний можно вводить и выводить информацию как в обычном консольном приложении. Это позволяет заниматься только языком в его первозданном виде. для этого нужны два файла IOPROC.ASM Код (Text): ; Модуль IOPROC: Процедуры ввода-вывода public procnl, procoutnum, procflush, procinch, procinint iocode segment assume cs:iocode ;********************************************************* ; ВЫВОД НА ЭКРАН ;********************************************************* ;========================================================= ; Перевод курсора на новую строку экрана ; Обращение: call procnl ; Параметров нет ;--------------------------------------------------------- procnl proc far push dx push ax mov ah,2 mov dl,13 ; CR (курсор на начало строки) int 21h mov dl,10 ; LF (курсор на следующую строку) int 21h pop ax pop dx ret procnl endp ;========================================================= ; Вывод целого числа-слова со знаком или без знака ; Обращение: call procoutnum ; На входе: ах - выводимое число ; dh - число со знаком (1) или без знака (0) ; dl - ширина поля вывода (>=0) ; (если поле больше, чем надо, то слева добавляются пробелы, ; если меньше - выводится только число) ;--------------------------------------------------------- procoutnum proc far push bp mov bp,sp push ax push dx push si sub sp,6 ; отвести 6 байтов в стеке под число ; учет знака cmp dh,1 ; вывод со знаком (dh=l) ? jne pon0 cmp ax,0 jge pon0 mov dh,2 ; если вывод со знахом и ах<0, neg ax ; то dh:=2, ax:=abs(ax) pon0: push dx ; спасти dh (знак) и dl (ширину) ; запись цифр числа в стек (в обратном порядке) xor si,si ; si - кол-во цифр в числе ponl: mov dx,0 ; ax -> (dx,ax) div cs: ten ; ax=ax div 10; dx=ax mod 10 add dl,'0' mov byte ptr [bp-8+si], dl ; цифра -> стек inc si or ax,ax jnz ponl ; еще не 0 ; запись.минуса, если есть, в стек pop dx cmp dh,2 jne pon2 mov byte ptr [bp-8+si],'-' inc si ; печать пробелов впереди pon2: mov dh, 0 ; dx - ширина поля вывода mov ah ,2 ; функция 02 прерывания 21h pon21:cmp dx,si jle pon3 ; ширина <= длина числа push dx mov dl,' ' int 21h pop dx dec dx jmp pon21 ; печать (минуса и) цифр pon3: dec si mov dl,byte ptr [bp-8+si] int 21h or si,si jnz pon3 ; выход из процедуры add sp,6 pop si pop dx pop ax pop bp ret ten dw 10 procoutnum endp ;**************************************************** ; ВВОД С КЛАВИАТУРЫ ;**************************************************** ; буфер ввода с клавиатуры (для работы с функцией OAh) maxb db 128 ; макc, размер буфера ввода sizeb db 0 ; число введенных символов в буфере buf db 128 dup(?) ; сам буфер ввода posb db 0 ; номер послед, считан, символа из buf ;==================================================== ; вспомогательная процедура ввода строки символов ; (включая Enter) в буфер buf (ввод без приглашения) ;---------------------------------------------------- readbuf proc near push ax push dx push ds mov dx,cs mov ds,dx lea dx,buf-2 ; ds:dx - адрес buf[-2] mov ah,0Ah ; ввод строки в буфер (включая Enter) int 21h call procnl ; курсор на новую строку экрана inc cs:sizeb ; в длине учесть Enter mov cs:posb,0 ; сколько символов ухе считано из buf pop ds pop dx pop ax ret readbuf endp ;==================================================== ; Очистка буфера ввода с клавиатуры ; Обращение: call prooflush ; Параметров нет ;---------------------------------------------------- procflush proc far push ax mov cs:sizeb,0 ;очистка buf mov cs:posb,0 mov ah,0Ch ;очистка DOS-буфера mov al,0 int 21h pop ax ret procflush endp ;==================================================== ; Ввод символа (с пропуском или без пропуска Enter) ; Обращение: call procinch ; На входе: al - Enter пропустить (0) или выдать как символ (1) ; На выходе: al - введенный символ (ah яе меняется) ;---------------------------------------------------- procinch proc far push bx princh1: mov bl,cs:posb ; номер последнего считанного символа inc bl ; след. номер cmp bl,cs:sizeb ; на последний символ буфера? jb princh2 jne princh10 ; буфер на считан до конца? cmp al,0 ; считывать ли конец строки (Enter)? jne princh2 princh10: call readbuf ; доввод в буфер jmp princh1 ; повторить princh2: mov cs:posb,bl ; запомнить номер считываемого символа mov bh,0 mov al,cs:buf[bx-1] ;al:=символ pop bx ret procinch endp ;==================================================== ; Ввод целого числа (со знаком и беэ) размером в слово ; Обращение: call proclnint ; На входе: нет ; На выходе: ах - введенное число ;---------------------------------------------------- procinint proc far push bx push cx push dx ; пропуск пробелов и хонцов отрок вначале prinint1: mov al,0 call procinch ;al - очередной символ (с пропуском Enter) cmp al,' ' ;пробел? je prinint1 ; проверка на знак mov dx,0 ; dx - вводимое число mov cx,0 ; ch = 0 - нет цифры, cl=0 - плюс cmp al, '+' je prinint2 cmp al,'-' jne prinint3 mov cl, 1 ; cl = 1 - минус ; цикл по цифрам prinint2: mov al,1 call procinch ; al - очередной символ (Enter - символ) prinint3: ; проверка на цифру cmp al,'9' ja prinint4 ; >'9'? sub al,'0' jb prinint4 ; <'0'? mov ch,1 ;ch = 1 - есть цифра mov ah,0 mov bx,ax ;bx - цифра как число mov ax,dx mul cs:prten ;*10 jc provfl ;>FFFFh (dx<>0) -> переполнение add ax,bx ;+ цифра jc provfl mov dx,ax ;спасти число в dx jmp prinint2 ;к след. символу ; кончились цифры (число в dx) prinint4: mov ax,dx cmp ch,1 ;были цифры? jne prnodig cmp cl,1 ;был минус? jne prinint5 cmp ax,8000h ;модуль отриц. числа > 8000h ? ja provfl neg ax ;взять с минусом prinint5: pop dx ;выход pop cx pop bx ret prten dw 10 ;------------реакция на ошибки при вводе числа provfl: lea cx,prmsgovfl ; переполнение jmp prerr prnodig:lea cx, prmsgnodig ; нет цифр prerr: push cs ;печать сообщения об ошибке pop ds ;ds = cs lea dX,prmsg mov ah,9 ;outstr int 21h mov dx,cx mov ah,9 ;outstr int 21h call procnl mov ah,4Ch ; finish int 21h prmsg db 'Ошибка при вводе числа: ','$' prmsgovfl db 'переполнение','$' prmsgnodig db 'нет цифры','$' procinint endp iocode ends end ; конец модуля ioproc и IO.ASM Код (Text): .xlist ;запрет записи этого файла в листинг ; Файл с макросами ввода-вывода, подключаемый к ; программе по директиве: include io.asm ;*********************************************************** ; ОКОНЧАНИЕ СЧЕТА ПРОГРАММЫ ;*********************************************************** ;=========================================================== ; Окончание счета программы ; обращение: finish ; на входе: al - код завершения (можно игнорировать) ;----------------------------------------------------------- finish macro mov ah,4Ch int 21h endm ;*********************************************************** ; ВЫВОД НА ЭКРАН (в текстовом режиме) ;*********************************************************** ;=========================================================== ; Переход на новую строку ; обращение: newline ;----------------------------------------------------------- extrn procnl:far newline macro call procnl endm ;=========================================================== ; Вывод символа ; обращение: outch с ; где с - i8, r8 или m8 ;----------------------------------------------------------- outch macro c push dx push ax mov dl,c mov ah,2 int 21h pop ax pop dx endm ;=========================================================== ; Вывод строки символов ; обращение: outstr ; на входе: ds:dx - начальный адрес строки ; (в конце строки д.6. символ $, код 36 (24h)) ;----------------------------------------------------------- outstr macro push ax mov ah,9 int 21h pop ax endm ;=========================================================== ; Вывод целого со знаком размером в слово ; обращение: outint num [,leng] ; где num - выводимое число: i16, r16, m16 ; leng - ширина поля вывода: i8, r8, m8 (со значением >=0) ; Особенности вывода: ; если поле больше, чем надо, то слева добавляются пробелы, ; если меньше - выводится только число (целиком); ; по умолчанию leng = 0 ;----------------------------------------------------------- extrn procoutnum:far outint macro num, leng outnum <num>,<leng>,1 endm ;=========================================================== ; Вывод целого без знака размером в слово ; обращение: outword num [,leng] ; num и leng - как в outint ;----------------------------------------------------------- outword macro num, leng outnum <num>,<leng>,0 endm ;----------------------------------------------------------- ; Вспомогательный макрос проверки написания имени ; разными (большими и малыми) буквами ;----------------------------------------------------------- same macro name,variants,ans ans = 0 irp v,<variants> ifidn <name>,<v> ans = 1 exitm endif endm endm ;----------------------------------------------------------- ; Вспомогательный макрос для outint (sign=1) и outword (=0) ;----------------------------------------------------------- outnum macro num,leng,sign local regdx? push ax push dx same <num>,<dx,DX,Dx,dX>,regdx? if regdx? ;;out dx,leng --> ifb <leng> ;;mov al, leng mov al,0 ;;xchg ax, dx else mov al,leng endif xchg ax,dx else ;;out num, leng (num<>dx) ifb <leng> ;;mov dl, leng mov dl,0 ;;movax, num else mov dl,leng endif mov ax,num endif mov dh,sign call procoutnum ;;ax=num, dl=leng, dh=sign pop dx pop ax endm ;********************************************************** ; ВВОД С КЛАВИАТУРЫ ;********************************************************** ;========================================================== ; Очистка буфера ввода с клавиатуры ; обращение: flush ;---------------------------------------------------------- extrn procflush:far flush macro call procflush endm ;========================================================== ; Ввод символа (с пропуском концов строк, т. е. Enter) ; обращение: inch х ; где х - r8, m8 ; на выходе: х - введенный символ ;---------------------------------------------------------- extrn procinch:far inch macro x local regax? same <x>,<ah,AH,Ah,aH>,regax? if regax? xchg ah,al ;;x=ah mov al,0 call procinch xchg ah,al else same <x>,<al,AL,Al,aL>,regax? if regax? mov al,0 ;;x=al call procinch else push ax ;;x - не ah и не al mov al,0 call procinch mov x,al pop ax endif endif endm ;========================================================== ; Ввод целого числа (со знаком и без) размером в слово ; обращение: inint х ; где х - r16, m16 ; на выходе: х - введенное число ; особенности ввода: ; пропускаются все пробелы и концы строк перед числом; ; число должно начинаться с цифры, перед ней возможен знак; ; при минусе число вводится как отрицательное; ; ввод идет до первой нецифры (в т.ч. до Enter), она глотается; ; при ошибке будет печать сообщения и останов программы; ; ошибки: "нет цифры" - в числе нет ни одной цифры ; "переполнение" - большое по модулю число ; (вне отрезка [-32768, +65535]) ;---------------------------------------------------------- extrn procinint:far inint macro x local regax? same <x>,<ax,AX,Ax,aX>,regax? if regax? call procinint ;;x=ax else push ax ;;x<>ax call procinint mov x,ax pop ax endif endm ;========================================================== ; восстановить запись в листинг: .list Используя их можно писать простые законченные програмки. Например, Вводим число(целое знаковое) X, а выводим (2*A - 1234 div (A+B)^2) mod 7 TESTIO.ASM Код (Text): INCLUDE IO.ASM data segment A dw ? B db -8 X dw ? data ends ;------------------------------- stack segment stack db 128 dup (?) stack ends ;------------------------------- code segment assume cs:code, ds:data, ss:stack start: mov ax, data mov ds, ax inint A mov bx, A mov al, B cbw add ax, bx add bx, bx imul ax mov cx, ax mov ax, 1234 cwd idiv cx sub bx, ax mov ax, bx cwd mov bx, 7 idiv bx mov X, dx outint X finish code ends end start Поигравшись с компиляторами, мне проще всего оказалась работа с этим: http://beleriand.narod.ru/programming.html Файл .bat будет примерно такой: cls echo off C:\MASM611\BIN\ML /c E:\WORK\ASM\Tutor\Ch1\MASM\IOPROC.ASM C:\MASM611\BIN\ML /c E:\WORK\ASM\Tutor\Ch1\MASM\TESTIO.ASM C:\MASM611\BINR\link "E:\WORK\ASM\Tutor\Ch1\MASM\TESTIO.OBJ"+"E:\WORK\ASM\Tutor\Ch1\MASM\IOPROC.OBJ" pause Может, это кому-то поможет.