如何理解bionic.c中bionic的这段代码片段?

Vic*_*r S 2 c android bionic

我在http://androidxref.com/4.0.4/xref/bionic/libc/string/bcopy.c中阅读了memcpy实现, 发现以下代码很难理解,有人可以解释一下吗?

 36 /*
 37  * sizeof(word) MUST BE A POWER OF TWO
 38  * SO THAT wmask BELOW IS ALL ONES
 39  */
 40 typedef long word;      /* "word" used for optimal copy speed */
 41 
 42 #define wsize   sizeof(word)
 43 #define wmask   (wsize - 1)
 44 
Run Code Online (Sandbox Code Playgroud)

...

        /*
 78          * Copy forward.
 79          */
 80         t = (long)src;  /* only need low bits */
 81         if ((t | (long)dst) & wmask) {
 82             /*
 83              * Try to align operands.  This cannot be done
 84              * unless the low bits match.
 85              */
 86             if ((t ^ (long)dst) & wmask || length < wsize)
 87                 t = length;
 88             else
 89                 t = wsize - (t & wmask);
Run Code Online (Sandbox Code Playgroud)

这些按位运算的意思是什么?他们的意图是什么?

tor*_*rek 7

基本思想是满足对齐约束:每次复制一个单词的每个"单词"必须在"单词"边界上对齐.

有些CPU将此作为基本约束,加载和存储必须出现在"自然"边界上.在较旧的ARM处理器上,地址的低位实际上完全被忽略,因此从奇数值地址加载或存储两个字节具有与以下相同的效果:

short w = *(short *)(addr & ~1);
Run Code Online (Sandbox Code Playgroud)

例如.在其他一些CPU上,未对齐的加载或存储会导致陷阱(例如MIPS和SPARC),还有其他CPU只会这样做,但会带来性能损失(x86).

因此,假设您正在将大量字节(例如,4096个)从地址0x12345复制到地址0x22345,并且"字大小"是4个字节.如果我们首先复制三个字节,地址现在将是0x12348和0x22348.此时,我们只能复制1023个4字节字,一次一个字,而不会因任何对齐问题而跳闸.之后我们将剩下一个要复制的字节,因为4096 = 3 +(4*1023)+ 1.

这一切都假设字节都是单独处理的,即使在加载和存储"单词"时也是如此.在某些机器上,这种假设是错误的:例如,旧的Data General MV10000 CPU将使用"字地址"来处理"字",字地址基本上是字节地址除以2.(因此不可能处理跨越两个字节的"字":位置0处的字具有字节地址0和1但字地址0;位置1处的字具有字节地址2和3;位置2处的字具有字节地址4和5;依此类推.)在这样的机器上,您可能需要使用不同版本的bcopy.c.

正如@Alex指出的那样,XOR只是确保它实际上可以对齐这两个地址.如果你从0x12345复制到0x22345,它是; 但如果您从0x12345复制到0x22344,这两个地址将永远不会对齐.


Ale*_*nze 6

一步一步做:

t = (long)src;
if ((t | (long)dst) & wmask)
Run Code Online (Sandbox Code Playgroud)

这些检查是否至少有一个,src并且dst不是sizeof(long).

if ((t ^ (long)dst) & wmask || length < wsize)
Run Code Online (Sandbox Code Playgroud)

此检查,如果srcdst被对准不同WRT sizeof(long)(IOW,都没有的"相等"的倍数sizeof(long)),或者如果length < sizeof(long)-1.

最后,你会收到t多少字节必须被复制为未对齐位置之间的字节,全部(length)或恰好足够(小于sizeof(long))到达地址的数量,sizeof(long)其余部分可以以其为单位复制其余部分long.后者是速度优化.

要看到所有你必须知道的一个整数,当用二进制表示时,是一个2的某个幂的倍数,当它低于2的幂的最低有效位都是零时.

例子:

100 2(4 10)是100的倍数2(4 10)
1100 2(12 10)是100的倍数2(4 10)
10000 2(16 10)是100 2(4 10)
0 2的倍数(0 10)是100的倍数2(4 10)
11 2(3 10)不是100的倍数2(4 10)
1101 2(13 10)不是100的倍数2(4 10)

这是& (sizeof(long)-1)用于.

您还需要知道XORed自身的值为0,而当您使用XOR不同的值时,结果为非零.所以你可以XOR用来比较.这(t ^ (long)dst)就是为了什么.