Добавьте два 32-битных целых числа в Ассемблере для использования в VB6 - PullRequest
4 голосов
/ 11 февраля 2011

Я хотел бы придумать байт-код в ассемблере (сборке?) Для машин Windows, чтобы добавить две 32-битные длины и выбросить бит переноса.Я понимаю, что часть «Windows-машин» немного расплывчата, но я предполагаю, что байты для ADD почти одинаковы во всех современных наборах команд Intel.

Я просто пытаюсь злоупотреблятьVB немного и сделать некоторые вещи быстрее.Итак ... если строка "8A4C240833C0F6C1E075068B442404D3E0C20800" является кодом сборки для SHL, который может быть "внедрен" в программу VB6 для быстрой операции SHL, ожидающей два параметра Long (мы игнорируемздесь, когда 32-битные значения в VB6 подписаны, только притворимся, что они не подписаны), что такое шестнадцатеричная строка байтов, представляющая инструкции ассемблера, которые будут делать то же самое для возврата суммы?

Шестнадцатеричный код выше дляSHL, по словам автора:

mov eax, [esp+4]
mov cl, [esp+8]
shl eax, cl
ret 8

Я плюнул эти байты в файл и попытался разобрать их в командной строке Windows, используя старую утилиту отладки, но я понял, что она не работает сболее новый набор инструкций, потому что ему не нравилось EAX, когда я пытался что-то собрать, но он был доволен AX.

Я знаю из комментариев в исходном коде, что SHL EAX, CL - это D3E0, ноУ меня нет ссылок, чтобы знать, что это за байты для инструкции ADD EAX, CL, или я бы попробовал. (хотя теперь я знаю, что операнды должны быть одинакового размера.)

Я попробовал плоский ассемблер и не получаю ничего, что я могу понять, как использовать,Я использовал его для сборки исходного кода SHL и получил совсем другой результат, а не те же байты.Помощь

1 Ответ

4 голосов
/ 11 февраля 2011

Я разобрал предоставленные вами байты и получил следующий код:

(__TEXT,__text) section
f:
00000000    movb    0x08(%esp),%cl
00000004    xorl    %eax,%eax
00000006    testb   $0xe0,%cl
00000009    jne     0x00000011
0000000b    movl    0x04(%esp),%eax
0000000f    shll    %cl,%eax
00000011    retl    $0x0008

Что, безусловно, сложнее, чем исходный код, предоставленный автором. Он проверяет, например, что второй операнд не слишком большой, чего нет в коде, который вы показывали вообще (см. «Правка 2» ниже для более полного анализа). Вот простая stdcall функция, которая добавляет два аргумента вместе и возвращает результат:

mov  4(%esp), %eax
add  8(%esp), %eax
ret  $8

Сборка, которая дает мне этот вывод:

(__TEXT,__text) section
00000000 8b 44 24 04 03 44 24 08 c2 08 00 

Я надеюсь, что эти байты делают то, что вы от них хотите!

Редактировать: Возможно, более полезно, я просто сделал то же самое в C:

__attribute__((__stdcall__))
int f(int a, int b) 
{
  return a + b;
}

Скомпилированный с -Oz и -fomit-frame-pointer он генерирует точно такой же код (ну, в любом случае, функционально эквивалентный):

$ gcc -arch i386 -fomit-frame-pointer -Oz -c -o example.o example.c
$ otool -tv example.o
example.o:
(__TEXT,__text) section
_f:
00000000    movl    0x08(%esp),%eax
00000004    addl    0x04(%esp),%eax
00000008    retl    $0x0008

Вывод машинного кода:

$ otool -t example.o
example.o:
(__TEXT,__text) section
00000000 8b 44 24 08 03 44 24 04 c2 08 00 

Конечно, лучше, чем рукописный код сборки!

Редактировать 2:

@ Emtucifor спросил в комментариях ниже, что произойдет, если будет предпринята попытка сдвига 32 бит или более. Разобранный код в верхней части этого ответа (для байтов, представленных в исходном вопросе) может быть представлен следующим кодом более высокого уровня:

unsigned int shift_left(unsigned int a, unsigned char b)
{
    if (b > 32)
        return 0;
    else
        return a << b;
}

Из этой логики довольно легко увидеть, что если вы передадите значение больше 32 в качестве второго параметра функции сдвига, вы просто получите 0 обратно.

...