Инструкция loop позволяют сократить определение цикла. Она уменьшает на 1 число в регистре RCX и переходит к определенной метке, если RCX не равен нулю. Пример использования на Linux:
global _start section .text _start: mov rcx, 5 ; регистр-счетчик mov rdi, 0 mainloop: ; цикл add rdi, 2 ; некоторые действия цикла loop mainloop ; уменьшаем значение в rcx на 1, переходим к метке mainloop, если rcx не содержит 0 mov rax, 60 syscall
Здесь вначале инициализируем регистр-счетчик число 5. То есть цикл сделает 5 проходов. Цикл проектируется на метку mainloop. В цикле для теста увеличивает значение в регистре RDI на 2 и
с помощью loopq mainloop
уменьшаем значение в RCX на 1. И если в RCX НЕ число 0, возвращаемся к метке mainloop.
Аналогичный пример на Windows:
global _start section .text _start: mov rcx, 5 ; регистр-счетчик mov rax, 0 mainloop: ; цикл add rax, 2 ; некоторые действия цикла loop mainloop ; уменьшаем значение в rcx на 1, переходим к метке mainloop, если rcx не содержит 0 ret
Инструкция loop
имеет два дополнительных варианта: loope и loopne. loope
продолжает цикл, если установлен флаг нуля. Инструкция loopne, наоборот, повторяет цикл, если флаг нуля не установлен.
Например, применение инструкции loopne:
global _start section .text _start: mov rcx, 6 ; регистр-счетчик mov rdi, 0 mainloop: ; цикл add rdi, 2 ; некоторые действия цикла loopne mainloop ; уменьшаем значение в rcx на 1 и переходим к метке mainloop, если rcx не содержит 0 mov rax, 60 syscall
В принципе тут все то же самое: loopne уменьшает значение в RCX на 1 и проверяет флаг нуля. Если флаг нуля не установлен, программа переходит обратно к метке mainloop.
Выполнение цикла часто зависит от некоторого счетчика - если счетчик равен определенному значению (чаще 0), то выполнение цикла прекращается. Традиционно в качестве подобного
регистра-счетчика используется регистр RCX. Так, инструкция loop
из начала статьи проверяет данный регистр. И для упрощения проверки условия архитектура
Intel x86-64 также предоставляет инструкцию jrcxz - она проверяет значение RCX, и если оно рано 0, то переходит к определенной метке.
global _start section .text _start: mov rcx, 5 ; регистр-счетчик mov rdi, 1 mainloop: ; цикл jrcxz exit ; если rcx = 0, то переход к метке exit add rdi, 2 ; некоторые действия цикла loop mainloop ; уменьшаем значение в rcx на 1, переходим к метке mainloop, если rcx не содержит 0 exit: mov rax, 60 syscall
Здесь в цикле мы сразу проверяем, не равен ли регистр RCX нулю:
jrcxz exit
Если rcx=0, то переходим к метке exit. Подобная инструкция позволяет нам сразу вначале цикла проверить условие и не выполнять цикл, если условие (rcx не равен нулю) неверно.