070-7738-xxxx 등에서 스팹 전화가 꾸준히 온다.

올때마다 블랙리스트로 하나씩 막아 두었는데

매번 뒷 4자리가 다르게 해서 오거나 070-4xxx 에서도 몇 달이 넘도록 전화가 온다.


그래서 전화번호 앞자리만 가지고 막는 방법을 찾아봤는데...

전화 --> 설정 --> 블랙리스트에 가보면 wildcard로 전화 번호를 막는 방법이 있다.


070-7738로 시작하는 전화번호를 막을려면 0707738.* 이런식으로 막을수 있다고 써있다.

그런데 이게 안 먹힌다.


그래서 어쩔수 없이 하나씩 막게 했는데 도저히 안되겠어서 CM11 소스를 가져와 BlacklistUtils.java 소스에 로그를 남기는

코드를 집어넣어 놓고 해보았지만 로그에서는 db query를 넘기기 전까지는 잘된다.


결국 BlacklistProvider.java 쪽에 문제가 있는것을 확인하고 전화앱을 교체해 봤는데 ... 전화앱만 바꾸니 자꾸만 다운 되었다.

어쩔수 없이 복구..


좀 시간이 지난후에 한번 BlacklistProvider.java 소스를 자세히 봤다..


전화번호 블랙리스트는 com.android.providers.telephony/databases 에 있는 blacklist.db에 데이터를 집어 넣고

이를 sql query 로 가져와 매칭이 된것이 있으면 블럭시키는 구조를 가졌고 db 구조는 아래와 같았다.



_id

number

normalized_number

is_regex

phone

message

 1

 0707078xxxx

 +82707078xxxx

 0

 1

 0

 2

 0704198xxxx

 +82704198xxxx

 0

 1

 0

 3

 0704.*

 0704_%

 1

 1

 0

 4

 0707738.*

 0707738_%

 1

 1

 0


number 컬럼은 내가 입력한 전화번호이고, normalized_number는 나중에 필터링 할때 쓰는 번호,

is_regex는 와일드 카드 사용여부, phone은 전화번호 여부, message는 sms여부다.


일반 전화번호는 (예를 들어 0707078xxxx) normalized_number 에 "+"와 국제 전화번호 "82"가 들어가있는데

이상하게 와일드 카드에는 "+" 와 국제전화번호가 "82" 가 안들어가 있다.


DB query를 분석해도


select * from blacklist where "전화온 전화번호(국제전화번호)" like normalized_number;


이다.


아!!! 국제 전화번호를 앞에 넣거나 혹은 ".*0707738.*" 이런식으로 앞뒤에 와일드 카드를 넣어야 했던것이다.


결국 국제 전화 번호를 앞에 넣어 테스트 해보니 잘 작동 된다.

예)  0707738.* --> +82707738.*



*****************************************************************

정리) 전화  블랙리스트에 0707738.* 이런식으로 와일드를 사용하지 말고

+82707738.* 이런식으로 국제전화 번호를 앞에 추가 해서 넣거나

.*707738.* 이런식으로 앞뒤에 와일드 카드를 넣어써라.


저번( http://fehead.tistory.com/211 )에 이어 이번에는 윈도우에서 ESC키를 누르면 영문으로 바뀌게 하는 것을  해보겠습니다.



=====================================

VIM을 쓸때 한글 상태에서 ESC 키를 누르고 :wq 를 누르면 :ㅈㅂ 이 나오는 현상을 많이 보셨을 겪어 보셨을 것입니다.

ESC키를 누르면 자동으로 영문 상태로 바꾸게 하는 방법들이 있습니다.


이것 들중 하나를 소개 해 드리겠습니다.


바로 한글 입력기에서 지원하는 것을 사용하는 것입니다.

=====================================


윈도우에서는 날개셋과 새나루가 지원합니다.

하지만 새나루는 개발이 끊긴지 오래 되어 날개셋을 설명하겠습니다.


1. 날개셋을 다운 받습니다.

site : http://moogi.new21.org에 접속하여 중간 쯤까지 스크롤을 내려 <날개셋>을 다운 받습니다.




2. 날개셋을 설치합니다.


3. 편집기는 설치할 필요가 없습니다. 편집기는 체크를 해제해도 됩니다.



4. 제어판에서 "국가 및 언어 옵션"으로 들어 갑니다.

아래 처럼 자세히를 눌러 텍스트 서비스 및 입력 언어를 설정합니다.


5. 기본 입련 언어를 한국어 - <날개셋> 한글입력기를 선택합니다.



6. 옵션 : <날개셋> 한글 입력기를 제외한 나머지를 모두 제거 합니다.

( 제거 하지 않아도 됩니다.)


7. <날개셋> 한글 입력기에 ESC키를 바꾸기 위해 설정으로 들어갑니다.


8. 좌측 "단축 글쇠" --> "추가(A).." 를 누릅니다.



9. ESC 영문키로 바꾸기 설정을 진행합니다.

아래 화면처럼 좌측에는 없음으로 모두  좌측으로 스크롤을 밀어 주시고

가상 키보드(V) 에는 Esc를 선택

용도(U) "1. 글자판(입력 항목) 전화"

계산식(E) 1 - 설명 : 영문으로 변경

글쇠 독점하지 않기 에 체크 합니다.



10. 다시 전화면으로 가서 입력 도구 모음을 선택합니다.


11. 바탕화면에 입력도구 모음이 표시 되도록 합니다.


12. 재로그인을 합니다.


13. 바탕 화면을 보시면 아래와 같은 한글 상태 표시줄이 표시 되는데 아래 화살표를 눌러 불필요한 아이콘을 없애 줍니다.

 아래에서는 입력모드와 한자 변환 아이콘만 표시 하도록 하였습니다.


14. 이제 사용하시면 됩니다.

혹시 ESC키가 잘 안되면 한글 상태 표시줄이 위와 같은 날개셋인지 잘 확인해주세요

VIM을 쓸때 한글 상태에서 ESC 키를 누르고 :wq 를 누르면 :ㅈㅂ 이 나오는 현상을 많이 보셨을 겪어 보셨을 것입니다.

ESC키를 누르면 자동으로 영문 상태로 바꾸게 하는 방법들이 있습니다.


이것 들중 하나를 소개 해 드리겠습니다.

바로 한글 입력기에서 지원하는 것을 사용하는 것입니다.


벼루 입력기를 보시겠습니다.(참고로 나비 입력기도 똑같이 지원합니다.)


일단 벼루 입력기를 설치하는 것을 보여 드리겠습니다.


민트 리눅스 기반으로 설명하겠습니다.


1. 먼저 제어판에서 언어 설정으로 들어갑니다.




2. 언어 설정으로 들어 왔으면 "언어 입력기" 를 선택합니다.

그리고 "UIM"을 설치합니다.(그림에  써진 2번을 클릭합니다)


3. UIM 입력기를 설치하는 중입니다.


4. 설치가 완료 되었으면 터미널을 열어 아래의 명령어로  한글 입력기 벼루를 설치합니다.


 $ sudo apt-get install uim-byeoru 



5. 언어 입력기에서 언어 입력기를  "UIM"으로 설정합니다.


6. 이제 다시 제어판으로 가셔서 아래와 같은 "입력기"를 클릭하여 UIM을 설정합니다.(혹시 안보이시면 재 로그인을 하세요)



7. 전체적인 설정에 들어가서 디폴트 입력기를 벼루로 선택합니다.



8. 벼루 설정으로 가서 "ESC를 누르면 영문모드로(vi 사용자용)" 이 체크 된 것을 확인합니다.



9. 벼루 키 설정 1로 가서 한영키로 한영을 변경할수 있도록 등록합니다.


이제 재 로그인를 하여 ESC로 한영키가 바꿔어 지는 것을 확인합니다.






linux mint 다운로드

http://www.linuxmint.com/download.php

가벼운 순으로

Xfce >> MATE >> Cinnamon 순으로 가볍습니다.


멋진 UI 순으로 보면

Cinnamon  >> MATE >> Xfce 순으로 멋집니다.


노트북에 설치하신다면 ,Xfce, MATE 설치하는것을 추천합니다.


램이 4G 이하라면 32Bit 버전,

램이 4G 이상이라면 64Bit 버전 설치를 추천합니다.


여기서는 Xfce 32Bit버전 혹은 MATE 32Bit버전을 설치합니다.


윈도우에서 usb 부팅디스크를 만들려면 아래것을 다운로드 받아 iso를 선택하여 부팅디스크를 만듭니다.

http://www.pendrivelinux.com/universal-usb-installer-easy-as-1-2-3/

http://www.pendrivelinux.com/yumi-multiboot-usb-creator/



노트북에 민트 리눅스 설치후 노트북용 전력 관리 프로그램, 한글 입력기, 테마를 설치합니다.

http://luckyyowu.tistory.com/281


상위 링크 요약 버전


$ sudo -i

 **** : 암호 입력

# add-apt-repository ppa:linrunner/tlp
# add-apt-repository ppa:snwh/pulp
# add-apt-repository ppa:numix/ppa


# apt-get update


# apt-get install tlp tlp-rdw paper-gtk-theme paper-icon-theme \
    numix-gtk-theme numix-icon-theme-circle numix-icon-theme \
    uim uim-byeoru tlp tlp-rdw rdesktop
    
# tlp start



커널 분석 환경 vim 설정

http://iamroot.org/wiki/doku.php?id=kernel_original_12_a:2015_06_27


 vim 사용법
    번들 설치(git clone https://github.com/ygpark/vimconfig.git ~/vimconfig)

ctags 사용법
    리눅스 커널 디렉토리에서 tag 만드는 법(make tags ARCH=arm)


Unix V6 함수 리턴과 스위칭 2(완)


그럼 실제로 UNIX V6에서 스위칭 되는 소스를 한번 봐보겠습니다


1. 데이터 영역 구조


일단 소스를 보기 전에 데이터 세그먼트 메모리 구조 부터 보기로 하겠습니다.

일단 주소는 간단한 설명을 위해 100부터 시작했음을 알려 드립니다.

UNIX V6 데이터 영역 0번지에는 user 구조체가 자리잡고 있고 그 위에 데이터 영역과 스택 영역이 자리 잡고 있습니다.

이해 하시는데 문제 없을 거라 생각하고 다음으로 넘어 가겠습니다.




2. fork() 함수와 newproc() 리턴 값 1

UNIX V6 72page 리스트 3.3 fork() 소스 13라인의 설명을 보면 부모 프로세스는 0을 리턴 받고

자식 프로세스는 1를 리턴 받는다고 나옵니다.


하지만 newproc() 함수를 보면 0을 리턴하는 소스는 있지만 눈을 씻고 봐도

1를 리턴하는 소스는 볼수가 없습니다.



 


소스 설명에는 switch() 함수가 1을 리턴해서 1을 가져 온다고 써있는데




도.대.체 어떻게 아무런 접점도 찾을수 없는 fork()함수와 switch()가

switch() 함수가 1을 리턴했는데 어떻게 fork()함수가 1을 리턴 받을까요?





3. fork() 함수와 newproc() 리턴 값 2


그럼 설명에 들어 가겠습니다.

일단 fork() 함수 13 라인과 데이터 영역 메모리 그림부터 보겠습니다.




저번에 했던 함수와 스택 구조 그림을 그대로 그려 보면서 그 과정을 보겠습니다.

fork() 함수 13라인이 실행 되고 있는 그림입니다.


R5 = 100

R6 = 99

R7 = fork() 13라인



지역변수가 여러개 혹은 없을수 있지만 신경 쓰지 않아도 되므로 지역변수들이라고 써놓았습니다.

그리고 위의 fork() 함수를 실행하고 있는 프로세스는 부모 프로세스입니다.(자식은 아직 생생도 되지 않았죠..)

여기서 newproc() 함수를 호출합니다.




4. newproc() 호출 1


자 그럼 이제 newproc를 호출 합니다.

전 게시글을 보셨으면 이해 하실수 있을겁니다.

스택에 리턴 어드레스 저장(fork함수 13라인), fork() 함수 프레임 저장(R5 = 100)

어셈블리언어로 하면(r6가 99에서 시작함)


mov r7, -(r6)    --> 스택에 리턴 어드레스(fork 함수 13라인)를 저장, 그리고 r6 = r6 -1

mov r5, -(r6)    --> 스택에 fork함수 프레임 주소(100) 저장, 그리고 r6 = r6 -1




5. newproc() 호출 2


이제 R5에 R6(97)값을 넣으면 되지요.


mov r6, r5    --> R5 = R6(97) --> R5 = 97





6. 함수 프레임및 스택 포인터 저장


자 이제 함수 프레임및 스택 포인터를 저장합니다.(newproc 함수 50라인)





savu 함수는 user 구조체에 r5, r6레지스터값을 저장하는 함수 입니다.

그림으로 보니 아무것도 아니죠? ^^





7. 프로세스 복제 1


자 이제 부모 프로세스가 자식 프로세스를 생성하는 작업을 완료하고



데이터 영역을(newproc 함수68라인) 복사합니다.






8. 프로세스 복제 2


데이터 영역 복제 완료하면 아래와 그림과 같습니다.



unix v6 PDP 11 시스템은 cpu가 하나 밖에 없으며 한번에 하나의 프로세서만 실행 시킬수 있습니다.

그러므로 부모로부터 복제된 자식 프로세스는 메모리 복제가 일어난 상태이고 실행중이 아닙니다.




9. 부모 프로세서의 리턴



부모 프로세서는 실행을 계속하여 newproc() 71라인으로 오게 되며 0을 리턴 받습니다.







10. 자식 프로세스의 실행 1


자식 프로세스는 실행중이 아니라고 했습니다.

그럼 자식 프로세스는 어디서 다시 실행될까요?


바로 switch() 함수 입니다.


일정 시간이 되거나 우선순위가 되면 자식 프로세스는 실행가능상태에서 실행상태로 변하고

실행을 재게 합니다.(switch 함수)




switch 함수 40라인 전에서 자식 프로세스가 선택되었다고 가정합니다.

40라인에서 retu 함수가 실행 됩니다.


retu 함수는 그림에 나타나 있듯이 user 구조체에 있는 R5, R6값을 cpu로 옮기는 작업을 합니다.

하지만 아직 cpu는 자식 프로세스를 완전하게 실행하고 있지 않습니다.





11. 자식 프로세스의 실행 2 - 데이터 영역 사용


아직 위그림까지는 데이터 영역을 완벽하게 사용하지 못하고 있습니다.

또한 자식 프로세스가 완벽하게 실행하고 있다고 볼수 없습니다.(아직 switch 함수 실행중)




이제 switch 41라인까지  왔습니다.

여기서 드디어 cpu가 데이터 영역을 완벽하게 자식프로세스로 바꿉니다.


하지만 아직도 소스는 switch 함수를 실행중입니다.

아직 자식 프로세스가 실행중이라고 말하기에는 좀 부족합니다.





12. 함수 리턴과 fork() 함수 복귀!!! - 스위칭 완료!!!!


무엇이 부족할까요?

fork 함수 13라인을 보면 자식 프로세스는 1를 리턴 받는다고 나옵니다.


책에서 fork() 함수가 newproc()호출하면 부모 프로세스는 0을 리턴받고

자식 프로세스는 1를 리턴 받는다고 했습니다.


자 그럼 switch 함수 48라인이 실행 되면 어떻게 될까요?




여기서 swtich 함수에서 return를 했습니다.

저번 게시물에서 봤던 함수 리턴입니다.



저번 게시물에서 봤던 그대로 따라해 보겠습니다.

그럼 아래와 그림 같이 될것입니다.




 (1). 스택에서 R5 값 100(fork 함수 프레임)을 가져온다.

 (2). 스택에서 리턴 어드레스 값을 가져온다. R7 = fork() 13라인

 (3). switch() 에서 리턴한 값 1을 가져온다.


자!!! 그럼 자식 프로세스는 이제 어디를 실행하고 있나요?


fork 함수 13라인을 실행하고 있습니다.(사실 14라인이지만 ㅎㅎ 캡쳐 실패)


이것이 스위치의 원리입니다.


참고로 위의 게시글과 같이 UNIX V6 exec 함수 14라인 (sleep 함수 호출)도 한번 해보세요.

동일하게 exec 14라인으로 되돌아 올것입니다.



그럼 이제 unix v6 스위치가 끝났습니다.



오타나 이해 되지 않으시면 댓글이나 혹은 다른 연락 가능한 곳으로 문의 주세요^^




Unix V6 함수 리턴과 스위칭 1


Unix v6 함수 리턴과 스위칭에 대해 한번 알아 보겠습니다.


저번 게시물에서 마지막에 스위칭에 대한 힌트를 마지막에 올렸습니다.


아래와 같았고 B함수에서 리턴(return) 되면 과연 어디로 리턴될 것인가를 묻고 끝냈었습니다.




그럼 오늘은 풀이를 한번 해보겠습니다.



1. 이상한 함수 리턴 문제 풀이 1

먼저 A() 함수에서  B() 함수를 호출하는 코드와 스택 구조를 한번 봐보겠습니다.





만약 위 그림이 이해 되지 않는다면 다시 첫 게시물부터 다시 보세요.

먼저 A() 함수 11라인을 보겠습니다.


여기서 r5 는 R5레지스터 라고 가정하겠습니다.

r5는 A함수 프레임 첫 스택 주소인 96를 가지고 있습니다.

s_r5 = r5(96) --> s_r5 = 96  : savu 함수와 비슷한 기능을 합니다.

R5 = 96

R6 = 94

R7 = 11 라인



2. 이상한 함수 리턴 문제 풀이 2


이제 A()함수에서 B()함수를 호출하고 17라인일때의 그림은 아래와 같습니다.




스택에 리턴 주소인 A() 함수 12라인과  A()함수 프레임 주소 96이 저장되어 있습니다.

R5 = 92

R6 = 92

R7 = B() 함수 17 line



3. 이상한 함수 리턴 문제 풀이 3



여기서 r5 = s_r5(96) 가 나옵니다.

그러면 r5 = 96 이 됩니다.


R5 = s_rt(96) -->R5 = 96  : unix v6의 retu 와 비슷한 기능을 합니다.

R6 = 92

R7 = B()함수 17 line




4. 이상한 함수 리턴 문제 풀이 4



그러면  B() 함수 18라인에서 return이 나오면 어떻게 될까요?

원래대로라면 A()함수 13라인으로 가야 맞겠지요..


하지만 위에서 R5 가 96(A함수 프레임)으로 바뀌었습니다.


이전 게시물에서 리턴을 한다면

1. 스택 포인터 R6에 R5를 넣고

2. R7(프로그램 카운터)에 리턴 어드레스(R6 기준)를 넣는다고 했습니다.


그럼 한번 그대로 한번 해보겠습니다.




5. 이상한 함수 리턴 문제 풀이  5




일단 R5에 스택에 저장되어 있는 main()함수  프레임 주소를 가져옵니다.

그리고 스택에서 R7에 리턴 주소인 main() 함수 6라인 값을 가져옵니다.

R6는 각각 1씩 줄어 98이 됩니다.


R5 = 100  --> 스택(주소 97)에서 main() 프레임 주소 100가져옴 

R6 = 98

R7 = 6 line --> 스택(주소 98)에서 리턴 어드레스(main() 6라인)를 가져옴


18라인 B()함수에서  리턴을 했는데  main()함수 6라인으로 리턴되었습니다.



6. Unix v6 스위칭 힌트


이것이 바로 Unix V6 스위칭힌트입니다.

savu 함수가 함수 프레임을 저장하는 것이고

retu 함수가 함수 프레임을 복구 시키는 것입니다.


결국 savu 는 현재 실행되고 있는 함수 위치를 저장하는 것이고

retu는 이전에 실행 되고 있는 함수 위치를 복구 시키는 것입니다.

단지 여기서는 R5, R6만 복구 하고 있다는 것입니다.


R5는 함수 프레임 시작위치이고 R6는 스택 포인터입니다.

하지만 이상하게도 R7(프로그램 카운터)는 복구 되지 않습니다.


그러나 잘 생각해 보시면 R7(프로그램 카운터) 값은 스택에 리턴 어드레스 값이  저장 되어 있다

사실을 알아둘 필요가 있습니다.


함수 프레임과 스택 프레임을 복구 시키고

C 언어에서 return를 만나게 되면 스택에서 리턴어드레스가 R7에 복구 되면서

비로소 기존에 실행 했던 함수 코드로 반환 되어 다시 실행 됩니다.


위에서는 같은 프로세스 내에서 B() 함수 프레임 위치를 A() 함수 프레임 위치로 바꾸어서 했습니다.

하지만 retu는 같은 프로세스의 R5, R6를 바꾸는것이 아니라

다른 프로세스의 R5, R6를 바꾸는것입니다.


그러므로 다른 프로세스의 다른 함수로 복구 된다는 말이 됩니다.


다음 게시물은 Unix V6 스위칭에 대해 써보겠습니다.


함수 호출과 스택 구조 네번째 글입니다.


이 게시글에서는 함수 리턴에 대해 설명하겠습니다.
이 글 끝에 보면 Unix V6에서 커널 switch 를 이해 할수 있는 힌트가 있습니다.



1. A 함수 리턴 1 - return 명령 실행





자 그럼 이어서 하겠습니다.

A 함수 13번째 라인를 실행한다고 하겠습니다.( 알아보기 쉽게 return 를 넣었습니다.)

이때 레지스터 값들은


R5 = 96 (A 함수 프레임)

R6 = 94 (스택 포인터)

R7 = 13 (code 13라인)





2. A 함수 리턴 2 - 스택 포인터 복구(R6)


A 함수가 리턴을 만났습니다.


먼저 R6 스택포인터(sp)를 R5로 바꿉니다

R5 = 96

R6 = R5(96) --> R6 = 96 

R7 = 13






3. A 함수 리턴 3 - main() 프레임 포인터 복구(R5)

이제 R6 가 가르키는 스택에서 main 함수 프레임 값을 가져와 R5에 복구 합니다.

R6 = R6(96) + 1 ; ( 으.. 그림를 살짝 잘못 캡쳐 했네요 ㅡ.ㅜ R6가 97이어야 하는데 이해좀 ㅡ.ㅜ)

R6 = 97;

R5 = 100;   -->  R5 = (R6)  R5 = (스택 97 번지의 값) (**그림 참고)








4. A 함수 리턴 4 - return address 복구(R7)


R5 = 100;

R6 = 97 + 1;

R7 = 5 라인;  --> 스택(99 주소)에서 리턴 어드레스 복구





이로서 A 함수에서 main함수로 리턴 되었습니다.


이것이 함수의 호출과 스택 구조가 되겠습니다.


설명이 좀 부실하네요 ^^




4. 이상한 함수 리턴과 커널 스위칭 힌트


자 그럼 게시글의 마지막으로 커널 스위칭에 대해 살짝 힌트를 드리겠습니다.




자 여기서 18라인을 실행하면 코드는 몇라인으로 갈까요?^^

위 코드에서 r5은 R5레지스터라 가정하겠습니다.^^


반드시 노트에 스택과 레지스터를 그려보시고

생각해 보십시요.

...

...



아 return 1; return 0; 에 대한것을 빼먹었군요.


마지막에 return 1; 를 하면

1이라는 값은 R0 에 저장됩니다.

호출한 함수에서는 호출이 끝나고 R0 레지스터 값을 반환값으로 처리합니다.





함수 호출과 스택 구조 세번째 글입니다.


저번 게시물에서


7. A 함수 종료 2 에서 아래의 빨간 글씨로 중요 하다고 써놨습니다.


7. A 함수 종료 2


이제 main 함수 5라인으로 복귀합니다.

여기서 다시 R5 = 100으로 바꾸고

R7를 5로 바꿉니다.


R5 = 100(?)

R6 = 98

R7 = 5(?)



****** 중요

여기서 의문인점이 생깁니다.

도대체 main 함수의 스택 위치100은 어디에서 왔으며(어디에 저장되어 있나?)

다음 실행라인(pc, R7)5라인은 어디에서 왔을까요?(어디에 저장되어 있나?)

이것은 다음 게시물에서 다루겠으며 어디에 저장할지 추측해 보세요.




여기서 main 함수의 스택 위치100

다음 실행라인(pc, R7)5라인 - 리턴 어드레스(return adress)

예상 하셨을텐데 스택에 저장 됩니다.


그럼 어떻게 저장될까요?

다시 그림 A() 함수를 호출할때를 보시겠니다.




1. A 함수 호출 1





여기 4라인에서 A 함수를 호출합니다.

저번 게시물에서는 R5를 98로 로 바꾸었는데요.

  R5 = R6(98) --> R5 = 98

  R6 = 98

  R7 = 4


원래는 최소 두가지 일을 더합니다.

저번 게시물때는 쉬운 설명을 위해 많은 것을 생략했었습니다.


1. 리턴 어드레스(return address)를 스택에 저장합니다. - 여기서는 메인함수 4라인이 아니라 다음에 실행할 메인함수 5라인 입니다.

2. R5(프레임포인터) 값을 스택에 저장합니다. - 여기서는 main 함수의 스택 시작값인 100

... (사실 이것 말고도 더 있습니다. 매개 변수라던가... 기타 레지스터라던가...)


그리고 다음에는 저번 게시물에 설명한  "4. A 함수 호출 9라인 - A함수 호출" 로 이동합니다.


그럼 다시 자세한 그림을 보겠습니다.




2. A 함수 호출 2 - 리턴 어드레스(return address) 값을 스택에 저장




스택에 다음 실행 위치(R7 + 1)인 5라인을 스택에 저장합니다. R7(프로그램 카운터 pc)


(R6) = R7(4) + 1 --> (98) = 5 line : 스택 주소 98에 코드 주소인 5라인을 저장

R6 = R6(98) - 1  --> R6 = 97

R7 = 4




3. A 함수 호출 3 -  R5(프레임포인터) 값을 스택에 저장



스택에 R5값(main 함수 스택 시작위치) 스택에 저장합니다.


(R6) = R5(100) --> (97) = 100 : 스택 주소 97에 R5((main 함수 스택 시작위치) 스택에 저장

R6 = R6(97) - 1  --> R6 = 96

R7 = 4





3. A 함수 호출 4 -  드디어 A함수로...




드디어 A 함수로 왔습니다.


R5 = R6(96) --> R5 = 96

R6 = 96

R7 = 9(A 함수 시작 라인)



오 드디어 이제 A 함수가 호출 되었습니다.


A 함수가 종료 될때는 위 역순으로 돌아 가게 되겠습니다.(노트에 추측해서 한번 그려보세요^^)

그럼 이제 종료하겠습니다..

..

..

..


..


다음 게시물에서 main 함수로 복귀를 보여 드리겠습니다.

함수 호출과 스택 구조 2 편입니다.


이번에는 함수를 한줄 한줄 넘어가면서 어떻게 스택이 생성되며

r5(프레임 포인터 레지스터, 인텔계열-ebp)

r6(스택포인터-sp, 인텔계열 - esp) 가 어떻게 변하는지 보겠습니다.



1. 먼저 main 함수가 시작될때 그림입니다.

R5 와 R6가 100으로 초기화 됩니다.

별다른 설명이 없어도 되겠죠?

아 그리고 코드 실행 위치가 1(라인) 이 됩니다.

코드실행 위치를 저장하는 레지스터가 R7(pc 라고도 합니다 program counter)입니다.

위에서는 R7 = 1 이겠군요.


R5(프레임포인터) = 100

R6(스택포인터) = 100

R7(프로그램카운터) = 1


2. main 함수 2라인 - m1 지역 변수 할당



일단 R6 가 가르키는 곳에 변수 m1를 할당합니다.

그리고 R6를 1 감소 시킵니다.


R6 = R6 -1;


R5 = 100

R6 = 99 (100 -1)

R7 = 2




3. main 함수 3라인 - m2 지역 변수 할당


또 다시 R6 가 가르키는 곳에 변수 m2를 할당합니다.

그리고 R6를 1 감소 시킵니다.


R5 = 100

R6= 98 (99 -1)

R7 = 3





4. A 함수 호출 9라인 - A함수 호출



여기가 조금 중요한 곳입니다. 일단 몇가지를 생략했다는걸 알아 주시기 바랍니다.


함수가 바뀌므로

R5를 R6가 가르키는 것으로 대입시킵니다.


R5 = R6(98) --> R5 = 98

R6 = 98

R7 = 9






5. A 함수 10라인~12 - 지역 변수 a1, a2 할당








6. A 함수 종료 1


여기서  A함수가 종료 됩니다.

R6(스택 포인터)를 R5값인 98로 바꿉니다

R6 = R5(98)


R5 = 98

R6 = R5(98) --> R6 = 98

R7 = 13




7. A 함수 종료 2



이제 main 함수 5라인으로 복귀합니다.

여기서 다시 R5 = 100으로 바꾸고

R7를 5로 바꿉니다.


R5 = 100(?)

R6 = 98

R7 = 5(?)



****** 중요

여기서 의문인점이 생깁니다.

도대체 main 함수의 스택 위치100은 어디에서 왔으며(어디에 저장되어 있나?)

다음 실행라인(pc, R7)5라인은 어디에서 왔을까요?(어디에 저장되어 있나?)

이것은 다음 게시물에서 다루겠으며 어디에 저장할지 추측해 보세요.



7. 지역 변수 m1 에 값 1을 대입하기



이제 R5(프레임 포인터)는 도대체 언제 쓰이는지 알아 볼 단계가 왔습니다.


지역 변수 m1에 1을 할당하려고 합니다.


m1 = 1;


그러면 m1 주소인 100번지에 값을 1을 넣으면 되겠지요.

하지만 위의 main() 함수니까 그나마 주소값이 고정 되어 있을지도 모르지만

A() 함수 값은 함수는 main()에 호출할수도 있고 또한 여기에 없는 또다른 함수에서 호출 할수도 있습니다. 여기서는 2번째에 호출되었지만 3, 4번째로 호출 할수 있으므로 주소가 수시로 바뀔수 있습니다.


그래서 지역변수를 접근할때  R5(프레임 포인터)가 사용됩니다.

R6(스택 포인터)는 값을 넣을때마다 수시로 변경이 되기 때문에

해당 함수가 끝나기 전까지 바뀌지 않는 R5를 사용하게 됩니다.


변수 m1는 100번지이지만

R5로 만들어 보면 R5 - 0(100-0) 값이 됩니다.

이런식으로 m2도 R5 - 1(100-1) 99가 됩니다.


그러므로 C언어로 한다면

m1 = 1; 은

(int*)(R5 - 0) = 1; --> (int*)(100) = 1;


m2 = 2; 는

(int*)(R5 - 1) = 2; --> (int*)(99) = 2;


또한 함수가 종료 될때 R6(스택 포인터)를 초기화 할때도 쓰입니다.(6. A 함수 종료 1 참고)


지역 변수는 해당 함수가 실행될때만 살아 있으므로 이는 R5를 사용하기에 알맞습니다.



그럼 다음 게시물에서  위에 빨간 글씨로 쓰인 뜻을 알아 보도록 하겠습니다.





마지막으로  지금까지의 강좌 gif 이미지



함수 호출과 이로 인해 생기는 스택 구조에 대해 간략 적으로 설명해 보겠습니다.

정말 간략적이기 때문에 상당 부분을 생략했습니다.(리턴 주소, 함수 매개변수, 환경프레임 주소 저장 등등... 생락)

다음 게시글에서 좀더 자세한 설명을 추가 할테니 일단은 개념 정도만 설명하도록 하겠습니다.


일단 C언어스택 부터 보시겠습니다.






간단합니다. main 함수 A 함수 달랑 두개가 있습니다.

그 안에 지역변수각각 2개씩 들어 있습니다.

그럼 처음 스택 구조를 보겠습니다.



스택은 데이터가 추가 되면 위에서 아래로 추가 됩니다.

옆에 있는 주소는 그냥 임의로 추가 하였고

원래는 2(16비트), 4(32비트) 단위로 감소 해야 하지만 편의를 위하여 간략하게 만들었습니다.



그럼 여기서 C언어에서 12라인까지 실행되면 스택 구조가 어떻게 되는지 대략적으로 그려보겠습니다.







대략 위와 같은 그림이 됩니다.

12라인을 실행할때 main()의 지역 변수 2개와 A()의 지역 변수 두개가 스택에 각각 위치합니다.

프로그램 수업이나 책에 보면 지역 변수는 스택에 저장 된다고 배우시잖아요.

저 그림이 그것입니다.


옆에 보시면 main()함수 구역 스택과 A()함수 스택 구조가 나뉘어있습니다.(논리적으로)

이 나뉜 부분이 unix v6책 에서 r5레지스터 환경 프레임을 가르킨다고 했는데

저 함수 구역이 환경 프레임이라고 보시면 됩니다.


그리고 하늘색으로 표시된 화살표가 다음에 스택에 데이터를 집어 넣을 장소를 가르키며

unix v6책 에서는 r6레지스터(sp - 스택 포인터 레지스터)가

저곳을 가르키는 주소(위 그림에서 주소 96)를 가지고 있습니다.

만약 스택에 데이터가 추가 되면 r6 레지스터 값이 하나가 감소(r6 = r6 - 1) 하는것이죠


그리고 주황색 화살표를 보시면 현재 함수 시작위치를 가르키고 있는데

이것이 바로 r5레지스터(인텔계열은 ebp 레지스터)가 가지고 있는 주소 값(위 그림에서 주소98)입니다.


main함수가 실행 중이면 r5 레지스터는 주소 100을 가지고 있고

A함수가 실행중이면 r5레지스터는 98를 가지고 있습니다.


다음 게시물에서는 main 함수 라인별로 따라가며 해보도록하겠습니다.


함수 호출과 스택 구조 2

http://fehead.tistory.com/200


+ Recent posts