Jak sprawdzić, czy plik binarny wymaga SSE4 lub AVX w systemie Linux

20

W systemie Linux /proc/cpuinfoumożliwia sprawdzenie wszystkich flag procesora, które ma maszyna w prosty sposób.
Zwykle, jeśli program wymaga nadzbioru zestawu instrukcji maszyny, najłatwiejszym sposobem ustalenia tego jest uruchomienie go i sprawdzenie, czy wywołuje SIGILLsygnał.

Ale w moim przypadku wszystkie moje procesory obsługują co najmniej SSE4.1 i AVX.
Czy istnieje prosty sposób sprawdzenia, czy plik binarny zawiera specjalne instrukcje?

użytkownik2284570
źródło
Być może istnieją emulatory, które pozwalają wybrać, które zestawy instrukcji są włączone. QEMU obecnie nie obsługuje AVX, więc może „nie działać” zgodnie z oczekiwaniami: superuser.com/questions/453786/how-do-i-get-avx-support-in-qemu || superuser.com/questions/548740/...
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件
2
objdump --disassemblewykonuje demontaż. Możesz użyć objdumpdo wygenerowania listy mnemoników. Jest częścią Binutils, więc jest dostępny w systemach GNU Linux. Ponadto dodatkowe instrukcje mogą być obecne, ale mogą nie zostać wykonane. Program może mieć strażników środowiska wykonawczego.
jww
@jww: heemm, tak, ale martwię się o to, aby plik wykonywalny działał wszędzie, a nie o uczenie się ponad 600 kodów w celu programowania w asemblerze.
user2284570
Cóż, musisz nauczyć się, czego możesz (i czego nie możesz) użyć. To twoja odpowiedzialność. Podejrzewam, że mógłbyś się skompilować, -mavxaby kompilator wybierał tylko z AVX ISA, ale istnieją sposoby, aby go ominąć. Na przykład asembler wbudowany może zwykle ominąć kontrole ISA kompilatora.
jww
@jww: a jeśli plik binarny jest zamkniętym źródłem (w tym sensie, że kod źródłowy jest usuwany po zbudowaniu), kompilacja obiektu współużytkowanego przez zastrzeżony skrypt / kompilator?
user2284570

Odpowiedzi:

11

Uderzyłem w program Rust, który próbuje to zrobić. Myślę, że to działa, chociaż jest nieudokumentowane i okropnie kruche:

https://github.com/pkgw/elfx86exts

Przykładowe użycie:

$ cd elfx86exts
$ cargo build
[things happen]
$ cargo run -- /bin/ls
   Compiling elfx86exts v0.1.0 (file:///home/peter/sw/elfx86exts)
    Finished dev [unoptimized + debuginfo] target(s) in 1.9 secs
     Running `target/debug/elfx86exts /bin/ls`
MODE64
CMOV
SSE2
SSE1
Piotr
źródło
Próbowałem uruchomić go na libtensorflow.so (sha224: 8f665acf0f455d5056014dfa2d48c22ab6cf83eb073842e8304878d0) z tego pakietu (wersja: 1.8.0-5) i zamroził cały mój komputer.
Philippe,
@Philippe Zgłoś problem na GitHub! Myślę, że to lepsze miejsce do dyskusji na takie tematy.
Peter
Ok, stworzyłem problem na twoim githubie.
Philippe,
18

Zetknąłem się z tym samym problemem, gdy próbowałem zrozumieć procesy optymalizacji GCC i dowiedzieć się, które instrukcje zostały lub nie zostały użyte podczas tego procesu. Ponieważ nie jestem przyjazny z ogromną liczbą kodów operacji, szukałem sposobu na wizualizację konkretnych (powiedzmy SSE3) instrukcji w zdemontowanym kodzie lub przynajmniej wydrukowania niektórych minimalnych statystyk, takich jak to, czy i ile tych instrukcji jest w pliku binarnym.

Nie znalazłem żadnego istniejącego rozwiązania, ale odpowiedź Jonathana Ben-Avrahama okazała się bardzo przydatna, ponieważ wskazuje na świetne (a nawet częściowo ustrukturyzowane) źródło kodów operacji. Na podstawie tych danych napisałem skrypt Bash, który może wizualizować określone zestawy instrukcji lub drukować statystyki na ich temat, grepgdy są zasilane danymi wyjściowymi objdump.

Lista kodów operacji została przekonwertowana na samodzielny skrypt Bash, który jest następnie dołączany (w celu lepszej czytelności) do głównego pliku, który po prostu nazwałem opcode. Ponieważ w opcodes gas.vim( uchylać w vimdefinicjach składniowych , od odpowiedzi Jonathana) były systematycznie grupowane (pozornie) według różnych architekturach procesora, starałem się zachować ten podział i złożyć zestaw architecture-> instrukcji mapowania; Nie jestem teraz pewien, czy to był dobry pomysł. Mapowanie nie jest dokładne i musiałem nawet wprowadzić pewne zmiany w oryginalegas.vimgrupowanie. Ponieważ zestawy instrukcji związane z architekturą nie były moim pierwotnym zamiarem, starałem się jedynie konstruować zestawy instrukcji głównych architektur opisanych w Internecie, ale bez konsultacji z dokumentacją producentów. Architektury AMD wcale nie wydają mi się wiarygodne (z wyjątkiem zestawów instrukcji takich jak 3DNow! I SSE5). Jednak postanowiłem zostawić kod dla zestawów instrukcji różnych architektur tutaj, aby ktoś mógł je zbadać i poprawić / poprawić i dać innym pewne wstępne wyniki.

Początek głównego pliku o nazwie opcode:

#!/bin/bash
#
# Searches disassembled code for specific instructions.
#
# Opcodes obtained from: https://github.com/Shirk/vim-gas/blob/master/syntax/gas.vim
#
# List of opcodes has been obtained using the following commands and making a few modifications:
#   echo '#!/bin/bash' > Opcode_list
#   wget -q -O- https://raw.githubusercontent.com/Shirk/vim-gas/master/syntax/gas.vim \
#    | grep -B1 -E 'syn keyword gasOpcode_|syn match   gasOpcode' | \
#    sed -e '/^--$/d' -e 's/"-- Section:/\n#/g' \
#    -e 's/syn keyword gasOpcode_\([^\t]*\)*\(\t\)*\(.*\)/Opcode_\1="\${Opcode_\1} \3"/g' \
#    -e 's/Opcode_PENT_3DNOW/Opcode_ATHLON_3DNOW/g' -e 's/\\//g' \
#    -e 's/syn match   gasOpcode_\([^\t]*\)*.*\/<\(.*\)>\//Opcode_\1="\${Opcode_\1} \2"/g' \
#    >> Opcode_list
#
# Modify file Opcode_list replacing all occurrences of:
#   * Opcode_Base within the section "Tejas New Instructions (SSSE3)" with Opcode_SSSE3
#   * Opcode_Base within the section "Willamette MMX instructions (SSE2 SIMD Integer Instructions)"
#                                        with Opcode_WILLAMETTE_Base

# return values
EXIT_FOUND=0
EXIT_NOT_FOUND=1
EXIT_USAGE=2

# settings
InstSet_Base=""
Recursive=false
Count_Matching=false
Leading_Separator='\s'
Trailing_Separator='(\s|$)' # $ matches end of line for non-parametric instructions like nop
Case_Insensitive=false
Invert=false
Verbose=false
Stop_After=0
Line_Numbers=false
Leading_Context=0
Trailing_Context=0

source Opcode_list   # include opcodes from a separate file

# GAS-specific opcodes (unofficial names) belonging to the x64 instruction set.
# They are generated by GNU tools (e.g. GDB, objdump) and specify a variant of ordinal opcodes like NOP and MOV.
# If you do not want these opcodes to be recognized by this script, comment out the following line.
Opcode_X64_GAS="nopw nopl movabs"


# instruction sets
InstSet_X86="8086_Base 186_Base 286_Base 386_Base 486_Base PENT_Base P6_Base KATMAI_Base WILLAMETTE_Base PENTM_Base"
InstSet_IA64="IA64_Base"
InstSet_X64="PRESCOTT_Base X64_Base X86_64_Base NEHALEM_Base X64_GAS"
InstSet_MMX="PENT_MMX KATMAI_MMX X64_MMX"
InstSet_MMX2="KATMAI_MMX2"
InstSet_3DNOW="ATHLON_3DNOW"
InstSet_SSE="KATMAI_SSE P6_SSE X64_SSE"
InstSet_SSE2="SSE2 X64_SSE2"
InstSet_SSE3="PRESCOTT_SSE3"
InstSet_SSSE3="SSSE3"
InstSet_VMX="VMX X64_VMX"
InstSet_SSE4_1="SSE41 X64_SSE41"
InstSet_SSE4_2="SSE42 X64_SSE42"
InstSet_SSE4A="AMD_SSE4A"
InstSet_SSE5="AMD_SSE5"
InstSet_FMA="FUTURE_FMA"
InstSet_AVX="SANDYBRIDGE_AVX"

InstSetDep_X64="X86"
InstSetDep_MMX2="MMX"
InstSetDep_SSE2="SSE"
InstSetDep_SSE3="SSE2"
InstSetDep_SSSE3="SSE3"
InstSetDep_SSE4_1="SSSE3"
InstSetDep_SSE4_2="SSE4_1"
InstSetDep_SSE4A="SSE3"
InstSetDep_SSE5="FMA AVX" # FIXME not reliable

InstSetList="X86 IA64 X64 MMX MMX2 3DNOW SSE SSE2 SSE3 SSSE3 VMX SSE4_1 SSE4_2 SSE4A SSE5 FMA AVX"


# architectures
Arch_8086="8086_Base"
Arch_186="186_Base"
Arch_286="286_Base"
Arch_386="386_Base"
Arch_486="486_Base"
Arch_Pentium="PENT_Base PENT_MMX" # Pentium = P5 architecture
Arch_Athlon="ATHLON_3DNOW"
Arch_Deschutes="P6_Base P6_SSE" # Pentium II
Arch_Katmai="KATMAI_Base KATMAI_MMX KATMAI_MMX2 KATMAI_SSE" # Pentium III
Arch_Willamette="WILLAMETTE_Base SSE2" # original Pentium IV (x86)
Arch_PentiumM="PENTM_Base"
Arch_Prescott="PRESCOTT_Base X64_Base X86_64_Base X64_SSE2 PRESCOTT_SSE3 VMX X64_VMX X64_GAS" # later Pentium IV (x64) with SSE3 (Willamette only implemented SSE2 instructions) and VT (VT-x, aka VMX)
Arch_P6=""
Arch_Barcelona="ATHLON_3DNOW AMD_SSE4A"
Arch_IA64="IA64_Base" # 64-bit Itanium RISC processor; incompatible with x64 architecture
Arch_Penryn="SSSE3 SSE41 X64_SSE41" # later (45nm) Core 2 with SSE4.1
Arch_Nehalem="NEHALEM_Base SSE42 X64_SSE42" # Core i#
Arch_SandyBridge="SANDYBRIDGE_AVX"
Arch_Haswell="FUTURE_FMA"
Arch_Bulldozer="AMD_SSE5"

ArchDep_8086=""
ArchDep_186="8086"
ArchDep_286="186"
ArchDep_386="286"
ArchDep_486="386"
ArchDep_Pentium="486"
ArchDep_Athlon="Pentium" # FIXME not reliable
ArchDep_Deschutes="Pentium"
ArchDep_Katmai="Deschutes"
ArchDep_Willamette="Katmai"
ArchDep_PentiumM="Willamette" # FIXME Pentium M is a Pentium III modification (with SSE2). Does it support also WILLAMETTE_Base instructions?
ArchDep_Prescott="Willamette"
ArchDep_P6="Prescott" # P6 started with Pentium Pro; FIXME Pentium Pro did not support MMX instructions (introduced again in Pentium II aka Deschutes)
ArchDep_Barcelona="Prescott" # FIXME not reliable
ArchDep_IA64=""
ArchDep_Penryn="P6"
ArchDep_Nehalem="Penryn"
ArchDep_SandyBridge="Nehalem"
ArchDep_Haswell="SandyBridge"
ArchDep_Bulldozer="Haswell" # FIXME not reliable

ArchList="8086 186 286 386 486 Pentium Athlon Deschutes Katmai Willamette PentiumM Prescott P6 Barcelona IA64 Penryn Nehalem SandyBridge Haswell Bulldozer"

Przykład Opcode_listpliku wygenerowanego i zmodyfikowanego zgodnie z instrukcjami opcodez 27 października 2014 r. Można znaleźć na stronie http://pastebin.com/yx4rCxqs . Możesz wstawić ten plik bezpośrednio opcodew miejsce source Opcode_listwiersza. Udostępniłem ten kod, ponieważ Stack Exchange nie pozwala mi wysłać tak dużej odpowiedzi.

Wreszcie reszta opcodepliku z rzeczywistą logiką:

usage() {
    echo "Usage: $0 OPTIONS"
    echo ""
    echo "  -r      set instruction sets recursively according to dependency tree (must precede -a or -s)"
    echo "  -a      set architecture"
    echo "  -s      set instruction set"
    echo "  -L      show list of available architectures"
    echo "  -l      show list of available instruction sets"
    echo "  -i      show base instruction sets of current instruction set (requires -a and/or -s)"
    echo "  -I      show instructions in current instruction set (requires -a and/or -s)"
    echo "  -c      print number of matching instructions instead of normal output"
    echo "  -f      find instruction set of the following instruction (regex allowed)"
    echo "  -d      set leading opcode separator (default '$Leading_Separator')"
    echo "  -D      set trailing opcode separator (default '$Trailing_Separator')"
    echo "  -C      case-insensitive"
    echo "  -v      invert the sense of matching"
    echo "  -V      print all lines, not just the highlighted"
    echo "  -m      stop searching after n matched instructions"
    echo "  -n      print line numbers within the original input"
    echo "  -B      print n instructions of leading context"
    echo "  -A      print n instructions of trailing context"
    echo "  -h      print this help"
    echo
    echo "Multiple architectures and instruction sets can be used."
    echo
    echo "Typical usage is:"
    echo "  objdump -M intel -d FILE | $0 OPTIONS"
    echo "  objdump -M intel -d FILE | $0 -s SSE2 -s SSE3 -V                    Highlight SSE2 and SSE3 within FILE."
    echo "  objdump -M intel -d FILE | tail -n +8 | $0 -r -a Haswell -v -m 1    Find first unknown instruction."
    echo "  $0 -C -f ADDSD                                                      Find which instruction set an opcode belongs to."
    echo "  $0 -f .*fma.*                                                       Find all matching instructions and their instruction sets."
    echo
    echo "The script uses Intel opcode syntax. When used in conjunction with objdump, \`-M intel' must be set in order to prevent opcode translation using AT&T syntax."
    echo
    echo "BE AWARE THAT THE LIST OF KNOWN INSTRUCTIONS OR INSTRUCTIONS SUPPORTED BY PARTICULAR ARCHITECTURES (ESPECIALLY AMD'S) IS ONLY TENTATIVE AND MAY CONTAIN MISTAKES!"
    kill -TRAP $TOP_PID
}

list_contains() {   # Returns 0 if $2 is in array $1, 1 otherwise.
    local e
    for e in $1; do
        [ "$e" = "$2" ] && return 0
    done
    return 1
}

build_instruction_set() {   # $1 = enum { Arch, InstSet }, $2 = architecture or instruction set as obtained using -L or -l, $3 = "architecture"/"instruction set" to be used in error message
    local e
    list_contains "`eval echo \\\$${1}List`" "$2" || (echo "$2 is not a valid $3."; usage)      # Test if the architecture/instruction set is valid.
    if [ -n "`eval echo \\\$${1}_${2}`" ]; then                                                 # Add the instruction set(s) if any.
        for e in `eval echo \\\$${1}_${2}`; do                                                  # Skip duplicates.
            list_contains "$InstSet_Base" $e || InstSet_Base="$e $InstSet_Base"
        done
    fi
    if [ $Recursive = true ]; then
        for a in `eval echo \\\$${1}Dep_$2`; do
            build_instruction_set $1 $a "$3"
        done
    fi
    InstSet_Base="`echo $InstSet_Base | sed 's/$ *//'`"                                         # Remove trailing space.
}

trap "exit $EXIT_USAGE" TRAP    # Allow usage() function to abort script execution.
export TOP_PID=$$               # PID of executing process.

# Parse command line arguments.
while getopts ":ra:s:LliIcf:Fd:D:CvVm:nB:A:h" o; do
    case $o in
        r) Recursive=true ;;
        a) build_instruction_set Arch "$OPTARG" "architecture" ;;
        s) build_instruction_set InstSet "$OPTARG" "instruction set" ;;
        L) echo $ArchList; exit $EXIT_USAGE ;;
        l) echo $InstSetList; exit $EXIT_USAGE ;;
        i)
            if [ -n "$InstSet_Base" ]; then
                echo $InstSet_Base
                exit $EXIT_USAGE
            else
                echo -e "No instruction set or architecture set.\n"
                usage
            fi
            ;;
        I)
            if [ -n "$InstSet_Base" ]; then
                for s in $InstSet_Base; do
                    echo -ne "\e[31;1m$s:\e[0m "
                    eval echo "\$Opcode_$s"
                done
                exit $EXIT_USAGE
            else
                echo -e "No instruction set or architecture set.\n"
                usage
            fi
            ;;
        c) Count_Matching=true ;;
        f)
            # Unlike architectures, instruction sets are disjoint.
            Found=false
            for s in $InstSetList; do
                for b in `eval echo \\\$InstSet_$s`; do
                    Found_In_Base=false
                    for i in `eval echo \\\$Opcode_$b`; do
                        if [[ "$i" =~ ^$OPTARG$ ]]; then
                            $Found_In_Base || echo -ne "Instruction set \e[33;1m$s\e[0m (base instruction set \e[32;1m$b\e[0m):"
                            echo -ne " \e[31;1m$i\e[0m"
                            Found_In_Base=true
                            Found=true
                        fi
                    done
                    $Found_In_Base && echo ""
                done
            done
            if [ $Found = false ]; then
                echo -e "Operation code \e[31;1m$OPTARG\e[0m has not been found in the database of known instructions." \
                "Perhaps it is translated using other than Intel syntax. If obtained from objdump, check if the \`-M intel' flag is set." \
                "Be aware that the search is case sensitive by default (you may use the -C flag, otherwise only lower case opcodes are accepted)."
                exit $EXIT_NOT_FOUND
            else
                exit $EXIT_FOUND
            fi
            ;;
        d) Leading_Separator="$OPTARG" ;;
        D) Trailing_Separator="$OPTARG" ;;
        C) Case_Insensitive=true ;;
        v) Invert=true ;;
        V) Verbose=true ;;
        m) Stop_After=$OPTARG ;;
        n) Line_Numbers=true ;;
        B) Leading_Context=$OPTARG ;;
        A) Trailing_Context=$OPTARG ;;
        h) usage ;;
        \?)
            echo -e "Unknown option: -$OPTARG\n"
            usage
            ;;
    esac
done
shift $((OPTIND-1))
[ -n "$1" ] && echo -e "Unknown command line parameter: $1\n" && usage
[ -z "$InstSet_Base" ] && usage

# Create list of grep parameters.
Grep_Params="--color=auto -B $Leading_Context -A $Trailing_Context"
[ $Count_Matching = true ] && Grep_Params="$Grep_Params -c"
[ $Case_Insensitive = true ] && Grep_Params="$Grep_Params -i"
[ $Invert = true ] && Grep_Params="$Grep_Params -v"
[ $Stop_After -gt 0 ] && Grep_Params="$Grep_Params -m $Stop_After"
[ $Line_Numbers = true ] && Grep_Params="$Grep_Params -n"

# Build regular expression for use in grep.
RegEx=""
for s in $InstSet_Base; do
    eval RegEx=\"$RegEx \$Opcode_$s\"
done
# Add leading and trailing opcode separators to prevent false positives.
RegEx="$Leading_Separator`echo $RegEx | sed "s/ /$(echo "$Trailing_Separator"|sed 's/[\/&]/\\\&/g')|$(echo "$Leading_Separator"|sed 's/[\/&]/\\\&/g')/g"`$Trailing_Separator"

[ $Verbose = true -a $Count_Matching = false ] && RegEx="$RegEx|\$"

# The actual search.
grep $Grep_Params -E "$RegEx" && exit $EXIT_FOUND || exit $EXIT_NOT_FOUND

Należy pamiętać, że jeśli zapytanie jest zbyt duże (np. Z zestawem instrukcji Haswella i -rprzełącznikiem - obejmuje to setki instrukcji), obliczenia mogą przebiegać powoli i zajmować dużo czasu na dużych danych wejściowych, dla których ten prosty skrypt nie był przeznaczony .

Szczegółowe informacje na temat użytkowania znajdują się w

./opcode -h

Cały opcodeskrypt (z dołączoną Opcode_list) można znaleźć na stronie http://pastebin.com/A8bAuHAP .

Ulepsz narzędzie i napraw błędy, które mogłem popełnić. Na koniec chciałbym podziękować Jonathanowi Ben-Avrahamowi za jego świetny pomysł na wykorzystanie gas.vimpliku Shirka .

EDYCJA: Skrypt może teraz znaleźć zestaw instrukcji, do którego należy kod operacji (można użyć wyrażenia regularnego).

Kyselejsyreček
źródło
9

Najpierw dekompiluj swój plik binarny:

objdump -d binary > binary.asm

Następnie znajdź wszystkie instrukcje SSE4 w pliku zespołu:

awk '/[ \t](mpsadbw|phminposuw|pmulld|pmuldq|dpps|dppd|blendps|blendpd|blendvps|blendvpd|pblendvb|pblenddw|pminsb|pmaxsb|pminuw|pmaxuw|pminud|pmaxud|pminsd|pmaxsd|roundps|roundss|roundpd|roundsd|insertps|pinsrb|pinsrd|pinsrq|extractps|pextrb|pextrd|pextrw|pextrq|pmovsxbw|pmovzxbw|pmovsxbd|pmovzxbd|pmovsxbq|pmovzxbq|pmovsxwd|pmovzxwd|pmovsxwq|pmovzxwq|pmovsxdq|pmovzxdq|ptest|pcmpeqq|pcmpgtq|packusdw|pcmpestri|pcmpestrm|pcmpistri|pcmpistrm|crc32|popcnt|movntdqa|extrq|insertq|movntsd|movntss|lzcnt)[ \t]/' binary.asm

(Uwaga: CRC32 może pasować do komentarzy.)

Znajdź najczęstsze instrukcje AVX (w tym skalar, w tym AVX2, rodzina AVX-512 i niektóre podobne do FMA vfmadd132pd):

awk '/[ \t](vmovapd|vmulpd|vaddpd|vsubpd|vfmadd213pd|vfmadd231pd|vfmadd132pd|vmulsd|vaddsd|vmosd|vsubsd|vbroadcastss|vbroadcastsd|vblendpd|vshufpd|vroundpd|vroundsd|vxorpd|vfnmadd231pd|vfnmadd213pd|vfnmadd132pd|vandpd|vmaxpd|vmovmskpd|vcmppd|vpaddd|vbroadcastf128|vinsertf128|vextractf128|vfmsub231pd|vfmsub132pd|vfmsub213pd|vmaskmovps|vmaskmovpd|vpermilps|vpermilpd|vperm2f128|vzeroall|vzeroupper|vpbroadcastb|vpbroadcastw|vpbroadcastd|vpbroadcastq|vbroadcasti128|vinserti128|vextracti128|vpminud|vpmuludq|vgatherdpd|vgatherqpd|vgatherdps|vgatherqps|vpgatherdd|vpgatherdq|vpgatherqd|vpgatherqq|vpmaskmovd|vpmaskmovq|vpermps|vpermd|vpermpd|vpermq|vperm2i128|vpblendd|vpsllvd|vpsllvq|vpsrlvd|vpsrlvq|vpsravd|vblendmpd|vblendmps|vpblendmd|vpblendmq|vpblendmb|vpblendmw|vpcmpd|vpcmpud|vpcmpq|vpcmpuq|vpcmpb|vpcmpub|vpcmpw|vpcmpuw|vptestmd|vptestmq|vptestnmd|vptestnmq|vptestmb|vptestmw|vptestnmb|vptestnmw|vcompresspd|vcompressps|vpcompressd|vpcompressq|vexpandpd|vexpandps|vpexpandd|vpexpandq|vpermb|vpermw|vpermt2b|vpermt2w|vpermi2pd|vpermi2ps|vpermi2d|vpermi2q|vpermi2b|vpermi2w|vpermt2ps|vpermt2pd|vpermt2d|vpermt2q|vshuff32x4|vshuff64x2|vshuffi32x4|vshuffi64x2|vpmultishiftqb|vpternlogd|vpternlogq|vpmovqd|vpmovsqd|vpmovusqd|vpmovqw|vpmovsqw|vpmovusqw|vpmovqb|vpmovsqb|vpmovusqb|vpmovdw|vpmovsdw|vpmovusdw|vpmovdb|vpmovsdb|vpmovusdb|vpmovwb|vpmovswb|vpmovuswb|vcvtps2udq|vcvtpd2udq|vcvttps2udq|vcvttpd2udq|vcvtss2usi|vcvtsd2usi|vcvttss2usi|vcvttsd2usi|vcvtps2qq|vcvtpd2qq|vcvtps2uqq|vcvtpd2uqq|vcvttps2qq|vcvttpd2qq|vcvttps2uqq|vcvttpd2uqq|vcvtudq2ps|vcvtudq2pd|vcvtusi2ps|vcvtusi2pd|vcvtusi2sd|vcvtusi2ss|vcvtuqq2ps|vcvtuqq2pd|vcvtqq2pd|vcvtqq2ps|vgetexppd|vgetexpps|vgetexpsd|vgetexpss|vgetmantpd|vgetmantps|vgetmantsd|vgetmantss|vfixupimmpd|vfixupimmps|vfixupimmsd|vfixupimmss|vrcp14pd|vrcp14ps|vrcp14sd|vrcp14ss|vrndscaleps|vrndscalepd|vrndscaless|vrndscalesd|vrsqrt14pd|vrsqrt14ps|vrsqrt14sd|vrsqrt14ss|vscalefps|vscalefpd|vscalefss|vscalefsd|valignd|valignq|vdbpsadbw|vpabsq|vpmaxsq|vpmaxuq|vpminsq|vpminuq|vprold|vprolvd|vprolq|vprolvq|vprord|vprorvd|vprorq|vprorvq|vpscatterdd|vpscatterdq|vpscatterqd|vpscatterqq|vscatterdps|vscatterdpd|vscatterqps|vscatterqpd|vpconflictd|vpconflictq|vplzcntd|vplzcntq|vpbroadcastmb2q|vpbroadcastmw2d|vexp2pd|vexp2ps|vrcp28pd|vrcp28ps|vrcp28sd|vrcp28ss|vrsqrt28pd|vrsqrt28ps|vrsqrt28sd|vrsqrt28ss|vgatherpf0dps|vgatherpf0qps|vgatherpf0dpd|vgatherpf0qpd|vgatherpf1dps|vgatherpf1qps|vgatherpf1dpd|vgatherpf1qpd|vscatterpf0dps|vscatterpf0qps|vscatterpf0dpd|vscatterpf0qpd|vscatterpf1dps|vscatterpf1qps|vscatterpf1dpd|vscatterpf1qpd|vfpclassps|vfpclasspd|vfpclassss|vfpclasssd|vrangeps|vrangepd|vrangess|vrangesd|vreduceps|vreducepd|vreducess|vreducesd|vpmovm2d|vpmovm2q|vpmovm2b|vpmovm2w|vpmovd2m|vpmovq2m|vpmovb2m|vpmovw2m|vpmullq|vpmadd52luq|vpmadd52huq|v4fmaddps|v4fmaddss|v4fnmaddps|v4fnmaddss|vp4dpwssd|vp4dpwssds|vpdpbusd|vpdpbusds|vpdpwssd|vpdpwssds|vpcompressb|vpcompressw|vpexpandb|vpexpandw|vpshld|vpshldv|vpshrd|vpshrdv|vpopcntd|vpopcntq|vpopcntb|vpopcntw|vpshufbitqmb|gf2p8affineinvqb|gf2p8affineqb|gf2p8mulb|vpclmulqdq|vaesdec|vaesdeclast|vaesenc|vaesenclast)[ \t]/' binary.asm

UWAGA: przetestowano za pomocą gawki nawk.

Andriy Makukha
źródło
6

Niestety, wydaje się, że na dzień dzisiejszy nie ma dobrze znanego narzędzia wykrywającego wymagany zestaw instrukcji z danego pliku wykonywalnego.

Najlepsze, co mogę zasugerować dla x86, to użycie objdump -dbinarnego ELF do dezasemblacji sekcji wykonywalnych na język Gnu Assemply ( gas). Następnie użyj definicji składni Shirka,vim aby albo grepprzejrzeć plik kodu asemblera, albo wizualnie przeskanować kod asemblera w poszukiwaniu którejkolwiek z instrukcji gasOpcode_SSE41lub gasOpcode_SANDYBRIDGE_AVXinstrukcji widocznych w gas.vimpliku Shirka .

Plik języka asemblera zawiera instrukcje na poziomie komputera („opcodes”), które kompilator wygenerował podczas kompilacji programu. Jeśli program został skompilowany z flagami czasu kompilacji instrukcji SSE lub AVX, a kompilator wyemitował instrukcje SSE lub AVX, to na liście dezasemblacji utworzonej przez powinien pojawić się jeden lub więcej kodów operacyjnych SSE lub AVX objdump -d.

Na przykład, jeśli zrobisz to grep vroundsdbw pliku kodu asemblera i znajdziesz dopasowanie, to wiesz, że plik binarny wymaga do działania możliwości AVX.

Jak widać z gas.vimpliku Shirka, jest kilka instrukcji specyficznych dla pod-architektury dla x86, więc greppingowanie wszystkich kodów operacyjnych dla każdej pod-architektury byłoby z pewnością nużące. Napisanie w tym celu programu C, Perl lub Python może być doskonałym pomysłem na projekt Open Source, szczególnie jeśli możesz znaleźć kogoś, kto rozszerzy go o ARM, PPC i inne architektury.

Jonathan Ben-Avraham
źródło
Jaki jest cel gazu: nie mogłem znaleźć tego, co to za program?
user2284570
@ user2284570: Zredagowałem odpowiedź dotyczącą twojego komentarza. HTH.
Jonathan Ben-Avraham
Sse4.2 + AVX + 3DNOW stanowią setki instrukcji. Rozpoczęcie wyszukiwania każdego z nich zajęłoby dużo czasu ...
user2284570,
@ user2284570: Tak, wspomniałem o tym. Jeśli musisz to robić regularnie, lepiej napisać skrypt Perla oparty na Shirku gas.vim. OTOH, jeśli jest to problem jednorazowy, możesz łatwo nauczyć się wzorców kodów rozróżniających poszczególne pod-architektury.
Jonathan Ben-Avraham
Wydaje
2

Dałem napisanie skryptu narzędzia python opartego na Jonathanie Ben-Avrahamsie i Kyselejsyrečeksie odpowiedzi. Jest to prymitywny skrypt, ale wykonuje zadanie.

https://gist.github.com/SleepProgger/d4f5e0a0ea2b9456e6c7ecf256629396 Automatycznie pobiera i konwertuje plik gas.vim oraz obsługuje zrzut wszystkich używanych (opcjonalnych nie podstawowych) operacji, w tym zestawu funkcji, z którego pochodzą. Dodatkowo obsługuje op do wyszukiwania zestawu funkcji.

Tries to detect which CPU features where used in a given binary.

positional arguments:
  executable            The executable to analyze or the command to lookup if
                        -l is set.

optional arguments:
  -h, --help            show this help message and exit
  -j JSON_SPECS, --json-specs JSON_SPECS
                        json file containing a command to feature mapping.
  -o JSON_OUTPUT, --json-output JSON_OUTPUT
                        json file to save the command to feature mapping
                        parsed from an gas.vim file. Defaults to same folder
                        as this scipt/specs.json
  -g GAS, --gas GAS     gas.vim file to convert to feature mapping.
  -nw, --no-json-save   Do not save converted mapping from gas.vim file.
  -b, --include-base    Include base instructions in the search.
  -l, --lookup-op       Lookup arch and feature for given command. Can be
                        regex.

SleepProgger
źródło