Chinaunix首页 | 论坛 | 博客
  • 博客访问: 362959
  • 博文数量: 38
  • 博客积分: 1935
  • 博客等级: 上尉
  • 技术积分: 724
  • 用 户 组: 普通用户
  • 注册时间: 2005-11-23 16:34
文章存档

2010年(4)

2009年(33)

2008年(1)

分类:

2009-05-03 23:40:21

6.1.4、  long mode 下的 call gate


6.1.4.1、 64 位的 call gate descriptor 中已经不支持 parameter count 域,offset 域被扩展至 64 位 base 值。


情景提示:
  64 位的 call gate descriptor 的中 selector 域必须是一个 64 位代码的 selector,也就是说:这个 selector 指向的 code segment descriptor 中的 L 属性必须是 1,并且 default operand size 为 32 位,即:D 属性为 0。否则将产生 #GP 异常。(L = 1 && D = 0)
  若要转到 32 位代码,须使用 32 位的 call gate descriptor。


  由于 64 位的 call gate descriptor 中不支持 parameter count 域,所以在 long mode 下,processor 不支持自动复制参数的行为(从 caller 的 stack 复制到 callee 的 stack 中)。

那么,在 long mode 下如何使用 call gate 调用例程时,如果确实需要传递参数,又是如何传递参数呢?  

  在 stack 不进行切换的情况下,和一般的例程调用别无两样。在要进行 stack 切换的情形下,原来的 stack 的 ss 和 rsp 值被保存至新的 stack 中(也就是 caller 的 ss 和 rsp 会保存至 callee 的 stack 中)。那么,例程 callee 将直将使用原来的 rsp 去获取参数。
  这样做的根本原因是,在 x64 的 long mode 下在硬件级下使用的是平坦内存管理模式,忽略了 segmentation 管理,callee 将可以直接使用 rsp 来获取参数。


看看下面的指令的情形:

caller: 
    ... ...
  push param1
  push param2 
    call [call_gate]            /* call gate */
  ... ...


  caller 中用 call gate 进行调用例程 callee, 假设这里需要进行 stack 的切换。


callee:

   ret         


  callee 中仅使用 ret 进行返回,无需进行清栈处理。


那么:
  caller 的 ss 和 rsp 将被保存至 callee 的 stack 中,如下:

------------------
     caller's SS       + 24
------------------
    caller's RSP      + 16
------------------
    caller's CS       + 8
------------------
    caller's RIP         <------------   callee's  rsp
------------------
 ... ...
------------------

  在例程 callee 中 [rsp+16] 处获取 caller's rsp 值,callee 中如下处理:

  push rbp
      mov rbp, rsp
      mov rax, [rbp + 24]           /* get caller's rsp */
      mov rbx, [rax]                   /* get param1  */
      ... ...

      和一般的调用例程,使用参数无异,不像 x86 下使用 call gate 调用例程,processor 会自动产生复制参数行为。



6.1.4.2、 前面提过,call gate 只能存放在 GDT / LDT 中,不能放在 IDT 中
  这造成 64 位的 call gate descriptors 的高 8 字节的 type 属性必须为 0000,以避免 32 位的 descriptor 与 64 位的 descriptors 重叠在一起。为 0 的 type 是属于无效的 descriptors 类型,processor 会检测这个 type 是否为 0,为 0 则是无效的 descriptors。
  这样的话,想提取 64 位的 descriptors 的高半部分作为 32 位 descriptors 使用就会产生一个 #GP 异常。
阅读(1018) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~