2016-07-20 5 views
1

Visual C++, используя компилятор Microsoft, позволяет определить встроенный код сборки с помощью:Как я могу вставить повторяющиеся инструкции NOP с помощью встроенного ассемблера Visual C++?

__asm { 
    nop 
} 

Что мне нужно, это макрос, который позволяет умножать такую ​​инструкцию п раз как:

ASM_EMIT_MULT(op, times) 

например:

ASM_EMIT_MULT(0x90, 160) 

Возможно ли это? Как я могу это сделать?

+0

https://msdn.microsoft.com/en-us/library/kyzds0ks.aspx, https://msdn.microsoft.com/en-us/library/352sth8z.aspx –

+0

@ JoseManuelAbarcaRodríguez благодарит вас для ссылок, но эти ссылки неясны, как я могу решить проблему. –

ответ

4

С MASM это очень просто сделать. Часть установки - это файл с именем listing.inc (так как все теперь получают MASM как часть Visual Studio, это будет расположено в корневом каталоге Visual Studio/VC/include). Этот файл определяет серию макросов npad, которые берут один аргумент size и расширяются до соответствующей последовательности неразрушающих «кодовых» опкодов. Если вам нужен только один байт заполнения, вы используете очевидную инструкцию nop. Но вместо того, чтобы использовать длинную серию nop с, пока вы не достигнете желаемой длины, Intel фактически рекомендует other non-destructive opcodes of the appropriate length, равно как и other vendors. Эти предопределенные макросы npad освобождают вас от необходимости запоминать эту таблицу, не говоря уже о том, чтобы сделать код более читаемым.

К сожалению, встроенная сборка не является полнофункциональным ассемблером. Есть много недостающих вещей, которые вы ожидаете найти в реальных ассемблерах, таких как MASM. Макросы (MACRO) и повторы (REPEAT/REPT) относятся к числу недостающих.

Однако ALIGN directivesare available in inline assembly. These will generate the required number of nops or other non-destructive opcodes to enforce alignment of the next instruction. Использование этой функции является простым. Вот очень глупый пример, где я взял рабочий код и засыпал его со случайными align с:

unsigned long CountDigits(unsigned long value) 
{ 
    __asm 
    { 
     mov edx, DWORD PTR [value] 
     bsr eax, edx 
     align 4 
     xor eax, 1073741792 
     mov eax, DWORD PTR [4 * eax + kMaxDigits+132] 
     align 16 
     cmp edx, DWORD PTR [4 * eax + kPowers-4] 
     sbb eax, 0 
     align 8 
    } 
} 

Это генерирует следующий вывод (сборочные списки MSVC используют npad x, где x является числом байт, просто как вы бы записать его в MASM):

PUBLIC CountDigits 
_TEXT SEGMENT 
_value$ = 8 
CountDigits PROC 
    00000 8b 54 24 04  mov edx, DWORD PTR _value$[esp-4] 
    00004 0f bd c2   bsr eax, edx 
    00007 90     npad 1  ;// enforcing the "align 4" 
    00008 35 e0 ff ff 3f  xor eax, 1073741792 
    0000d 8b 04 85 84 00  
      00 00    mov eax, DWORD PTR _kMaxDigits[eax*4+132] 
    00014 eb 0a 8d a4 24  
      00 00 00 00 8d  
      49 00    npad 12  ;// enforcing the "align 16" 
    00020 3b 14 85 fc ff  
      ff ff    cmp edx, DWORD PTR _kPowers[eax*4-4] 
    00027 83 d8 00   sbb eax, 0 
    0002a 8d 9b 00 00 00  
      00     npad 6  ;// enforcing the "align 8" 
    00030 c2 04 00   ret 4 
CountDigits ENDP 
_TEXT ENDS 

Если вы на самом деле не хочет, чтобы обеспечить соблюдение выравнивания, а просто вставить произвольное число nop с (возможно, в качестве наполнителя для последующего горячекатаного ПАТС ? Повесят), то вы можете использовать C макросы для имитации эффекта:

#define NOP1 __asm { nop } 
#define NOP2 NOP1 NOP1 
#define NOP4 NOP2 NOP2 
#define NOP8 NOP4 NOP4 
#define NOP16 NOP8 NOP8 
// ... 
#define NOP64 NOP16 NOP16 NOP16 NOP16 
// ...etc. 

А затем перец код по желанию:

unsigned long CountDigits(unsigned long value) 
{ 
    __asm 
    { 
     mov edx, DWORD PTR [value] 
     bsr eax, edx 
     NOP8 
     xor eax, 1073741792 
     mov eax, DWORD PTR [4 * eax + kMaxDigits+132] 
     NOP4 
     cmp edx, DWORD PTR [4 * eax + kPowers-4] 
     sbb eax, 0 
    } 
} 

произвести следующий вывод:

PUBLIC CountDigits 
_TEXT SEGMENT 
_value$ = 8 
CountDigits PROC 
    00000 8b 54 24 04  mov edx, DWORD PTR _value$[esp-4] 
    00004 0f bd c2   bsr eax, edx 
    00007 90    npad 1  ;// these are, of course, just good old NOPs 
    00008 90    npad 1 
    00009 90    npad 1 
    0000a 90    npad 1 
    0000b 90    npad 1 
    0000c 90    npad 1 
    0000d 90    npad 1 
    0000e 90    npad 1 
    0000f 35 e0 ff ff 3f xor eax, 1073741792 
    00014 8b 04 85 84 00 
     00 00   mov eax, DWORD PTR _kMaxDigits[eax*4+132] 
    0001b 90    npad 1 
    0001c 90    npad 1 
    0001d 90    npad 1 
    0001e 90    npad 1 
    0001f 3b 14 85 fc ff 
     ff ff   cmp edx, DWORD PTR _kPowers[eax*4-4] 
    00026 83 d8 00   sbb eax, 0 
    00029 c2 04 00   ret 4 
CountDigits ENDP 
_TEXT ENDS 

Или, даже более холодный, мы можем использовать немного шаблона мета-программирования шаблона, чтобы получить тот же эффект в style.Просто определите следующие функции шаблона и его специализации (важно, чтобы предотвратить зацикливание):

template <size_t N> __forceinline void npad() 
{ 
    npad<N-1>(); 
    __asm { nop } 
} 
template <> __forceinline void npad<0>() { } 

И использовать его как это:

unsigned long CountDigits(unsigned long value) 
{ 
    __asm 
    { 
     mov edx, DWORD PTR [value] 
     bsr eax, edx 
    } 
    npad<8>(); 
    __asm 
    { 
     xor eax, 1073741792 
     mov eax, DWORD PTR [4 * eax + kMaxDigits+132] 
    } 
    npad<4>(); 
    __asm 
    { 
     cmp edx, DWORD PTR [4 * eax + kPowers-4] 
     sbb eax, 0 
    } 
} 

Это будет производить желаемый результат (точно так же, как один чуть выше) во всех оптимизированных сборках - оптимизируйте ли вы размер (/O1) или скорость (/O2) - и hellip, но не в отладочных сборках. Если вам это нужно в отладочных сборках, вам придется прибегнуть к макросам C. :-(

+0

Удивительно! C++ шаблон метапрограммирования - это потрясающе! Это очень плохо, что это не работает для/Od :( –

+0

'npad()' действительно приятно , Я бы хотел, чтобы мы могли также предоставить байт, который должен быть встроен в '_emit', например:' ... void npad (BYTE byte) {...; _asm {_emit byte}} ', чтобы мы могли испускать определенный байт N раз – karliwson

+0

Вы должны это сделать, @karliwson. Просто передайте 'byte' как параметр * template *, а не параметр функции. –