linux_0.11-memory.c-get_free_page

2021/6/2 7:24:15

本文主要是介绍linux_0.11-memory.c-get_free_page,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

unsigned long
get_free_page (void)
{
  register unsigned long __res asm ("ax");

  __asm__ ("std ; repne ; scasb\n\t"
    "jne 1f\n\t"
    "movb $1,1(%%edi)\n\t"
    "sall $12,%%ecx\n\t"
    "addl %2,%%ecx\n\t"
    "movl %%ecx,%%edx\n\t"
    "movl $1024,%%ecx\n\t" 
    "leal 4092(%%edx),%%edi\n\t" 
    "rep ; stosl\n\t" 
    "movl %%edx,%%eax\n"
"1:": "=a" (__res): "" (0), "i" (LOW_MEM), "c" (PAGING_PAGES), "D" (mem_map + PAGING_PAGES - 1):"di", "cx",
    "dx");
  return __res;   
}

    函数作用分配一页(4K)。稍后嵌入式汇编的格式要稍作介绍一下,其实我也不是很熟悉,多练习吧。

    代码分析:

1,:register unsigned long __res asm ("ax");

定义了一个名为__res的变量,使用了register修饰符(register修饰符暗示编译程序相应的变量将被频繁地使用,如果可能的话,应将其保存在CPU的寄存器中,以加快其存储速度)。asm("ax")则表示__res的值保存在寄存器ax中。

2:"std ; repne ; scasb\n\t"

一下子来了三兄弟。std设置方向,先设置方向嘛!立场原则还是要有的(还有一个cld清除方向,指示di和si寄存器的移动方向;cld时fd=0,地址从低到高,std相反)。repne scasb联合使用,repne重复命令(按计数寄存器 ((E)CX) 中指定的次数重复执行字符串指令,或是重复到 ZF 标志不再满足指定的条件。REP(重复)、REPE(相等时重复)、REPNE(不相等时重复)、REPZ(为零时重复)及 REPNZ(不为零时重复)助记符都是可以添加到一些字符串指令中的前缀)。scasb命令比较增加,将al中的值域es:di比较,inc di或dec di(取决于DF)。

此步骤的操作变量位于”输入寄存器“。如果es:di的值不等于al则dec di,否则执行下一步。

3:"jne 1f\n\t"

如果es:di的值相均不和al相等,即均不为零。跳转到标签1f处执行,Nf表示向前标签,Nb表示向后标签,N是取值1-10的十进制数字

4:"movb $1,1(%%edi)\n\t"

找到未使用的页面置1,表示已经被分配。

5:"sall $12,%%ecx\n\t"

算法左移,相当于c中<<,intel汇编中sal命令,长整型的操作。此时ecx保存的是mem_map[i]的下标i,即相对页面数,

6:"addl %2,%%ecx\n\t"

加上低端内存的地址,即是页面的物理地址,%2即是第二个输入参数"i" (LOW_MEM)。

7:"movl %%ecx,%%edx\n\t"

将ecx寄存器的值存在edx中,即将实际物理地址存入edx中。

8:"movl $1024,%%ecx\n\t"

将1024存入ecx中,1k。一页4k,实际物理内存每项占4个字节,一共1024项。

9:"leal 4092(%%edx),%%edi\n\t"

即是edx+4092存入edi。按照4字节对齐,4096即是最后一项,4096 - 4 = 4092 = 1023*4 = (1024-1)*4

leal 8(%ebp),%eax  即把8+(%ebp)的地址送入寄存器%eax中,类似的还有其他方式:

传送a值到eax:movl a, %%eax         

传送a地址到edi: movl $a, %%edi

movl与leal的区别:

lead s,d 将&s->d

movl s, d 将s->d

10:"rep ; stosl\n\t"

重复1024次,将1024项物理地址全部存入eax中,

11:"movl %%edx,%%eax\n"

将物理地址的其实页面存入eax,interl的EABI规则eax用来保存函数的输出值。

12:"1:"
标签1,用于"jne 1f\n\t"语句跳转返回0值。

具有输入和输出参数的嵌入式汇编语句的基本格式为:

             asm("汇编语句"

                      :输出寄存器

                      :输入寄存器

                      :会被修改的寄存器);

                                                                 

                                                                                                                          常用寄存器说明

代码说明代码说明
a使用寄存器eaxm使用内存地址
b使用寄存器ebxo使用内存地址并可以加偏移值
c使用寄存器ecxI使用常数0-31
d使用寄存器edxJ使用常数0-63
S使用esiK使用常数0-255
D使用ediL使用常数0-65535
q使用动态分配字节可寻址寄存器(eax,ebx,ecx或edx)M使用常数0-3
r使用任意动态分配的寄存器N使用1字节常数(0-255)
g使用通用有效的地址即可(eax,ebx,ecx,edx或内存变量)O使用常数0-31
A使用eax与edx联合(64位)=输出操作数,输出值将替换前值
+表示操作数可读可写&

早期汇编的操作数。表示在使用完操作数之前,内容会被修改

 

   



这篇关于linux_0.11-memory.c-get_free_page的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程