assembly 较短的x86调用指令

xxb16uws  于 2023-01-30  发布在  其他
关注(0)|答案(1)|浏览(166)

对于上下文,我是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位偏移量,但理想情况下,我会使用像call reg这样的2字节指令。

iecba09b

iecba09b1#

没有call rel8,也没有任何方法可以将返回地址和jmp压入少于5个字节。
要想领先call reg,需要在寄存器中生成少于3个字节的完整地址,即使是RIP相关的莱亚也无济于事,因为它只以rel32的形式存在,而不是rel8
对于一个单一的call,显然不值得。

如果您可以为多个2字节call reg指令重用同一个函数指针寄存器,那么即使只使用2个call指令,您也会取得成功。(5字节mov reg, imm32加上2个2字节call reg总共是9字节,而2个5字节call总共是10字节)。但这确实会花费您一个寄存器。

大多数操作系统不允许你在最低页Map任何东西(所以NULL指针deref错误),所以在32或64位模式下可用地址大于16位。66 E8 rel16(4字节callw)即使在32位模式下也不是一个选项;这会将EIP截短为IP.https://www.felixcloutier.com/x86/call
在32位/ 64位代码中,我会考虑将代码Map到零页所需的链接器选项作为代码高尔夫答案的字节计数的一部分。(And also the /proc/sys/vm/mmap_min_addr kernel setting,或其他操作系统上的等效项)通常我们认为在代码高尔夫中根本不计算ELF元数据是合理的,只计算.text部分的字节,因此特殊的链接器技巧会在那里打开一个蠕虫罐头。
如果可以的话,一般避免在代码高尔夫中使用call。通常最好是构造循环以避免代码重用。例如,将jmp插入循环中间,以使循环的一部分运行正确的次数,而不是多次调用一个块。
我想我通常会看代码高尔夫问题,这些问题很自然地适合机器代码,并且可以避免需要来自多个地方的相同代码块。我已经可以花几个小时调整一个短函数,所以对我来说,开始回答一个需要更多代码的问题(因此在部分之间/跨部分优化的空间更大)是罕见的。

相关问题