更短的x86调用指令

时间:2018-04-06 20:48:49

标签: x86 call

对于上下文我是x86打高尔夫球。

00000005 <start>:
   5:   e8 25 00 00 00          call   2f <cube>
   a:   50                      push   %eax

以后多次通话......

0000002f <cube>:
  2f:   89 c8                   mov    %ecx,%eax
  31:   f7 e9                   imul   %ecx
  33:   f7 e9                   imul   %ecx
  35:   c3                      ret   

call占用5个字节,即使偏移量适合单个字节!是否有任何方法可以编写call cube并使用GNU汇编程序进行汇编并获得较小的偏移量?我知道可以使用16位偏移,但理想情况下,我有一个2字节指令,如call reg

1 个答案:

答案 0 :(得分:2)

没有call rel8,或以任何方式推送返回地址,jmp少于5个字节。

要提前call reg,您需要在寄存器中生成少于3个字节的完整地址。即使是与RIP相关的LEA也无济于事,因为它只以rel32形式存在,而不是rel8

对于单个call,显然不值得。 如果你可以为多个2字节call reg指令重复使用相同的函数指针寄存器,那么即使只有2 call s (5字节{{1}分摊超过2 mov reg, imm32每次调用需要花费2.5个字节。)但这会花费你一个寄存器。

大多数操作系统不允许您在最低页面中映射任何内容(因此NULL指针deref错误),因此可用地址大于16位,超出16位模式。

在32位/ 64位代码中,我会考虑将代码映射到零页面所需的链接器选项,作为代码 - 高尔夫答案的字节数的一部分。 (And also the /proc/sys/vm/mmap_min_addr kernel setting或其他操作系统上的等效文件)

如果可以的话,一般在代码高尔夫中避免使用call。通常最好构建循环以避免需要代码重用。例如call进入循环的中间,以使循环的一部分运行正确的次数,而不是多次调用一个块。

我想我通常会查看代码高尔夫问题,它们自然适用于机器代码,并且可以避免从多个地方需要相同的代码块。我已经花了好几个小时调整一个简短的函数,所以开始回答一个需要更多代码的问题(因此在它之间/之间有更多的优化空间)对我来说很少见。