Для получения текущего адреса в ассемблере NASM применяется оператор точка $. Например:
currentAddr dq $
Здесь переменная currentAddr хранит свой собственный адрес.
Мы можем манипулировать подобной переменной также, как и другими переменными. Например, получим значение, которое идет до этой переменной на примере программы на Linux:
global _start section .data nums dq 112, 113, 114, 115, 116 ; массив чисел qword currentAddr dq $ section .text _start: mov rdi, [currentAddr - 8] ; rdi = 116 mov rax, 60 syscall
Выражение [currentAddr - 8]
обращается к значению, которое идет на 8 байт назад от расположение переменной currentAddr, а это последний элемент массива nums - число 116.
Получение текущего адреса может помочь в ряде задач. Распространенная задача - получение длины строки или массива чисел. В общем случае мы можем определить переменную и непосредственно присвоить ей размер. Однако при этом можно ошибиться, неправильно подсчитать. Использование текущего адреса позволяет решить эту задачу:
global _start section .data nums dq 112, 113, 114, 115, 116 ; массив чисел qword numsLength equ $ - nums ; хранит размер массива nums section .text _start: mov rdi, numsLength ; rdi = 40 mov rax, 60 syscall
Здесь выражение $ - nums
отнимает от текущего адреса адрес переменной nums, и таким образом константа numsLength фактически представляет размер массива nums.
То есть в регистрре RDI будет помещаться число 40 (5 чисел по 8 байт). Поскольку размер массива - величина не изменяемая, то в данном случае длина массива определена как константа, а не переменная
Однако нам бы хотелось найти количество элементов в массиве, а не просто его длину. В этом случае можно разделить полученное значение на размер элемента (пример на Linux):
global _start section .data nums dq 112, 113, 114, 115, 116 ; массив чисел qword numsCount equ ($ - nums) / 8 ; хранит количество элементов массива nums section .text _start: mov rdi, numsCount ; rdi = 5 mov rax, 60 syscall
Поскольку мы имеет дело с 8-байтными числами, то размер массива делим на 8 и таким образом получаем количество элементов.
numsCount equ ($ - nums) / 8
Аналогичный пример на Windows:
global _start section .data nums dq 112, 113, 114, 115, 116 ; массив чисел qword numsCount equ ($ - nums) / 8 ; хранит количество элементов массива nums section .text _start: mov rax, numsCount ; rax = 5 ret