将寄存器值读入C变量

Bri*_*ian 40 c assembly gcc inline-assembly cpu-registers

我记得有一种方法可以使用扩展的gcc内联汇编来读取寄存器值并将其存储到C变量中.我不能为我的生活记住如何形成asm陈述.任何帮助深表感谢.

eph*_*ent 31

到目前为止,与其他答案的方向不同,因为我不确定你想要什么.

GCC手册§5.40指定寄存器中的变量

register int *foo asm ("a5");
Run Code Online (Sandbox Code Playgroud)

a5是应该使用的寄存器的名称......

当然,寄存器名称是依赖于cpu的,但这不是问题,因为特定的寄存器通常对显式汇编程序指令很有用(参见Extended Asm).这两件事通常都要求您根据cpu类型对程序进行条件化.

定义这样的寄存器变量不会保留寄存器; 在流量控制确定变量的值不是活动的地方,它仍可用于其他用途.

GCC手册§3.18代码生成约定的选项

-ffixed-REG

将名为reg的寄存器视为固定寄存器; 生成的代码永远不应该引用它(除了可能作为堆栈指针,帧指针或其他一些固定的角色).

这可以用更简单的方式复制理查德的答案,

int main() {
    register int i asm("ebx");
    return i + 1;
}
Run Code Online (Sandbox Code Playgroud)

虽然这是毫无意义的,因为你不知道ebx寄存器里有什么.

如果你把这两个结合起来,用这个来编译gcc -ffixed-ebx,

#include <stdio.h>
register int counter asm("ebx");
void check(int n) {
    if (!(n % 2 && n % 3 && n % 5)) counter++;
}
int main() {
    int i;
    counter = 0;
    for (i = 1; i <= 100; i++) check(i);
    printf("%d Hamming numbers between 1 and 100\n", counter);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

您可以确保C变量始终使用驻留在寄存器中以便快速访问,也不会被其他生成的代码破坏.(很方便,ebx在通常的x86调用约定下是被调用者保存的,所以即使它被调用没有编译的其他函数搞砸了,-ffixed-*它也应该被恢复.)

另一方面,这绝对不是可移植的,并且通常也不是性能优势,因为你限制了编译器的自由.


Ric*_*ton 20

以下是获取ebx的方法:

int main()
{
    int i;
    asm("\t movl %%ebx,%0" : "=r"(i));
    return i + 1;
}
Run Code Online (Sandbox Code Playgroud)

结果:

main:
    subl    $4, %esp
    #APP
             movl %ebx,%eax
    #NO_APP
    incl    %eax
    addl    $4, %esp
    ret
Run Code Online (Sandbox Code Playgroud)


编辑:

"= r"(i)是输出约束,告诉编译器第一个输出(%0)是应该放在变量"i"中的寄存器.在此优化级别(-O5),变量i永远不会存储到存储器中,而是保存在eax寄存器中,该寄存器恰好也是返回值寄存器.

  • 我会使用`= rm`约束而不是`= r`.编译器的优化器将尝试选择最佳路径.如果内联汇编程序恰好处于寄存器饥饿状态,则`= r`可能会强制它生成不太理想的代码.如果它恰好是最佳选择,`= rm`将为优化器提供使用内存引用的机会.在这个简单的例子中,它不会是一个问题,但如果代码处于更复杂的情况,那么为编译器提供选项可能是有益的. (2认同)

Jac*_*cob 6

我不知道gcc,但在VS中这是如何:

int data = 0;   
__asm
{
    mov ebx, 30
    mov data, ebx
}
cout<<data;
Run Code Online (Sandbox Code Playgroud)

基本上,我将数据移动ebx到您的变量中data.

  • 为什么不只是`mov data,30`? (2认同)

R S*_*hko 5

这会将堆栈指针寄存器移动到 sp 变量中。

intptr_t sp;
asm ("movl %%esp, %0" : "=r" (sp) );
Run Code Online (Sandbox Code Playgroud)

只需将 'esp' 替换为您感兴趣的实际寄存器(但确保不要丢失 %%),并将 'sp' 替换为您的变量。


Kor*_*icz -1

不是您要找的吗?

句法:

 asm ("fsinx %1,%0" : "=f" (result) : "f" (angle));
Run Code Online (Sandbox Code Playgroud)