mov& jmp to& jmp back vs call& RET

时间:2016-07-23 13:35:41

标签: assembly x86-64

我正在查看一些汇编代码,我看到了这个:

    mov r12, _read_loopr
    jmp _bzero
_read_loopr:
...
_bzero:
    inc r8
    mov byte [r8+r15], 0x0
    cmp r8, 0xff
    jle _bzero
    jmp r12

我想知道这样做是否有任何特别优势(mov _read_loopr到函数寄存器jmp然后jmp返回)而不是通常调用_bzero和ret?

1 个答案:

答案 0 :(得分:3)

这看起来就像是脑死亡代码,特别是如果返回地址标签总是在jmp _bzero之后,就像你在评论中说的那样。

也许作者认为他们不能使用call"因为函数会调用clobber寄存器"。如果您正在调用不属于同一代码库的函数,则必须根据调用约定假设这一点。但您可以call / ret使用自定义调用约定。

当然,对于这么小的代码,它应该是内联的(即使其成为宏,而不是函数)。

更重要的是,通常可以比一次存储一个字节更聪明,并且如果有多个字节为零,则可能值得潜在的分支误预测。如果始终需要将至少8个(或更好,16个)字节的数据归零,则可以使用宽存储执行此操作。使最终存储写入要归零的缓冲区的最后一个字节,可能与前一个存储重叠。 (这比以分支结束决定最终的4B商店,2B商店和1B商店要好得多。)请参阅标签wiki,了解有关编写高效asm的资源。

如果返回地址位于jmp _bzero 之后的某个位置,那么最糟糕的可能是push _read_loopr / jmp _bzero和{{在ret中的1}}。那会打破return-address predictor stack,导致对调用树的下一个〜_bzero进行误预测。

最好是内联循环并在其后面直接ret

我不确定如何将jmp的地址传递给_bzero,以便与jmp / callret进行比较在jmp之后。

call / call相当便宜,但不是英特尔的单用指令。如果只有一个来电者,ret / jmp _bzero会更好。