ГЛАВА 13
ПЕРЕХОДЫ И ЦИКЛЫ
(часть 2/5)
Выводы
Псевдокод команд JMP SHORT и JMP NEAR – ADD IP/EIP/RIP,
число_со_знаком. Команда JMP в зависимости от типа своего операнда изменяет либо содержимое только одного регистра IP/EIP/RIP, либо – в случае JMP FAR – содержимое двух регистров CS и IP/EIP/RIP.
- Если операнд в команде JMP – метка в текущем сегменте команд, то ассемблер формирует машинную команду, операнд которой является значением со знаком, являющимся смещением перехода относительно следующей за JMP команды. При этом виде перехода изменяется только значение в регистре IP/EIP/RIP;
- Если операнд в команде JMP – адрес, по которому необходимо передать управление. Этот адрес может быть двух видов:
- значением абсолютного смещения метки перехода относительно начала сегмента кода. Размер этого
смещения может быть 16/ 32 или 64 бит в зависимости от режима адресации;
- дальним указателем на метку перехода в реальном и защищенном режимах, содержащим два компонента адреса – сегментный и смещение. Размеры этих компонентов также зависят от установленного режима адресации (use16/use32 или use64). Если текущим является 16-битный режим, то адрес сегмента и смещение занимают по 16 бит, причем смещение располагается в младшем слове двойного слова, отводимого под этот полный адрес метки перехода. Если текущим является 32-битный режим, то адрес сегмента и смещение занимают, соответственно, 16 и 32 бит, – в младшем двойном слове находится смещение, в старшем – адрес сегмента.
js06.asm
| | .286 |
| | .model medium |
| | code1 segment |
| | assume cs:code1 |
| 000200: E90200 | start: | jmp near ptr a2 |
| 000203: EB00 | | jmp short a2 |
| 000205: EA00000001;jmp 0001:0000 | a2: | jmp far ptr code2:a3 |
| 00020A: EA00000001;jmp 0001:0000 | | jmp far ptr a3 |
| 00020F: 00 | code1 ends |
| | code2 segment |
| | assume cs:code2 |
| 000210: B44C | a3: | mov ah,4Ch |
| 000212: CD21 | | int 21h |
| | code2 ends |
| | end start |
js06.map
| | Start | Stop | Length | Name | Class |
| cs=0000 | 00000H | 00009H | 0000AH | CODE1 | CODE |
| cs=0001 | 00010H | 00013H | 00004H | CODE2 | CODE |
Ассемблер рассчитывает смещение автоматически, и если значение смещения лежит в пределах от -128 до +127 байт, то, по умолчанию, будет подставлена более короткая двухбайтная инструкция JMP SHORT, хотя в кодах вы можете подставить и более длинные инструкции JMP NEAR и JMP FAR. Более длинные инструкции могут использоваться для написания самомодифицируемого кода либо для того, чтобы сбить с толку отладчик, либо для выравнивания кода.
| Код | Команда | Описание |
|---|
| EB cb | JMP rel8 | Короткий переход, ассемблер формирует машинную команду, операнд которой является значением со знаком, являющимся смещением перехода относительно следующей за jmp команды. К содержимому регистра счетчика команд IP/EIP/RIP добавляется 8-битное число со знаком |
| E9 cw | JMP rel16 | Близкий переход. Не поддерживается в 64-разрядном режиме |
| E9 cd | JMP rel32 | Близкий переход, к содержимому регистра счетчика команд EIP/RIP добавляется 32-разрядное число со знаком |
| EA cd | JMP ptr16:16 | Дальний переход, адрес задан в операнде |
| EA cp | JMP ptr16:32 | |
| EA cq | JMP ptr16:64 | |
JMP не дает возможности перемещаться между сегментами – для этого есть JMP FAR. Это в случае, если сегменты не пересекаются. Если пересекаются – можно перемещаться как угодно.
Прямые переходы требуют указания в качестве точки перехода программной метки. Такой переход в некоторых случаях неудобен – он имеет статический характер, его нельзя настроить по ходу выполнения программы. Прямой переход также не дает возможности перейти по известному абсолютному адресу, например, в том случае, если наша программа взаимодействует либо с системными средствами, либо с другими загруженными в память программами. Программы операционной системы не имеют меток, так как метки – это атрибут исходного текста программы, а программы операционной системы транслировались не нами и присутствуют в памяти только в виде исполнимых модулей. А вот адреса характерных точек системных программ определить можно, например, из векторов прерываний. Для обращения по абсолютным адресам используют команды косвенных переходов, которые могут быть как ближними, так и дальними.
Косвенный переход
JMP <Reg>|<Memory>
В случае косвенного перехода в качестве операнда указывается не сам адрес перехода, а то место где находится этот адрес. Таким местом может быть регистр общего назначения или ячейка памяти: Синтаксис команды: JMP <TAGER>
Возможные варианты команды:
jmp reg
jmp [reg]
jmp mem
В этих командах берется содержимое указанного регистра или ячейки памяти, оно рассматривается как адрес некоторой команды перехода и по этому адресу делается переход. Косвенные переходы используются, как правило в тех случаях, когда адрес перехода вычисляется во время выполнения программы, либо когда требуется осуществить переход по известному абсолютному адресу.
| Assembler |
1
2
3
4
5
6
| A DD L
JMP A;перейти по адресу содержащемуся в ячейке A,
... ;то есть перейти на метку L
MOV EDX,A;перейти по адресу, который содержится
JMP EDX;в регистре EDX, то есть перейти на метку L
L:... |
|
Алгоритм работы: если операнд в команде JMP – символический идентификатор ячейки памяти (m16, m32, m16:32) или регистр, то ассемблер предполагает, что там находится адрес, по которому необходимо передать управление. Этот адрес может быть трех видов:
- значением абсолютного смещения метки перехода. Размер этого смещения может быть 16/32 или 64 бита в зависимости от режима адресации;
- дальним указателем на метку перехода в реальном и защищенном режимах, содержащим два компонента адреса – сегментный и смещение. Размеры этих компонентов также зависят от установленного режима адресации (use16/use32 или use64). Если текущим является 16-битный режим, то адрес сегмента и смещение занимают по 16 бит, причем смещение располагается в младшей части двойного слова, отводимого под полный адрес метки перехода. Если текущим является 32-битный режим, то адрес сегмента и смещение занимают, соответственно, 16 и 32 бита, – в младшей части двойного слова находится смещение, в старшей – адрес сегмента;
- адресом в одном из 16 или 32-разрядных регистров – этот адрес представляет собой абсолютное смещение метки относительно начала сегмента кода, на которую необходимо передать управление, относительно начала сегмента команд.
| Код | Команда | Пример использования | Описание |
|---|
| FF/4 | JMP m16 | JMP DS:[BX] | Близкий переход, в m16 адрес перехода=число со знаком. Не поддерживается в 64-разрядном режиме |
| | JMP m32 | JMP [EBX] | Близкий переход, в m32 адрес перехода=число со знаком. Не поддерживается в 64-разрядном режиме |
| | JMP m64 | JMP [RBX] | Близкий переход, в RIP передается 64-битное смещение из ячейки памяти |
| FFE0+reg | JMP r16 | JMP BX | Близкий переход, в r16 адрес перехода=число со знаком. Не поддерживается в 64-разрядном режиме |
| | JMP r32 | JMP EDI | Близкий переход, в r32 адрес перехода=число со знаком. Не поддерживается в 64-разрядном режиме |
| | JMP r64 | JMP RDI | Близкий переход, в RIP передается 64-битное смещение из регистра |
| FF /5 | JMP far ptr m16:16/32 | JMP far ptr [HugePtr] | Дальний переход, адрес перехода задан в ячейке m16:16/32 в формате сегмент:смещение |
| REX.W+FF/5 | JMP far ptr m16:64 | | Дальний переход, адрес перехода задан в ячейке m16:64 в формате сегмент:смещение |
Допустим, что ячейка памяти A первоначально пуста, по ходу выполнения программы в нее, в зависимости от каких-либо условий, помещается адрес той либо иной точки перехода. В этом случае создается возможность перед выполнением перехода определить или даже вычислить адрес перехода, требуемый в данных условиях.
| Assembler |
1
2
3
4
5
6
7
8
9
| a1:JMP A;перейти по адресу содержащемуся в ячейке A
...
mov A,offset N1
jmp a1
...
mov A,offset N2
jmp a1
...
A dd 0 |
|
Допустим мы программируем в 16-разрядном режиме. Ячейка памяти A описана как двойное слово. Ассемблер допускает различные формы описания косвенного перехода по адресу, заданному через ячейку памяти. Если мы напишем jmp far ptr A – ассемблер однозначно генерирует код дальнего косвенного перехода, независимо от того какая размерность у ячейки памяти. Если написать jmp A – ассемблер начинает рассуждать следующим образом – ячейка A по определению двойное слово, значит она содержит полный двухсловный (сегмент:смещение) адрес – необходимо генерировать код дальнего косвенного перехода. Если написатьjmp word ptr A – это заставит транслятор считать, что ячейка памяти имеет размерность слово, независимо от действительного размера, что приведет к генерации кода ближнего косвенного перехода.
| Assembler |
1
2
3
4
5
6
7
| A dd L
...
mov edx,A;перейти по адресу содержащемуся в ячейке A,
jmp edx;то есть перейти на метку L
mov edx,offset A;перейти по адресу, который содержится
jmp dword ptr [edx];в регистре EDX, то есть перейти на метку L
L:... |
|
Адрес перехода можно задавать через регистр общего назначения с использованием базово-индексной адресации. Эту адресацию используют в тех случаях, когда имеется несколько альтернативных точек перехода, выбор которых зависит от некоторых условий. В этом случае создается таблица адресов переходов. Например, в индексный регистр передается определенный тем или иным способом индекс в таблице. Переход осуществится в точку, соответствующую заданному индексу.
| Assembler |
1
2
3
4
5
6
7
| mov esi,2;вычисленное каким-то образом смещение в таблице
jmp table[esi*4];если esi=2,тогда переход на метку N3
N1:...;первая точка перехода
N2:...;вторая точка перехода
N3:...;третья точка перехода
... ... ...
table dd N1,N2,N3,N4;таблица с адресами переходов |
|
Использование косвенного перехода позволяет создать на языке ассемблера структуру выбора CASE – выбор из множества значений, определяемое значением индексного регистра.
Никто не может нам запретить использовать для косвенной адресации пару регистров общего назначения. Это дает возможность одновременно использовать несколько таблиц переходов.
| Assembler |
1
2
3
4
5
6
7
| mov esi,2;вычисленное каким-то образом смещение
mov ebx,offset table1;вычисленная каким-то образом таблица
jmp [ebx][esi*4];если esi=2 и ebx=table1,тогда переход
... ...;на метку N3
...
table1 dd N1,N2,N3,N4;таблицы с адресами переходов
table2 dd N5,N6,N7,N8 |
|
Как и в случае ближнего перехода, дальний косвенный переход осуществляется по адресу, который содержится в ячейке памяти, которая имеет размер двойного слова (16-разрядный режим) или три слова (32-разрядный режим) и в ней содержится полный (сегмент:смещение) адрес точки перехода. Программа в этом случае должна включать по меньшей мере два сегмента кода. Для дальнего косвенного перехода ассемблер допускает различные формы адресации через регистры общего назначения.
При кодировании под TASM было замечено, что ассемблер фирмы Borland подменяет дальний косвенный переход инструкциями PUSH CS (код 0Eh) и инструкция ближнего косвенного перехода:
JMP FAR [BP][DI]

0EFF23h вместо FF2Bh
MASM также не может правильно сгенерировать команды дальнего косвенного перехода.
| Машинный код | Интерпретация команды | Ассемблерный текст | комментарий |
|---|
| 09: FF23 | JMP [BP][DI] | JMP [BP+DI] | ближний переход по адресу, содержащемуся в [BP+DI] |
| 0B: FF2B | JMP FAR [BP][DI] | db 0FFh,2Bh | дальний переход по адресу, содержащемуся в [BP+DI] (только в кодах) |
| 0D: FFA7009A | JMP [BX+9A00] | JMP [BX+9A00h] | ближний переход по адресу, содержащемуся в [BX+9A00h] |
| 11: FFAF009A | JMP FAR [BX+9A00] | db 0FFh,0AFh,0,9Ah | дальний переход по адресу, содержащемуся в [BX+9A00h] (только в кодах) |
| 15: 26 | ES: | | |
| 16: FF27 | JMP [BX] | JMP ES:[BX] | ближний переход по адресу, содержащемуся в ES:[BX] |
| 18: 26 | ES: | | |
| 19: FF2F | JMP FAR [BX] | db 26h,0FFh,2Fh | дальний переход по адресу в ES:[BX] (только в кодах) |
Чтобы сгенерировать дальний переход и при этом не терять 1 байт на команду PUSH CS, необходимо написать код ближнего перехода и добавить ко второму байту команды 8, например: код FF17 соответствует команде JMP [BX], а код FF17+0008=FF1F – команде JMP FAR [BX].
Вывод – программируйте дальние переходы в машинных кодах.
Примечание: Не слишком увлекайтесь метками. Существует правило: квалификация программиста обратно пропорциональна числу меток в программе.
Оператор SHORT
| Код | Команда | Назначение | Пример использования | Длина кода (байт) |
|---|
| use16 |
| EB | JMP rel8 | короткий переход | JMP short a1 | 2 |
| E9 | JMP rel16 | внутрисегментный прямой переход | JMP near a1 | 3 |
| EA | JMP ptr16:16 | межсегментный прямой переход | JMP far ptr a1 | 5 |
| use32 |
| EB | JMP rel8 | короткий переход | JMP short a1 | 2 |
| E9 | JMP rel32 | внутрисегментный прямой переход | JMP near a1 | 5 |
| EA | JMP ptr16:32 | межсегментный прямой переход | JMP far ptr a1 | 9 |
По команде JMP транслятор может сгенерировать от 2 до 9 байт кода. В командах прямого перехода относительный адрес перехода задается в виде байта, слова или двойного слова. В этих командах операнд рассматривается как целое со знаком (для байта от –128 до +127, для слова от –2
15 до 2
15–1, для двойного слова от –2
31 до 2
31–1), поэтому при сложении его с IP/EIP значение этого регистра может и увеличиться, и уменьшиться. Обычно программист не вычисляет длину относительных адресов переходов. Программируя на языке ассемблера, мы указываем лишь метку нужной команды. Ассемблер сам подсчитывает разность между адресом этой метки и адресом команды перехода и подставляет эту разность в машинную команду. Транслятор просматривает текст программы сверху вниз. Встречая символьную команду перехода с меткой, ассемблер вычисляет разность между адресом этой метки и адресом самой команды перехода и оценивает величину этой разности. Если она небольшая, укладывается в байт, ассемблер формирует машинную команду короткого перехода в 2 байта, а если разность большая – формируется команда длинного перехода в 3 байта для 16-битного режима и в 5 байт для 32-битного. Если ваш ассемблер настроен только на один проход («старый» однопроходный MASM или трансляция осуществляется ассемблером TASM без ключа /m#) тогда сделать выбор между короткой или длинной формой команды JMP ассемблер может, только если метка описана до команды перехода, то есть если эта метка является ссылкой назад. Но если в команде перехода указана метка со ссылкой вперед, ассемблер генерирует «на всякий случай» команду длинного перехода.
| | Комментарий | Адрес | Код |
|---|
| jmp short a1 | Явно указан короткий переход, под него сразу отведено 2 байта | 4000C4: | EB05 |
| jmp a1 | Переход вперед на неизвестную метку, ассемблер отвел на переход 5 байтов | 4000C6: | E900000000 |
| | Теперь ассемблер рассчитал длину смещения, подставил код JMP SHORT, а на освободившееся место поставил код 90h (NOP) | 4000C6: 4000C8:4000C9: 4000CA: | EB03 90 90 90 |
| a1: | | 4000CB: | |
В большинстве случаев переход делается на команды, расположенные недалеко от команд перехода, и мы можем потерять на этом три байта. Избежать избыточности при кодировании переходов вперед можно за счет явного задания дальности перехода. Поставив после команды JMP оператор SHORT, мы предупреждаем ассемблер о необходимости формирования команды короткого перехода длиной в 2 байта. Если мы ошиблись, при трансляции будет выдана ошибка, подобная этой:
test.asm(94) : error A2075: jump destination too far : by 150 byte(s)
В файле test.asm на 94 строке находится инструкция jmp short, которая ссылается на метку до которой 127+150=277 байт. Необходимо убрать оператор SHORT с 94 строки или сократить код.
В некотрых случаях нужно наоборот принудительно сделать из jmp short

jmp near используя лишние байты в целях выравнивания для того, что бы обойтись без дополнительных команд и тактов процессора.
Пример:
| 4000C4:E902000000 | JMP L;ближний переход (5 байт) |
| 4000C9:EB00 | JMP SHORT L;короткий переход (2 байта) |
| 4000CB:... | L:... |
BIOS (Basic Input/Output System – базовая система ввода-вывода – программа, управляющая элементарными функциями компьютера). BIOS отвечает за то, как процессор взаимодействует с системной памятью, накопителями, дисплеем и клавиатурой. После включения или перезагрузки микропроцессор переходит по адресу, куда помещен BIOS и начинает выполнять команды BIOS'а. Это наталкивает на мысль, что для «мягкой» перезагрузки надо начать выполнять команды оттуда, откуда их начинает выполнять сам микропроцессор. Чтобы перезагрузить компьютер в реальном режиме понадобится программа длиной всего 8 байт, состоящая из одной команды jmp dword ptr reboot – переход туда, где лежит первая программа микропроцессора.
Единственная команда в вашей программе заставляет микропроцессор перейти по адресу, который находится в переменной reboot. Число 0FFFF0000h – это значение адреса, куда мы прыгаем. Именно по этому адресу микропроцессор считывает первую команду после включения или перезагрузки.
| Assembler |
1
2
3
4
5
6
7
| .model tiny
.code
org 100h
.startup
jmp dword ptr reboot
reboot dd 0FFFF0000h
end |
|
Но 8 байт это еще не предел! Оказывается, можно написать и вдвое короче:
| Assembler |
1
2
3
4
5
6
| .model tiny
.code
org 100h
.startup
db 0EAh,0,0,0FFh,0FFh
end |
|
У этой полезнейшей программы длина всего 5 байт (это даже не ассемблер, а программирование в машинных кодах – просто нельзя написать напрямую jmp 0FFFF:0000h.
Эквиваленты команды jmp a1
| 1) | push offset a1 retn | загружаем в стек адрес перехода переходим на a1 |
| 2) | mov eax,offset a1 mov dword ptr [esp],eax retn | более изощренная загрузка в стек адреса перехода |
| 3) | call a1 . . . a1: pop ecx | удаляем из стека адрес возврата |
| 4) | loop a1 | если ecx 1 и расстояние до a1в пределах от -128 до +127 байт, можно перейти по loop |
| 5) | jnc a1 | если в результате логической или арифметической операции CF не изменялся, а до этого CF=0 |
| 6) | push seg a1 push offset a1 retf | аналог jmp far |
Команды сравнения и условного переходаЕсли переход осуществляется только при выполнении некоторого условия, то такой переход называется условным. Команды условного перехода применяют для проверки различных условий, возникающих в ходе выполнения программы.
Так как конструкция if ... then в языке ассемблера отсутствует, эту операцию приходится осуществлять в два этапа. Команда CMP сравнивает два числа, в результате чего соответствующим образом устанавливаются флаги в регистре EFLAGS/FLAGS (ZF, SF и т.д.). Для начала достаточно запомнить три основных состояния: меньше (below или less), больше (above или greater) и равно (equal). Семейство команд условного перехода Jcc проверяют код условия (cc – condition code) и если он истинный, совершают переход по указанному адресу. Например, переход по команде JE произойдет, если два числа равны (Jump if Equal), а переход по команде JNE – если неравны (Jump if Not Equal).
Команды JB/JA сравнивают числа без знака, а JL/JG – числа со знаком. Любые два не противоречащих друг другу условия могут быть скомбинированы друг с другом, например: JBE – переход, если одно беззнаковое число меньше или равно другому.
Кроме команды CMP сравнение можно выполнить командами TEST и CMPXCHG. Так же можно использовать команды AND, OR, SUB и т.п.
Команда CMP
(Сравнение операндов = ”COMPARE operands”)
Синтаксис команды: CMP <DEST>,<SRC>
Семантика команды: сравнение двух операндов.
Возможные варианты команды:
cmp reg/mem,reg
cmp reg,mem
cmp reg/mem,imm
Алгоритм работы:
- выполнить вычитание DEST-SRC;
- в зависимости от результата установить флаги, операнд DEST и операнд SRC не изменять (то есть результат не запоминать).
Применение: данная команда используется для сравнения двух операндов методом вычитания, при этом операнды не изменяются. По результатам выполнения команды устанавливаются флаги. Команда CMP применяется с командами условного перехода Jcc, условной пересылки данных CMOVcc или условной установки байтов SETcc.
| Assembler |
1
2
3
| cmp eax,10
jnz M1;на M1 мы перейдем если [EAX]<>10
M2:;на M2 мы окажемся если [EAX]=10 |
|
Эквивалент команды CMP DEST, SRC:
push DEST
sub DEST,SRC
pop DEST
Эквиваленты команды cmp eax,10h, если по условию задачи можно
изменять значение в регистре EAX:
| xor eax,10h | sub eax,10h | add eax,0FFFFFFF0h |
| jz m1 | jz m1 | jz m1 |
Если необходимо сравнить значение в регистре с нулем:
| test eax,eax | or eax,eax | and eax,eax |
Если необходимо получить значение в переменной булевского типа (то есть FALSE(=0) или TRUE(=1)):
| Assembler |
1
2
| dec reg
jz m1 ;if false |
|
Обычно функции возвращают значение в EAX. Если нет необходимости сохранять значение в ECX тогда
| Assembler |
1
2
| xchg eax,ecx;1 байт
jecxz m1;2 байта |
|
Команда CMPXCHG
(Сравнение и обмен операндов =
”COMPARE and EXCHANGE operands”)

Синтаксис команды: CMPXCHG <DEST>,<SRC>
Возможные варианты команды:
cmpxchg reg, reg
cmpxchg mem, reg
Семантика команды: сравнение значения, находящегося в аккумуляторе (регистр AL, AX или EAX) с операндом DEST(память или регистр). Если они равны, то содержимое операнда SRC (только регистр) загружается в операнд DEST. В противном случае операнд DEST загружается в аккумулятор.
псевдокод: IF {AL/AX/EAX} = DEST
THEN ZF

1 ;Set the zero flag
DEST := SRC
ELSE
ZF

0 ;Clear the zero flag
{AL/AX/EAX} := DEST
ENDIF
| Assembler |
1
2
3
4
| mem dd 123
mov eax,148
mov ebx,60
cmpxchg mem,ebx; [mem]<>eax [mem]=123, ebx=60, eax=123 |
|
| Команда | Пример использования |
|---|
| CMPXCHNG r/m8,r8 | CMPXCHNG DH,DL |
| CMPXCHNG r/m16,r16 | CMPXCHNG DeltaY,CX |
| CMPXCHNG r/m32,r32 | CMPXCHNG [EBP],EDX |
Команда CMPXCHG полезна при тестировании и модификации семафоров. Она выполняет проверку, чтобы посмотреть, свободен ли семафор и есть ли такая отметка, в противном случае команда получает идентификатор текущего владельца в одной непрерываемой операции. В системах с одним процессором она исключает необходимость переключения на уровень 0 для блокировки прерываний для выполнения многократных команд. Для многопроцессорных систем команда CMPXVHG может быть объединена с командой LOCK для выполнения всех циклов шины автоматически.
Команда CMPXCHG8B
(Сравнение и обмен 8 байтов = ”
COMPARE and EXCHANGE 8 Bytes”)

Синтаксис команды: CMPXCHG8B m8byte
Семантика команды: выполнение в одной операции сравнения и обмен 8-байтовых операндов. Команда требует один операнд m8byte и неявным образом использует еще два операнда – пары регистров EDX:EAX и ECX:EBX. В качестве явного операнда команды m8byte может выступать только 64-битная (8-байтовая) ячейка памяти. Команда выполняет сравнение операнда m8byte в памяти с содержимым EDX:EAX. Если сравниваемые значения совпадают, то операнд DEST в памяти замещается 64-битным значением ECX:EBX. Если сравниваемые значения не совпадают, содержимое памяти поступает в пару регистров EDX:EAX, замещая сравниваемый операнд DEST.
Пример 1
| Assembler |
1
2
3
4
5
6
7
| mem dq 1122334455667788h
mov ECX, 9
mov EBX, 5
mov EDX, 11223344h
mov EAX, 55667788h
cmpxchg8b mem ;[mem]=EDX:EAX ECX:EBX->[mem]
;mem=0000000900000005h |
|
Пример 2
| Assembler |
1
2
3
4
5
6
| mem dq 1122334455667788h
mov EAX, 9
mov EDX, 5
cmpxchg8b mem ;[mem]<>EDX:EAX [mem]->EDX:EAX
;mem=1122334455667788h
;EDX=11223344h EAX=55667788h |
|
При работе с многобайтовыми данными не следует забывать о том, что в памяти байты всегда выстраиваются в порядке их номеров, то есть от младших к старшим, в то время как при изображении чисел применяется обратный порядок. В то же время символьные строки изображаются так же, как они располагаются в памяти.
Пример 3
| Assembler |
1
2
3
4
5
6
7
8
| mem1 db ‘12345678’;строка операнд
mem2 db ‘12345678’;сравниваемая строка
mov ECX, 68676665h ;’efgh’
mov EBX, 64636261h ;’abcd’
mov EDX,dword ptr mem2+4;забираем старшую часть строки
mov EAX,dword ptr mem2;забираем младшую часть строки
cmpxchg8b qword ptr mem1;операнды совпадают
;mem1=’abcdefgh’ ZF=1 ECX:EBX и EDX:EAX без изменений |
|
Пример 4
| Assembler |
1
2
3
4
5
6
7
8
9
10
| mem1 db ‘12345678’;строка операнд
mem2 db ‘abcdefgh’;сравниваемая строка
mov ecx, 68676665h ;’efgh’
mov ebx, 64636261h ;’abcd’
mov edx,dword ptr mem2+4;забираем старшую часть строки
mov eax, dword ptr mem2;забираем младшую часть строки
cmpxchg8b qword ptr mem1 ;операнды не совпадают
;ZF=0 edx=38373635=’5678’eax=34333231=’1234’
;mem1 без изменений, при неравенстве
; ecx:ebx не принимают участие в операции |
|