Нужно ли мне создавать несколько исполняемых файлов для разных наборов инструкций?

Допустим, у меня есть программа для выполнения операций AES.

Некоторые продвинутые ЦП имеют набор инструкций AES-NI, а другие ЦП не имеют.

Должен ли я компилировать свою программу в два исполняемых файла: A_with_aes_ni.exe и B_without_aes_ni.exe?


person xmllmx    schedule 04.03.2014    source источник
comment
альтернативой является разделение материала шифрования в динамической/разделяемой библиотеке, которая затем имеет 2 версии.   -  person Cheers and hth. - Alf    schedule 04.03.2014
comment
Вы можете написать две функции в одном и том же exe: одна использует инструкции AES, другая использует AES в программном обеспечении, а затем выбирать между ними во время выполнения на основе вывода из CPUID.   -  person Andrew Tomazos    schedule 04.03.2014
comment
@AndrewTomazos, вы имеете в виду, что я должен встраивать ассемблерные коды в свои исходные файлы C?   -  person xmllmx    schedule 04.03.2014


Ответы (2)


То, что вам нужно, называется диспетчером ЦП. У Агнера Фога есть 10 страниц текста на эту тему в третьей главе «Создание критического кода в нескольких версиях для разных наборов инструкций» его Руководство по оптимизации C++ . Он обсуждает это как с GCC, так и с ICC.

Вам нужен только один исполняемый файл, но вам нужно скомпилировать два разных объектных файла с включенным AES и без него. Затем диспетчер определяет, какой набор инструкций доступен, и на его основе выбирает путь кода.

Я попытался сделать это с помощью MSVC2010 диспетчера процессора для визуальной студии для AVX и SSE, но безуспешно. Я подозреваю, что я мог бы заставить его работать сейчас.

Изменить: в vectorclass Агнера Фога есть файл dispatch_example.cpp и instrset_detech.cpp, в котором должна быть большая часть того, что вы нужно сделать диспетчер. Вам все еще нужно выяснить, как определить, имеет ли процессор AES. Вам необходимо дополнить файл intrset_detect.cpp. Согласно википедии, когда вы читаете бит CPUID 23 в регистре ECX, устанавливается, если процессор имеет AES. В Википедии также есть примеры кода для чтения CPUID (помимо instrset_detech.cpp — еще один хороший пример находится на https://github.com/Mysticial/Flops в файле cpuid.c)

person Z boson    schedule 04.03.2014

Один из способов сделать это в Solaris — иметь библиотеки аппаратных возможностей, которые динамически загружаются компоновщиком во время выполнения.

Другой вариант — сначала загрузить обработчик ловушек для недопустимых инструкций, а затем проверить инструкции на желаемом машинном языке. Если вы попали в ловушку, то вы знаете, что не можете использовать оптимизированную версию и должны загрузить неоптимизированную (или менее оптимизированную).

Хотя мне нравится предложение Эндрю выше, я думаю, что безопаснее проверить конкретные инструкции, которые вам нужны. Таким образом, вам не нужно постоянно обновлять свое приложение для получения новых выходных данных CPUID.

Отредактировано для добавления: я понимаю, что должен был привести пример. Для libc Solaris на платформе x64 мы предоставляем аппаратно-оптимизированные версии библиотеки — три для 32-битных и одна для 64-битных. Мы можем увидеть различия, запустив elfdump -H в интересующем файле:

s11u1:jmcp $ elfdump -H /usr/lib/libc/libc_hwcap1.so.1 

Capabilities Section:  .SUNW_cap

 Object Capabilities:
     index  tag               value
       [0]  CA_SUNW_HW_1     0x86d  [ SSE MMX CMOV SEP CX8 FPU ]

 Symbol Capabilities:
     index  tag               value
       [2]  CA_SUNW_ID       hrt
       [3]  CA_SUNW_HW_1     0x40002  [ TSCP TSC ]

  Symbols:
     index    value      size      type bind oth ver shndx          name
       [1]  0x000f306c 0x00000225  FUNC LOCL  D    0 .text          gettimeofday%hrt
       [2]  0x000f2efc 0x00000165  FUNC LOCL  D    0 .text          gethrtime%hrt

Capabilities Chain Section:  .SUNW_capchain

 Capabilities family: gettimeofday
  chainndx  symndx      name
         1  [702]       gettimeofday
         2  [1]         gettimeofday%hrt

 Capabilities family: gethrtime
  chainndx  symndx      name
         4  [1939]      gethrtime
         5  [2]         gethrtime%hrt

s11u1:jmcp $ elfdump -H /usr/lib/libc/libc_hwcap2.so.1 

Capabilities Section:  .SUNW_cap

 Object Capabilities:
     index  tag               value
       [0]  CA_SUNW_HW_1     0x1875  [ SSE2 SSE MMX CMOV AMD_SYSC CX8 FPU ]

 Symbol Capabilities:
     index  tag               value
       [2]  CA_SUNW_ID       hrt
       [3]  CA_SUNW_HW_1     0x40002  [ TSCP TSC ]

  Symbols:
     index    value      size      type bind oth ver shndx          name
       [1]  0x000f253c 0x00000225  FUNC LOCL  D    0 .text              gettimeofday%hrt
       [2]  0x000f23cc 0x00000165  FUNC LOCL  D    0 .text          gethrtime%hrt

Capabilities Chain Section:  .SUNW_capchain

 Capabilities family: gettimeofday
  chainndx  symndx      name
         1  [702]       gettimeofday
         2  [1]         gettimeofday%hrt

 Capabilities family: gethrtime
  chainndx  symndx      name
         4  [1939]      gethrtime
         5  [2]         gethrtime%hrt

Угадайте, что из вышеперечисленного подходит для систем AMD, а что для Intel?

Компоновщик Solaris умеет загружать правильную библиотеку hwcap во время выполнения до вызова _init() вашего процесса.

person James McPherson    schedule 04.03.2014