对于上下文我是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
。
答案 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
进入循环的中间,以使循环的一部分运行正确的次数,而不是多次调用一个块。
我想我通常会查看代码高尔夫问题,它们自然适用于机器代码,并且可以避免从多个地方需要相同的代码块。我已经花了好几个小时调整一个简短的函数,所以开始回答一个需要更多代码的问题(因此在它之间/之间有更多的优化空间)对我来说很少见。