С 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 nop
s 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. :-(
https://msdn.microsoft.com/en-us/library/kyzds0ks.aspx, https://msdn.microsoft.com/en-us/library/352sth8z.aspx –
@ JoseManuelAbarcaRodríguez благодарит вас для ссылок, но эти ссылки неясны, как я могу решить проблему. –