임베디드/임베디드 레시피

함수 포인터와 실행 주소 변경

twoweeks-within 2024. 12. 8. 16:38

함수의 이름 : Symbol > Physical 주소 점유

실제 함수의 이름 > 함수의 시작주소를 의미

1. 함수포인터의 선언

자료형 (* 함수포인터 이름) (인자목록)

 > character형을 가르키는 pointer
char * cdata;

포인터 함수
 EX)
integer형을 return
integer형 argument를 하나 받는 포인터함수

int (*function)(int a);
<>
int * function (int a);

 function 함수 > integer형 포인터를 return받음

포인터 함수 선언
  pointer함수 > int recipe(int a)라는 함수 엮으려면

function = recipe;
또는
function = &recipe;

주의) 함수의 이름 : 시작주소를 의미
    function = recipe(); > x
> recipe() 함수의 값을 넣으라는 뜻 > 다른의미

2. 함수포인터 Array

 (plus(), minus(), multiply(), divide() 함수가 우리가 아는 그 사칙연산을  해주는 함수라고 가정했을 때. )

int (* functions[3][4]) (int, int) = { plus, minus, multiply, divide }
//  {plus, minus, multiply, divide},
//  {plus, minus, multiply, divide},
//  {plus, minus, multiply, divide}
>
function[2][0](1, 3) 의 값은?

 > multiply (1,3) 호출 > return값: 3


typedef enum  //  이 함수의 특징
{
    PLUS = 0,   // 0 이라고 해두면
    MINUS,       // 1
    MULTIPLY,   // 2 
    DIVIDE       // 3
    NUM_MAX;  // 4 라고 자동 정의
} cal_type;

int Calculation (cal_type how, int a, int b)
{
if (how >= NUM_MAX){
return NULL;
}
else{
return function[0][how](a, b);

}
}
   calculation (PLUS, 3, 4) > plus (3, 4) > 7


또는 4칙 연산을 자동으로 모두 시행하려면

void Calculation_All (int a, int b)
{
int loop;

for (loop =0; loop<4; loop++)
{
    printf ( "%d \n", function[0][loop] (a, b);
}

return;
}

 

3. 함수 포인터의 응용 → Device Drivers

함수 포인터 > Device Driver들을 그때그때 다르게 쓰고 싶을 때 사용
ex)
 주변 Device들 중에 같은 기능을 하지만 여러 가지 Vendor의 Device들을 한꺼번에 지원하고 싶을 때
ex)
어떤 device가 read, write의 기능 >

typedef struct {
    const char  *name;
    void (*read) (byte *buffer, int count);
    void(*write) (byte *buffer, int count);
} device_type;


 device driver들을 선언

device_type device =
{
    "It's me",
    device_read, // device_read 함수 포인터를 가짐
    device_write
}

Device driver를 끼워 넣을 수 있음

device_type *device_target;
device_target = &device

 >> device driver를 사용하는 사용자 입장

(*device_target->read)(buffer, count)
이런 식으로 호출 > 그때그때 Driver가 바뀌는 효과

// read 에 devie_read 의 주소가 들어감
// device_target 에는 device 구조체의 주소가 들어감
//  *device_target : devie 구조체에
    > ->read : devie_read > buffer, count 대입

이때 drivce_read (buffer, count)가 불림!

  device2 선언 > device_target = &device2 라고 선언
   device2에 엮인 driver들이 불림

4. 함수포인터와 typedef 

typedef int (funtion)(void) 로 선언하면?
 > function : int return값 + void 인자를 받는 함수
유식하게는  int ()(void)라는 뜻

ex)
typedef int (funtion)(void);

int example_function(void) {
    return 42;
}
funtion *func_ptr = example_function;
// function type : void를 인자로 받고 return이 int형인 함수
int result = func_ptr();  // result는 42
*/

function *temp = hello;

 helllo() : int형 return, (void) 인자를 갖는 함수
> temp() 를 호출 ==  hello()를 호출

5. 함수 포인터의 완전 응용 → 원하는 주소로 억지로 branch

 Embedded System을 만들다 특정 주소로 branch해야 할 경우
ex) 뭔가 하다가 꼭 0x7777 주소로 branch해야함.
  > 0x7777주소를 일단 void형의 함수 pointer임을 알려주는 casting
  > () : 함수라는 표현 >( void (*)() )이용 ( void형 포인터 함수라는 뜻 )

/*
주소를 넣을 때 이걸 붙여줘야 안전함
// ( void *) :void 를 반환하는 포인터 
// ( void (*)() ) void 반환 , void를 인자로 받는 포인터 함수
*/

>>
void (*example) (void);
example = (void (*)())0x7777; // example :  void를 반환 포인터함수(void를 인자로받는) > 0x7777 을 넣음
(*example)(); // example == 0x7777 에 해당하는 값으로 jump
// 함수 이름은 시작주소
 > 억지로 pc : 0x7777로 만들어줌

(*(void(*)())0x7777)(); // 한줄요약

 NOR flash : NOR flash를 probing하기 위해 command set
  >  NOR 영역 모두 status를 return >너 누구냐 하고 묻는 순간 > NOR flash에서 software 실행
   > Undefined Exception이 나는 현상.
> 해결

static unsigned int32 find_id[] = { // 명령어를 배열에 저장
// id_code PROC
// In values: R0 = base of code section
0x1c01,            // MOV     r1, r0
// unsigned int32  codes;
// *base = (word)0x90;
0x2090,            // MOV     r0, #0x90
......
// return codes;
0x4770              // BX       r14
// out values, mfg id in top 16 bits R0
//             part id in bottom 16 bits R0
// ENDP
};

 미리 nmemonic : 32bit array에 넣어둠 >  PSRAM에 올려놓고 > 실행

id = ((unsigned int32(*)()) ((unsigned char *) find_id)) (base);

// (unsigned char *) find_id) : 배열을 포인터 형으로 바꿈
// (unsigned int32(*)()) : int 를 반환하는 포인터함수 선언
// base : 인자

 id 명령어 > char형으로 align,  unsigned int32형을 return해주는 함수 포인터형으로 casting
  > id_code의 시작 주소를 함수처럼 실행

그러면 맨 처음에 했던 선언을 기준으로 다음의 선언을 해석해 보세요.

ⓐ int (*ifunc)(int a);
ⓑ char *(*cfunc)(char *p[]);
ⓒ void (*vfunc)(void);

ⓐ int 형의 return값을 갖고, int a의 인자를 갖는 ifunc 라는 함수 포인터
ⓑ char 포인터형의 return값을 갖고, char형의 포인터 배열을 인자로 갖는 cfunc 이라는 함수 포인터
ⓒ return값이 없고, 인자값도 없는 vfunc라는 함수 포인터

// 포인터 함수의 연산은 허용하지 않음
 

'임베디드 > 임베디드 레시피' 카테고리의 다른 글

6장) RTOS, Kernel  (0) 2024.12.11
linked list, Queue  (0) 2024.12.11
Stack의 Size  (0) 2024.12.07
stack 메모리 dump  (0) 2024.12.07
stack : 함수를 불렀을때  (1) 2024.12.06