Embedded Recipes 5. SW Vinetting

Sireal·2024년 3월 4일

Embedded Recipes

목록 보기
7/10
post-thumbnail

Embedded Recipes 5. SW Vinetting


C와 ARM을 하는데 있어서 필요한 몇가지를 알아본다

포인터와 배열


  • 얕은 복사: 데이터의 주소를 가져오는 것
  • 깊은 복사: 데이터를 가져오는 것
  • 포인터: 주소를 담는 자료형 (Word. ARM에선 4Bytes)
  • 배열 관련
array\[번호] = \* (array주소 + 번호)
  • 이중포인터: 포인터 변수의 주소를 담는 그릇
    - 포인터변수의 주소를 알고 싶으면 어떻게 해야할까?
    - &포인터변수 하면 되긴 하다
    - 하지만 &포인터변수를 지원하지 않는 컴파일러가 많다
    - 이중 포인터를 사용해 포인터의 주소를 따볼 수 있다.

  • 해당 식은 틀린식이다.

// 코드의 의도: 포인터 변수 tag에 heap메모리 할당과 주소를 직접 삽입하는 것
void gettag(cahr* ptag)
{
	ptag=(char*)malloc(40);// malloc(n): 메모리 할당 후 첫 주소값 리턴
	strncpy(ptag, "pointer tag", sizeof(char)*40);
}

void process()
{
	char *tag;
	gettag(tag);
	free(tag);
}
  • 깊은 복사로 포인터변수의 값을 사용하는데 해당 함수에서 벗어나면 무용지물이 된다.
  • 그럼 &를 써서 얕은복사 후 사용하면 되는거 아닌가 싶은데, 그냥 사용하면 컴파일러가 바보가 된다.
  • 함수에 이중포인터를 넣어 사용하면 바보가 안되고 내가 원하는 대로 사용할 수 있다.
void gettag(char** ptag)
{
	*ptag=(char*)malloc(40);// malloc(n): 메모리 할당 후 첫 주소값 리턴
	strncpy(*ptag, "pointer tag", sizeof(char)*40);
}

void process()
{
	char *tag;
	gettag(&tag);
	free(tag);
}

(추가)

  • (void *): void 포인터 변수
    - 순수하게 아무 형태없이 주소만 담을 때 사용
    - 값을 가져올때 원하느 형태로 typecast 해서 사용하면 됨

struct, typedef, PACKED


stuct: stucture 변수

typedef: 해당 Data를 새로운 Data 형으로 선언해주는 것.

  • 해당 데이터 형을 손쉽게 여러번 쓸 수 있음

__packed: 구조체 내에 변수크기를 padding없이 꽉꽉채우게 해주는 친구

Stack, Heap에 관한 소고


Stack은 History 기능을 가지고, Heap은 메모리를 꿔줄수 있다.

Stack에서의 Init


Stack에서 사용하는 어셈이 참 많은데, 그것에 대해 정리해본다.

Stack push = STMDB, STMFD

  • STMDB: STore Multi Decrease Before
    - SP를 역순으로 쌓되, Data 처리전 SP 삽입

  • STMFD: STore Multi Full Descending
    - SP를 꽉꽉 채우며 반대로 쌓기

PUSH를 할 때, 높은주소에서 낮은주소로 데이터를 쌓으며 동작하며, 정말 동작하는 차례로 쌓인다.

Stack 파보기


Stack은 히스토리랬다.
실제 디버깅시 어떻게 사용되는지 살펴보자면
1. SP 찾기
2. LR 찾기
3. LR과 당시 함수로 PC 추정하기

이것의 무한반복

명령어별 LR을 통한 PC값은 아래와 같다

BL은 왜 1Cycle(4Byte)만 + 해주는건가?

  • Pipeline으로 보자면 BL은 Excute에서 동작 하니까 PC는 2Cycle 앞에 가있음

  • 근데 BL은 이미 동작을 했으니까 PC가 1Cycle 앞당겨짐

  • 그래서 PC + 2 가 아닌, PC + 1 해주는 거임

Thumb Mode는 Branch 할때 홀수 주소를 보게되어있음

  • 그렇담 실제로 LR주소를 봐야할 땐 -1을해서 짝수로 보고 PC로 봐야함.

Stack Size 관련


Stack에서 Push, Pop 한 자리는 일일이 0x00 으로 Clear하지 않고 사용됨
Stack을 쓸땐 메모리도 좀 넉넉히 줘야하는데, 실제 사용된 Stack사이즈보다 4배 더 주면 좋댄다

함수 포인터


함수 포인터

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

함수 포인터 Array

  • int (*function[3])(int, int)(plus, minu, mulltiply, dived)
    - function[2](1,3) -> 3

함수 포인터 응용. Device Driver

  • 함수 포인터를 구조체에 담아서 사용하는 구조이며 이런식으로 사용된다.
typdef struct
{
	const char *name;
	void (*read)(byte *buffer, int count);
}device_type;

device_type =
{
	"HelloWorld",
	device_read,
}

함수포인터와 typedef

  • typedef int (function)(void) -> funcion = int ()(void) 타입이 된다는 뜻을 가진다.
    - typdedf int (fucntion)(void);
    - function *temp = hello
    - hello라는 int reutrn값을 가진 함수가 포인터 함수 temp와 연결됨.
  • 쪼매 복잡한데 느낌을 익히자

함수포인터의 완전 응용. 브랜치

  • 함수포인터를 잘사용하여 접근할 수 없는 메모리에 직접 접근 하여 실행 가능하다.
void (*example)(void);        // 1. void형 함수포인터 선언 (example)
example (void(*)())0x7777;    // 2. 0x7777을 void형 함수포인터 형으로 typecast를 한 후 exmaple 에 넣고 초기화
(*example)();  // 0x7777 실행

이렇게도 되고

(*(void(*)())0x7777); // 얘도 됨
profile
달리다 넘어져도 아픔마저 즐기려하는 사람

0개의 댓글