<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=95.25.47.253&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=95.25.47.253&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/95.25.47.253"/>
		<updated>2026-08-10T05:41:39Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:SkudarnovYaroslav/%D0%9B%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%B0%D1%81%D1%81%D0%B5%D0%BC%D0%B1%D0%BB%D0%B5%D1%80%D1%83_%D0%B7%D0%B0_3_%D0%BC%D0%B0%D1%80%D1%82%D0%B0&amp;diff=21823</id>
		<title>Участник:SkudarnovYaroslav/Лекция по ассемблеру за 3 марта</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A3%D1%87%D0%B0%D1%81%D1%82%D0%BD%D0%B8%D0%BA:SkudarnovYaroslav/%D0%9B%D0%B5%D0%BA%D1%86%D0%B8%D1%8F_%D0%BF%D0%BE_%D0%B0%D1%81%D1%81%D0%B5%D0%BC%D0%B1%D0%BB%D0%B5%D1%80%D1%83_%D0%B7%D0%B0_3_%D0%BC%D0%B0%D1%80%D1%82%D0%B0&amp;diff=21823"/>
				<updated>2012-05-03T14:11:53Z</updated>
		
		<summary type="html">&lt;p&gt;95.25.47.253: /* Арифметические команды */ так читабельнее&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
= Регистры =&lt;br /&gt;
&lt;br /&gt;
Регистры &amp;amp;mdash; память процессора.&lt;br /&gt;
&lt;br /&gt;
Регистры '''общего назначения''' (в скобках &amp;amp;mdash; изначальное предназначение)&lt;br /&gt;
   eax (accumulator)&lt;br /&gt;
   ebx (base)&lt;br /&gt;
   ecx (counter)&lt;br /&gt;
   edx (data)&lt;br /&gt;
   ebp (stack base pointer)&lt;br /&gt;
   esp (stack pointer) трогать &amp;lt;s&amp;gt;нежелательно&amp;lt;/s&amp;gt; аккуратно, стек ПЫЩЬ&lt;br /&gt;
   esi (source)&lt;br /&gt;
   edi (destination)&lt;br /&gt;
&lt;br /&gt;
То, что вторые буквы &amp;amp;mdash; первые четыре буквы латинского алфавита &amp;amp;mdash; случайность. Это видно в том числе и по тому, что их естественный порядок виден при переносе на стек: eax, edx, ecx, ebx...&lt;br /&gt;
&lt;br /&gt;
Ещё регистры:&lt;br /&gt;
   eip (instruction pointer)&lt;br /&gt;
   eflags: куча битов, которые означают флаги. пример:&lt;br /&gt;
   zf &amp;amp;mdash; 1, если последняя операция вернула 0, 1 otherwise&lt;br /&gt;
   cf &amp;amp;mdash; знак переноса (если результат последней операции не влезает в нужное кол-во битов и один переносится)&lt;br /&gt;
   sf &amp;amp;mdash; знаковый бит. 0 &amp;amp;mdash; полож., 1 &amp;amp;mdash; отриц.&lt;br /&gt;
&lt;br /&gt;
На вышеперечисленные флаги влияет результат выполнения ТОЛЬКО арифметических операций, в том числе comp и test.&lt;br /&gt;
&lt;br /&gt;
   df &amp;amp;mdash; направление выполнения строковых операций.&lt;br /&gt;
&lt;br /&gt;
Регистры e** 32-битны. На 64-битных системах действует следующие наименования:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;&lt;br /&gt;
\underbrace {\fbox{32 \quad\quad\quad\quad}&lt;br /&gt;
   \overbrace{\fbox{16 \quad\quad}&lt;br /&gt;
      \overbrace{&lt;br /&gt;
         \underbrace{\fbox{8 \quad}}_{*h}&lt;br /&gt;
         \underbrace{\fbox{8 \quad}}_{*l}&lt;br /&gt;
      }^{*x}&lt;br /&gt;
   }^{e*x}&lt;br /&gt;
}_{r*x}&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Собственно, этимология названий: буква '''e''' (extended) появилась в названиях регистров с 386 процессором и 32-битным режимом работы. '''h''' и '''l''' пошли от high и low соответственно (старший и младший байты)&lt;br /&gt;
&lt;br /&gt;
= Обзор команд =&lt;br /&gt;
&lt;br /&gt;
== Команды загрузки ==&lt;br /&gt;
   mov register|memory, register|memory|immediate ; записать значение второго операнда в первый, размер данных должен совпадать&lt;br /&gt;
   mov al, 5 ; загрузить в al 5&lt;br /&gt;
   mov cx, di ; скопировать значение di в cx&lt;br /&gt;
&lt;br /&gt;
   movzx register, register|memory ; копирование значений меньшей разрядности в регистр большей разрядности, недостающие биты заполняются нулями&lt;br /&gt;
   movsx register, register|memory ; копирование значений меньшей разрядности в регистр большей разрядности, недостающие биты заполняются знаковым битом&lt;br /&gt;
&lt;br /&gt;
   cmov(cc) register, register|memory ; cc &amp;amp;mdash; условие, команда выполняется только если условие верно&lt;br /&gt;
&lt;br /&gt;
   xchg register|memory, register|memory ; обмен значений&lt;br /&gt;
&lt;br /&gt;
   bswap register ; меняет порядок байт в регистре на обратный&lt;br /&gt;
&lt;br /&gt;
Уточнение про порядок байт:&lt;br /&gt;
   //little-endian:&lt;br /&gt;
   //байты загружаются в память в порядке:&lt;br /&gt;
   //0...7...15...31&lt;br /&gt;
   //&lt;br /&gt;
   //big-endian:&lt;br /&gt;
   //31...15...7...0&lt;br /&gt;
   //&lt;br /&gt;
   //процессоры: x86 &amp;amp;mdash; little-endian, при обмене данными по сети &amp;amp;mdash; big-endian&lt;br /&gt;
&lt;br /&gt;
Обращаться можно и к памяти:&lt;br /&gt;
   mov eax, [ebx] ; загрузка в eax того, что находится по адресу ebx (в C выглядело бы как eax = *ebx)&lt;br /&gt;
&lt;br /&gt;
[] - косвенная адресация. не более одних скобок за раз, ** недопустимы. Может использоваться как для левого, так и правого аргумента mov. В команде может быть не больше одного обращения к памяти.&lt;br /&gt;
   &amp;lt;s&amp;gt;mov [eax], [ebx]&amp;lt;/s&amp;gt; ; так делать нельзя!&lt;br /&gt;
&lt;br /&gt;
Оперативную память попортить нельзя, она разделена между процессами.&lt;br /&gt;
&lt;br /&gt;
В квадратных скобках при использовании 16-битных регистров можно писать три опциональные части:&lt;br /&gt;
   bx   si&lt;br /&gt;
      +     +/- offset (16-битное число)&lt;br /&gt;
   bp   di&lt;br /&gt;
В квадратных скобках при использовании 32-битных регистров позволено писать довольно много разных вещей:&lt;br /&gt;
   eax&lt;br /&gt;
   ebx   eax&lt;br /&gt;
   ecx   ebx   1&lt;br /&gt;
   edx   ecx   2 &lt;br /&gt;
       + edx *   +/- offset (32-битное число)&lt;br /&gt;
   ebp   ebp   4&lt;br /&gt;
   esp   edi   8&lt;br /&gt;
   edi   esi&lt;br /&gt;
   esi&lt;br /&gt;
&lt;br /&gt;
== Работа со стеком ==&lt;br /&gt;
&lt;br /&gt;
   push register|memory|immediate ; положить значение на стек&lt;br /&gt;
&lt;br /&gt;
Сишный псевдокод:&lt;br /&gt;
   esp -= sizeof(eax) // минус потому, что стек &amp;quot;растёт вниз&amp;quot;, чем он больше, тем на меньшее число указывает esp (и наоборот)&lt;br /&gt;
   *esp = eax&lt;br /&gt;
Эквивалентный код на ассемблере:&lt;br /&gt;
   sub esp, 4&lt;br /&gt;
   mov [esp], eax&lt;br /&gt;
&lt;br /&gt;
   pop register|memory ; записать значение верхнего элемента стека в регистр/память&lt;br /&gt;
&lt;br /&gt;
Как это выглядит на ассемблере:&lt;br /&gt;
   mov eax, [esp]&lt;br /&gt;
   add esp, 4&lt;br /&gt;
&lt;br /&gt;
Стек-пойнтеру (sp) в 16-битном режиме довольно желательно бы быть чётным, в 32-битном &amp;amp;mdash; кратным четырём: всё будет работать существенно быстрее.&lt;br /&gt;
Стек &amp;amp;mdash; хорошее быстрое временное хранилище. Не слишком большое (1-2 мб).&lt;br /&gt;
//malloc и free &amp;amp;mdash; системные функции, их можно свободно использовать в любом языке (и в Си, и здесь, и в дельфи)&lt;br /&gt;
&lt;br /&gt;
   pusha(d) ; сохранить в стек все 8 регистров общего назначения&lt;br /&gt;
   popa(d) ; вытащить их из стека&lt;br /&gt;
&lt;br /&gt;
(push|pop)ad работают с 32-битными регистрами, (push|pop)a &amp;amp;mdash; c 16-битными.&lt;br /&gt;
При восстановлении не меняется esp (логично, дабы с esp не произошло трешака).&lt;br /&gt;
//&amp;quot;Вас никто не заставляет делать разумные вещи. Если вы хотите делать безумные вещи, вы можете это делать совершенно свободно!&amp;quot;&lt;br /&gt;
&lt;br /&gt;
*Начало второй лекции. Начало пропущено:*&lt;br /&gt;
&lt;br /&gt;
== Арифметические команды ==&lt;br /&gt;
&lt;br /&gt;
   add eax, ebx ; eax += ebx&lt;br /&gt;
   adc eax, ebx ; eax += ebx + CF // CF - флаг переноса&lt;br /&gt;
   sub / sbb&lt;br /&gt;
   mul / div&lt;br /&gt;
   imul / idiv&lt;br /&gt;
&lt;br /&gt;
   mul OP &amp;amp;mdash; после этой команды в edx:eax 64 бита &amp;amp;mdash; результат умножения eax на OP&lt;br /&gt;
   div OP &amp;amp;mdash; после этой команды в edx edx:eax / ebx&lt;br /&gt;
                             в eax же eds:eax % ebx&lt;br /&gt;
&lt;br /&gt;
как при делении на ноль, так и переполнении при делении вылетает исключение и программу убивает система. последнее может лечиться обнулением edx'а.&lt;br /&gt;
//в документации указана обработка всего этого в 8- и 16-битных случаях&lt;br /&gt;
&lt;br /&gt;
   imul и idiv &amp;amp;mdash; аналогично mul и div, НО: работают со знаковыми числами&lt;br /&gt;
&lt;br /&gt;
кроме того, у imul есть такие формы записи:&lt;br /&gt;
   imul ecx, ebx == ecx *= ebx (верхние биты обнуляются)&lt;br /&gt;
   imul ecx, ebx, 5 == ecx = ebx * 5&lt;br /&gt;
&lt;br /&gt;
   inc и dec. принимают один операнд, увеличивают (уменьшают) его на один; не трогают флаг переноса&lt;br /&gt;
&lt;br /&gt;
Команда, которая неизвестно для чего изначально нужна.&lt;br /&gt;
&lt;br /&gt;
   lea (load effective adress):&lt;br /&gt;
&lt;br /&gt;
   lea eax, [ebx+ecx] ; фактически, трёхоперандное сложение. eax = abx + ecx&lt;br /&gt;
&lt;br /&gt;
   lea eax, [ebx+ebx*4] ; eax = ebx * 5 (yasm поддерживает запись вида lea eax, [ebx*5], но по стандарту так нельзя)&lt;br /&gt;
&lt;br /&gt;
Как быстрее всего умножить число на 10?&lt;br /&gt;
&lt;br /&gt;
   lea eax, [ebx*5]&lt;br /&gt;
   add eax, eax&lt;br /&gt;
&lt;br /&gt;
== Команды логики ==&lt;br /&gt;
   and, or, xor, not. Все, кроме not имеют два аргумента.&lt;br /&gt;
&lt;br /&gt;
   xor eax, eax &amp;amp;mdash; быстрое обнуление регистра&lt;br /&gt;
&lt;br /&gt;
команда mov anything, 0 имеет смысл, но редко. когда:&lt;br /&gt;
1) когда нужно сохранить флаги. логика их меняет&lt;br /&gt;
2) когда нужно обнулять память. ксорить память нельзя (её можно указать лишь один раз)&lt;br /&gt;
&lt;br /&gt;
Команды cmp/test аналогичны командам (sub/and). результаты не пишут никуда (!!!), но ставят флаги.&lt;br /&gt;
&lt;br /&gt;
   test eax,eax &amp;amp;mdash; самый короткий способ проверить, 0 ли регистр&lt;br /&gt;
&lt;br /&gt;
== Команды сдвига ==&lt;br /&gt;
Во всех сдвигах последний сдвигаемый бит идёт в cf&lt;br /&gt;
&lt;br /&gt;
   shr/shl &amp;amp;mdash; сишные сдвиги (&amp;gt;&amp;gt;, &amp;lt;&amp;lt;). второй аргумент команды &amp;amp;mdash; либо константа, либо cl. деление на степени двойки &amp;amp;mdash; самое быстрые, ибо сдвиги, которые гораздо более быстрее, нежели &amp;quot;реальное&amp;quot; деление.&lt;br /&gt;
   sar &amp;amp;mdash; сдвиг справо со знаком. Сишное &amp;gt;&amp;gt; компилируется в зависимости от &amp;quot;знаковости&amp;quot; переменной в shr/sar. shl, очевидно, == sal.&lt;br /&gt;
&lt;br /&gt;
   shrd/shld принимают три аргумента.&lt;br /&gt;
   shrd eax,ebx,3:&lt;br /&gt;
   ebx,eax двигаются на 3 вправо (О_О). первые k (где k &amp;amp;mdash; третий аргумент) битов того, что указано в первом аргументе == последние k того, что указано во втором.&lt;br /&gt;
&lt;br /&gt;
=== Команды вращения (о_О) ===&lt;br /&gt;
   rol, ror: тупое вращение по кругу, ничего ниоткуда не берётся, не теряется и не придумывается.&lt;br /&gt;
   rcl, rcr:&lt;br /&gt;
&lt;br /&gt;
   rcl:&lt;br /&gt;
&lt;br /&gt;
   cf &amp;lt;- 31...&amp;lt;первый аргумент&amp;gt;...0-^&lt;br /&gt;
   |                                |&lt;br /&gt;
   v--------------------------------&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Аналогично rol/ror'у, но флаг cf &amp;amp;mdash; часть того, что сдвигается (т.о., сдвигаются 33 бита)&lt;br /&gt;
&lt;br /&gt;
== Команды передачи управления ==&lt;br /&gt;
&lt;br /&gt;
   jmp метка (jmp eax)&lt;br /&gt;
фактически &amp;amp;mdash; mov eip, smth&lt;br /&gt;
&lt;br /&gt;
Так же есть условия, зависящие от флагов:&lt;br /&gt;
   j(cc)&lt;br /&gt;
   ex.: jz &amp;amp;mdash; условный переход, если флаг нуля установлен.&lt;br /&gt;
   jnz &amp;amp;mdash; переход, если флаг нуля не установлен.&lt;br /&gt;
   jc, jnc &amp;amp;mdash; аналогично для флага переноса, и так далее... тысячи их!&lt;br /&gt;
&lt;br /&gt;
   ja, jb, jae, jbe, jl, jg, jle, jge (к каждой можно устроить отрицание(&lt;br /&gt;
   ja &amp;amp;mdash; above (если больше, без знака)&lt;br /&gt;
   jb &amp;amp;mdash; below (если меньше, без знака)&lt;br /&gt;
   jae &amp;amp;mdash; above/equal (больше или равно без знака)&lt;br /&gt;
   jbe &amp;amp;mdash; below/equal (меньше или равно без знака)&lt;br /&gt;
   jg  \&lt;br /&gt;
   jl  |} &amp;amp;mdash; аналогично вышеуказанным,&lt;br /&gt;
   jge |} &amp;amp;mdash; но с учётом знаков.&lt;br /&gt;
   jle /&lt;br /&gt;
&lt;br /&gt;
к каждым командам существуют отрицания. j(n)cc&lt;br /&gt;
логично, что, например, jb == jnae&lt;br /&gt;
&lt;br /&gt;
те же самые условия используеются в командах условной загрузки (mov(cc))&lt;br /&gt;
&lt;br /&gt;
   call &amp;amp;mdash; аналогично jmp, НО.&lt;br /&gt;
   call x ~= &lt;br /&gt;
       | push eip&lt;br /&gt;
       | mov eip, x&lt;br /&gt;
   ret ~= &lt;br /&gt;
       | pop eip&lt;br /&gt;
   &lt;br /&gt;
У ret есть опциональный параметр &amp;amp;mdash; число.&lt;br /&gt;
   ret x ~=&lt;br /&gt;
       pop eip&lt;br /&gt;
       add esp, x ; выкинуть со стека x байт&lt;br /&gt;
&lt;br /&gt;
//пара команд, которые все любят&lt;br /&gt;
   nop &amp;amp;mdash; Команда, Которая Ничего Не Делает&lt;br /&gt;
   ud2 &amp;amp;mdash; Команда, Которой Не Существует. Если она выполняется, программа падает с ошибкой. И БУДЕТ ПАДАТЬ. ВСЕГДА. И НЫНЕ. И ПРИСНО. ВО ВЕКИ. ВЕКОВ&lt;/div&gt;</summary>
		<author><name>95.25.47.253</name></author>	</entry>

	</feed>