我是软件故障注入领域的新研究员,目前我的最终目标是编写一段能够更改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年前一样,在单个课程单元上工作了几个月,所以目前我正在尝试回顾一下我对该语言的一点知识。
答案 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的一些注意事项:
答案 1 :(得分:2)
基于Intel的处理器提供一次操作一位的指令。这些指令通常被忽略,并由AND
,OR
,XOR
和TEST
指令替代,这些指令可以同时处理多个位。旧的处理器也会真的慢地执行它们。我不知道他们是否仍然很慢,可能不是。
相应的汇编指令是(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在执行读/修改/写入循环时访问该内存。)因此它可用于创建锁和信号量。