Fra*_*mes 1 x86 assembly inline-assembly visual-studio cl
使用Microsoft的编译器的Visual C ++,允许我们使用以下命令定义内联汇编代码:
__asm {
nop
}
Run Code Online (Sandbox Code Playgroud)
我需要的是一个宏,可以将这样的指令乘以n次:
ASM_EMIT_MULT(op, times)
Run Code Online (Sandbox Code Playgroud)
例如:
ASM_EMIT_MULT(0x90, 160)
Run Code Online (Sandbox Code Playgroud)
那可能吗?我该怎么办?
使用MASM,这非常简单。安装的一部分是一个名为的文件listing.inc(由于每个人现在都将MASM作为Visual Studio的一部分获得,因此它将位于您的Visual Studio根目录/ VC / include中)。该文件定义了一系列npad带有单个size参数的宏,并扩展为适当的非破坏性“填充”操作码序列。如果只需要填充一个字节,则使用显而易见的nop指令。但是,而不是使用一长串nops,至到达所需的长度,英特尔实际上是建议适当长度的其他非破坏性的操作码,如做其他厂商。这些预定义npad 宏使您不必记住该表,更不用说使代码更具可读性了。
不幸的是,内联汇编不是功能齐全的汇编器。在像MASM这样的实际汇编程序中,可能会缺少很多东西。缺少宏(MACRO)和重复(REPEAT/REPT)。
但是,内联汇编中提供了ALIGN指令 。这些将生成所需数量的s或其他非破坏性操作码,以强制执行下一条指令的对齐。使用它很简单。这是一个非常愚蠢的示例,其中我使用了工作代码,并在其中添加了random s:nopalign
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
}
}
Run Code Online (Sandbox Code Playgroud)
这将生成以下输出(MSVC的程序集清单use 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
Run Code Online (Sandbox Code Playgroud)
如果您实际上不是想要强制对齐,而是只想插入任意数量的nops(也许用作以后的热修补的填充符?),则可以使用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.
Run Code Online (Sandbox Code Playgroud)
然后根据需要添加代码:
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
}
}
Run Code Online (Sandbox Code Playgroud)
产生以下输出:
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
Run Code Online (Sandbox Code Playgroud)
或者,甚至更酷,我们可以使用一些模板元编程魔术来获得相同的style效果。只需定义以下模板函数及其特化(对防止无限递归很重要):
template <size_t N> __forceinline void npad()
{
npad<N-1>();
__asm { nop }
}
template <> __forceinline void npad<0>() { }
Run Code Online (Sandbox Code Playgroud)
并像这样使用它:
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
}
}
Run Code Online (Sandbox Code Playgroud)
无论是针对大小(/O1)还是速度(/O2)进行优化,这都会在所有优化的版本中产生所需的输出(与上面的输出完全相同),但是在调试版本中则不会。如果在调试版本中需要它,则必须诉诸C宏。:-(
| 归档时间: |
|
| 查看次数: |
647 次 |
| 最近记录: |