转载请注明出处:
http://blog.csdn.net/weifenghai/article/details/52794872
概述:
内核中分配文件描述符时找第一个0的位置的一个底层函数,了解Linux内核嵌入式汇编知识参见《LINUX内核源代码情景分析(上)》中的1.5节《1.5Linux内核源代码中的汇编语言代码》,内核汇编指令参见《汇编语言程序设计(美)布鲁姆_着,马朝晖_等译》,代码摘自2.6.11.1内核。
函数代码:
/**
*find_first_zero_bit - find the first zero bit in a memory region
*@addr: The address to start the search at
*@size: The maximum size to search
*
*Returns the bit-number of the first zero bit, not the number of the byte
*containing a bit.
*/
static inline int find_first_zero_bit(constunsigned long *addr, unsigned size)
{
intd0, d1, d2;
intres;
if(!size)
return0;
/*This looks at memory. Mark it volatile to tell gcc not to move it around */
__asm__ __volatile__(
"movl$-1,%%eax
"
"xorl%%edx,%%edx
"
"repe;scasl
"
"je1f
"
"xorl-4(%%edi),%%eax
"
"subl$4,%%edi
"
"bsfl%%eax,%%edx
"
"1: subl%%ebx,%%edi
"
"shll$3,%%edi
"
"addl%%edi,%%edx"
:"=d"(res), "=&c" (d0), "=&D" (d1), "=&a"(d2)
:"1"((size + 31) >> 5), "2" (addr), "b" (addr) :"memory");
returnres;
}
代码分析:
输出部:
代码::"=d" (res), "=&c" (d0), "=&D"(d1), "=&a" (d2)
解释:
%0: res放入edx
%1: d0放入ecx
%2:d1放入edi
%3:d2放入eax
输入部:
代码::"1" ((size + 31) >> 5), "2" (addr),"b" (addr)
%4:与$1相同,(size + 31) >>5放入ecx
%5:与$2相同,addr放入edi
%6:addr 放入ebx
损坏部:: "memory"
指令部:
"movl$-1,%%eax
":把eax的所有位都置成1
"xorl%%edx,%%edx
":把edx置0
"repe;scasl
":在edi(即addr)中搜索与eax不匹配的(即不全为1的)
"je1f
" 没有找到
"xorl-4(%%edi),%%eax
" 把eax中edi为0的位置1,其它位置0
"subl$4,%%edi
" edi存当前找到的位置
"bsfl%%eax,%%edx
" edx存放eax中从右边第一个为1的位的索引,从0开始,edx存放目标字节内的偏移
"1: subl%%ebx,%%edi
" 现在edi中存放字节偏移位置
"shll$3,%%edi
" edi左移3位,存偏整体移位数
"addl%%edi,%%edx" 计算偏移位数
转载请注明出处:
http://blog.csdn.net/weifenghai/article/details/52794872