// linux-2.6.35/arch/x86/include/asm/checksum_64.h
static inline __sum16 ip_fast_csum(const void *iph, unsigned int ihl)
{
unsigned int sum;
asm(" movl (%1), %0\n" /* %1初始值为iph指针,先把第1个32bit值赋给 %0 */
" subl $4, %2\n" /* %2为ihl,ihl*4才是ip header的实际长度,这里先减去4,因为下面要连续计算4个32bit值*/
" jbe 2f\n" /* 当ihl不足4时,跳到下面2处,也就是结束返回了 */
" addl 4(%1), %0\n" /* 4(%1)为偏移4byte,也就是第2个32bit,和 %0 相加 */
" adcl 8(%1), %0\n" /* adc是带进位相加,8(%1) 为第3个32bit,和 %0 相加 */
" adcl 12(%1), %0\n" /* 12(%1) 为第4个32bit,和 %0 相加 */
"1: adcl 16(%1), %0\n" /* adc是带进位相加,16(%1) 为第5个32bit,和 %0 相加 */
" lea 4(%1), %1\n" /* %1向生偏移4byte,再赋给 %1,也就是说首指针往后偏移4byte */
" decl %2\n" /* %2个数自减, 以后每次只计算一个4byte */
" jne 1b\n" /* 非0,表示长度还有值,再往上跳回到1处计算一个32bit */
" adcl $0, %0\n" /* 为0时,表示所有长度都已算完,剩下就是进位还没算,这里再加0计算进位 */
" movl %0, %2\n" /* 把%0值放到%1中 */
" shrl $16, %0\n" /* 因为ip 校验位是16bit的,所以这里%0右移16bit,得到高16bit放到%0中 */
" addw %w2, %w0\n" /* w表示计算16bit值,%2 + %0 表示再加上上面的高16bit */
" adcl $0, %0\n" /* 在上面基础上,再计算进位 */
" notl %0\n" /* 取反运算,结果存入%0中,也就是存入sum中 */
"2:"
/* Since the input registers which are loaded with iph and ihl
are modified, we must also specify them as outputs, or gcc
will assume they contain their original values. */
: "=r" (sum), "=r" (iph), "=r" (ihl)
: "1" (iph), "2" (ihl)
: "memory");
return (__force __sum16)sum;
}
注:1. ip header checksum计算比较频繁,所以用汇编写可以提高效能。
2. ip header,长度为20-60 bytes,而且一定是按4-byte对齐的。
|