lock指令

今天看源码发现了一条以前没关注的汇编指令lock,查了一篇日志,解释比较清除,转来参考。

以下为转载内容:

转载地址:http://ooooooo.blogbus.com/logs/1357939.html

今天看L4的代码,其中一个名为L4_KernelInterface的API让我迷惑了很久。其实现如下:

void * L4_KernelInterface(
         L4_Word_t *ApiVersion,
         L4_Word_t *ApiFlags,
         L4_Word_t *KernelId
         )
{
void * base_address;

__asm__ __volatile__ (
         " lock; nop"
         : /* outputs */
         "=a" (base_address),
         "=c" (*ApiVersion),
         "=d" (*ApiFlags),
         "=S" (*KernelId)
         /* no inputs */
         /* no clobbers */
         );

         return base_address;
}

整个函数的核心就是一条内联汇编语句,而汇编指令只有一条:

lock; nop

我们知道,lock是一个指令前缀,Intel的手册上对其的解释是:

Causes the processor's LOCK# signal to be asserted during execution of the accompanying instruction (turns the instruction into an atomic instruction). In a multiprocessor environment, the LOCK# signal insures that the processor has exclusive use of any shared memory while the signal is asserted.

真正的指令是nop,nop指令是一条什么也不干的指令,意思是no operation,一般用来做指令对齐。

所以,从代码上看,你无论如何都不明白,为什么一条什么也不干的指令最后,可以通过eax来得到KernelInterface的基地址。

由于我们看到的是C语言语句,有可能编译器做了一些我们看不到的事情,所以我们应该检查一下生成的汇编:

push   %ebp         
mov    %esp,%ebp
push   %esi
push   %ebx
sub    $0xc,%esp    #为base_address分配空间
lock nop            #C代码中的内联汇编
mov    %edx,%ebx
mov    0x8(%ebp),%edx
mov    %ecx,(%edx)  # *ApiVersion = %ecx
mov    0xc(%ebp),%edx
mov    %ebx,(%edx)  # *ApiFlags = %edx
mov    0x10(%ebp),%edx
mov    %esi,(%edx)  # *KernelId = %esi
add    $0xc,%esp
pop    %ebx
pop    %esi
leave
ret                 # return %eax
mov    %esi,%esi

从汇编代码中看不出任何倪端,因为生成的代码正是C语言所表达的意思。那问题到底出在哪儿?难道有鬼了不成?

仔细查看一下源代码,难道lock本身可能会导致异常?然后异常处理程序会改变%eax, %ecx, %edx和%esi的值?

赶紧再翻出IA-32的指令手册,果然,上面写着:

An undefined opcode exception will be generated if the LOCK prefix is used with any other instruction except ADD, ADC, AND, BTC, BTR, BTS, CMPXCHG,DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, and XCHG.

原来如此,赶紧搜索一个L4的异常处理程序,果然看到了下面代码段:

case 0xf0: /* lock prefix */
     if (space->get_from_user(addr_offset(addr, 1)) == 0x90)
     {
          /* lock; nop */
          frame->eax = (u32_t)space->get_kip_page_area().get_base();
          frame->ecx = get_kip()->api_version;
          frame->edx = get_kip()->api_flags;
          frame->esi = get_kip()->get_kernel_descriptor()->kernel_id.get_raw();
          frame->eip+= 2;
          return;
      }

真相终于大白。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值