C /汇编:如何更改CPU寄存器中的单个位?

时间:2014-07-17 14:35:12

标签: c gcc assembly inline-assembly cpu-registers

我是软件故障注入领域的新研究员,目前我的最终目标是编写一段能够更改CPU寄存器中单个位的代码。我想用C语言(在代码中包含一些程序集调用)。考虑到这一点,我在Stack Overflow中找到了这个伟大的线程&关于如何访问32位CPU寄存器内容的简单示例:Is it possible to access 32-bit registers in C?这样,我就能编写这个简单的代码:

#include <stdio.h>

int main()
{
    register int value;

    register int ecx asm("ecx");
    printf("Contents of ecx: %d\n", ecx);

    asm("movl %%ecx, %0;" : "=r" (value) : ); //Assembly: this stores the ecx value into the variable value
    printf("Contents of value: %d\n", value);

    return 0;
}

这似乎是对这个主题的一个很好的介绍,那里提供的答案给了我很好的见解和信息来源(我已经阅读了GCC文档),但现在我需要进一步,我。例如,我需要了解如何更改CPU寄存器中单个位的内容(或者至少,要启动,更简单:如何更改CPU寄存器值?)。如果有人可以给我一个提示或告诉我最合适的来源,我会非常感激。

一切顺利&amp;提前致谢, 若昂

P.S。:不知道这是否有帮助,但我正在使用CentOS 6.5 32位系统(虽然CPU是64位,更准确地说是Intel Pentium双CPU E2180 @ 2.00 GHz)。此外,我之前曾与大会有过接触,但就像10年前一样,在单个课程单元上工作了几个月,所以目前我正在尝试回顾一下我对该语言的一点知识。

2 个答案:

答案 0 :(得分:3)

在汇编中修改寄存器位子集的常用方法是使用带常量的逻辑运算。

AND %eax, 0xFFFFFFFE取消第0位。

OR %eax, 0x01设置第0位。

XOR %eax, 0x01翻转第0位。

(感谢@harold进行更正)。

话虽如此,正如评论中所述,您可能不希望在程序中直接使用内联汇编来模拟硬件故障。它将与您引入修改的位置紧密绑定,并且在源和二进制级别混合故障引入不是我建议的方法(您的编译器可以并将重新组织和优化代码,因此很可能是最终会导致出乎意料的行为。请参阅.Balakrishnan和Reps'你所看到的不是你所执行的行为。)

您可以使用二进制检测平台,例如Intel的PIN或现有的故障注入框架。

修改 由于OP在评论中要求内联asm的“hello world”示例,因此它是:

#include <stdlib.h>
#include <stdio.h>

int main()
{
    register int eax asm("%eax");
    asm("xorl %eax, %eax");
    asm("xorl $1, %eax");
    printf("Content of eax: %d\n", eax);
    return 0;
}

另存为test.c,然后使用:

进行编译
gcc test.c -o test

或更好:

gcc test.c -S

将创建test.s,这是一个包含程序汇编输出的文件。此文件将让​​您了解有关代码的许多内容,并且您应该在使用内联asm进行编译之前生成程序集(至少在您不理解的情况下)。

然后,您可以使用以下组件从程序集中组装二进制文件:

gcc test.s -o test

以下是关于x86的一些注意事项:

  • 在实际指令中,我将目标寄存器放在指令的末尾。
  • 立即以“$”为前缀,以“%”
  • 注册
  • 操作扩展寄存器的指令(32位寄存器,前缀为“e”)后缀为“l”

答案 1 :(得分:2)

基于Intel的处理器提供一次操作一位的指令。这些指令通常被忽略,并由ANDORXORTEST指令替代,这些指令可以同时处理多个位。旧的处理器也会真的慢地执行它们。我不知道他们是否仍然很慢,可能不是。

相应的汇编指令是(AT&amp; T语法)

测试一下(CF =位值):

BT imm8, reg
BT reg, reg
BT reg, mem

测试和补码(CF =旧位值;新位值=〜旧位值):

BTC imm8, reg
BTC reg, reg
BTC reg, mem

测试和复位(CF =旧位值;新位值= 0)

BTR imm8, reg
BTR reg, reg
BTR reg, mem

测试并设置(CF =旧位值;新位值= 1)

BTS imm8, reg
BTS reg, reg
BTS reg, mem

当用于内存时,它可以原子使用(只有一个CPU在执行读/修改/写入循环时访问该内存。)因此它可用于创建锁和信号量。