Jer*_*fin 60
我可能会为每个写一个小的包装类:
template <class T>
class read_only {
T volatile *addr;
public:
read_only(int address) : addr((T *)address) {}
operator T() volatile const { return *addr; }
};
template <class T>
class write_only {
T volatile *addr;
public:
write_only(int address) : addr ((T *)address) {}
// chaining not allowed since it's write only.
void operator=(T const &t) volatile { *addr = t; }
};
Run Code Online (Sandbox Code Playgroud)
至少假设你的系统有一个合理的编译器,我希望这两个都得到优化,所以生成的代码与使用原始指针无法区分.用法:
read_only<unsigned char> x(0x1234);
write_only<unsigned char> y(0x1235);
y = x + 1; // No problem
x = y; // won't compile
Run Code Online (Sandbox Code Playgroud)
我会使用结构组合来覆盖寄存器和一对函数来处理它们.
在一个fpga_register.h你会有类似的东西
#define FPGA_READ = 1;
#define FPGA_WRITE = 2;
typedef struct register_t {
char permissions;
} FPGARegister;
FPGARegister* fpga_init(void* address, char permissions);
int fpga_write(FPGARegister* register, void* value);
int fpga_read(FPGARegister* register, void* value);
Run Code Online (Sandbox Code Playgroud)
使用xor中的READ和WRITE来表达权限.
比在fpga_register.c你定义一个新的结构
typedef struct register_t2 {
char permissions;
void * address;
} FPGARegisterReal;
Run Code Online (Sandbox Code Playgroud)
以便您返回指向它的指针而不是指向FPGARegisteron 的指针fpga_init.
然后,打开fpga_read并fpga_write检查权限和
FPGARegister则将参数从a转换为a FPGARegisterReal,执行所需的操作(设置或读取值)并返回成功代码这样,包括头文件在内的任何人都不能访问该FPGARegisterReal结构,因此它不能直接访问寄存器地址.显然,人们可以破解它,但我很确定这种故意的黑客行为不是你真正关心的问题.
我曾经使用过很多硬件,其中一些硬件只有"只读"或"只写"寄存器(或者根据你是否读取或写入寄存器而使用不同的函数,当有人决定这样做时,这会很有趣) reg | = 4;"而不是记住它应该具有的值,设置第2位并写入新值,就像你应该的那样.没有什么比尝试调试具有随机位的硬件而从你无法读取的寄存器中消失的东西!到目前为止,我还没有看到任何实际阻止从只写寄存器读取或写入只读寄存器的尝试.
顺便说一句,我是否说过具有"只写"的寄存器是一个非常糟糕的主意,因为你无法读回来检查软件是否正确设置了寄存器,这使调试变得非常困难 - 以及编写驱动程序的人不喜欢通过两行VHDL或Verilog代码来调试可以变得非常简单的难题.
如果您对寄存器布局有一定的控制权,我建议您将"readonly"寄存器放在4KB对齐的地址上,将"writeonly"寄存器放在另一个4KB对齐的地址中[超过4KB就可以了].然后,您可以编程硬件的内存控制器以防止访问.
或者,如果正在读取不应该读取的寄存器,或者写入不应写入的寄存器,则让硬件产生中断.我认为硬件确实会产生其他用途的中断?
使用各种C++解决方案提出的其他建议很好,但它并没有真正阻止那些有意直接使用寄存器的人,所以如果它真的是一个安全问题(而不是"让它变得尴尬"),那么你应该有硬件,以防止滥用硬件.
在C中,您可以使用指向不完整类型的指针来阻止所有解除引用:
/* writeonly.h */
typedef struct writeonly *wo_ptr_t;
Run Code Online (Sandbox Code Playgroud)
/* writeonly.c */
#include "writeonly.h"
struct writeonly {
int value
};
/*...*/
FOO_REGISTER->value = 42;
Run Code Online (Sandbox Code Playgroud)
/* someother.c */
#include "writeonly.h"
/*...*/
int x = FOO_REGISTER->value; /* error: deref'ing pointer to incomplete type */
Run Code Online (Sandbox Code Playgroud)
只有writeonly.c,或者通常任何具有定义的代码都struct writeonly可以取消引用指针.当然,该代码也可能意外地读取该值,但至少所有其他代码都被阻止将所有指针解除引用,同时能够传递这些指针并将它们存储在变量,数组和结构中.
writeonly.[ch] 可以提供写入值的功能.
我没有看到在C中做到这一点的优雅方式.但我确实看到了这样做的方法:
#define DEREF_PTR(type, ptr) type ptr; \
typedef char ptr ## _DEREF_PTR;
#define NO_DEREF_PTR(type, ptr) type ptr; \
#define DEREFERENCE(ptr) \
*ptr; \
{ptr ## _DEREF_PTR \
attempt_to_dereference_pointer_ ## ptr;}
int main(int argc, char *argv[]) {
DEREF_PTR(int*, x)
NO_DEREF_PTR(int*, y);
DEREFERENCE(x);
DEREFERENCE(y); // will throw an error
}
Run Code Online (Sandbox Code Playgroud)
这样可以为您提供静态错误检查.当然,使用这种方法,你必须出去修改所有指针声明才能使用宏,这可能不是很有趣.
编辑: 如评论中所述.
#define READABLE_PTR(type, ptr) type ptr; \
typedef char ptr ## _READABLE_PTR;
#define NON_READABLE_PTR(type, ptr) type ptr; \
#define GET(ptr) \
*ptr; \
{ptr ## _READABLE_PTR \
attempt_to_dereference_non_readable_pointer_ ## ptr;}
#define SET(ptr, value) \
*ptr = value;
int main(int argc, char *argv[]) {
READABLE_PTR(int*, x)
NON_READABLE_PTR(int*, y);
SET(x, 1);
SET(y, 1);
int foo = GET(x);
int bar = GET(y); // error
}
Run Code Online (Sandbox Code Playgroud)