将寄存器值读入 C 变量 [英] Reading a register value into a C variable

查看:31
本文介绍了将寄存器值读入 C 变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我记得看到一种使用扩展 gcc 内联汇编读取寄存器值并将其存储到 C 变量中的方法.

我终其一生都不记得如何形成 asm 语句.

解决方案

编者注:这种使用本地 register-asm 变量的方式是 现在被 GCC 记录为不支持".它通常仍然可以在 GCC 上工作,但会因叮当声而中断.(我认为,文档中的这个措辞是在发布此答案后添加的.)

全局固定寄存器变量版本对于32位x86来说性能开销很大,只有7个GP-integer寄存器(不算栈指针).这会将其减少到 6.仅当您有一个所有代码都大量使用的全局变量时才考虑这一点.


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

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

<块引用>

register int *foo asm ("a5");

这里a5是应该使用的寄存器的名字……

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

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

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

<块引用>

-ffixed-reg

<块引用>

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

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

int main() {register int i asm(ebx");返回 i + 1;}

尽管这毫无意义,因为您不知道 ebx 寄存器中的内容.

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

#include register int counter asm(ebx");无效检查(int n){如果 (!(n % 2 && n % 3 && n % 5)) 计数器++;}int main() {国际我;计数器 = 0;for (i = 1; i <= 100; i++) check(i);printf(%d 个介于 1 和 100 之间的汉明数
",计数器);返回0;}

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

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

I remember seeing a way to use extended gcc inline assembly to read a register value and store it into a C variable.

I cannot though for the life of me remember how to form the asm statement.

解决方案

Editor's note: this way of using a local register-asm variable is now documented by GCC as "not supported". It still usually happens to work on GCC, but breaks with clang. (This wording in the documentation was added after this answer was posted, I think.)

The global fixed-register variable version has a large performance cost for 32-bit x86, which only has 7 GP-integer registers (not counting the stack pointer). This would reduce that to 6. Only consider this if you have a global variable that all of your code uses heavily.


Going in a different direction than other answers so far, since I'm not sure what you want.

GCC Manual § 5.40 Variables in Specified Registers

register int *foo asm ("a5");

Here a5 is the name of the register which should be used…

Naturally the register name is cpu-dependent, but this is not a problem, since specific registers are most often useful with explicit assembler instructions (see Extended Asm). Both of these things generally require that you conditionalize your program according to cpu type.

Defining such a register variable does not reserve the register; it remains available for other uses in places where flow control determines the variable's value is not live.

GCC Manual § 3.18 Options for Code Generation Conventions

-ffixed-reg

Treat the register named reg as a fixed register; generated code should never refer to it (except perhaps as a stack pointer, frame pointer or in some other fixed role).

This can replicate Richard's answer in a simpler way,

int main() {
    register int i asm("ebx");
    return i + 1;
}

although this is rather meaningless, as you have no idea what's in the ebx register.

If you combined these two, compiling this with 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
", counter);
    return 0;
}

you can ensure that a C variable always uses resides in a register for speedy access and also will not get clobbered by other generated code. (Handily, ebx is callee-save under usual x86 calling conventions, so even if it gets clobbered by calls to other functions compiled without -ffixed-*, it should get restored too.)

On the other hand, this definitely isn't portable, and usually isn't a performance benefit either, as you're restricting the compiler's freedom.

这篇关于将寄存器值读入 C 变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆