7

在 Linux 源代码树中,文件arch/x86/boot/header.S具有与此类似的 x86 代码,用于在调用之前清除BSS部分:main

...
# Zero the bss
    movw    $__bss_start, %di
    movw    $_end+3, %cx
    xorl    %eax, %eax
    subw    %di, %cx
    shrw    $2, %cx
    rep; stosl
...

为什么_end地址加了3?为什么不movw $_end, %cx代替movw $_end+3, %cx

4

1 回答 1

7

如果代码逐字节清除BSSmovw $_end, %cx部分就足够了。但是,此代码不会使用他们使用STOSL 的STOSB将BSS归零。一次存储 32 位通常比 8 位更有效。

STOSL将存储EAX(使用 设置为零)足够的时间以将BSSxorl %eax, %eax的整个范围清除为 0。+3 确保如果BSS部分的长度($_end-$__bss_start)不能被 4 整除,计算需要清除的DWORD的数量将被四舍五入。如果没有发生这种向上取整,那么在大小不能被 4 整除的情况下,最后一个字节可能不会被清除。

此处进行的计算假设__bss_start是指向 BSS 段开头的指针,并且是指向BSS_end结尾的指针。计算要清除的 32 位DWORD数量的等式实际上是:

NUMDWORDS=(_end+3-__bss_start) >> 2

(在计算shrw $2, %cx>>2)是整数除以 4,结果总是向下舍入。我们将 +3 添加到字节数,以便在除以 4 时有效地向上舍入到最接近的DWORD数。然后将该值用作DWORD的数量STOSL将设置为零。

于 2016-04-26T04:41:01.230 回答