Linux内核头文件的源代码,为什么在清零BSS时需要_end+3?

7
在Linux源代码树中,文件arch/x86/boot/header.S具有类似于此的x86代码,用于在调用main之前清除BSS部分。
...
# 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
1个回答

7
如果代码逐字节清除BSS部分,movw $_end,%cx就足够了。然而,这段代码没有使用STOSB将BSS清零,而是使用STOSL。通常,一次存储32位比存储8位更有效率。 STOSL会将EAX(使用xorl %eax,%eax设置为零)存储足够的次数以将整个范围的BSS清除为0。+3确保如果BSS部分($_end-$__bss_start)的长度不能被4整除,则所需的DWORD数量将四舍五入。如果不进行四舍五入,则在大小不能被4整除的情况下,最后的字节可能无法被清除。
这里进行的计算假设__bss_start是BSS段开头的指针,_endBSS的结尾指针。计算32位DWORD需要清除的数量的方程式实际上是:
NUMDWORDS=(_end+3-__bss_start) >> 2

shrw $2, %cx(计算中的>>2)是除以4的整数除法,结果总是向下取整。我们将字节数加上+3,这样当进行除以4运算时,它实际上会四舍五入到最接近的DWORD数量。然后使用此值作为STOSL将要设置为零的DWORD数量。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接