Часто задаваемые вопросы по ассемблеру.
Сборник 2.
Q1: Покажите маленькую программку типа 'Hello, world!'
A: Вот пример: Слинковать в com файл (я бы вам пока вообще не рекомендовал
использовать EXE).

..model tiny                     ; модель памяти - делаем com-файл
..code                           ; сегмент кода или пpосто - код
..startup                        ; стаpтовая точка пpогpаммы

        mov ah,09               ; фyнкция N9 - вывод текста на экpан
        mov dx,offset msg       ; в dx заносим адpес сообщения msg
        int 21h                 ; вызов так называемого Сеpвиса Доса
                                ; (в ah для него номеp фyнкции)
        ret                     ; в СОМ-файле так можно завеpшать пpогpамму
                                ; в ЕХЕ - немного сложнее...
msg     db 'Hello, world! $'    ; сообщение (должно оканчиваться на '$')
end                             ; конец файла

----------------------------------------------------------------------------
Q2: А как ее запустить (слинковать, асссемблировать)?
A: Вот так:

tasm hello.asm
tlink /t hello.obj

----------------------------------------------------------------------------
Q3: А где можно взять tasm и tlink?
A: Они вообще-то не freeware, но если очень надо :)
   http://bsg.nm.ru/minimum.zip
A2:  а факсервере 2:5058/96.111, под именем tasm. (~250 Kb UUE)

----------------------------------------------------------------------------
Q4: Что такое PSP?
A:  PSP  -  структура,  формируемая  для  каждой  запущенной  программы,
содержащая  множество полезной информацию, в частности, командную строку
и  ее длину. Пpи запуске пpогpаммы (как СОМ, так и ЕХЕ) ds и es содеpжат
сегментный адpес PSP. Для COM-файлов он равен еще и cs.

----------------------------------------------------------------------------
Q5: Где хранится командная строка и как ее получить?
A: Командная строка (аргументы, передаваемые запускаемой программе
через командную  строку  DOS (DOS-prompt) и указываемые после имени
программы) хранятся по адресу PSP:[80h] в формате pascal-строки.

Пример:

 C:\DOS> format a:/u/t:80/n:9

Командная строка " a:/u/t:80/n:9", переданная программе format, будет
хранится по указанному адресу в следующем виде:

   db           0Eh," a:/u/t:80/n:9"

+=[x]=Dump=================================
|  ds:0080 0E 20 61 3A 2F 75 2F 74 . a:/u/t
|  ds:0088 3A 38 30 2F 6E 3A 39 0D :80/n:9

----------------------------------------------------------------------------
Q6: Как узнать полный путь к запущенной пpогpамме из нее самой?
A:
        mov     ax,1203h
        int     2Fh              ;получим сегмент данных DOS
        mov     ax,ds
        lds     si,ds:[bp-1Ah]   ;в ds:si - указатель на полный путь


----------------------------------------------------------------------------
Q7: Что такое прерывание и как оно работает?
A:   Прерывание   -  это  именно  прерывание  программы  для  выполнения
какой-либо другой работы.
     Необходимо   pазличать   пpогpаммные   и   аппаpатные   пpеpывания.
Аппаpатные   генеpятся  устpойствами,  а  пpогpаммные  вызываются  самой
пpогpаммой  и являются фактически аналогами вызова подпpогpамм, вызовами
системных   функций   DOS,  напpимеp.  Аппаратные  прерывания  прерывают
программу в необходимый момент, например, по приходу байта от модема, по
движению мыши и т.п.
     Смотрите  первый пример 'Hello, world!', там используется int 21h -
прерывание  номер  21h, которое отвечает за функции ДОС. В ah у нас было
09h - это функция вывода текста на экран, начиная с адреса ds:dx.
---------------------------------------------------------------------------
Q8: Что такое вектор прерывания?
A:  Это  адрес,  по  которому  будет  сделан  переход  в  случае  вызова
соотвествующего  прерывания.  Например, в случае, если в программе стоит
'INT  21h',  адрес перехода берется из ячейки по адресу 0000:21h*4 (по 4
байта на один вектор прерывания).

----------------------------------------------------------------------------
Q9: А как можно сгенерировать звук?
A: Вот так:

            ;
            ; подпрограмма генерации звука
            ; Вход: АX= частота звука в Гц
            ;
 Sound      proc     near
            push     ax        ;сохранить регистры
            push     bx
            push     dx
            mov      bx,ax     ;частота
            mov      ax,34DDh
            mov      dx,12h    ;(dx,ax)=1193181
            cmp      dx,bx     ;если bx < 18Гц, то выход
            jnb      Done      ;чтобы избежать переполнения
            div      bx        ;ax=(dx,ax)/bx
            mov      bx,ax     ;счетчик таймера
            in       al,61h    ;порт РВ
            or       al,3      ;установить биты 0-1
            out      61h,al
            mov      al,00001011b   ;управляющее слово таймера:
                               ;канал 2, режим 3, двоичное слово
            mov      dx,43h
            out      dx,al     ;вывод в регистр режима
            dec      dx
            mov      al,bl
            out      dx,al     ;младший байт счетчика
            mov      al,bh
            out      dx,al     ;старший байт счетчика
 Done:
            pop      dx        ;восстановить регистры
            pop      bx
            pop      ax
            ret
 Sound      endp

Выключение звука:

 No_Sound   proc     near
            push     ax
            in       al,61h    ;порт РВ
            and      al,not 3  ;сброс битов 0-1
            out      61h,al
            pop      ax
            ret
 No_Sound   endp

----------------------------------------------------------------------------
Q10: Что лучше - стандартные или упрощенные директивы определения сегментов?
A: Однозначно проще - упрощенные. Что лучше - решается индивидуально.
   Использование стандартных директив имеет смысл или в педагогических
   целях, или при наличии причин, требующих использования именно стандартных
   директив. Например, необходимость использования специальных имен
   сегментов, специальных атрибутов и особой группировки. Последнее
   опять-таки вовсе не означает, что упрощенные директивы не могут быть
   использованы. Например:

   .MODEL LARGE
          MyGroup       group   MySpecialSeg,$LibTable
          MySpecialSeg  segment word public use16 'DATA'
   ...
          ends
          $LibTable     segment para common use16 'DATA'
          ...
          ends
   .DATA
   .CODE
   end

   Поэтому вполне разумным видится использование упрощенных директив,
   совмещенное (при необходимости) с использованием стандартных.


---------------------------------------------------------------------------
Q11: Для чего нужна команда LEA. То же самое может и OFFSET, да и Tasm заменяет
   LEA на MOV...OFFSET.
A: MOV...OFFSET короче LEA, поэтому в режиме SMART tasm заменяет LEA на MOV
   для тех случаев, когда это возможно:

        lea   di,Array
        mov   di,offset Array

   Но такая замена возможна не всегда:

        lea   di,Array[si+bx.FieldName]

   Логика работы LEA в данном случае эквивалентна такому фрагменту:

        mov   di,offset Array
        add   di,si
        add   di,bx
        add   di,FieldName

   Результат этого фрагмента не может быть вычислен на этапе компиляции
   из-за неизвестных величин, а следовательно, LEA в данном случае не может
   быть заменена командой MOV...OFFSET


---------------------------------------------------------------------------
Q12: mov ax,@data
     mov ds,ax

   Откуда программа узнает адрес сегмента? После компиляции стоит mov ax,1.
   А в отладчике появляется сразу нужный адрес: mov ax,140Fh
   Кто его туда прописывает?

A: Т.к. EXE может быть загружен по различным адресам, вместо явных значений
   cегментов в EXE указаны номера 16-байтных параграфов [0...FFFF] этих
   cегментов, начиная от начала образа EXE. Загрузчик, после считывания образа
   EXE в память, используя информацию в заголовке EXE, находит ссылки на
   явные значения сегментов и прибавляет к значению параграфа, указанное
   непосредственно в команде, реальное значение сегмента, начиная с которого
   загружен EXE.

   Например, образ EXE считан в память, начиная с адреса 140Eh:0 После
   корректировки значений сегментов вместо mov ax,1 получается mov ax,140F

---------------------------------------------------------------------------
Q13: Как сделать COM с отладочной информацией, понимаемой TD ?
A:   comdbg.bat TEST

   tasm /zi %1
   tlink /v %1,%1,,,
   tdstrip -s -c %1.exe

----------------------------------------------------------------------------
Q14: Не получается! COM есть, TDS есть, а TD отладочную информацию не видит:
  "Program has no symbol table"
A: У TDS время меньше, чем у COM - такое бывает в Винде.
   Воспользуйтесь утилитой touch из NWDOS (в MS DOS она похуже)

   touch %1.tds

---------------------------------------------------------------------------
Q15: Как расчитать количество памяти, необходимое для резидента?
A: FirstFreeByteSeg - PspSeg + ((FirstFreeByteOffs+15) div 16)

Resident        macro FirstFreeByteSeg,FirstFreeByteOffs
        mov     dx,FirstFreeByteSeg
        sub     dx,[PspSeg]
        mov     ax,FirstFreeByteOffs
        dec     ax
        shr     ax,4
        inc     ax
        add     dx,ax

        mov     ah,31h
        mov     al,[ErrorLevel]
        int     21h
endm

Resident        seg Install,<offset Install>

---------------------------------------------------------------------------
Q16: Не могу запустить дочернюю задачу функцией 4Bh
Q17: Не выделяется память по функции 48h
A: Нет свободной памяти.

---------------------------------------------------------------------------
Q18: Да вроде все есть, почему не выделяет-то?
A: Да потому что она уже тебе выделена, теперь ее осталось только сжать.

---------------------------------------------------------------------------
Q19: Как сжать блок памяти, занимаемый программой?
A:  Сжимать  ее  следует через функцию DOS 4Ah. Алгоритм тот же, что и у
макроса Resident:

ShrinkMem       macro FreeSeg,FreeOffs
   mov          bx,FreeSeg
   sub          bx,[PspSeg]
   mov          ax,FreeOffs

   dec          ax
   shr          ax,4
   inc          ax

   add          bx,ax
   mov          ah,4Ah
   mov          es,[PspSeg]
   int          21h
endm

ShrinkMem       <seg stack>,<(size stack)+1>
В случае полного/дополнительного ручного объявления сегментов и их особого
упорядочивания необходимо указать имя последнего сегмента.

----------------------------------------------------------------------------
Q20: А что за команда такая rdtsc?
A:  read  tsc - Read Time Stamp Counter. Читает регистр tsc, проще говоря
возвращает  в  edx:eax  количество  тактов  с  момента последнего сброса
процессора.  Опкод  - 0F 31, команда появилась на процессорах Pentium (и
то не на всех.)

---------------------------------------------------------------------------
Q21:. И еще, расскажите русским языком, что такое рекурсия (никогда не
   сталкивался!)?
A: Вызов функцией самой себя.

Q: Примерчик приветствуется.
A: Классический пример - вычисление факториала:

..model farstack small, pascal
   .386
   locals @@
..stack          2048
..code
Factorial       PROC           ; function factorial(@@N:Word):DWord;
   arg          @@N:word       ; begin
   mov          ax,@@N
   cmp          ax,1           ; if (@@N=1) or (@@N=0) then
   ja           @@calc
   mov          ax,1           ;    factorial:=1
   xor          dx,dx
   ret
@@calc:
   dec          ax             ; else
   push         ax
   call         Factorial      ;    factorial := factorial(@@N-1)
   mul          @@N            ;                                  * @@N;
   ret                         ; end;
endp

MAIN            PROC
   .startup
   push         4
   call         Factorial
   .exit
ENDP

end             MAIN


----------------------------------------------------------------------------
Q22: Расскажите про сопроцессор, как его использовать?
A: Вот тебе пример программы с комментариями:

..model tiny
..code
..386                                            ; привычка :)
..387                                            ; использование сопроца
..startup

                         finit                  ; инициализация сопроца
                         fild data1             ; загрузка data1
                         fiadd data2            ; складывание с data2
                         fist _result           ; сохранение результата в
                                                ; _result

                         ret
data1   dw 1
data2   dw 200
_result dw ?

end

Теперь немного теории.
Пример команды:
fild
^^^^
||++
|||
||+-- 'ld' - load, загрузка числа в стек сопроцессора
|+--- 'i' - integer, означает, что работаем с ЦЕЛЫМИ данными (
|           еще варианты - '', то есть fld, например - загрузка вещественного
|           числа в сопроцессор, 'b', т.е. fbld - загрузка BCD числа)
+---- 'f' - обозначает, что это команда сопроцессора

Примеры команд:

fld data1                       ; загрузка вещественного числа из памяти
                                ; по адресу data1 в сопроцессор

fist _result                    ; сохранение числа как целого в память по
                                ; адресу _result (при необходимости оно
округляется -
                                ; это делает сам сопроц)

fistp _result                   ; то же самое, но при сохранении числа оно
                                ; выталкивается из стека сопроца

fsqrt                           ; вычисление квадратного корня из st0, то
                                ; есть аргумент берется из стека, туда же и
                                ; помещается значение корня

fcos, fsin                      ; вычисляет косинус и синус угла, заданного
                                ; в стеке сопроца. Угол должен быть в
                                ; _радианах_.

fsincos                         ; одновременно вычисляет и sin и cos, в
                                ; st0 помещается sin, в st1 - cos.


Вообще для понимания механизма работы возьмите Turbo Debugger:

F10/View/Numeric processor:
Здесь видно, что в стеке сопроца находится число 300 :)

+=[x]=80486 IPTR=54CE3 OPCODE=706 OPTR=54CEE==2=[][]=+
|Valid ST(0) 300                         | im=1 | ie=0 |
|Empty ST(1)                             | dm=1 | de=0 |
|Empty ST(2)                             | zm=1 | ze=0 |
|Empty ST(3)                             | om=1 | oe=0 |
|Empty ST(4)                             | um=1 | ue=0 |
|Empty ST(5)                             | pm=1 | pe=0 |
|Empty ST(6)                             |iem=0 | ir=0 |
|Empty ST(7)                             | pc=3 | cc=0 |
|                                        | rc=0 | st=7 |
|                                        | ic=0 |      |
+xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+======+=====-+

Выполняем:

cs:0107 D9FA           fsqrt

+=[x]=80486 IPTR=54CE7 OPCODE=1FA OPTR=54BE0==2=[][]=+
|Valid ST(0) 17.320508075688773          | im=1 | ie=0 |
|Empty ST(1)                             | dm=1 | de=0 |
|Empty ST(2)                             | zm=1 | ze=0 |
|Empty ST(3)                             | om=1 | oe=0 |
|Empty ST(4)                             | um=1 | ue=0 |
|Empty ST(5)                             | pm=1 | pe=1 |
|Empty ST(6)                             |iem=0 | ir=0 |
|Empty ST(7)                             | pc=3 | cc=0 |
|                                        | rc=0 | st=7 |
|                                        | ic=0 |      |
+xXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX+======+=====-+

Получили вещественное число в стеке сопроцессора. Сохраним его в памяти
по адресу ds:[110] как целое:

cs:0109 DF1E1001       fistp  word ptr[0110]

Смотрим содержимое:

ds:0110 11 00 FF 16 57 9A A5 1B
        ^^^^^ вон он наш результат :)

----------------------------------------------------------------------------
Q23: Народ, как обойти "Relative jump out of range"?
A: Поставь  директиву  .386  или  даже  больше  -  .586,  напpимеp  - и
наслаждайся...  ;)  А  по умолчанию используется 8086. У него только jmp
short есть.
A2:  А  если  все же пpиспичило писать под пpоцессоp менее 386, то можно
воспользоваться директивой 'jumps':

JUMPS
   ....
   CMP чего надо
   JZ куда надо
   ....
NOJUMPS

И это автоматом постpоит констpукцию, подобную этой:

   CMP чего надо
   JNZ @2
   JMP куда_надо
@2:

     Диpектива   JUMPS   заменяет   все   коpоткие   пеpеходы  на  такую
констpукцию,  в  случае  необходимости.  Поэтому  пользоваться  ей можно
всегда.

----------------------------------------------------------------------------
Q25: А что такое CMOS и как с ней работать?
A: Сейчас под термином CMOS (в рамках компьютерщиков) понимают 64 (уже
говорят, что 128) байт энергонезависимой памяти.
     PC  класса  AT  имеют  питаемые от батарейки часы реального времени
(RTC) и 64 байта постоянной CMOS-памяти.
     Эта  память  содержит  разнообразную информацию, включающую текущие
дату  и  время,  сведения  о конфигурации машины и байт статуса закрытия
системы  (этот  байт  используется  механизмом,  позволяющим  машине  AT
рестартовать   после   выполнения   сброса   процессора,  выводящего  из
защищенного режима).

Работать с ней надо так:

     Чтобы  прочитать  байт  из  CMOS, выполните команду OUT 70H, адрес;
затем  выполните  IN 71H. Чтобы записать байт в CMOS, выполните OUT 70H,
адрес; затем OUT 71H, значение.

Пример:  ;------- прочитать тип установленного твердого диска
         mov     al,12H
         out     70H,al        ;выбрать адрес CMOS 12H
         jmp     $+2           ;требуется небольшая задержка
         in      al,71H        ;теперь в AL тип устройства (0-15)

     Адреса   10H..20H   защищены   контрольной  суммой,  что  позволяет
обнаружить  износ  батарейки или порчу информации в записи конфигурации.
Контрольная сумма - это просто 16-битовая сумма защищаемых байт памяти.
----------------------------------------------------------------------------
Q26:  Тут  такое  дело,  в процедурах у меня часто метки одинаковые, или
вставляю  из  разных  своих  исходников куски, tasm ругается, мол, метки
одинаковые :( Приходится все иправлять... Что сделать-то можно? И вообще
как можно удобно сделать работу с метками?
A: Есть два способа, один простой, другой хитрый :)

Способ  простой:  ставим  в  начале  исходника  locals  @@  и все метки,
начинающиеся  с символов '@@' будут _локальными_, то есть существовать в
пределах одной процедуры и не вызывать конфликта с одинаковыми именами.

Способ  хитрый: у tasm'а есть такой режим работы, при котором существуют
метки  типа  @@,@b,@f (@b и @f соответственно переходят на ближнюю метку
@@  назад, либо вперед), этот режим включается словами 'masm' и 'quirks'
(обязательны обе директивы, иначе работать не будет!). Работает так:
   +------------+
@@:|            |
   +    nop     |
        nop     |
        jmp @b -+
        nop
        jmp @f -+
@@:+    nop     |
   +------------+
----------------------------------------------------------------------------
Q27: А как напечатать число в шестнадцатеричном виде?
A: Можно сделать так:
(результат помещяется в es:di)

byte2hex        proc    near
                push    cx
                mov     cx,2
@@L1:           rol     dl,4
                mov     ax,300fh
                and     al,dl
                aaa
                aad     11h
                stosb
                loop    @@L1
                pop     cx
                ret
byte2hex        endp

word2hex        proc    near
                push    cx
                mov     cx,2
@@L1:           rol     dx,8
                call    byte2hex
                loop    @@L1
                pop     cx
                ret
word2hex        endp

dword2hex       proc    near
                mov     cx,2
@@L1:           rol     edx,16
                call    word2hex
                loop    @@L1
                ret
dword2hex       endp

>Еще:
Преобразует hex-цифру в AL в ASCII-код

Вход:  AL - hex-цифра (00h - 0Fh)
Выход: AL - ASCII - код символа.

cmp     al,10
sbb     al,69h
das

Вот и всё!

После SBB числа 0-9 превращаются в 96h - 9Fh, а числа 0Ah - 0Fh - в 0A1h -
0A6H. Затем DAS вычитает 66h из первой группы чисел, переводя их в 30h - 39h, и
60h из второй группы чисел, переводя их в 41h - 46h

>А вот наиболее очевидный но немного менее быстрый и удобный способ: команда
XLATB. Она помещает в AL байт из таблицы в памяти по адресу ES:BX (или ES:EBX)
со смещением относительно начала таблицы равным AL.

Пример:

Вход:  AL - hex-цифра (00h - 0Fh)
       ES - сегментный адрес таблицы.

Выход: AL - ascii-код символа.

В сегменте кода:

lea   bx,htable
xlatb

В сегменте данных:

htable db "0123456789ABCDEF"

Вот и все.


----------------------------------------------------------------------------
Q28: А как слинковать драйвер устройства (sys, или просто сделать файл с
org0?)
A: Вот так:
tasm driver.asm /m4
tlink driver.obj, driver.sys /t
>               ^ обратите внимание, это самое главное :)

p.s.  Есть  одна  тонкость, на которую я напоролся и имел много проблем.
Тонкость  вот  в  чем.  Если  у  вас  tlink  вызывается через батник, то
слинковать  драйвер вы не сможете, так как батник при разборе параметров
%1  %2  и  т.п.  Е передаст tlink'у символ запятой, которая здесь играет
решающую  роль.  Так  что линкуйте без батника, либо в нем явно напишите
'tlink driver.obj, driver.bin /t'
----------------------------------------------------------------------------

Q29: Программа выполняется под Turbo Debugger'ом.
     А если её запустить без него, то она виснет/работает неправильно.
Q29: Программа выполняется в операционной системе X.
     А в операционной системе Y - виснет.

A: Возможная причина - программа предполагает, что регистр AA имеет значение
   BB при старте, а инициализация регистров в различных ОС и отладчиках может
   отличаться. Регистры нужно инициализировать самому, не полагаясь на то,
   что при старте в них должно быть что-то записано. Исключение из этого
   правила - сегментные регистры.
----------------------------------------------------------------------------

Q30: А как под Windows на ассемблере писать?
A:   Чтобы писать на ассемблере под Windows. нужен MASM 5 for Windows
(http://win32asm.newmail.ru/), либо TASM 5 с include-файлами.

Пример программы на Tasm'е:

(комментарии -  Anatoly Romashkin)

;tasm32 /m /ml file.asm - если нет tasm32, то можно попpобовать tasm 4.1
;tlink32 /c file.obj

..386
..model flat, stdcall
includelib import32.lib

extrn MessageBoxA:proc
extrn ExitProcess:proc

o equ offset
MB_OK equ 0

..data   ; y меня tasm 4.1 мог глючить, если нет данных
MsgCaption      db 'Qwerty',0
MsgText         db 'Hello, World!',0

..code
start:          call MessageBoxA, 0, o MsgText, o MsgCaption, MB_OK
                call ExitProcess, 0
end start

Пример консольной программы:

;tasm32 /m /ml file.asm - если нет tasm32, то можно попpобовать tasm 4.1
;tlink32 /c /ap file.obj

..386
..model flat, stdcall
includelib import32.lib

extrn ExitProcess:proc
extrn GetStdHandle:proc
extrn WriteFile:proc
extrn ReadFile:proc
extrn SetConsoleMode:proc

o equ offset
STD_INPUT_HANDLE equ -10
STD_OUTPUT_HANDLE equ -11
MB_OK equ 0

..data   ; y меня tasm 4.1 мог глючить, если нет данных
MsgText         db 'Hello, World!'
MsgTextLen=$-MsgText
hIn             dd 0
bWritten        dd 0
Buff            db 0
BuffLen=$-Buff

..code
start:
                call    GetStdHandle, STD_OUTPUT_HANDLE
;полyчаю стандаpтный хэндл в eax
                call    WriteFile, eax, o MsgText, MsgTextLen, o bWritten, 0
;пишy в stdout
                call    GetStdHandle, STD_INPUT_HANDLE
                mov     hIn, eax
                call    SetConsoleMode, eax, 0
;yстанавливаю pежим консоли
GetEnter:       call    ReadFile, hIn, o Buff, BuffLen, o bWritten, 0
;читаю с stdin
                cmp     Buff, 0dh ;enter
                jne     GetEnter

                call    ExitProcess, 0

end start

Если не будет pаботать пеpвый ваpиант компиляций указанный в коментаpиях
пpогpаммы или скомпилится с галами, то попpобуйте пpогpаммы откомпилиpовать
вот так:
tasm32 /ml !.asm
tlink32 /Tpe /aa /c !.obj


----------------------------------------------------------------------------
Qlast: А как это ... сделать?
A: Напишите в эху, вам ответят :)

----------------------------------------------------------------------------
Ссылки в интернете:

Ассемблер NASM (freeware)
http://nasm.2y.net/

Дока по NASM на русском языке (спасибо AsmOS Team)
http://asmdev.narod.ru/asmos/our_files/docs/nasm.win.rar

Interrupt list (хорошее описание прерываний)
http://www.pobox.com/~ralf

Различные базы, дополнения, NG, TechHelp!.
http://www.whitetown.com/ru/ng/
http://www.shortway.to/posohov

Программирование на ASM'е под Windows:
http://win32asm.newmail.ru/

TechHelp! 4.0 RUS
http://bsg.nm.ru/techhelp.zip

Хоpоший тyтоpиал asm под Win32
http://www.wasm.zite.ru/win32asmtutor/files/tutorial/contents.html

Asm под DOS, аpхив pассылки. Полезно, но написано кpиво, поэтомy читать
сложно и неинтеpесно. Но полезно.
http://www.kalashnikoff.ru/Assembler/Issues/index.htm


Бypжyйский сайт, тоже есть тyтоpиалы и пpого пpимеpов. Win32.
http://spiff.tripnet.se/~iczelion/

Список пpеpываний. Понадобится навеpняка. (2.7 mb, на английском)
http://www.cs.cmu.edu/~ralf/interrupt-list/inter61a.zip
....
http://www.cs.cmu.edu/~ralf/interrupt-list/inter61f.zip


Не знаю что там, пpосто URL'ы валялись.
http://win32asm.chat.ru/
http://www.thomasbleeker.nl/exagone/page/int.html
http://sources.fitkursk.ru/articles/art0000037.asp


----------------------------------------------------------------------------
FAQServer                                      2:5058/96.111
----------------------------------------------------------------------------

Все вопросы по содержанию и дополнению FAQ'а отправлять мне -
Alexander Zigar' 2:5058/96

В создании FAQ принимали участие:

 Alexander Zigar'                    2:5058/96
 Anatoly Romashkin                   2:5093/56
 Dima Marakasov                      2:5020/1826.5
 Kirill Barashkin                    2:5080/500.271
 Max Vorobyov                        2:5025/150.24
 Mihail Epihin                       2:5023/29.34
 Roman Perminov                      2:5070/313
 Semen Panevin                       2:5025/121.8
 Victor Petrenko (AsmOS Team)        2:5061/6.40
 Yury Suharev                        2:5023/19.11
 И все те, кого я забыл упомянуть...

 Также спасибо всем подписчикам эх RU.ASM.CHAINIK, TALKS.ASM, PC.CODING и
 им подобных.

Назад

Сайт создан в системе uCoz