#1D Ассемблер, просто Ассемблер ....

Вступление

Ты, видимо, все перепутал:
Оккупантом не может быть партизан.
Разве ты здесь защищаешь свой город?
Разве твой долг хранить от неверных Ислам?
Здравствуйте!
Нет ничего я не перепутал. Ассемблер это конечно совсем дургой язык и учить его вас никто не заставляет. Но вы должны знать о связи этих двух языков. К тому же разумное использование может дать существенный выйгрыш в скорости программы. Программист обязан знать что-то знать о процессоре, о регистрах, о прерываниях, о стеке!
Это мой ответ на вопрос: зачем началось повествование об Ассемблере. Я ведь не погружаюсь в программирование на этом языке. Это самый вводный курс. Просто это должен знать каждый. К тому же это последний выпуск, посвящённый Ассемблеру.

Новости сайта

28.02.03] В раздел Документация добавлена книга "Дорога в будущее" автор Б.Гейтс

В этой книге великий и ужастный Билл Гейтс делится своим видением того, что ждет нас в скором времени. Он раскрывает перед читателем свое видение будущего, рассказывает об основах информатики, развитии мировой компьютерной индустрии, о влиянии вычислительной техники на все стороны жизни общества, в том числе на бизнес и образование.
-довольно интересная книжка, сам недавно прочитал. рекомендую. Заодно, если вы не поняли про двоичную систему счисления, прочитаете объяснения самого Гейтса на лампочках :)

Теория

В прошлый раз мы остановились на регистре флажков. Это регистр содержит такие флаги (* - не используемые биты):
Номер бита 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Флаг С * P * A * Z S T I D O * * * *
Некоторые команды устанавливают определённые значения флагов при ошибках или для других надобностей. Например команда сранения cmp (CoMPare - сравнить). Сравнивает 2 операнда. В зависимости от результата устанавливает флаги. Например сравним bx и 0:

cmp bx, 00
Как же узнать какой флаг установился, а какой нет? Для этого есть команды для перехода на метку, если флаг установлен. Всех их писать я не буду. Но например, если в предыдущем примере BX = 0, тогда сравнение вызовет установку флага ZF (Zero Flag - флаг нуля). Команда jz вызывает переход на метку, если установлен ZF. Для нашего примера:
cmp bx, 00
jz Label1
....это будет выполняться, если bx не равно 0
.....
Label1:
... здесь если bx равно 0
Во встроенном ассемблере могут использоваться три предопределённых имени:
  • @CODE - текущий сегмент кода
  • @Data - текущий сегмент данных
  • @Result - ссылка, куда надо занести результат выполняемой функции
Остановимся подробнее на @Result. Например напишем функцию, возвращающую наименьшее из 2-х чисел.
function Min (x,y : integer): integer;
begin
   asm
     mov ax, x  
     cmp ax, y
     jl @less
     mov ax, y
     @less:
     mov @Result, ax
   end
end;
Обратим взгляд на неизвестную нам команду jl - переход если меньше. Т.е. в нашем случае если AX меньше Y, то совершается переход на метку @less. Кстати откуда такое странное название (начинается с @)? Это так называемые локальные метки - метки в которые можно передать управление только внутри ассемблерной вставки. Т.е. вы не можете прыгнуть на неё с помощью goto. С другой стороны нам не надо объявлять такую метку в разделе label, так что начинайте свои метки с символа @. Этот символ говорит компилятору, о том что метка локальная.

Так вот значит, если AX меньше Y (т.е. если X меньше Y), тогда мы переходим на метку @less. И записываем в @Result значение АХ (а там у нас Х). Если же Y меньше Х, тогда переход на метку не состоится и мы сначала занесём в АХ Y, а потом значение АХ в @Result.

Вот таким образом компилятор преобразовывает наши высоко уровневые конструкции if-else к машинным cmp. Естесственно в силу превосходства человека над машиной, наш код меньше, чем генерируемый компилятором.

Однако давайте обратим свой взор на использование функций процедур, написанных на ассемблере. Во перых объявление таких подпрограмм должно идти с директивой assembler. Во вторых исполняемая чать вместо привычного begin - end обрамляется asm - end. Т.е. шаблон выглядит так:

procedure NAME; assembler;
asm
   .... текст на ассемблере
end
При этом ассемблерные функции должны возвращать свои значения следующим образом:
Как видите в ассемблерных функциях разрешено использовать @Result только, если возвращаемое значение строкового типа. Так как наша функция Min не содержит "паскалевских" строк перепишем её в виде ассемблерной подпрограммы:

function Min (x,y : integer): integer;assembler;
asm
     mov ax, x  
     cmp ax, y
     jl @less
     mov ax, y
     @less:
end;
так как мы возвращаем значение типа integer, то нам надо запихать это значение в АХ (что мы и делаем). Обратите внимание, что наш код сократился ещё на одну строку. Нам не надо записывать возвращаемоео значение в @Result. Метка @less теперь у нас соответствует выходу из подпрограммы.

Следующие строки будут целиком понятны только для людей знакомых с ассемблером более чем поверхностно. Однако и вам полезно это знать. Итак на входе и выходе в ассемблерную подпрограмму генерируется следующий код (он добавляется в ехе файл):

Вход в процедуру:

push bp - сохраняем значение bp
mov bp, sp - bp теперь содержит текущую границу стека
sub sp, local - резервируем часть стека для локальных данных, local - длинна в байтах всех объявленных в подпрограмме переменных

Выход из процедуры:

mov sp, bp - восстанавливаем границу стека
pop bp - восстанавливаем bp
ret param - удаляем из стека все параметры и выходим из подпрограммы, param - длинна всех параметров
Если входные и выходные параметры отсутствуют, то создаётся код содержащий единственную инструкцию ret.

Как я уже когда-то писал все параметры передаются в подпрограммы черз стек. Так же все локальные переменные хранятся в стеке. Поэтому при входе в процедуру создается локальный стек: в bp помещается текущая граница стека, а сама эта граница сдвигается на суммарную длинну всех локальных переменных что бы работа со стеком не разрушила локальные переменные. Например:

procedure some; assembler;
var
 x : integer;
 y : byte;
 asm
   mov X, ax - скомпилируется в mov [bp - 2], ax
   mov al, Y - скомпилируется в mov al, [bp - 3]
 end;
Как я написал выше, результат функции других вещественных чисел возвращается в регистре ST (0) сопроцессора. Что же такое сопроцессор?

Как следует из названия это "дополнительный" процессор. Сопроцессор - это процессор для работы с числами с плавающей запятой. Вообще-то полное название - арифметический сопроцессор. Этот сопроцессор имеет свою систему команд разработанную специально для ускорения математических расчётов. Раньше не все компьютеры были оснащены сопроцессором. Сейчас он неизменно присутствует на всех машинах. Поэтому компилятор Турбо Паскаля содержит 2 режима компиляции с поддержкой сопроцессора : Options->Compiler раздел Numeric processing. Галочка у 8087/80287 - при компиляции будут использованы команды сопроцессора. Галочка у Emulation - будет использован режим эмуляции. Т.е. при компиляции будет эмулироваться сопроцессор.

Помимо арифметического сопроцессора существует куча сопроцессоров. Самый яркий пример - графический, для ускорения работы с графикой (он содержит в себе функции для рисования графических примитивов).

Кул-][ацкерам

Хотите почувствовать себя героем фильма Матрица и иже с ними? Нет ничего проще! Правда во времена создания BP никто о существовании Матрицы не подозревал, но такую возможность предоставили.

Итак возьмём простенькую програмульку из прошлого выпуска:

begin
  asm
    jmp @next
    @msg: db 'Hello world!$'
    @next:
    push ds
    push cs
    pop ds
    mov ah, 9
    mov dx, offset @msg
    int 21h
    pop ds
  end
end.
сохраняем, делаем ехе файл и выходим из Паскаля.

теперь запускаем bp\bin\td.exe - это Turbo Debugger. Отладчик фирмы Borland. Выбираете File->Change Dir В появившемся окне вводите путь к программе (без имени!). Помните, что путь должен быть короче 8 символов (имеется ввиду длинна имени каждой папки). Если сразу затрудняетесь, то введите только имя диска, на котором находится ехе файл. Дальше File->Open и выбираем нужный нам ехе файл (видите именно ехе, а не pas). На все появшиеся сообщения (если такие будут) ответьте Ок.

Окно у вас должно представлять собой нечто такое:
+-[_]-CPU 80486-------------------------------------------------------1----[]-+
|  cs:0000>9A0000925D     call   5D92:0000                      ax 0000   |c=0|
|  cs:0005 55             push   bp                           |  bx 0000   |z=0|
|  cs:0006 89E5           mov    bp,sp                        |  cx 0000   |s=0|
|  cs:0008 31C0           xor    ax,ax                        |  dx 0000   |o=0|
|  cs:000A 9ACD02925D     call   5D92:02CD                    |  si 0000   |p=0|
|  cs:000F EB0D           jmp    001E                         |  di 0000   |a=0|
|  cs:0011 48             dec    ax                           |  bp 0000   |i=1|
|  cs:0012 656C           insb   gs:                          |  sp 4000   |d=0|
|  cs:0014 6C             insb                                |  ds 5D7E   |   |
|  cs:0015 6F             outsw                               |  es 5D7E   |   |
|  cs:0016 20776F         and    [bx+6F],dh                   |  ss 5E16   |   |
|  cs:0019 726C           jb     0087                         |  cs 5D8E   |   |
|  cs:001B 642124         and    fs:[si],sp                   |  ip 0000   |   |
|  cs:001E 1E             push   ds                           |            |   |
|  cs:001F 0E             push   cs                                       |   |
|___________________________________________________________+----------------|
|  ds:0000 CD 20 00 A0 00 9A F0 FE =  а ЪЁ_                   |  ss:4002 0000  |
|  ds:0008 1D F0 E4 01 56 24 AE 01 ЁфV$о                   |  ss:4000>0000  |
|  ds:0010 56 24 80 02 B1 1E 1F 10 V$А_                   |  ss:3FFE 0000  |
|  ds:0018 01 01 01 00 02 FF FF FF  ___                   |  ss:3FFC 0000  |
|  ds:0020 FF FF FF FF FF FF FF FF ________                   |  ss:3FFA 0000  |
+------------------------------------------------------------------------------+

Нечто похожее показывают во всех фильмах о компьютерах.

Итак что мы имеем. Сейчас я вам проведу обзорную экскурсию. Большую часть окна (вверху слева) занимает наша программа. Как, а где begin, где end? Я этого не писал ! - такие мысли наверняка уже посетили вас. Скажу сразу. Это машинный код нашей программы переделанный в "понятные" нам команды ассемблера. Вот в это и преобразовывает наши прекрасные программы компилятор.

Чуть правее вы видите уже знакомые нам имена регистров. Ну и в самую правую часть окна выведен регист флажков по битам (выведены сответственно имена битов и их состояние).

Под кодом программы распологается дамп сегмента данных. Процитирую в очередной раз Serrgio

"Картинка", которую вы увидели, называется "дамп памяти" (что в переводе с английского означает "свалка") и она насыщена не только важной информацией, но и специальной низкоуровневой энергетикой. Да чего уж там греха таить - каждый ассемблерщик знает, что рассматривание дампа памяти поднимает настроение, жизненный тонус и другие, не менее важные вещи ;)
Так что поднимайте ваш жизненный тонус и отправимся изучать подробнее этот дамп. Итак слева как можно догадаться адресс (вернее только смещение, т.к. сегмент задаётся DS). В центре идут hex числа, справа их расшифровка в коды символов. Так например первый байт по адресу DS:0000 имеет значение5 CDh, а символ с номером CD это = (равно). Следующий за ним байт со значением 20h - это пробел и т.д.

Последнюю часть окна мы пока трогать не будем.

Теперь давайте посмотрим как вставился наш ассемблерный код ... ищем в коде программы jmp @next.... как вы не нашли ? Правильно. Ведь при компиляции имена меток заменяются адресами. Так что мы пойдём другим путём.

Итак давим до боли знакомую клавишу F8 (нам надо именно Step Over, так что именно F8 иначе можете оказаться где-то в месте далёком от нашего кода :) Обратите внимание: зажглись регистры - только, те которые измениись. Это запустилась наша программа.

Итак мы дошли до места

cs:001E 1E             push   ds 
похоже на то, что мы писали ? но ведь текст начинался с jmp @next, где же он? Давайте рассмотрим текущую строчку: вначале идёт смещение текущей команды относительно сегмента кода (посмотрите кстати на регистр ip). Дальше идёт цифра означающая код команды в hex виде. Т.е. для команды push ds это 1E. Ну и дальше идёт соответственно команда ассемблера. Итак нам надо искать jmp, который ссылается на строчку с адресом 001E - ведь именно её мы пометили меткой @next. Такой jmp находится по адресу cs:000F - jmp 001E - это и есть наш jmp @next

Теперь смотрите на строку mov dx, offset @msg- эта строка скомпилировалась в mov dx, 0011 - 'эта адрес строки в сегменте кода, на который у нас ссылается ds. Выберете View -> Dump и посмотрите на дамп - там и правда будет строка Hello World! Теперь обратим взгляд на код нашей програмки именно с адреса 0011 - там находятся команды, которые мы перепрыгнули - а ведь, это то, во что скомпилировался наш Hello World!. А именно в это:

    dec    ax
    insb   gs:
    insb
    outsw
    and    [bx+6F],dh
    jb     0087
    and    fs:[si],sp
такие вот дела. Ну что именно с помощью вот такого простого изучения кода и орудуют взлощики программ. Естественно средства у них более разнообразные и современные. Теперь, когда к вам придут друзья можете запутить td и смотреть на их расширяющиеся от удивления глаза :)

Это должен посетить каждый!

Продолжаем публикацию ссылок. Несмотря на призыв мне никто ничего не прислал :( ну что ж продолжим разгребать моё избранное:

  • http://www.bib.com.ua/ - проект Библиотека программиста. - большое количество исходников, в том числе и на Паскале. Немного документции.
  • http://www.bookcase.ru - Архив компьютерной документации - множество статей, книг и документов по самым различным компьютерным темам: программирование, ОС, форматы файлов, БД, графика и т.д.
  • http://www.helloworld.ru/ - на сайте можно найти доку и исходники по программированию. насколько мне помнится он не обновлялся, хотя я там давно не был.
  • http://www.phantom.az.ee - Железные призраки прошлого - История персональных компьютеров от MITS Altair 8800 до Pentium 200. Рассказы о старом железе и старом программном обеспечении, история фирм и отдельных моделей, судьбы знаменитых людей. Довольно интересный проект.
  • http://et701.com.ru/fun/lol.htm весьма интересная ссылка :) к паскалю она не имеет никакого отношения, но зайдите... не пожалеете.
На этом мы пожалуй на сегодня закончим, а то выложу сразу всё - что же будет потом ?

[Назад] [Содержание] [Дальше]
Hosted by uCoz