2016-07-20 6 views
1

Visual C++, en utilisant le compilateur de Microsoft, permet de définir le code assembleur en ligne en utilisant:Comment puis-je insérer des instructions NOP répétées à l'aide de l'assembleur en ligne de Visual C++?

__asm { 
    nop 
} 

Ce que je dois est une macro qui permet de multiplier cette instruction n fois comme:

ASM_EMIT_MULT(op, times) 

par exemple:

ASM_EMIT_MULT(0x90, 160) 

Est-ce possible? Comment pourrais-je faire ça?

+0

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

+0

@ JoseManuelAbarcaRodríguez merci pour les liens, mais ces références ne font pas clair comment puis-je résoudre le problème –

Répondre

4

Avec MASM, c'est très simple à faire. Une partie de l'installation est un fichier nommé listing.inc (puisque tout le monde obtient MASM dans le cadre de Visual Studio maintenant, cela sera situé dans votre répertoire racine Visual Studio/VC/include). Ce fichier définit une série de macros npad qui prennent un seul argument size et développent une séquence appropriée d'opcodes de "remplissage" non destructifs. Si vous n'avez besoin que d'un octet de remplissage, vous utilisez l'instruction nop. Mais plutôt que d'utiliser une longue série de nop jusqu'à ce que vous atteigniez la longueur désirée, Intel recommande effectivement other non-destructive opcodes of the appropriate length, tout comme other vendors. Ces macros pré-définies npad vous libèrent de devoir mémoriser cette table, sans parler de rendre le code beaucoup plus lisible.

Malheureusement, l'assemblage en ligne n'est pas un assembleur complet. Il y a beaucoup de choses manquantes que vous attendez de trouver dans de vrais assembleurs comme MASM. Macros (MACRO) et les répétitions (REPEAT/REPT) sont parmi les choses qui manquent. Cependant, 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. L'utilisation de ceci est simple. Voici un exemple très stupide, où j'ai pris le code de travail et poivré avec align aléatoires s:

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 
    } 
} 

Cela génère la sortie suivante (les listes de montage de MSVC utilisent npad x, où x est le nombre d'octets, juste comme vous écririez dans 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 

Si vous n'êtes pas vouloir réellement faire respecter l'alignement, mais juste à insérer un nombre arbitraire de nop s (peut-être en tant que charge pour plus tard chaud patc ? Hing), vous pouvez utiliser des macros C pour simuler l'effet:

#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. 

Et puis poivrer votre code comme vous le souhaitez:

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 
    } 
} 

pour produire la sortie suivante:

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 

Ou, encore plus cool, nous pouvons utiliser un peu de magie de méta-programmation de modèle pour obtenir le même effet dans style.Il suffit de définir la fonction de modèle suivant et sa spécialisation (important pour éviter une récursion infinie):

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

Et l'utiliser comme ceci:

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 
    } 
} 

qui va produire la sortie désirée (exactement le même que le un juste au-dessus) dans toutes les versions optimisées - que vous optimisiez pour la taille (/O1) ou la vitesse (/O2) - & hellip; mais pas dans les versions de débogage. Si vous en avez besoin dans les versions de débogage, vous devrez utiliser les macros C. :-(

+0

Incroyable! C++ modèle métaprogrammation est génial! C'est une très mauvaise chose, il ne fonctionne pas pour/Od aussi :( –

+0

'npad()' est vraiment sympa , Je souhaite que nous puissions aussi fournir un octet pour être en ligne avec '_emit', comme:' ... void npad (BYTE byte) {...; _asm {_emit byte}} 'pour que nous puissions émettre un certain octet N fois – karliwson

+0

Vous devriez être capable de le faire, @karliwson. Il suffit de passer 'byte' comme paramètre * template *, plutôt que comme paramètre de fonction. –