Сборка И это C поразрядно &
, не логично &&
. (То же самое для ИЛИ). Таким образом, вы хотите eax &= esi
.
(Использование &=
«составного присваивания» делает C даже похожим на двухсоперандный асм в стиле x86, поэтому я рекомендую это. )
NOT также поразрядно переворачивает все биты, не логическое значение 0/1. В C это edi = ~edi;
Прочтите руководство для инструкций x86, таких как https://www.felixcloutier.com/x86/not, и для C операторов, таких как ~
и !
, чтобы убедиться, что они / не то, что вы хотите. https://en.cppreference.com/w/c/language/expressions https://en.cppreference.com/w/c/language/operator_arithmetic
Вы должны пошагово отыграть свой C и ваш ассемблер в отладчике, чтобы вы заметили первый дивергенция, и знать, какую инструкцию / C заявление исправить. Не просто запустить все это и посмотреть на один номер для результата! Отладчики очень полезны для asm; не тратьте свое время без него.
CL - младший байт ECX , а не отдельная переменная C. Вы можете использовать объединение между uint32_t
и uint8_t
в C, или просто использовать eax <<= ecx&31;
, поскольку у вас нет ничего, что пишет CL отдельно от ECX. (сдвиги x86 маскируют их количество; оператор C может компилироваться в shl eax, cl
. https://www.felixcloutier.com/x86/sal: sar: shl: shr ). Младшие 5 битов ECX также являются младшими 5 битами CL.
SHR
- это логическое смещение вправо, а не арифметика c, поэтому вам нужно использовать unsigned
, а не int
в минимум для >>
. Но на самом деле просто используйте его для всего.
Вы работаете с EBX совершенно неправильно; это указатель.
MOV EBX, mask
ADD EBX, 16
Это похоже на unsigned int *ebx = mask+4;
Размер меча составляет 4 байта, но C математика указателя масштабируется по размеру шрифта, поэтому +1
- это целый элемент, а не 1 байт. Таким образом, 16 байтов - это 4 слова = 4 unsigned int
элементов.
MOV ESI, DWORD [EBX]
Это загрузка с использованием EBX в качестве адреса. Это должно быть легко увидеть, если вы выполняете одностадийную ассемблер в отладчике: это не просто копирование значения.
CMP EBX, mask - 4
JNE .L
Это синтаксис NASM; он сравнивается с адресом меча до начала массива. По сути, это дно вполне обычного do {}, в то время как l oop. ( Почему циклы всегда компилируются в стиле "do ... while" (прыжок с хвоста)? )
do { // .L
...
} while(ebx != &mask[-1]); // cmp/jne
Он зацикливается с конца массива mask
, останавливаясь при указатель идет за конец.
Эквивалентно, сравнение может быть ebx !-= mask - 1
. Я написал это с помощью унарного &
(address-of) отмены []
, чтобы было ясно, что это адрес того, что будет одним элементом перед массивом.
Обратите внимание, что он прыгает на не равно; у вас был if()goto
задом наперед, прыгая только на равенство. Это al oop.
unsigned mask[]
должно быть static
, потому что оно в section .data
, а не в стеке. И не const
, потому что снова он находится в .data
, а не .rodata
(Linux) или .rdata
(Windows))
Этот не влияет на логику c, только эта деталь декомпиляции.
Могут быть и другие ошибки; Я не пытался все проверить.