繁体   English   中英

是否可以找到GCC可以生成的所有汇编指令的列表?

[英]Is it possible to find a list of all of the assembly instructions that GCC can generate?

在分配给OpenSecurityTraining的Xeno Kovah的x86大会简介的第一天的作业中,他指出

我们现在知道的说明(24)

NOP PUSH / POP CALL / RET MOV / LEA ADD / SUB JMP / Jcc CMP / TEST和/或/ XOR / NOT SHR / SHL IMUL / DIV REP STOS,REP MOV LEAVE

编写程序以查找我们尚未涵盖的指令,并明天报告指令。

他进一步预测了作业,

  • 以后要说明的指示不计算在内: SAL / SAR
  • 跳跃的变化或IMUL / DIVMUL / IDIV变体也不计算在内
  • 额外的禁止指令:任何浮动点(因为我们没有覆盖此类中的那些。)
  • 他在视频中说你不能使用内联汇编。 (被问及时提到)。

而不是objdump荷兰国际集团执行随机和审计他们再创造的源泉, 是有可能找到的是GCC目前输出的x86汇编指令列表?

这个问题的基础似乎是实际使用的指令子集很少,需要知道逆向工程(这是课程的重点)。 Xeno似乎试图找到一种有趣的指导方式来表达这一点,

我认为知道大约20-30(不计算变化)是足够好的,你将很少检查手册

虽然我欢迎大家和我一起参加OpenSecurityTraining这个很棒的课程,但问题是关于我提出的从GCC中找出它的方法(如果可能的话)。 不是,人们实际上做了Xeno的任务。 ;)

这个问题的基础似乎是实际使用的指令子集非常少,需要知道逆向工程

是的,这通常是正确的。 有一些指令GCC将绝不会发出, 就像enter (因为它比慢得多 push rbp / mov rbp, rsp / sub rsp, some_constant在现代的CPU)。

其他旧/模糊的东西,如xlatloop也将被闲置,因为它们并不快,而gcc的-Os并没有全力以赴地优化尺寸而不关心性能。 clang -Oz更具侵略性,但IDK如果有人clang -Oz教它loop指令。)

当然,gcc永远不会发出像wrmsr这样的特权指令。 有些内在函数( __builtin_...函数)用于某些非特权指令, rdtsccpuid ,它们不是“正常”。


是否可以找到GCC当前输出的x86汇编指令列表?

这将是gcc机器定义文件。 作为可移植编译器的GCC具有自己的基于文本的语言,用于描述编译器指令集的机器定义文件。 (每个指令的作用,它可以使用的寻址模式,以及优化器可以最小化的某种“成本”。)

请参阅gcc-internals文档


这个问题的另一种方法是查看x86指令参考手册(例如这个HTML提取 ,并查看标签wiki中的其他链接)并查找尚未看到的那些。 然后编写一个函数,gcc会发现它很有用。

例如,如果你还没有看过movsx (符号扩展名),那就写吧

long long foo(int x) { return x; }

和gcc -O3将发出( 来自Godbolt编译器资源管理器

    movsx   rax, edi
    ret

或者为了获得rax符号扩展的cdqe (在AT&T语法中也称为cltq ,强制gcc在符号扩展之前进行数学运算,因此它可以首先在eax生成结果(使用复制和添加lea )。

long long bar(unsigned x) { return (int)(x+1); }

    lea     eax, [rdi+1]
    cdqe
    ret

   # clang chooses inc edi  /  movsxd rax, edi

另见Matt Godbolt的CppCon2017演讲: “我的编译器最近为我做了什么? 解开编译器的盖子“ ,以及如何从GCC / clang组件输出中消除”噪音“?


让gcc发出旋转指令很有意思。 C ++中循环移位(旋转)操作的最佳实践 你把它写成移位/ OR,gcc可以识别为旋转。

因为C不提供现代CPU可以做的许多事情的标准函数(旋转,弹出,计数前导/尾随零),唯一可移植的东西是编写一个等效函数并让编译器识别该模式。 如果你很幸运,gcc和clang可以在使用-mpopcnt进行编译时将整个循环优化为单个popcnt指令(例如,由-march=haswell启用)。 如果没有,你会得到一个愚蠢的慢循环。 可靠的非可移植方式是使用__builtin_popcount() ,如果目标支持,则编译为popcnt指令,否则进行表查找。 _mm_popcnt_u64popcnt或什么都没有:如果目标不支持该指令,它不会编译。


当然,这种方法的缺陷是它只有在您已经知道x86指令集并且任何给定指令是优化编译器的正确选择时才有效!

(以及gcc选择做什么,例如内联字符串在某些情况下对于短字符串比较rep cmpsb ,虽然我不确定这是最优的。只有rep movs / rep stos rep movs在现代CPU上有“快速字符串”支持。但是我不要以为gcc会使用lods ,或任何带有rep前缀的“字符串”指令。)

是否可以找到GCC当前输出的x86汇编指令列表,而不是随机执行随机可执行文件并审核它们然后创建源代码

您可以查看gcc使用的机器描述文件 在其源代码树中,查看gcc / config / i386并查看.md文件。 i86的核心是i386.md ; 还有其他用于x86的各种扩展(并且可能包含在针对不同处理器进行优化时使用的启发式调整)。

警告:这绝对不是一个容易阅读。

我认为知道大约20-30(不计算变化)是足够好的,你将很少检查手册

这是真的; 根据我进行逆向工程的经验,99%的代码总是相同的东西,指令方面; 比了解整个x86指令集更有用的是熟悉程序集习语,尤其是编译器经常发出的习惯用法。


话虽如此,从我的脑海中,一些非常常见的指令缺失(经常发出并且没有启用扩展指令集)是:

  • movzx / movsx
  • inc / dec (gcc很少见, 与VC ++相同
  • neg
  • cdqidiv之前
  • jcxz / jecxz (gcc很少见,VC ++有些常见)
  • setCC
  • cmpxchg (同步代码中);
  • cmovCC
  • adc (在32位代码中进行64位运算时)
  • int3 (通常在函数边界上发出,通常作为填充int3
  • 一些其他字符串指令( scas / cmps ),尤其是旧编译器上的固定序列

然后就是整个世界的SSE&co ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM