C - 读取和设置汇编程序寄存器

时间:2015-12-28 08:11:04

标签: c gcc assembly cpu-registers

我需要能够从我的C代码访问汇编寄存器。我有一个简单的方法将寄存器的值设置为变量的值,并将寄存器的值作为变量??希望这是有道理的......

3 个答案:

答案 0 :(得分:3)

如果您使用的是VC(Microsoft的C编译器)

int regVal;
__asm {
  mov [regVal], eax
}

这会加载eax所持有的regVal

如果您正在使用GCC:

int regVal;
asm("movl %%eax, %0" : "=r"(regVal) :);

希望我说得对,我实际上并没有在GCC中进行内联汇编。

答案 1 :(得分:2)

如果您真的想在某些代码执行时知道寄存器的值,那么使用调试器会使很多更有意义。 (就像带有layout asm; layout reg的gdb)。在没有看到asm代码的情况下查看寄存器值也没什么意义。

请参阅 wiki中的链接和指南。

但是,使用GNU inline asm,您可以执行类似

的操作
int eax_snapshot;
asm volatile (
    ""
    : "=a" (eax_snapshot)
    // no inputs, no clobbers
);
// any amount of intervening code
printf("eax was %x\n", eax_snapshot);  // print whatever eax had at the point where the inline asm appeared in program order

The a constraint表示操作数必须使用%eax寄存器。你的内联asm的主体然后变成no-op,因为你的输出操作数已经告诉编译器了。

无法保证gcc在asm块之前不会发出代码%eax的代码。这就是为什么这样做没有多大意义。 volatile告诉编译器不要相对于其他源指令重新排序asm语句,但优化仍然意味着早期的初始化被折叠到后来使用它们的代码中。或相反亦然。结合使用this和显式寄存器局部变量可能有助于避免gcc使用您选择的寄存器作为临时寄存器来计算其他东西。 (见下文)。

要设置寄存器,请使用带有"a"约束的内联asm来强制该操作数的值位于%eax(或%ebx约束"b"等,在内联asm出现的位置查看x86特定机器约束的文档。如果你想实际使用那个寄存器值,可以从内联asm语句中进行,否则寄存器可能被别的东西覆盖。

你也可以声明必须在特定寄存器中分配的变量,但我认为在没有初始化的情况下使用它们会使编译器不满意。 (代码转换通过检测未定义的行为,例如这可能会导致问题.IDK。)语法将是

register int eax asm ("eax");  // don't do this to read eax, it probably doesn't do what you think it would

The docs make it sound like using it for reading registers is not going to be a good idea.但是,为了设置寄存器值,这应该可以正常工作。 (只要寄存器分配器接受您的提示并将该变量保存在请求的寄存器中。)

不要这样做除非你有充分的理由。它对于正常编程非常不可能有用。正常的内联asm或调用函数是组合C和asm的更好方法。这只有在你想要在你的程序的内部状态下进行某种kludgy戳时才有用。

由于您没有给出用于此的原因的用例,我强烈建议您不要编写执行此操作的代码。这听起来很难看。

答案 2 :(得分:0)

由于您使用的是gcc,以下是在gcc中使用asm模板的文档:https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#AssemblerTemplate

要设置寄存器的值,请执行以下操作:

uint64_t rax = 0;
__asm__ __volatile__("mov %0, %%rax\n\t"
                     : /* no output */
                     : "a" (rax)
                     : "%rax");

为了读取寄存器的值,您需要执行以下操作:

uint64_t rax;
__asm__ __volatile__("mov %%rax, %0\n\t"
                     : "=a"(rax)
                     : /* no input */
                     : /* no clobbers */);