如何在Linux上检查二进制文件是否需要SSE4或AVX


20

在Linux上,/proc/cpuinfo允许以一种简单的方式检查计算机具有的所有CPU标志。
通常,如果程序需要机器指令集的超集,那么确定该指令集的最简单方法就是运行它,然后查看它是否发出SIGILL信号。

但就我而言,我所有的处理器都至少支持SSE4.1和AVX。
因此,有没有一种简单的方法可以检查二进制文件内部是否具有特殊指令?


也许有模拟器可以让您选择启用哪些指令集。QEMU当前不支持AVX,因此可能无法按预期的那样“工作”:superuser.com/questions/453786/how-do-i-get-avx-support-in-qemu || superuser.com/questions/548740/...
西罗桑蒂利新疆改造中心法轮功六四事件

2
objdump --disassemble进行拆卸。您可以objdump用来生成助记符列表。它是Binutils的一部分,因此可以在GNU Linux系统上使用。此外,可能会出现其他指令,但可能不会执行。该程序可能具有运行时防护。
jww

@jww:嘿,是的,但是我不喜欢在各处运行可执行文件,而不是为了汇编而学习600多个操作码。
user2284570

好吧,您有点必须学习可以(也不能)使用的东西。那是你的责任。我想您可以进行编译-mavx以确保编译器仅从AVX ISA中进行选择,但是有回避它的方法。例如,内联汇编程序通常可以避开编译器的ISA检查。
jww

@jww:如果二进制文件是封闭的源代码(从某种意义上说,源代码在生成后会被删除),那么专有脚本/编译器会生成共享对象?
user2284570

Answers:


11

我在Rust中撞出一个程序试图这样做。我认为它是有效的,尽管它没有记录且非常脆弱:

https://github.com/pkgw/elfx86exts

用法示例:

$ 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

我试着libtensorflow.so(SHA224:8f665acf0f455d5056014dfa2d48c22ab6cf83eb073842e8304878d0)运行它从这个包(版本:1.8.0-5),并冻结了我的整个计算机。
菲利普

@Philippe请在GitHub上提交问题!我认为,这是讨论此类主题的好地方。
彼得

好的,我在您的github上创建了一个问题。
菲利普

18

当我试图了解GCC优化过程并找出在此过程中使用或未使用哪些指令时,遇到了同样的问题。由于我对大量的操作代码不满意,因此我一直在寻找一种方法来可视化反汇编代码中的特定(例如SSE3)指令,或者至少打印一些最小的统计信息,例如这些指令是否存在以及有多少?在二进制文件中。

我还没有找到任何现有的解决方案,但是Jonathan Ben-Avraham的答案非常有用,因为它指出了一个很好的(甚至是部分结构化的)操作代码源。基于此数据,我编写了一个Bash脚本,该脚本可以可视化特定的指令集或grep在从中馈入输出时使用这些指令集打印统计信息objdump

操作代码列表已转换为独立的Bash脚本,然后将其包含在主文件中(出于更好的可读性)(我已将其简单命名为)opcode。由于gas.vim(根据乔纳森的回答,Shirk的vim语法定义中的)操作码是根据不同的CPU体系结构进行系统分组的(貌似),因此,我尝试保留这种划分并进行体系结构->指令集映射;我现在不确定这是否是个好主意。映射不准确,我什至必须对原始图像进行一些更改gas.vim分组。由于与体系结构相关的指令集不是我的初衷,因此我仅尝试构建Internet上描述的主要体系结构的指令集,而没有咨询制造商的文档。AMD架构对我来说似乎一点也不可靠(除了3DNow!和SSE5之类的指令集)。但是,我决定将各种体系结构的指令集的代码留在这里,以供其他人检查和更正/改进并为其他人提供一些初步的结果。

主文件开头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"

可以在http://pastebin.com/yx4rCxqs上找到按照2014年10月27日Opcode_list的说明生成和修改的文件的示例。您可以将此文件直接插入该行。我之所以把这段代码放出来是因为Stack Exchange不允许我发送这么大的答案。opcodeopcodesource Opcode_list

最后,其余opcode文件具有实际逻辑:

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

请注意,如果您的搜索查询过大(例如,使用Haswell指令集和-r开关-其中包含数百条指令),则可能会缓慢进行计算,并且在大型输入上进行此操作会花费很长时间,而这个简单的脚本本来不打算这样做。

有关使用的详细信息,请咨询

./opcode -h

整个opcode脚本(包括Opcode_list)可以在http://pastebin.com/A8bAuHAP找到。

随时改进工具并纠正我可能犯的任何错误。最后,我要感谢乔纳森·本·阿夫拉罕(Jonathan Ben-Avraham)使用Shirk gas.vim文件的好主意。

编辑:脚本现在能够找到操作码所属的指令集(可以使用正则表达式)。


9

首先,反编译您的二进制文件:

objdump -d binary > binary.asm

然后在汇编文件中找到所有 SSE4指令:

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

(注意:CRC32可能与注释匹配。)

查找最常见的AVX指令(包括标量,包括AVX2,AVX-512系列和一些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

注意:已通过gawk和测试nawk


6

不幸的是,到目前为止,似乎还没有任何知名的实用程序可以从给定的可执行文件中检测所需的指令集。

我对x86的最佳建议是objdump -d在ELF二进制文件上使用,以将可执行部分反汇编为Gnu Assemply语言gas)。然后使用谢淑丽的vim语法定义要么grep通过汇编代码文件或视觉扫描的汇编代码的任何gasOpcode_SSE41gasOpcode_SANDYBRIDGE_AVX说明你在推卸的看gas.vim文件。

汇编语言文件包含编译器在编译程序时生成的机器级指令(“操作码”)。如果程序是使用SSE或AVX指令的编译时标志编译的,并且编译器发出了SSE或AVX指令,则您应该在产生的反汇编清单中看到一个或多个SSE或AVX操作码objdump -d

例如,如果grep vroundsdb对汇编代码文件进行处理并找到匹配项,则说明二进制文件需要AVX功能才能执行。

从Shirk的gas.vim文件中可以看到,有很多针对x86的特定于子体系结构的指令,因此grepping每个子体系结构的所有操作码无疑是乏味的。编写C,Perl或Python程序来执行此操作对于开源项目而言可能是一个绝妙的主意,尤其是如果您可以找到某人对其进行扩展以用于ARM,PPC和其他体系结构。


gas的目的是什么:我找不到那个程序?
user2284570 2014年

@ user2284570:我编辑了与您的评论相关的答案。HTH。
Jonathan Ben-Avraham 2014年

Sse4.2 + AVX + 3DNOW代表数百条指令。对它们中的每一个进行搜索都将花费很长时间……
user2284570 2014年

@ user2284570:是的,我提到过。如果您需要定期执行此操作,则最好基于Shirk's编写Perl脚本gas.vim。OTOH如果这是一站式问题,那么您可以轻松学习区分子架构的操作码模式。
乔纳森·本·阿夫拉罕

我猜想一个用于处理操作码的库对于启动...将是一件很棒的事情……
user2284570 2014年

2

我给出了一些基于乔纳森·本·阿夫拉罕斯(Jonathan Ben-Avrahams)的python实用程序脚本,而Kyselejsyrečeks回答了。它的脚本简陋,但可以完成工作。

https://gist.github.com/SleepProgger/d4f5e0a0ea2b9456e6c7ecf256629396 它会自动下载并转换gas.vim文件,并支持转储所有使用过的(可选的非基本的)操作,包括它们来自的功能集。另外,它还支持对功能集的查找。

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.

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.