伪造寄存器读C语言

伪造寄存器读C语言,c,macros,embedded,arm,cpu-registers,C,Macros,Embedded,Arm,Cpu Registers,我有一个没有操作系统的嵌入式系统的现有代码库。我正在尝试使用x86GCC而不仅仅是交叉编译器来构建它,作为在主机上进行单元测试的第一步。不幸的是,到处都是直接寄存器读写,而不是使用提供的抽象层。当然,一个选择是解决这个问题;将直接寄存器访问替换为对GPIO访问函数的调用。我希望通过引入宏(仅用于x86构建)来重新定义代码片段,如 myvar = (GPIOC->IDR >> 6) & 0x03; // Read bits 6 and 7 GPIOD->CRL

我有一个没有操作系统的嵌入式系统的现有代码库。我正在尝试使用x86GCC而不仅仅是交叉编译器来构建它,作为在主机上进行单元测试的第一步。不幸的是,到处都是直接寄存器读写,而不是使用提供的抽象层。当然,一个选择是解决这个问题;将直接寄存器访问替换为对GPIO访问函数的调用。我希望通过引入宏(仅用于x86构建)来重新定义代码片段,如

myvar = (GPIOC->IDR >> 6) & 0x03;   // Read bits 6 and 7
GPIOD->CRL &= 0xFFFFFF0F;
例如:

myvar = (myGpiocIdrReadFunc() >> 6) & 0x03;   // Read bits 6 and 7
myGpiodClrWriteFunc() &= 0xFFFFFF0F;
GPIOx被定义为指向物理地址的指针。当然,如果我试图用x86构建的可执行文件直接读写PC上的地址,那将是访问冲突。不幸的是,如果我尝试这样的方法:

#define GPIOC->IDR { myGpiocIdrReadFunc() }
#ifdef USE_REAL_HW

typedef volatile uint32_t HW_REGISTER32;

#else // (USE_REAL_HW not defined)

template<class T>
class RegisterAbstractionClass {
public:
    const T operator= (const T value) {
        data = value;
        return value;
    };
    operator const T() {
        return data;
    };
    // Other operators...
protected:
    volatile T data;
};

typedef RegisterAbstractionClass<uint32_t> HW_REGISTER32;

#endif // (USE_REAL_HW)

typedef struct {
    HW_REGISTER32 IDR;
    HW_REGISTER32 CRL;
} gpio_t;
编译器不喜欢“->”,即“宏名称后缺少空格”


如果您以前解决过此类问题,您是如何解决的?

看起来您是在从字面上替换源代码中的字符串。为什么不使用非交互式编辑器,如
sed
?您可能有一个构建系统,它可以根据体系结构进行替换或不替换。

我认为这并不容易

请注意,SFR通常是易变的,许多算术运算是原子运算。那么,代码呢

GPIOD->CRL &= 0xFFFFFF0F;
不等于

setter(CLR_reg, getter(CLR_reg) & 0xFFFFFF0F);
还要注意的是,可能会有一个繁忙的等待中断的循环,甚至是中断处理程序。

您的#定义错误。在测试系统上为宏尝试“#定义mygpiocidreadfunc()x86ReadFunc()”。当然,您需要用MyGpiocIdrReadFunc()替换从GPIOC->IDR读取的所有内容。您还需要实现该功能。这可能和修复代码以使用您提到的抽象层一样多

typedef struct {
    int IDR;
    int CRL;
} gpio_t;

gpio_t c;
gpio_t d;

gpio_t * GPIOC = &c;
gpio_t * GPIOD = &d;
只要不断地向
struct
添加像
IDR
这样的寄存器,编译器就会向您发出尖叫


编辑在看到您的评论后,我编辑了答案,您实际上希望模拟值,您可以这样做,但请记住,您需要像在硬件中一样初始化这些值。

如果hexa的解决方案不够,这里有第二个选项,这允许您实际模拟所引用寄存器的行为(包括副作用等)。作为一个缺点,这需要C++(并且你现有的C代码可以编译为C++,这通常是一个困难的要求),并且结构不直接使用本地类型,而是使用一些别名。 您可以定义一个类来实现
操作符=
操作符int
,以及您可能需要的任何其他访问函数(
&=
等)。如果struct
GPIOC
中指向的字段属于您可以更改的类型,则只需更改该类型以引用您的register类即可

大致如下:

#define GPIOC->IDR { myGpiocIdrReadFunc() }
#ifdef USE_REAL_HW

typedef volatile uint32_t HW_REGISTER32;

#else // (USE_REAL_HW not defined)

template<class T>
class RegisterAbstractionClass {
public:
    const T operator= (const T value) {
        data = value;
        return value;
    };
    operator const T() {
        return data;
    };
    // Other operators...
protected:
    volatile T data;
};

typedef RegisterAbstractionClass<uint32_t> HW_REGISTER32;

#endif // (USE_REAL_HW)

typedef struct {
    HW_REGISTER32 IDR;
    HW_REGISTER32 CRL;
} gpio_t;
#ifdef使用(真实)
typedef volatile uint32\u t硬件寄存器32;
#else//(使用未定义的实际值)
模板
类RegisterAbstractionClass{
公众:
常量T运算符=(常量T值){
数据=价值;
返回值;
};
运算符常量T(){
返回数据;
};
//其他运营商。。。
受保护的:
挥发性T数据;
};
typedef RegisterAbstractionClass HW_REGISTER32;
#endif/(使用实际值)
类型定义结构{
HW_寄存器32 IDR;
HW_寄存器32 CRL;
}gpio\t;

(请注意,上面的内容有些简化:在这种情况下,
IDR
CRL
的行为相同,这可能与硬件不同。)

我假设目标不仅仅是盲目地允许I/O“成功”,而是从这样的I/O中产生副作用?否则,您可以只使用带有CRL元素的结构(GPIOD)。@Yann:我将发布相同的(re:structs)作为答案,如果您发布答案,我将+1您的答案。同意@Yann:您是要模拟硬件还是只想忽略它?你知道,通常它确实做了一些事情。我想能够设置“读取”值和检索“写入”值。哦,当然。。。定义我自己的抽象函数,当为目标构建时,它执行实际的读写操作,当为x86构建时,它执行我想要的操作。我希望避免修改原始的源代码,因为我还没有访问目标硬件以确保我没有破坏任何东西,但请小心,这可能是正确的方法。这没有任何帮助。他想假装,你说得对。也许我可以用我自己的抽象函数替换所有直接寄存器访问,然后对于交叉构建#将这些函数调用定义回直接访问中。。。啊。