Я пытаюсь XOR 128-битного вектора инициализации с открытым текстом, как показано здесь
В Linux x86-64 gcc 12.2
есть один лайнер
*(unsigned __int128 *)( plaintext ) ^= *(unsigned __int128 *)( ivvectext );
Например, https://godbolt.org/z/sc8e66qeo
#include <stdio.h>
#include <stdint.h>
int main()
{
uint8_t plaintext[16] = {'t','h','e','q','u','i','c','k','b','r','o','w','n','f','o','x'};
uint8_t ivvectext[16] = {'w','a','1','2','o','b','s','q','m','v','c','s','s','q','u','w'};
*(unsigned __int128 *)( plaintext ) ^= *(unsigned __int128 *)( ivvectext );
for (int i = 0; i < sizeof(plaintext); i++) { printf("%02X ", (unsigned char)plaintext[i]); }
return 0;
}
Вопрос
Какой предпочтительный метод XOR для этих 128-битных значений в MSVC?
Обновлять
Как отмечено в одном из ответов, используйте встроенный компилятор _mm_xor_si128
#include <stdint.h>
#include <immintrin.h>
#include <iostream>
#include <ios>
#include <iomanip>
int main() {
uint8_t plaintext[16] = { 't','h','e','q','u','i','c','k','b','r','o','w','n','f','o','x' };
uint8_t ivvectext[16] = { 'w','a','1','2','o','b','s','q','m','v','c','s','s','q','u','w' };
__m128i plain = _mm_loadu_si128((__m128i*)plaintext);
__m128i ivvec = _mm_loadu_si128((__m128i*)ivvectext);
__m128i xored = _mm_xor_si128(plain, ivvec);
uint8_t* xored_array = (uint8_t*)&xored;
for (int i = 0; i < 16; i++) {
std::cout << std::uppercase << std::setw(2) << std::setfill('0') << std::hex << (int)xored_array[i] << " ";
}
std::cout << std::endl;
return 0;
}
Вывод соответствует линукс
03 09 54 43 1A 0B 10 1A 0F 04 0C 04 1D 17 1A 0F
Однако другие ответы предлагают более читаемый код
for (int i = 0; i < sizeof(plaintext); i++)
{
plaintext[i] ^= ivvectext[i];
}
и позвольте оптимизации компилятора разобраться во внутреннем ассемблерном коде. :)
Почему это помечено C и C++? Выберите один язык.
Как упоминалось в моем комментарии, я бы использовал intrincis: вот как это сделать в MSVC:
#include <immintrin.h>
int main() {
uint8_t plaintext[16] = { 't','h','e','q','u','i','c','k','b','r','o','w','n','f','o','x' };
uint8_t ivvectext[16] = { 'w','a','1','2','o','b','s','q','m','v','c','s','s','q','u','w' };
__m128i plain = _mm_loadu_si128((__m128i*)plaintext);
__m128i ivvec = _mm_loadu_si128((__m128i*)ivvectext);
__m128i xored = _mm_xor_si128(plain, ivvec);
return 0;
}
Если ваша цель — оптимизировать код, оставьте эту задачу компилятору. (Конечно, вам, возможно, придется включить оптимизацию.)
Вы можете написать простой цикл, например
for (int i = 0; i < sizeof(plaintext); i++)
{
plaintext[i] ^= ivvectext[i];
}
и пусть компилятор оптимизирует это.
Например, x86 msvc v19.latest с параметром -O2
создает инструкции SSE2 из этого цикла, что приводит к одной 128-битной операции.
_main PROC ; COMDAT
sub esp, 36 ; 00000024H
mov eax, DWORD PTR ___security_cookie
xor eax, esp
mov DWORD PTR __$ArrayPad$[esp+36], eax
mov DWORD PTR _plaintext$[esp+36], 1902471284 ; 71656874H
mov DWORD PTR _plaintext$[esp+40], 1801677173 ; 6b636975H
mov DWORD PTR _plaintext$[esp+44], 2003792482 ; 776f7262H
mov DWORD PTR _plaintext$[esp+48], 2020566638 ; 786f666eH
movups xmm1, XMMWORD PTR _plaintext$[esp+36]
mov DWORD PTR _ivvectext$[esp+36], 842097015 ; 32316177H
mov DWORD PTR _ivvectext$[esp+40], 1903387247 ; 7173626fH
mov DWORD PTR _ivvectext$[esp+44], 1935898221 ; 7363766dH
mov DWORD PTR _ivvectext$[esp+48], 2004185459 ; 77757173H
movups xmm0, XMMWORD PTR _ivvectext$[esp+36]
push esi
xor esi, esi
pxor xmm1, xmm0
movups XMMWORD PTR _plaintext$[esp+40], xmm1
...
Смотрите https://godbolt.org/z/afTPK5von
Дополнительные подсказки из комментариев:
Даже если вы решите, что вам нужно вручную оптимизировать код и явно использовать встроенные функции (например, оптимизатор по какой-то причине их не использует, грустная панда), я рекомендую также сохранить простую реализацию в качестве эталонной реализации для разработки. и отладки. (комментарий Элджея)
Иногда компилятор MS не оптимизирует то, что выглядит как простой цикл, в этом случае вы можете включить сообщения векторизатора и параллелизатора , которые могут дать вам подсказки, почему это не так. ( комментарий пользователя 20716902)
Мне нравится это решение. Это НАМНОГО более читабельно, чем использование встроенного! Напишите это просто и позвольте оптимизации компилятора разобраться во внутреннем ассемблерном коде. :)
@vengy - даже если вы решите, что вам нужно вручную оптимизировать код и явно использовать встроенные функции (например, оптимизатор по какой-то причине не использует их, грустная панда), я рекомендую также сохранить простую реализацию в качестве эталона реализация для целей разработки и отладки.
Иногда компилятор MS не оптимизирует то, что выглядит как простой цикл, в этом случае вы можете включить сообщения Vectorizer и parallilizer, которые могут дать вам подсказки, почему это не так.
Взгляните на
XOR
intrinsics