Ваша проблема может быть связана с add $0x1, -4(%ebp)
, который использует неоднозначный размер операнда. Если GAS выбирает размер байтового операнда, это может вызвать проблемы? Хотя, если старшие байты равны нулю, он просто будет простираться в ноль. Причина вашей проблемы не очевидна, но странно, что вы смешиваете 16- и 32-битный размер адреса для BP и EBP.
Серьезно, просто поместите число в регистр и l oop с dec reg
/ jnz
как нормальный человек.
Или используйте отладчик, чтобы посмотреть на память и разобраться, что происходит. Ваш cmpl $127, -4(%ebp)
указывает размер операнда, поэтому он определенно сравнивает слова, а не обрабатывает 128
как -128
с дополнением к 8-битному 2.
Я заметил, что операнд Команда cmpl имеет длину 4 байта в примере 128, тогда как в примере 127 она составляет всего 1 байт. Я подозреваю, что что-то об этом является причиной этой ошибки.
Это не ошибка. Большинство основных ALU-инструкций basi c x86 содержат код операции для версии с 32-разрядной немедленной версией, а другой - с расширенным знаком 8-разрядной немедленной .
На оригинальном 8086 это сохранил 1 байт для инструкций, таких как cmp r/m16, imm8
против cmp r/m16, imm16
. В 32/64-битном коде это экономит 3 байта для imm8 против imm32. https://www.felixcloutier.com/x86/cmp перечисляет доступные формы.
Точка отсечения, конечно, -128 .. +127, потому что это знак - расширенный немедленный. Ваш ассемблер всегда выбирает наименьшую возможную кодировку для данной исходной строки asm, поэтому все работает так, как задумано.
Если вы собираете 32-битный режим, но работаете как 16-битный В режиме cmpl $imm32, r/m32
будет работать не так, как остальной код .
Все остальные инструкции имеют одинаковую длину независимо от режима, но выполняются с противоположным размером операнда (16 против 32). Но код операции для cmpl
и cmpw
одинаков; разница только в размере операнда (переключается на префикс 66
значения, отличного от значения по умолчанию для режима).
Поэтому, когда ваш cmpl
собран для 32-битных декодеров в 16- битовый режим, осталось 2 байта немедленного. Эти байты равны 00 00
, что является местом назначения памяти add [something], al
(я забыл, который регистрирует, что 00
modrm кодирует в 16-битном режиме адресации.) Это приведет к сбою флагов из cmp
.
Используйте .code16
или параметр командной строки для создания 16-разрядного машинного кода.