Chinaunix首页 | 论坛 | 博客
  • 博客访问: 602870
  • 博文数量: 68
  • 博客积分: 2621
  • 博客等级: 少校
  • 技术积分: 1498
  • 用 户 组: 普通用户
  • 注册时间: 2010-10-23 21:04
文章分类

全部博文(68)

文章存档

2013年(8)

2012年(52)

2010年(8)

分类: LINUX

2012-02-12 14:35:19

     内核中的汇编代码是AT&T格式的,和Intel的不太一样。本来想从网上直接转过来AT&T汇编指令说明,可是发现太多了,我只是需要了解一下而已。所以,下面我摘取一段很短的内核代码,先对此有个认识,以后遇到更复杂的再继续完善。    

linux-0.11/fs/bitmap.c
#define clear_block(addr) \
__asm__("cld\n\t" \
                 rep\n\t \
                 stosl" \
                 ::"a" (0), "c" (BLOCK_SIZE/4), "D" ( (long) (addr) : "cx", "di")
  
    该段代码的汇编代码为:
       
movl $0, %eax
        movl (BLOCK_SIZE/4), %ecx
        movl addr, %edi
     这样,我们说明一下该代码的含义:
         向addr中写入(BLOCK_SIZE/4)个0,即
将指定地址addr处的一块1024字节内存清零。

解释一下出现的指令含义:
     cld: clear direction     //清方向位
     rep: repeat                  //重复执行下面的存储数据
     stosl: store string       //存储数据,
相当于将EAX中的值保存到ES:EDI指向的地址中

下面说一下基本的行内汇编 :
      基本的行内汇编很简单,一般是按照下面的格式 :
     
asm("statements")    例如:asm("nop") 
      注:1. asm 和 __asm__是完全一样的

            
2. 如果有多行汇编,则每一行都要加上 "\n\t"
            实际上gcc在处理汇编时,是要把asm(...)的内容"打印"到汇编文件中,所以格式控制字符是必要的.

再扩展的行内汇编 :

      扩展的行内汇编类似于Watcom.
      基本的格式是:
     
asm ( "statements" : output_regs : input_regs : clobbered_regs)
      注:冒号后的语句指明输入,输出和被改变的寄存器.通过冒号以后的语句,编译器就知道你的指令需要和改变哪些寄存器,从而可以寄存器的分配.

例子__asm__("...": :"a" (0), "c" (BLOCK_SIZE/4), "D" ( (long) (addr) : "cx", "di")  中的
                     "a" (0):把0放入%eax中
                     "c" (BLOCK_SIZE/4):把(BLOCK_SIZE/4)放入%ecx中
                     "D" ( (long) (addr):把addr放入%edi中

说明一下字母代表的含义:

a :eax ; b :ebx ;c : ecx;d :edx ;S :esi ; D :edi

“...”即statements, 第一个 : 后没有东西,表明没有输出寄存器,

                               第二个 :后为"a" (0), "c" (BLOCK_SIZE/4), "D" ( (long) (addr) ,表明%eax, %ecx, %edi是输入寄存器

                                第三个:后是"cx", "di",表明是被改变的寄存器


下面,说一个稍微复杂一点的。

linux-0.11/fs/super.c

#define set_bit(bitnr, addr)  ( {  \

register int __res __asm__("ax");

__asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \

                 __res; } )

     首先,我们说明一下这段代码的含义:

            测试指定位偏移处比特位的值,并返回该原比特位的值。命名为test_bit()更好。

     具体的解释一下这段代码:

            1. set_bit(bitnr, addr) 参数的含义:

                    bitnr - 比特位偏移值; addr - 测试比特位操作的起始地址。

            2. register int __res __asm__("ax"):

                    定义了一个局部寄存器变量。该变量将被保存在eax寄存器中,以便于高效访问和操作
这种定义变量的方法主要用于内嵌汇编程序中
__res值尽量放在eax中。

            3. __asm__("bt %2,%3;setb %%al":"=a" (__res):"a" (0),"r" (bitnr),"m" (*(addr))); \

                             __res; } ) :

                     (1) 指令bt (bit test) : 用于对比特位进行测试

                     (2) “=” :表示输出寄存器。

                     (3) 数字%n的用法:数字表示的寄存器是按照出现和从左到右的顺序映射到请求

的寄存器。   
                           那么,例子中的
%0 : __res,  %1 : 0,  %2 : bitnr, %3 :addr
                    
                     (4)
bt %2, %3 : bt会把比特位偏移量 bitnr(%2)和地址addr(%3)指定的比特位的值放入进位标志(CF)中。
                    
                     (5) 指令setb: 根据进位标志CF设置操作数%al。若CF = 1, %al = 1; CF = 0, %al = 0。
阅读(2303) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~