转自:http://blog.csdn.net/astrotycoon/article/details/8109899
以下是glibc-2.10.1中memcpy函数的源码
现在让我们来一步步分析源码。
首先要明确一点的是glibc中的库函数都是经过反复优化过的,所以memcpy的实现不可能是通过one byte by one byte实现的,如果真是那样,肯定会笑掉大牙的^-^。
其次我们还应该考虑到字节对齐问题,因为在大多数平台下,从内存对齐边界开始拷贝会有许多的优化方案可以使用,glibc中memcpy正是利用了这一点!
1. 判断需要拷贝的字节数是否大于某一临界值。如果大于临界值,则可以使用更加强大的优化手段进行拷贝;否则,直接按照一般的方法,即one byte by one byte来拷贝,
即
if判断中的OP_T_THRES就是我们所说的临界值,根据不同情况,OP_T_THRES的值是16或者8。
2.假设要拷贝的目的地址如下所示:
其中start为拷贝目的地的起始地址 ,end为拷贝目的地的结束地址,align border为内存中的对齐边界。
现在要计算start到align border的距离,此处使用了一个非常聪明的小技巧。
是不是很奇怪,为什么(-dstp) % OPSIZ就是start到align border的距离?dstp是unsigned long int型的数据,现在前面加了一个负号,会发什么有趣的事情呢?
我们假设n是unsigned long int数据类型,值为9,十六进制为0x00000009,那么负n的十六进制为0xfffffff7,但是,因为unsigned long int类型是不可能出现负值的,所以此时会把0xfffffff7当作一个无符号数,这是一个很大的数值了。所以(-n) % 3就相当于这个很大的数与3相余。
3.对于特殊平台,可以使用page copy的方法。由于限制条件太多,一般x86平台下不会使用。
4.使用word copy的方法进行one word by one word进行拷贝,此处是memcpy的优化关键,优化的条件是拷贝地址处于对齐边界。
5.剩余的不能采用word copy的尾部使用one byte by one byte进行拷贝。
现在来分析实现内存拷贝的宏。
以下是memcopy.h中的代码
利用x86的movsb指令实现字节拷贝。首先使用cld指令将DF标志清零(如果DF标志被清零,那么每条movs指令执行之后ESI和EDI寄存器中的数值就会递增。如果DF标志通过STD指令被设置,那么每条movs指令执行之后ESI和EDI寄存器中的数值就会递减。) 接着使用"rep movsb"指令实现one byte by one byte的拷贝。
参考链接: 点击打开链接