【问题标题】:Intel x86-64 XSAVE/XRSTOR英特尔 x86-64 XSAVE/XRSTOR
【发布时间】:2014-04-02 01:12:48
【问题描述】:

我是一名 CS 学生,正在编写 Intel x86-64 程序集,使用 nasm 进行编译,并在以 Ubuntu 12.04 作为客户操作系统的 Core i7 处理器上运行。有没有人有一个如何使用XSAVEXRSTOR 的例子?我已经多次阅读英特尔架构软件开发人员手册中关于XSAVE 的部分。我尝试在 C++ 中实现xsave,然后反汇编二进制文件以了解它在做什么。当然,我已经在 Internet 上搜索了示例。如有任何建议,我们将不胜感激。

【问题讨论】:

  • 您是在问XSAVEXRSTOR 是做什么的,或者如何使用它们?
  • 嗨杰森,感谢您的询问。我对实现更感兴趣。我和我的同学已经厌倦了 100 行左右的代码来备份注册表并在每个作业中恢复它们。更不用说 XSAVE 可能比挑选要备份的注册表更有效。
  • 该实现是特定于硬件的,但通常它在 fpu 和 simd 寄存器中获取值,并将它们的值存储/恢复到内存中。您必须阅读 cpuid 信息以了解有关您的 cpu 存储内容和位置的详细信息。它主要用于操作系统以支持进程的快速上下文切换。这有帮助吗?
  • 谢谢。我了解基于 CPUID 标志检查 XSAVE 支持的过程,但我不知道如何实现 XSAVE。
  • 你的意思是执行指令吗?您要在内存中保存/恢复哪些寄存器?你的代码是用户空间还是内核空间?我不确定您所说的 implement 是什么意思。这些指令已经在硬件中实现。

标签: assembly x86-64


【解决方案1】:

xsave/xrstor/xsaveopt 指令用于将处理器中的扩展状态完全保存/恢复到内存或从内存中恢复。类似于fxsave/fxrstor,除了支持ymm[0..15]和未来的扩展(zmm[0..31])之外,它还保存/恢复fpu状态st[0..7]xmm[0..7]mxcsr等。保存的实际值和数据布局通过相关的cpuid 叶枚举。使用一般是操作系统context switchingprogrammer reference 描述了如何正确使用它们。

对于一般的用户空间寄存器保存/恢复,汇编程序通常具有保存/恢复一组寄存器的功能。

例如...

masm

foo PROC USES eax,ebx,ecx
    xor    ebx, ebx

loop:
    mov    eax, [esi + ebx*4]
    mov    [edi + ebx*4], eax
    inc    ebx
    dec    ecx

    jnz    loop

    ret

foo ENDP

yasm

%macro  mpush 1-*

  %rep  %0
        push    %1
  %rotate 1
  %endrep

%endmacro

%macro  mpop 1-*

  %rep %0
  %rotate -1
        pop     %1
  %endrep

%endmacro


foo:
    mpush  rax,rbx,rcx
    xor    rbx, rbx

loop:
    mov    rax, [rsi + rbx*8]
    mov    [rdi + rbx*8], rax
    inc    rbx
    dec    rcx

    jnz    loop

    mpop   rax,rbx,rcx
    ret

在 ia-32 中,有一个 pushad 来保存所有通用寄存器,但是对于 amd64,您需要为您使用的每个寄存器有对应的 push/pop 对。

【讨论】:

  • 这太好了,谢谢杰森。我正在期中考试,所以我会尽快消化您的回复。如果有人有任何示例,我仍然对 XSAVE 和 XRSTOR 感到好奇。我注意到 gcc 4.8 现在有 -XSAVE 和 -XRSTOR 标志。我还没有让它工作,但我猜 gcc 只是将你的代码包装在适当的汇编指令中。似乎我应该能够使用这些参数进行编译并查看程序集。
  • 没问题。编译器选项只是让编译器知道它可以发出指令。除非您编写程序集,否则您可能需要在编译器参考中查找内在函数才能实际使用它们。可能,找到使用的xrstor/xsave/xsaveopt 的好例子的最佳位置是 linux 内核源代码本身。祝你期中考试好运。
【解决方案2】:

最后,这个问题的答案。感谢用户:harold 帮我回答了这个问题。我发现的总结:

在 .data 中设置一个内存空间,并在 64 字节边界上对齐。然后您可以使用该内存空间的命令。如果你想使用堆栈,你应该能够以类似的方式确保堆栈是 64 字节对齐的,但这种方式对我来说似乎更容易实现这一目的。

eax:edx 用于设置您想要保存、恢复的寄存器的标志。这个组合是 64 位的,并且与一个内部控件进行了与运算,该内部控件知道您可以保存/恢复哪些寄存器(这允许例如没有 ymm 的处理器忽略这些寄存器)我发现将所有位设置为最简单的和保存/恢复一切:

段.data

align   64
regsave times 1024 dq 0

段 .text

mov     rdx, 0xFFFFFFFFFFFFFFFF
mov     rax, 0xFFFFFFFFFFFFFFFF
xsave   [regsave]

vzeroall

mov     rdx, 0xFFFFFFFFFFFFFFFF
mov     rax, 0xFFFFFFFFFFFFFFFF
xrstor  [regsave]

【讨论】:

  • (vzeroall 只是更改寄存器的临时代码示例。)
  • 太棒了!谢谢 C_Rod 和哈罗德。代码效果很好。我期待该命令备份通用寄存器,但显然它只是备份的浮点寄存器。在这和 Jason 的回复之间,我们应该能够相当有效地备份两者。再次感谢!
猜你喜欢
  • 1970-01-01
  • 2013-02-24
  • 1970-01-01
  • 2012-02-25
  • 1970-01-01
  • 1970-01-01
  • 2018-10-15
  • 2012-11-01
相关资源
最近更新 更多