뇌 마음 반반저장소

[42_so_long] "MiniLibX" 1.함수 알아보기 본문

42/so_long

[42_so_long] "MiniLibX" 1.함수 알아보기

맹진저 2023. 1. 2. 01:11
728x90

Votre projet doit respecter les règles suivantes :

프로젝트는 다음 규칙을 준수해야 합니다.
• Vous devez utiliser la MiniLibX. Soit la version disponible sur les machines de l’école, soit en l’installant par les sources.

MiniLibX를 사용해야 합니다. 학교 컴퓨터에서 사용할 수 있는 버전이거나 소스에서 설치하여 사용할 수 있습니다.
• Vous devez rendre un Makefile qui compilera vos fichiers sources. Il ne doit pas relink.

소스 파일을 컴파일할 Makefile을 렌더링해야 합니다. relink는 안 됩니다.
• Votre programme doit prendre en paramètre un fichier de carte se terminant par l’extension .ber.

프로그램은 .ber 확장자로 끝나는 맵 파일을 매개변수로 사용해야 합니다.

더 알아보기

MiniLibX란?

미니립엑스는 아주 간단한 그래픽 라이브러리다. 우리가 만든 libft 같은 라이브러리라고 생각하면 쉬울 것이다. 이것을 통해서 우리는 화면에 움직이고 작동하는 무언가를 만들 수 있다! 아주 쉽고 간단한 2D게임을 만드는 프로그램이라고 생각하면 쉽겠다.

 

so_long프로젝트 설명서 위에 여러 가지 tgz파일이 있다. 나는 linux버전으로 만들 것이기 때문에 minilibx-linux.tgz를 다운로드하였다.

tgz란?

tgz를 알기 위해서는 tar를 먼저 알아야 한다. tar파일은 유닉스 운영체제에서 압축은 하지 않고 파일을 묶어주는 기능을 하는 친구이다. tgz는 tar로 묶은 파일들을 gzip으로 압축해서 tar.gz 또는 tar.tgz로 사용한다.

 

우리는 예비 개발자이기 때문에 안철수 아저씨의 알집으로 이 파일을 풀지 않을 것이다!!

일단 tar관련 명령어를 살펴보자.

-c : 파일 압축하기

-x : 파일 압축 해제하기

-v : 과정 출력하기

-f : 지정한 파일명으로 

-z : tar로 묶고 gzip으로 

-p : 소유권 등 퍼미션 그대로 유지하기

 

압축 풀기

$ tar -xvf minilibx-linux.tgz

MiniLibX 파일들 살펴보기

minilibX 가이드: https://harm-smits.github.io/42docs/

압축을 풀고 나면 안에 정말 다양한 c 코드들과 헤더파일, 맥파일이 있다. 하나하나 차근차근 살펴보자!

mlx.h : 헤더에 아주 친절하게 함수별로 설명해 두었다.

Makefile

Makefile.mk

 

!함수의 시작!

void	*mlx_init();
  • 모든 것 이전에 필요한 것.
  • 소프트웨어와 디스플레이를 연결해 준다.
  • 실패하면 return((void *)0)

 

!기초적인 액션들!

void	*mlx_new_window(void *mlx_ptr, int size_x, int size_y, char *title);
  • 새 창을 스크린에 띄운다. 여러 창 제어가능.
  • size_x와 size_y는 창사이즈이다.
  • 창의 타이틀 바에 title 이름이 표시된다.
  • mlx_ptr은 mlx_init이 반환한 값으로 연결된 창이다.
  • 다른 Minilibx 호출에서 사용가능한 void*인 창 식별자를 반환하고, 실패하면 return((void *)0)
int	mlx_clear_window(void *mlx_ptr, void *win_ptr);
  • 지정된 창을 검은색으로 지워버린다.
  • mlx_ptr은 무엇과 연결되었는지 알려준다.
  • win_ptr은 어떤 창인지 알려준다.
int	mlx_pixel_put(void *mlx_ptr, void *win_ptr, int x, int y, int color);
  • 지정된 픽셀을 color(color is 0x00RRGGBB)색으로 win_ptr창에 x, y좌표에 그린다.
  • (0,0)은 좌측 상단을 의미한다.
  • x는 오른쪽으로 뻗어나가고, y는 양수로 아래를 향해 뻗어나간다.
  • mlx_ptr로 연결해주는 것이 필요하다!
  • 해당함수는 굉장히 느리다. pixel 하나하나에 직접 값을 입력하기 때문이다. 대안으로 image함수를 활용한다.

 

!이미지 스터프(stuff)!

void	*mlx_new_image(void *mlx_ptr,int width,int height);
  • 새 이미지를 메모리에 할당한다.
  • 실패하면 return((void *)0)
  • 나중에 이 이미지를 조작할 때 필요한 주소를 리턴한다.
  • 이미지 사이즈와 mlx_ptr 연결 식별자만 있으면 된다.
  • 이 안에는 mlx_new_image2라는 함수도 있는데, image2 데이터는 비트 평면을 사용하여 저장한다.
  • mlx_put_image_to_window를 사용하여 수행된다.
char	*mlx_get_data_addr(void *img_ptr, int *bits_per_pixel, int *size_line, int *endian);
  • 생성된 이미지에 대한 정보를 리턴해서 나중에 이미지를 수정할 수 있도록 한다.
  • imp_ptr은 사용할 이미지를 지정한다.
  • 나머지 int형 포인터 매개변수들은 유효한 정수의 주소여야 한다.
  • bits_per_pixel : 픽셀 색상을 나타내는데 필요한 비트수. (mlx에서는 색을 ARGB로 표현하기 때문에 32로 고정)
  • size_line : 이미지의 한 줄을 메모리에 저장하는 데 사용되는 바이트 수. (이 정보는 한줄한줄 이동하는데 필요)
  • endian : 이미지의 픽셀 색상을 little endian(0) 또는 big endian(1)으로 저장해야 하는지 알려줌.
  • image2의 경우 mlx_get_data_addr의 두 번째 인수는 number_of_planes이다.
  • 이 함수는 설정된 라인 사이즈를 사용하여 픽셀의 주소를 계산한다.

엔디안이란? 👇

더보기

엔디안이란?
엔디안(Endian)은 컴퓨터의 메모리와 같은 1차원의 공간에 여러 개의 연속된 대상을 배열하는 방법을 뜻하며, 바이트를 배열하는 방법을 특히 바이트 순서(Byte order)라 합니다. 

 

엔디안은 보통 큰 단위가 앞에 나오는 빅 엔디안(Big-endian)과 

작은 단위가 앞에 나오는 리틀 엔디안(Little-endian)으로 나눌 수 있으며, 

두 경우에 속하지 않거나 둘을 모두 지원하는 것을 미들 엔디안(Middle-endian)이라 부르기도 합니다.

사람이 숫자를 쓰는 방법과 같이 큰 단위의 바이트가 앞에 오는 방식이 빅 엔디안입니다. 16진수는 2개가 1바이트이므로 묶어서 계산합니다.

  빅 엔디안 리틀 엔디안
0x1234 12 34 34 12
0x1a3ecd 1a 3e cd cd 3e 1a


장단점
빅 엔디안은 소프트웨어의 디버그를 편하게 해 주는 경향이 있습니다. 사람이 숫자를 읽고 쓰는 방법과 같기 때문입니다.

반대로 리틀 엔디언은 메모리에 저장된 값의 하위 바이트들만 사용할 때 별도의 계산이 필요 없다는 장점이 있습니다. 예를 들어, 32비트 숫자인 0x2A는 리틀 엔디언으로 표현하면 2A 00 00 00이 되는데, 이 표현에서 앞의 두 바이트 또는 한 바이트만 떼어 내면 하위 16비트 또는 8비트를 바로 얻을 수 있습니다.

반면 32비트 빅 엔디언 환경에서는 하위 16비트나 8비트 값을 얻기 위해서는 변수 주소에 2바이트 또는 3바이트를 더해야 합니다. 

int	mlx_put_image_to_window(void *mlx_ptr, void *win_ptr, void *img_ptr, int x, int y);
  • 내부 이미지를 그릴 수 있다.
  • 지정된 창에 언제든지 이미지를 덮어 화면에 표시할 수 있다.
  • (x,y) 좌표에 mlx_ptr의 win_ptr 창에다가 img_ptr 이미지를 넣는다.
int	mlx_get_color_value(void *mlx_ptr, int color);
  • 디스플레이에 따라 저장하는 픽셀 색상의 비트수를 계산한다.
  • 표준 RGB 색상을 color 매개변수에 넣는다.

 

!이벤트 만지기!

int	mlx_mouse_hook (void *win_ptr, int (*funct_ptr)(), void *param);
int	mlx_key_hook (void *win_ptr, int (*funct_ptr)(), void *param);
int	mlx_expose_hook (void *win_ptr, int (*funct_ptr)(), void *param);
  • 이 세 함수는 정확히 같은 방식으로 작동한다.
  • funct_ptr은 이벤트가 발생할 때 호출하려는 함수에 대한 포인터이다.
  • win_ptr의 창에 적용이 된다.
  • param 주소는 호출될 때마다 함수에 전달이 되며 필요한 매개 변수를 저장하는 데 사용해야 한다.
int	mlx_loop_hook (void *mlx_ptr, int (*funct_ptr)(), void *param);
  • 이 함수는 위의 함수와 동일하지만 이벤트가 발생하지 않으면 인자로 받았던 param과 함께 함수가 호출된다.
  • 이벤트를 발견했을 경우, MiniLibX는 아래와 같이 해당 함수를 고정 매개변수로 호출한다. 이들은 라이브러리의 일부가 아니라서 임의로 작성되었다. (그래서 어쩌라는 거지..?) 👉 https://gontjarow.github.io/MiniLibX/mlx_loop.html
  • expose_hook(void *param);
  • key_hook(int keycode, void *param);
  • mouse_hook(int button, int x,int y, void *param);
  • loop_hook(void *param);
  • 이벤트 발생 조건 없이 funct_ptr에 매개변수로 입력된 함수를 무한대로 실행한다.
int	mlx_loop (void *mlx_ptr);
  • 키보드나 마우스로 "이벤트"를 수신하는 함수이다.
  • 이벤트를 기다린다음 이 이벤트와 관련된 사용자정의함수를 호출하는 무한 루프이다.
  • 키를 눌렀다면 -> mlx_key_hook
  • 마우스 버튼을 눌렀다면 -> mlx_mouse_hook
  • 창의 일부를 다시 그려야 한다면 -> mlx_expose_hook
  • 무한루프이기 때문에 함수 마지막에 쓰여야 한다.
int	mlx_loop_end (void *mlx_ptr);
  • loop를 끝낼 때 사용한다.

 

!보통 요구하는..!

int	mlx_string_put(void *mlx_ptr, void *win_ptr, int x, int y, int color, char *string);
  • 지정된 string을 color색으로 win_ptr창의 x, y좌표에 그린다.
  • (0,0)은 좌측 상단을 의미한다.
  • x는 오른쪽으로 뻗어나가고, y는 양수로 아래를 향해 뻗어나간다.
  • mlx_ptr로 연결해주는 것이 필요하다!
void	mlx_set_font(void *mlx_ptr, void *win_ptr, char *name);
  • mlx_string_put에서 사용할 글꼴을 지정할 수 있다.
  • 고정 너비 비트맵 글꼴만 지원한다. (xfontsel을 참조)
  • 이 기능에 유효한 글꼴 이름을 name에 가져오는 도구이다.
void	*mlx_xpm_to_image(void *mlx_ptr, char **xpm_data, int *width, int *height);
void	*mlx_xpm_file_to_image(void *mlx_ptr, char *filename, int *width, int *height);
  • 같은 방법으로 새로운 이미지를 생성한다.
  • 함수에 따라 지정된 xpm_data 또는 filename으로 채운다.
  • 오류가 발생하면 NULL을 반환한다. 
int	mlx_destroy_window(void *mlx_ptr, void *win_ptr);
  • 지정된 창을 끈다.
int	mlx_destroy_image(void *mlx_ptr, void *img_ptr);
  • 주어진 이미지를 삭제한다.
int	mlx_destroy_display(void *mlx_ptr);
  • 디스플레이를 닫는다.


generic hook system for all events, and minilibX functions that can be hooked. Some macro and defines from X11/X.h are needed here.
모든 이벤트에 대한 일반 후크 시스템 및 연결할 수 있는 minilibX 기능. X11/X.h의 일부 매크로 및 정의가 여기에 필요합니다.

int	mlx_hook(void *win_ptr, int x_event, int x_mask, int (*funct)(), void *param);
  • 이벤트를 생성한다.
  • win_ptr 창에 funct 이벤트를 포착하면 x_event를 발생시킨다.
  • mlx_hook은 누르고 있는 상태에서 이벤트가 무한반복된다. (mlx_key_hook은 키를 누를 때마다 일시적으로 발생)
  • param은 함수 내에서 쓰일 변수들을 입력한다. (쓰일 변수가 많을 경우, 구조체로 묶읍시다.)

hooking이란? 👇

더보기

후킹(영어: hooking)은 소프트웨어 공학 용어로, 운영 체제나 응용 소프트웨어 등의 각종 컴퓨터 프로그램에서 소프트웨어 구성 요소 간에 발생하는 함수 호출, 메시지, 이벤트 등을 중간에서 바꾸거나 가로채는 명령, 방법, 기술이나 행위를 말한다. 이때 이러한 간섭된 함수 호출, 이벤트 또는 메시지를 처리하는 코드를 훅(영어: hook)이라고 한다.

 

크래킹(불법적인 해킹)을 할 때 크래킹 대상 컴퓨터의 메모리 정보, 키보드 입력 정보 등을 빼돌리기 위해서 사용되기도 한다.
예를 들어 특정한 API를 후킹 하게 되면 해당 API의 리턴값을 조작하는 등의 동작을 수행할 수 있다. (ㄷㄷㄷ)

 

일반적으로 훅은 소프트웨어가 이미 실행중일 때 삽입되지만, 후킹은 응용 프로그램이 실행되기도 전에 쓰일 수 있는 전략이다. 이 두 기술은 아래에 더 자세히 설명되어 있다.

 

런타임 수정 (우리가 사용하는 후킹)
운영체제와 소프트웨어는 훅을 삽입하는 프로세스에 충분한 권한이 부여된 경우 런타임도중 이벤트 훅을 쉽게 삽입할 수 있다. 예를 들어, Microsoft Windows에서는 대화 상자, 스크롤바 및 메뉴뿐만 아니라 다른 항목에 대한 시스템 이벤트와 응용 프로그램 이벤트를 처리하거나 수정하는 데 사용될 수 있는 훅을 삽입할 수 있다. 또한 훅은 키보드 및 마우스 이벤트를 삽입, 제거, 프로세스 또는 수정할 수 있다. 리눅스에서는 훅이 넷필터를 통해 커널 내의 네트워크 이벤트를 처리하기 위해 비슷한 방식으로 사용될 수 있는 또 다른 예를 제공한다.

이러한 기능이 제공되지 않은 경우, 후킹의 특별한 형태는 프로세스에 의해 만들어진 라이브러리 함수 호출을 차단하는 방법을 사용한다. 후킹은 대상 함수의 첫 번째 몇몇 코드가 주입 코드로 이동하도록 지시를 변경하여 구현된다. 또는 공유 라이브러리의 개념을 사용하는 시스템에서는 인터럽트 벡터 테이블 또는 임포트 디스크립터 테이블이 메모리에서 수정될 수 있다. 기본적으로 이러한 전술은 물리적 수정과 같은 아이디어를 사용한다. 하지만 이미 실행되어 있는 상태라면 프로세스의 메모리에 있는 명령과 구조를 변경한다.

 

물리적 수정
응용 프로그램이 실행되기 전에 리버스 엔지니어링 기법으로 실행 또는 라이브러리를 물리적 수정함으로써 후킹을 할 수 있다. 이러한 기법은 일반적으로 다른 모니터로 함수 호출을 가로채거나 그것들을 완전히 다른 함수로 대체하는 데 사용된다.

예를 들어, 역어셈블러를 사용하여 모듈 내에서 함수의 시작점을 찾을 수 있다. 그다음, 다른 라이브러리 모듈을 동적으로 로드하고, 로드된 라이브러리 내에서 원하는 함수를 실행하도록 변경할 수 있다. 해당되는 경우, 후킹으로 얻을 수 있는 관련된 다른 접근 방법은 실행 파일의 임포트 테이블을 변경하는 것이다. 이 테이블은 추가 라이브러리 모듈을 로드하도록 수정될 수 있을 뿐만이 아니라 함수가 응용 프로그램에 의해 호출될 때 외부 코드가 호출되는 것으로 바뀔 수도 있다.

후킹을 하기 위한 대체 방법은 래퍼 라이브러리를 통해 함수 호출을 차단하는 것이다. 래퍼를 만들 때, 응용 프로그램을 로드하는 라이브러리는 원본 라이브러리와 동일한 기능을 가진 자신만의 라이브러리를 만든다. 즉, 접근할 수 있는 모든 기능은 원본과 대체된 라이브러리 모두 동일한 것이다. 이 래퍼 라이브러리는 원래 라이브러리의 기능 중 하나를 호출하거나, 논리의 완전히 새로운 설정으로 대체되도록 설계할 수 있다.

 

위키백과 : 후킹

int	mlx_do_key_autorepeatoff(void *mlx_ptr);
int	mlx_do_key_autorepeaton(void *mlx_ptr);
int	mlx_do_sync(void *mlx_ptr);
  • 키 자동 반복을 활성화하거나 비활성화할 수 있다.
  • 키 자동반복을 활성화한다 -> autorepeaton
  • 키 자동반복을 비활성화한다 -> autorepeatoff
  • 모든 창의 프레임을 동기화한다 -> sync (무슨 말일까!?)
int mlx_mouse_get_pos(void *mlx_ptr, void *win_ptr, int *x, int *y);
int mlx_mouse_move(void *mlx_ptr, void *win_ptr, int x, int y);
int mlx_mouse_hide(void *mlx_ptr, void *win_ptr);
int mlx_mouse_show(void *mlx_ptr, void *win_ptr);
  • 현재 윈도 위 위의 마우스 위치를 가져온다 -> mouse_get_pos
  • 커서를 주어진 위치로 이동한다 -> mouse_move
  • 마우스를 숨겨준다. ->mouse_hide
  • 마우스를 보여준다 -> mouse_show
int	mlx_get_screen_size(void *mlx_ptr, int *sizex, int *sizey);
  • 현재 스크린 사이즈의 최대 해상도를 구한다.

 


위의 함수들을 이해하고 매뉴얼을 읽으면서 차근차근 mknilibx의 구조를 시각화해봤다.

MiniLibX의 설정구조!

참고 : MiniLibX - Simple Graphical Interface Library for students


*흥미로운 점 :  아니 도대체 void 함수가 어떻게 반환값을 돌려줍니까?

void 함수인데 return 값이 가능하다구?

728x90

'42 > so_long' 카테고리의 다른 글

[42_so_long] perror, strerror, exit 자세히 알아보기  (0) 2022.12.28
[42_so_long] 시작하며  (0) 2022.12.27
Comments