2016-06-15 5 views
0

Я следующий код, который должен XOR блок памяти:C/C++ Инлайн ASM неподходящий операнд типа

void XorBlock(DWORD dwStartAddress, DWORD dwSize, DWORD dwsKey) 
{ 
DWORD dwKey; 
__asm 
{ 
    push eax 
    push ecx 
    mov ecx, dwStartAddress   // Move Start Address to ECX 
    add ecx, dwSize     // Add the size of the function to ECX 
    mov eax, dwStartAddress   // Copy the Start Address to EAX 

    crypt_loop:       // Start of the loop 
     xor byte ptr ds:[eax], dwKey  // XOR The current byte with 0x4D 
     inc eax       // Increment EAX with dwStartAddress++ 
     cmp eax,ecx      // Check if every byte is XORed 
    jl crypt_loop;      // Else jump back to the start label 

    pop ecx // pop ECX from stack 
    pop eax // pop EAX from stack 
} 
} 

Однако аргумент dwKey дает мне ошибку. Код работает отлично, если, например, dwKey заменяется на 0x5D.

+0

Что заставляет вас думать, что это быстрее, чем просто писать его на C или C++? И не имеет значения, насколько быстро это происходит, учитывая, что шифр Цезаря может быть разбит за миллисекунды. –

+1

Является ли 'DWORD dwsKey' опечаткой. Похоже, что лишние 's' являются ошибкой? а затем удалить локальную переменную 'DWORD dwKey;'? –

+0

В чем смысл этого кода? Вы специально записываете медленный asm, чтобы остановить компилятор от использования 4-байтового xor или SSE2 PXOR? –

ответ

4

Я думаю, у вас есть две проблемы.

Во-первых, «xor» не может принимать два операнда памяти (ds: [eax] - это ячейка памяти, а dwKey - ячейка памяти); во-вторых, вы использовали «байт ptr», чтобы указать, хотите ли вы байт, но вы пытаетесь использовать DWORD, и сборка не может автоматически преобразовать их.

Итак, вам, вероятно, придется загрузить свое значение в 8-битный регистр, а затем сделать это. Например:

void XorBlock(DWORD dwStartAddress, DWORD dwSize, DWORD dwsKey) 
{ 
    DWORD dwKey; 
    __asm 
    { 
     push eax 
     push ecx 
     mov ecx, dwStartAddress   // Move Start Address to ECX 
     add ecx, dwSize     // Add the size of the function to ECX 
     mov eax, dwStartAddress   // Copy the Start Address to EAX 
     mov ebx, dwKey     // <---- LOAD dwKey into EBX 

     crypt_loop :       // Start of the loop 
      xor byte ptr ds : [eax], bl  // XOR The current byte with the low byte of EBX 
      inc eax       // Increment EAX with dwStartAddress++ 
      cmp eax, ecx      // Check if every byte is XORed 
      jl crypt_loop;      // Else jump back to the start label 

     pop ecx // pop ECX from stack 
     pop eax // pop EAX from stack 
    } 
} 

Хотя, он также выглядит dwKey не инициализирован в коде; возможно, вам нужно просто «mov bl, 0x42». Я также не уверен, что вам нужно нажать и поместить регистры; Я не могу вспомнить, какие регистры вам разрешают сжимать с помощью встроенного ассемблера MSVC++.

Но, в конце концов, я думаю, что Алан Стокс прав в своем комментарии: это очень маловероятно, что сборка на самом деле быстрее, чем код C/C++ в этом случае. Компилятор может легко сгенерировать этот код самостоятельно, и вы можете обнаружить, что компилятор действительно делает неожиданные оптимизации, чтобы заставить его работать даже быстрее, чем «очевидная» сборка (например, loop unrolling).

+0

Я считаю, что '__asm' заботится о сохранении и восстановлении регистров, которые используются в инструкции' __asm', если это необходимо. MSVC анализирует __asm ​​для определения использования регистров. О единственных регистрах (помимо селекторов), которые необходимо обрабатывать вручную (сохранены), являются ESP и EBP. GCC не анализирует встроенные инструкции ассемблера, но MSVC делает. –

+2

«При использовании __asm ​​для написания языка ассемблера в функциях C/C++ вам не нужно сохранять регистры EAX, EBX, ECX, EDX, ESI или EDI» (https://msdn.microsoft.com/en- нас/библиотека/k1a8ss06.aspx). На странице также подразумевается, что анализ Майкл упоминает, чтобы оптимизировать, какие регистры необходимо сохранить/восстановить автоматически. – Steven

+0

Спасибо, это решило проблему. – Zer0Mem0ry

Смежные вопросы