Преобразование al oop из сборки x86 в C язык с инструкциями AND, OR, SHR и SHL и массивом - PullRequest
2 голосов
/ 11 апреля 2020

Я не понимаю, в чем проблема, потому что результат правильный, но в нем что-то не так, и я не понимаю.

1.Это код x86, который я должен преобразовать в C:

%include "io.inc"  
SECTION .data
mask    DD      0xffff, 0xff00ff, 0xf0f0f0f, 0x33333333, 0x55555555

SECTION .text
GLOBAL CMAIN
CMAIN:
    GET_UDEC        4, EAX
    MOV             EBX, mask
    ADD             EBX, 16
    MOV             ECX, 1
.L:
    MOV             ESI, DWORD [EBX]
    MOV             EDI, ESI
    NOT             EDI
    MOV             EDX, EAX
    AND             EAX, ESI
    AND             EDX, EDI
    SHL             EAX, CL
    SHR             EDX, CL
    OR              EAX, EDX
    SHL             ECX, 1
    SUB             EBX, 4
    CMP             EBX, mask - 4
    JNE             .L

    PRINT_UDEC      4, EAX
    NEWLINE
    XOR             EAX, EAX
    RET

2.Мой преобразованный код C, когда я ввожу 0, он выводит мне правильный ответ, но в моем коде есть что-то неверное. Я не понимаю, что это такое:

#include "stdio.h"
int main(void)
{
    int mask [5] =  {0xffff, 0xff00ff, 0xf0f0f0f, 0x33333333, 0x55555555};


    int eax;
    int esi;
    int ebx;
    int edi;
    int edx;
    char cl = 0;
    scanf("%d",&eax);
    ebx = mask[4];
    ebx = ebx + 16;
    int ecx = 1;
    L:
    esi = ebx;
    edi = esi;
    edi = !edi;
    edx = eax;
    eax = eax && esi;
    edx = edx && edi;
    eax = eax << cl;
    edx = edx >> cl ;
    eax = eax || edx;
    ecx = ecx << 1;
    ebx = ebx - 4;

    if(ebx == mask[1]) //mask - 4
    {
        goto L;
    }

    printf("%d",eax);
    return 0;
}

Ответы [ 2 ]

4 голосов
/ 12 апреля 2020

Сборка И это 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, только эта деталь декомпиляции.


Могут быть и другие ошибки; Я не пытался все проверить.

1 голос
/ 12 апреля 2020
if(ebx != mask[1]) //mask - 4
{
    goto L;

}

// JNE ПОДРАЗУМЕВАЕТ a! =

...