Ассемблер

Как в ассемблер записать отрицательное число

В ассемблере отрицательное число обычно можно записать прямо через минус: mov eax, -5, db -1, dd -100. Assembler сам закодирует значение в дополнительном коде, если размер операнда позволяет это сделать. Главное понимать, сколько байт выделено под число и как потом вы будете его интерпретировать: как signed или как unsigned

Простой пример NASM:

mov eax, -5

В eax окажется битовое представление числа -5 для 32-битного регистра. Это не текст -5, а набор битов

Что такое дополнительный код

Современные x86 и x86-64 хранят отрицательные целые числа в two’s complement, по-русски часто говорят «дополнительный код»

Для 8 бит:

  1  = 00000001
 -1  = 11111111
 -2  = 11111110

Для 32 бит -1 выглядит как:

FFFFFFFFh

Но эти же биты как unsigned означают 4294967295. Поэтому сам набор битов не говорит, «положительное» число перед вами или «отрицательное». Смысл зависит от операции и перехода

Запись в данные

В NASM можно писать так:

section .data
    a db -1
    b dw -300
    c dd -100000
    d dq -5

Размеры:

  • db — 1 байт;
  • dw — 2 байта;
  • dd — 4 байта;
  • dq — 8 байт.

Число должно помещаться в выбранный размер. Например, для signed 8-битного значения диапазон от -128 до 127

Запись в регистр

mov al, -1
mov ax, -1
mov eax, -1
mov rax, -1

В каждом случае размер разный. al — 8 бит, ax — 16 бит, eax — 32 бита, rax — 64 бита. Визуально значение одно, но битовое представление занимает разное количество байт

Как получить отрицательное число через NEG

Инструкция neg меняет знак:

mov eax, 5
neg eax

После этого в eax будет -5. Внутри neg eax фактически делает 0 - eax

Это удобно, когда знак зависит от вычислений, а не от константы в исходном коде

Знаковое расширение

Если маленькое отрицательное число нужно перенести в больший регистр, важен знак. Для этого есть инструкции вроде movsx:

mov al, -5
movsx eax, al

movsx расширяет значение с сохранением знака. Если использовать обычное нулевое расширение, отрицательное число может превратиться в большое положительное

Пример:

mov al, -1
movzx eax, al

После movzx в eax будет 255, потому что байт FFh расширили нулями

Как сравнивать отрицательные числа

Для отрицательных чисел используйте signed-переходы:

cmp eax, -10
jl less_than_minus_10
jg greater_than_minus_10

Переходы jl, jle, jg, jge подходят для signed-логики. Переходы jb, jbe, ja, jae используются для unsigned-логики

Частые ошибки

Записывают число не в тот размер

db -200 не подходит для signed 8-битного числа. Оно не помещается в диапазон

Смотрят на значение как unsigned

Биты FFh могут означать -1 или 255. Нужно знать, как программа трактует эти биты

Используют movzx вместо movsx

Для отрицательных байтов и слов при расширении нужен movsx, если вы хотите сохранить знак

Сравнивают signed-число unsigned-переходом

Для отрицательных чисел почти всегда смотрите в сторону jl, jle, jg, jge

Что почитать дальше по ассемблеру

Если нужен общий маршрут по теме, откройте рубрику ассемблеру. Для соседних задач пригодятся эти разборы:

Подписаться
Уведомить о
guest
0 комментариев
Старые
Новые Популярные

Настройки cookie

0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x