programing

쓰기 전용 포인터 유형

yoursource 2022. 8. 13. 12:40
반응형

쓰기 전용 포인터 유형

임베디드 시스템용 소프트웨어를 만들고 있습니다.

포인터를 사용하여 FPGA 디바이스의 레지스터에 액세스하고 있습니다.
일부 레지스터는 읽기 전용이고 다른 레지스터는 쓰기 전용입니다.

읽기 전용 레지스터는 읽을 때 정의되지 않은 값을 생성합니다.

컴파일러가 쓰기 전용 레지스터에서 값을 읽을 때 탐지할 수 있는 포인터 유형을 정의합니다(예: 참조).

C 언어 구문만 사용하여 쓰기 전용 포인터를 만들 수 있습니까?
(C를 사용하여 1차 시제품을 개발 중이지만, 2세대부터는 C++로 이행합니다.)

C++에서 효율적인 쓰기 전용 포인터를 작성하려면 어떻게 해야 합니까?(이것은 동적 메모리 내의 항목을 추적하는 것이 아니라 하드웨어 주소에 액세스하는 것입니다).

이 코드는 안전과 품질이 가장 중요한 임베디드 시스템에서 사용됩니다.

아마 각각에 대해 작은 래퍼 클래스를 작성할 것입니다.

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

적어도 당신의 시스템이 합리적인 컴파일러를 가지고 있다고 가정한다면, 나는 이 두 가지 모두를 최적화해서 생성된 코드를 원시 포인터와 구별할 수 없을 것이라고 예상한다.사용방법:

read_only<unsigned char> x(0x1234);
write_only<unsigned char> y(0x1235);

y = x + 1;         // No problem

x = y;             // won't compile

저는 많은 하드웨어로 작업해 왔습니다만, 그 중 일부는 "읽기 전용" 또는 "쓰기 전용" 레지스터(또는 레지스터에 읽기 또는 쓰기 여부에 따라 다른 함수)를 가지고 있습니다.이러한 함수는 누군가가 값을 기억하는 대신 "reg |= 4;"를 실행하기로 결정했을 때 재미를 줍니다. 비트 2를 설정하고 새 값을 씁니다.판독할 수 없는 레지스터에서 랜덤 비트가 표시되거나 표시되지 않는 하드웨어를 디버깅하는 것 같은 것은 없습니다!) 지금까지 쓰기 전용 레지스터로부터의 읽기나 읽기 전용 레지스터에의 쓰기를 실제로 차단하는 시도는 본 적이 없습니다.

덧붙여서, 「쓰기 전용」의 레지스터를 가지는 것은 정말로 나쁜 생각입니다.왜냐하면 소프트웨어가 레지스터를 올바르게 설정했는지 확인하기 위해서 판독을 할 수 없기 때문에, 디버깅이 매우 어려워집니다.드라이버를 쓰는 사람은 VHDL 또는 Verilog 코드의 2행으로 간단하게 할 수 있는 어려운 문제를 디버깅하는 것을 좋아하지 않기 때문입니다.

레지스터 레이아웃을 어느 정도 제어할 수 있다면, 4KB로 정렬된 주소에 "읽기 전용" 레지스터를 배치하고 다른 4KB로 정렬된 주소에 "쓰기 전용" 레지스터를 배치하는 것이 좋습니다.그런 다음 접근을 방지하도록 하드웨어의 메모리 컨트롤러를 프로그래밍할 수 있습니다.

또는 읽으면 안 되는 레지스터가 읽혀지거나 쓰이면 안 되는 레지스터가 쓰여지면 하드웨어가 인터럽트를 발생시킵니다.하드웨어는 다른 목적으로 인터럽트를 발생시키나요?

다양한 C++ 솔루션을 사용하는 다른 제안도 괜찮지만, 레지스터를 직접 사용하는 것을 꺼리는 것은 아니기 때문에 ('어색하게 하자'가 아니라) 정말 안전상의 문제라면 하드웨어 오용으로부터 보호할 수 있는 하드웨어가 필요합니다.

레지스터를 복원하기 위한 구조와 그것들을 처리하기 위한 함수 쌍을 조합하여 사용합니다.

①의 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);

또는 xor에서 READ 및 WRITE를 사용하여 권한을 표현합니다.

서서 the fpga_register.c합니다.

typedef struct register_t2 {
    char permissions;
    void * address;
} FPGARegisterReal;

.FPGARegisterfpga_init.

러......에...fpga_read ★★★★★★★★★★★★★★★★★」fpga_write하고 ""를 선택합니다.

  • 수 있습니다.FPGARegisterFPGARegisterReal 액션을하여 성공 인 "Success Code"를
  • 작업이 허용되지 않으면 오류 코드를 반환합니다.

하면 한 어느 도 ""에 수 .FPGARegisterReal따라서 레지스터 주소에 직접 액세스할 수 없습니다.물론 해킹도 가능하겠지만, 그런 고의적인 해킹은 당신의 실제 관심사가 아니라고 확신합니다.

C에서는 불완전한 유형에 대한 포인터를 사용하여 모든 비참조를 방지할 수 있습니다.


/* writeonly.h */
typedef struct writeonly *wo_ptr_t;

/* writeonly.c */
#include "writeonly.h"

struct writeonly {
  int value 
};

/*...*/

   FOO_REGISTER->value = 42;

/* someother.c */
#include "writeonly.h"

/*...*/

   int x = FOO_REGISTER->value; /* error: deref'ing pointer to incomplete type */

만.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
}

이를 통해 정적 오류를 확인할 수 있습니다.물론 이 방법을 사용하면 매크로를 사용하기 위해 포인터 선언을 모두 수정해야 합니다.이것은 그다지 즐겁지 않을 것입니다.

편집: 댓글에 기재되어 있는 바와 같습니다.

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

Dan Saks가 Youtube 프레젠테이션을 하는데, 임베디드 기기용 쓰기 전용 레지스터를 어디서 도입하는지 찾을 수 없었습니다.

다행히 그는 검색하기 쉬운 기사를 https://www.embedded.com/how-to-enforce-write-only-access/에 썼다.

이것은 C++11용으로 갱신된 기사의 코드입니다.

class write_only_T{
public:
    write_only_T(){}
    write_only_T(T const& v) : m(v){}
    write_only_T(T&& v) : m(std::move(v)){}
    write_only_T& operator=(T const& v){
        m = v;
        return *this;
    }
    write_only_T& operator=(T&& v){
        m = std::move(v);
        return *this;
    }
    write_only_T(write_only_T const&) = delete;
    write_only_T(write_only_T&&) = delete;
    write_only_T& operator=(write_only_T const&) = delete;
    write_only_T& operator=(write_only_T&&) = delete;
private:
    T m;
};

쓰기 전용이 값의 속성이기 때문에 이것을 사용했다면 특별한 포인터 타입은 필요 없다고 생각합니다만, 값 타입을 건너뛰는 합성 포인터 타입은 상상할 수 있습니다.기입 전용 레퍼런스 타입 등을 도입할 필요가 있을 가능성이 있습니다.

언급URL : https://stackoverflow.com/questions/16049329/write-only-pointer-type

반응형