简体   繁体   中英

C / Assembly: how to change a single bit in a CPU register?

I'm a new researcher on the software fault injection field, and currently my ultimate goal is to write a simple piece of code that is able to change a single bit in a CPU register. I was thinking of doing it in C (with some Assembly calls included amongst the code). With that in mind, I found here in Stack Overflow this great thread & simple example on how to access the contents of a 32 bit CPU register: Is it possible to access 32-bit registers in C? This way, I was able to write this simple code:

#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;
}

This seems to be a great introduction to this theme, and the answers provided there gave me great insight and information sources (I'm already reading the GCC documentation), but now I need to move further, ie, I need to understand how can I change the contents of a single bit in a CPU register (or at least, to start, something simpler: how can I change a CPU register value?). If someone can give me a hint or tell me the most approriate source to look for it, I'd be deeply grateful.

All the best & thanks in advance, João

PS: Don't know if this helps, but I'm working on a CentOS 6.5 32 bit system (although the CPU is a 64 bit one, more precisely a Intel Pentium Dual CPU E2180 @ 2.00 GHz). Also, I have had previous contact with Assembly, but it was like 10 years ago, on a single course unit for a couple of months, so currently I'm trying to review the little knowledge I have on the language.

The usual way of modifying a subset of the bits of a register in assembly is to use logical operations with constants.

AND %eax, 0xFFFFFFFE unsets the 0th bit.

OR %eax, 0x01 sets the 0th bit.

XOR %eax, 0x01 flips the 0th bit.

(thanks @harold for the corrections).

That being said, and as noted in the comments, you probably don't want to directly use inline assembly in the program to simulate hardware faults. It will be tightly bound to the place where you introduced the modification, and mixing fault introduction at the source and at the binary level is not an approach I would recommend (your compiler can and will reorganize and optimize code, so it is likely that it will ultimately lead to unexpected behavior. See . Balakrishnan's and Reps' What You See Is Not What You eXecute).

you could use a binary instrumentation platform such as Intel's PIN or an existing fault injection framework.

EDIT: Since OP asked for a "hello world" example of inline asm in comments, here it is:

#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;
}

Save as test.c then compile with:

gcc test.c -o test

or better:

gcc test.c -S

which will create test.s, a file containing the assembly output of your program. This file will let you understand many things about your code, and you should produce the assembly before compiling when using inline asm (at least when there is something you don't understand).

You can then assemble the binary from the assembly with:

gcc test.s -o test

Here are a few things to note on x86:

  • In actual instructions, I put the destination register at the end of the instruction.
  • Immediate are prefixed with "$", registers with a "%"
  • The instructions that manipulate extended registers (32 bits registers, prefixed with "e") are suffixed with "l"

The Intel-based processors offers instructions to manipulate one bit at a time. These instructions are most often ignored and replaced by the AND , OR , XOR , and TEST instructions which can manipulate multiple bits at once. Also older processors would be really slow executing them. I do not know whether they are still slow, probably not.

The corresponding assembly instructions are (AT&T syntax)

Test a bit (CF = bit value):

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

Test and complement (CF = old bit value; new bit value = ~old bit value):

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

Test and reset (CF = old bit value; new bit value = 0)

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

Test and set (CF = old bit value; new bit value = 1)

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

When used against memory, it can be used atomically (only one CPU accessing that memory while doing the read / modify / write cycle.) So it can be used to create locks and semaphores.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM