assembly 最常用的指令[已关闭]

41zrol4v  于 2022-11-24  发布在  其他
关注(0)|答案(1)|浏览(155)

已关闭。此问题为opinion-based。当前不接受答案。
**想要改进此问题吗?**请更新问题,以便editing this post可以用事实与引用来回答.

3天前关闭。
Improve this question
我时不时地在某个地方读到,在CPU的所有指令中,只有很少一部分是在大部分时间使用的,上一次是here,作者写道:“只有少数几条不同的指令占所有执行操作的90%”。
最常用的指令是什么?我对x86-64和arm 64最感兴趣。

w6mmgewl

w6mmgewl1#

这将因操作系统、编译器、编译器版本、编程语言以及可能的目标架构扩展而异。这还取决于您在"相同"指令与"不同"指令之间的界限。
在arm64上,如果你认为movz w0, 0movz w0, 1是不同的,那么你可以取任何二进制,将它分成4字节的块,以十六进制打印并通过sort | uniq -c运行。
如果你认为所有的movz都是同一条指令,那么问题就来了:movz w0movz x0是否相同?如果答案是肯定的,还有其他的指令,比如add,它们有不同的形式,第三个操作数是寄存器或立即数。索引模式引入了额外的效果。除此之外,还有一些伪指令,如mov,可以根据操作数编码为movzmovnorr
但让我们看一个具体的例子:macOS 12.6.1上的/bin/bash二进制文件。
arm64e片的__TEXT.__text部分有118587条指令,如果我们将其全部分解,并尝试通过以下命令将所有立即数替换为...,将所有通用寄存器以及(w|x)zr(w)sp替换为rN,将所有浮点寄存器替换为fN来对其进行规范化:

perl -pe 's/b\.\w{2}/b.cond/g;s/\b(x[0-9]+|sp|xzr)\b/rN/g;s/\bw([0-9]+|sp|zr)/rN/g;s/\b[dq][0-9]+/fN/g;s/-?0x[0-9a-f]+/.../g;s/, -?\d+/, .../g;s/(lsl|lsr|asr|uxtw|sxtw) (\d+|0x[0-9a-f]+)/.../g;s/, \.\.\.\]/]/g'

然后按频率对结果进行排序:

sort | uniq -c | perl -pe 's/^\s+//g' | sort -V

然后在ret指令处选择一个任意截止值,我们得到:

265 ret
268 brk ...
269 autibsp
271 eor rN, rN, rN, ...
284 sub rN, rN, rN
299 cset rN, eq
312 cmn rN, ...
322 ldur rN, [rN]
332 add rN, rN, rN, ...
363 csel rN, rN, rN, eq
392 orr rN, rN, ...
432 paciza rN
450 ldr rN, [rN, rN]
476 strb rN, [rN]
507 ldp fN, fN, [rN]
578 sxtw rN, rN
745 and rN, rN, ...
780 tbnz rN, ..., ...
805 tbz rN, ..., ...
866 stp rN, rN, [rN]!
871 add rN, rN, rN
978 ldp rN, rN, [rN], ...
1028 invalid
1141 stp fN, fN, [rN]
1170 retab
1290 pacibsp
1457 sub rN, rN, ...
1520 cbnz rN, ...
1567 cmp rN, rN
1622 ldrb rN, [rN]
1695 adrp rN, ...
2548 ldr rN, ...
3504 stp rN, rN, [rN]
3537 ldp rN, rN, [rN]
3996 adr rN, ...
4644 cmp rN, ...
4664 add rN, rN, ...
4728 cbz rN, ...
4966 b ...
5294 str rN, [rN]
5601 b.cond ...
7451 mov rN, ...
7691 nop
8270 ldr rN, [rN]
10181 bl ...
11585 mov rN, rN

这相当于112015条指令,占指令总数的94.5%。

  • 这是一个"arm64e"二进制文件,这是苹果公司为他们的ABI和指针认证而命名的。在一个常规的arm64目标上,所有的retab都是ret,而pacibspautibsppaciza根本不存在。
  • 几乎所有brk的出现都是在autibsp之后,这是Apple为了解决FEAT_PAuth架构扩展的结构性弱点而被迫做出的编译器更改。其余的出现很可能是源代码中__builtin_trap()的调用。
  • nop是非常常见的。这是由于PC相对寻址,编译器发出两个或三个类似adrp x0, ...; add x0, x0, ...的指令,如果目标地址足够接近指令,则可以在链接到adr x0, ...; nop时优化这些指令。nop是否"运行",或者是否只是从指令流水线中删除,这是有争议的。
  • invalid非常常见。这些是在使用它们的函数之后找到的跳转表。它们是数据,而不是代码,因此实际上从未运行过。
  • 浮点寄存器只在两条指令中出现:stpldp。编译器通常将浮点寄存器用于memcpy和memset操作,一是因为这些寄存器可以容纳多达128位,二是因为它避免了溢出通用寄存器,通用寄存器比浮点寄存器更有可能已经被分配。至少在bash这样的命令行二进制文件中是这样的。我希望在操作系统内核和嵌入式固件中有类似的情况,但在图形相关代码或机器学习中,这可能看起来非常不同。
  • 绝大多数cmn指令都会检查值-1。这很可能是C语言中API设计的结果,而不是架构所固有的。

现在,这取决于你是否想减少其中的一些指令。但总的来说,我认为模式是明确的:

  • 套准移动
  • 立即施工
  • 函数调用
  • 无条件分支
  • 条件分支
  • 寄存器比较
  • 内存负载
  • 内存存储

弥补了绝大多数指令,这是有意义的,因为有了这些构建块,你基本上可以做任何事情。几乎所有其他指令都是对这些指令的某种优化,它们更适合利基市场,因此出现的频率更低。剩下的指令是特定于体系结构的,并暴露了你无法通过其他方式获得的东西,如brkmsr。但这种情况将更加罕见。无论你看什么架构,这种情况都很可能发生。

相关问题