So prüfen Sie, ob für eine Binärdatei unter Linux SSE4 oder AVX erforderlich ist

19

Unter Linux /proc/cpuinfokönnen Sie auf einfache Weise alle CPU-Flags des Computers überprüfen.
Wenn ein Programm eine Obermenge des Befehlssatzes einer Maschine benötigt, können Sie dies am einfachsten feststellen, indem Sie es ausführen und prüfen, ob es ein SIGILLSignal auslöst.

Aber in meinem Fall unterstützen alle meine Prozessoren mindestens SSE4.1 und AVX.
Gibt es also eine einfache Möglichkeit zu überprüfen, ob eine Binärdatei spezielle Anweisungen enthält?

user2284570
quelle
Möglicherweise gibt es Emulatoren, mit denen Sie auswählen können, welche Befehlssätze aktiviert sind. QEMU unterstützt derzeit AVX nicht, sodass dies dort möglicherweise nicht wie erwartet funktioniert: superuser.com/questions/453786/how-do-i-get-avx-support-in-qemu || superuser.com/questions/548740/…
Ciro Santilli
2
objdump --disassembleführt eine Demontage durch. Mit können Sie objdumpeine Liste mit Mnemonics erstellen. Es ist Teil von Binutils und daher auf GNU Linux-Systemen verfügbar. Die zusätzlichen Anweisungen sind möglicherweise vorhanden, werden jedoch möglicherweise nicht ausgeführt. Das Programm könnte Laufzeitwächter haben.
Mittwoch,
@jww: heemm, ja, aber ich kümmere mich darum, dass eine ausführbare Datei überall läuft, und nicht darum, mehr als 600 Opcodes zu lernen, um sie in Assembler zu programmieren.
user2284570
Nun, Sie müssen lernen, was Sie können (und was nicht). Das liegt in Ihrer Verantwortung. Ich nehme an, Sie könnten mit kompilieren, -mavxum sicherzustellen, dass der Compiler nur aus dem AVX ISA auswählt, aber es gibt Möglichkeiten, ihn zu umgehen. Beispielsweise kann der Inline-Assembler die ISA-Prüfungen des Compilers normalerweise umgehen.
Jww
@jww: und wenn die Binärdatei eine geschlossene Quelle ist (in dem Sinne, dass der Quellcode nach dem Erstellen gelöscht wird), ein gemeinsames Objekt, das von einem proprietären Skript / Compiler erstellt wurde?
user2284570

Antworten:

11

Ich habe ein Programm in Rust rausgeschmissen, das dies versucht. Ich denke, es funktioniert, obwohl es undokumentiert und furchtbar zerbrechlich ist:

https://github.com/pkgw/elfx86exts

Anwendungsbeispiel:

$ 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
Peter
quelle
Ich habe versucht, es auf libtensorflow.so (sha224: 8f665acf0f455d5056014dfa2d48c22ab6cf83eb073842e8304878d0) aus diesem Paket (Version: 1.8.0-5) auszuführen und es hat meinen gesamten Computer eingefroren.
Philippe
@Philippe Bitte melde eine Ausgabe auf GitHub an! Das ist der bessere Ort, um solche Themen zu diskutieren, denke ich.
Peter
Ok, ich habe ein Problem mit deinem Github erstellt.
Philippe
18

Ich bin auf dasselbe Problem gestoßen, als ich versuchte, die GCC-Optimierungsprozesse zu verstehen und herauszufinden, welche Anweisungen während dieses Prozesses verwendet wurden oder nicht. Da ich mit der enormen Anzahl von Operationscodes nicht einverstanden bin, habe ich nach einer Möglichkeit gesucht, bestimmte Anweisungen (z. B. SSE3) innerhalb des zerlegten Codes zu visualisieren oder zumindest einige minimale Statistiken auszudrucken, z. B. ob und wie viele diese Anweisungen vorhanden sind in der binären.

Ich habe keine existierende Lösung gefunden, aber die Antwort von Jonathan Ben-Avraham erwies sich als sehr nützlich, da sie auf eine großartige (und sogar teilweise strukturierte) Quelle von Operationscodes hinweist. Basierend auf diesen Daten habe ich ein Bash-Skript geschrieben, mit dem bestimmte Anweisungssätze visualisiert oder Statistiken darüber gedruckt werden können, grepwenn die Ausgabe von eingespeist wird objdump.

Die Liste der Operationscodes wurde in ein eigenständiges Bash-Skript konvertiert, das dann (zur besseren Lesbarkeit) in der Hauptdatei enthalten ist, die ich einfach benannt habe opcode. Da Opcodes in gas.vim( Shirk's vimSyntaxdefinitionen , aus Jonathans Antwort) systematisch (scheinbar) nach verschiedenen CPU-Architekturen gruppiert wurden, habe ich versucht, diese Unterteilung beizubehalten und eine Architektur-> Befehlssatzzuordnung vorzunehmen . Ich bin mir jetzt nicht sicher, ob das eine gute Idee war. Die Zuordnung ist nicht korrekt und ich musste sogar einige Änderungen am Original vornehmengas.vimGruppierung. Da architekturbezogene Befehlssätze nicht meine ursprüngliche Absicht waren, habe ich versucht, nur Befehlssätze der im Internet beschriebenen Hauptarchitekturen zu erstellen, ohne die Dokumentationen der Hersteller zu konsultieren. AMD-Architekturen erscheinen mir überhaupt nicht zuverlässig (mit Ausnahme von Befehlssätzen wie 3DNow! Und SSE5). Ich habe mich jedoch entschlossen, den Code für Befehlssätze verschiedener Architekturen hier zu belassen, damit andere ihn untersuchen und korrigieren / verbessern und anderen vorläufige Ergebnisse liefern können.

Anfang der Hauptdatei mit dem Namen 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"

Ein Beispiel für eine Opcode_listDatei, die gemäß den Anweisungen opcodevom 27. Oktober 2014 erstellt und geändert wurde, finden Sie unter http://pastebin.com/yx4rCxqs . Sie können diese Datei direkt opcodeanstelle der source Opcode_listZeile einfügen . Ich habe diesen Code ausgegeben, weil Stack Exchange nicht zulässt, dass ich eine so große Antwort sende.

Schließlich der Rest der opcodeDatei mit der eigentlichen 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

Beachten Sie, dass -rdie Berechnung bei zu großen Suchanfragen (z. B. mit Haswell-Befehlssatz und Switch - dazu gehören Hunderte von Anweisungen) möglicherweise langsam vonstatten geht und bei großen Eingaben, für die dieses einfache Skript nicht vorgesehen war, viel Zeit in Anspruch nimmt .

Ausführliche Informationen zur Verwendung finden Sie unter

./opcode -h

Das gesamte opcodeSkript (einschließlich Opcode-Liste) finden Sie unter http://pastebin.com/A8bAuHAP .

Fühlen Sie sich frei, das Tool zu verbessern und eventuelle Fehler zu korrigieren. Zuletzt möchte ich Jonathan Ben-Avraham für seine großartige Idee danken, die gas.vimDatei von Shirk zu verwenden.

BEARBEITEN: Das Skript kann jetzt feststellen, zu welchem ​​Befehlssatz ein Operationscode gehört (regulärer Ausdruck kann verwendet werden).

Kyselejsyreček
quelle
9

Dekompilieren Sie zunächst Ihre Binärdatei:

objdump -d binary > binary.asm

Dann finden Sie alle SSE4-Anweisungen in der Assembly-Datei:

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

(Hinweis: CRC32 stimmt möglicherweise mit Kommentaren überein.)

Hier finden Sie die gebräuchlichsten AVX-Anweisungen (einschließlich Skalar, einschließlich AVX2, AVX-512-Familie und einiger FMA-ähnlicher Anweisungen 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

HINWEIS: getestet mit gawkund nawk.

Andriy Makukha
quelle
6

Leider scheint es zum jetzigen Zeitpunkt kein bekanntes Hilfsprogramm zu geben, das den erforderlichen Befehlssatz einer bestimmten ausführbaren Datei erkennt.

Das Beste, was ich für x86 vorschlagen kann, ist die Verwendung objdump -dder ELF-Binärdatei, um die ausführbaren Abschnitte in die Sprache Gnu Assemply ( gas) zu zerlegen . Verwenden Sie dann Shirk die vimSyntaxdefinitionen entweder grepdurch die Assembler - Code - Datei oder visuell scannen Sie den Assembler - Code für eine der gasOpcode_SSE41oder gasOpcode_SANDYBRIDGE_AVXAnweisungen, die Sie in Shirk sehen gas.vimDatei.

Die Assemblersprachendatei enthält die Anweisungen ("Opcodes") auf Maschinenebene, die der Compiler beim Kompilieren des Programms generiert hat. Wenn das Programm mit Kompilierungszeit-Flags für SSE- oder AVX-Anweisungen kompiliert wurde und der Compiler SSE- oder AVX-Anweisungen ausgegeben hat, sollten Sie einen oder mehrere SSE- oder AVX-Opcodes in der Disassembly-Liste von sehen objdump -d.

Wenn Sie beispielsweise grep vroundsdbin der Assemblycodedatei eine Übereinstimmung finden, wissen Sie, dass für die Ausführung der Binärdatei AVX-Funktionen erforderlich sind.

Es gibt einige unterarchitekturspezifische Anweisungen für x86, wie Sie aus der gas.vimDatei von Shirk grepersehen können. Es wäre also zugegebenermaßen mühsam , für alle Opcodes für jede Unterarchitektur zu pingen. Das Schreiben eines C-, Perl- oder Python-Programms, um dies zu tun, könnte eine hervorragende Idee für ein Open Source-Projekt sein, insbesondere wenn Sie jemanden finden, der es für ARM, PPC und andere Architekturen erweitert.

Jonathan Ben-Avraham
quelle
Was ist der Zweck von Gas: Ich konnte das Programm nicht finden?
user2284570
@ user2284570: Ich habe die Antwort so bearbeitet, dass sie sich auf Ihren Kommentar bezieht. HTH.
Jonathan Ben-Avraham
Sse4.2 + AVX + 3DNOW stehen für Hunderte von Anweisungen. Es würde lange dauern, eine Suche nach jedem von ihnen zu starten ...
user2284570
@ user2284570: Ja, das habe ich erwähnt. Wenn Sie dies regelmäßig tun müssen, ist es besser, ein Perl-Skript zu schreiben, das auf Shirk's basiert gas.vim. OTOH Wenn dies ein One-Shot-Problem ist, können Sie die Muster der Opcodes, die zwischen den Unterarchitekturen unterscheiden, leicht lernen.
Jonathan Ben-Avraham
Ich denke, eine Bibliothek für den Umgang mit Opcodes wäre etwas großartiges für den Start ...
user2284570
2

Ich habe versucht, ein Python-Hilfsprogramm zu schreiben, das auf Jonathan Ben-Avrahams basiert, und Kyselejsyrečeks antwortet. Es ist ein grobes Drehbuch, aber es erledigt den Job.

https://gist.github.com/SleepProgger/d4f5e0a0ea2b9456e6c7ecf256629396 Die gas.vim-Datei wird automatisch heruntergeladen und konvertiert, und es werden alle verwendeten (optionalen, nicht grundlegenden) Vorgänge einschließlich des Funktionsumfangs, von dem sie stammen, gespeichert. Außerdem unterstützt es die Suche nach Funktionssätzen mit op.

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
quelle