Попытка преобразовать этот ассемблерный код в C-код

# x at %ebp+8, n at %ebp+12
movl 8(%ebp), %esi
movl 12(%ebp), %ebx
movl $-1, %edi
movl $1, %edx
.L2:
movl %edx, %eax
andl %esi, %eax
xorl %eax, %edi
movl %ebx, %ecx
sall %cl, %edx
testl %edx, %edx
jne .L2
movl %edi, %eax

Я преобразовал приведенный выше код в приведенный ниже код, но я не совсем уверен, что он правильный.

    int loop(int x, int n){

    int result = -1;

    for (mask = 1; mask >= result; mask = x&1) {

    result ^= n;

    }
return result;
}

x и n - это два целых числа, которые хранятся в памяти%ebp и перемещаются в реестр%esi и%ebx. Result и Mask имеют значения -1 и 1, и это из первой части кода, который я думаю после .L2: цикл начинается, и вот где я запутался. В конце возвращается результат movl %edi, %eax

1 ответ

Решение

Ваш код полностью неверен. Вы должны были сделать некоторые тесты самостоятельно, прежде чем отправлять вопросы.

Прежде всего, mask в вашем коде не объявлено в вашей функции.

Затем, после объявления mask как int, функция loop попадет в бесконечный цикл, когда result не станет положительным через result ^= n;, С другой стороны, ассемблерный код не попадет в бесконечный цикл, если только n кратно 32 (включая ноль).

Чтобы преобразовать код в сборку:

1. Я сделал прямое преобразование из сборки в C.

Обратите внимание, что я использовал неподписанный тип uint32_t так как

  • Используйте беззнаковый тип, потому что операция сдвига влево на целое число со знаком приведет к неопределенному поведению, когда происходит переполнение или значение, которое должно быть смещено, является отрицательным.
  • использование uint32_t потому что размер unsigned int зависит от окружения и может иметь длину менее 32 бит, в то время как регистры используются здесь (за исключением %cl) 32-битные

Цитата из N1570 6.5.7 Операции побитового сдвига:

4 Результат E1 << E2 является E1 сдвинуты влево E2 битовые позиции; освобожденные биты заполнены нулями. Если E1 имеет тип без знака, значение результата E1 × 2 E2, уменьшено по модулю на единицу больше максимального значения, представляемого в типе результата. Если E1 имеет тип со знаком и неотрицательное значение, и E1 × 2 E2 представимо в типе результата, то есть полученное значение; в противном случае поведение не определено.

Также обратите внимание, что stdint.h или же inttypes.h должен быть включен для использования uint32_t,

Ширина для сдвига маскируется до 5-битной длины в процессорах x86, то есть 80286 или более поздней.

uint32_t loop(uint32_t x, uint32_t n) {
    uint32_t esi = x;              /* movl 8(%ebp), %esi         */
    uint32_t ebx = n;              /* movl 12(%ebp), %ebx        */
    uint32_t edi = -1;             /* movl $-1, %edi             */
    uint32_t edx = 1;              /* movl $1, %edx              */
    uint32_t eax, ecx;
    do {                           /* .L2:                       */
        eax = edx;                 /* movl %edx, %eax            */
        eax &= esi;                /* andl %esi, %eax            */
        edi ^= eax;                /* xorl %eax, %edi            */
        ecx = ebx;                 /* movl %ebx, %ecx            */
        edx <<= (ecx & 0xff) & 31; /* sall %cl, %edx             */
    } while (edx != 0);            /* testl %edx, %edx ; jne .L2 */
    eax = edi;                     /* movl %edi, %eax            */
    return eax;
}

2. Я ввел имена переменных, чтобы прояснить их роли.

uint32_t loop(uint32_t x, uint32_t n) {
    uint32_t result = -1;
    uint32_t mask = 1;
    uint32_t eax, ecx;
    do {
        eax = mask;
        eax &= x;
        result ^= eax;
        ecx = n;
        mask <<= (ecx & 0xff) & 31;
    } while (mask != 0);
    return result;
}

3. Я слил некоторые выражения.

uint32_t loop(uint32_t x, uint32_t n) {
    uint32_t result = -1;
    uint32_t mask = 1;
    do {
        result ^= mask & x;
        mask <<= n & 31;
    } while (mask != 0);
    return result;
}

4. Я изменился do цикл до for цикл, потому что ваша попытка использует его.

uint32_t loop(uint32_t x, uint32_t n) {
    uint32_t result = -1;
    uint32_t mask;
    for (mask = 1; mask != 0; mask <<= n & 31) {
        result ^= mask & x;
    }
    return result;
}

Полный код для тестирования и демонстрации:

#include <stdio.h>
#include <inttypes.h>
#include <limits.h>

__asm__ (
/* support both environments that does and doesn't add underscore before function name */
"loop_asm:\n"
"_loop_asm:\n"
"push %ebp\n"
"mov %esp, %ebp\n"
"push %esi\n"
"push %edi\n"
"push %ebx\n"

"# x at %ebp+8, n at %ebp+12\n"
"movl 8(%ebp), %esi\n"
"movl 12(%ebp), %ebx\n"
"movl $-1, %edi\n"
"movl $1, %edx\n"
".L2_test:\n" /* rename .L2 to .L2_test to avoid collision */
"movl %edx, %eax\n"
"andl %esi, %eax\n"
"xorl %eax, %edi\n"
"movl %ebx, %ecx\n"
"sall %cl, %edx\n"
"testl %edx, %edx\n"
"jne .L2_test\n"
"movl %edi, %eax\n"

"pop %ebx\n"
"pop %edi\n"
"pop %esi\n"
"leave\n"
"ret\n"
);

uint32_t loop_asm(uint32_t, uint32_t);

uint32_t loop_convert(uint32_t x, uint32_t n) {
    uint32_t result = -1;
    uint32_t mask;
    for (mask = 1; mask != 0; mask <<= n & 31) {
        result ^= mask & x;
    }
    return result;
}

int mask;
    int loop(int x, int n){

    int result = -1;

    for (mask = 1; mask >= result; mask = x&1) {

    result ^= n;

    }
return result;
}

int main(void) {
    int x, n;
    uint32_t raw, test, conv;
    int miss_count = 0;
    /* search for mismatch in some range */
    for (n = 1; n < 32; n++) {
        uint32_t x_test;
        for (x_test = 0; x_test < UINT32_C(100000); x_test++) {
            if (loop_asm(x, n) != loop_convert(x, n)) {
                printf("mismatch at x=%"PRIu32", n=%d\n", x_test, n);
                if (miss_count < INT_MAX) miss_count++;
            }
        }
    }
    printf("%d mismatch(es) found.\n", miss_count);
    /* print some examples */
    x = 100;
    n = 5;
    raw = loop_asm(x, n);
    conv = loop_convert(x, n);
    printf("loop_asm(%d, %d) = %"PRIu32"\n", x, n, raw);
    printf("loop_convert(%d, %d) = %"PRIu32"\n", x, n, conv);
    fflush(stdout);
    test = loop(x, n);
    printf("loop(%d, %d) = %"PRIu32"\n", x, n, test);
    return 0;
}
Другие вопросы по тегам