Dev_bob

[PintOs] Argument Passing 주요 개념 정리 본문

프로젝트/pintOs

[PintOs] Argument Passing 주요 개념 정리

킹대왕너구리 2025. 5. 25. 17:00

과제 내용

✅ 변경 전

기존의 pintOs 코드에서 process_execute(”echo x y z”)를 호출하면,

Thread name으로 “echo x y z” 문자열이 통째로 사용된다.

그렇게되면, “echo x y z”라는 문자열을 찾게되는데, 이는 당연히 실패하게 된다.

또한 argv, argc 또 한 전달 되지 않는다.

 

✅ 변경 후

똑같은 호출 process_execute(”echo x y z”) 이지만, 내부적으로는

Thread name : "echo" 첫 토큰만 사용

파일탐색 : "echo" 이라는 실행파일 찾음

Argument passing : "echo", "x", "y", "z" 를 스택에 복사, argc =4, argv[ ]를 구성하여 사용자 프로그램으로 전달

int main(int argc, char *argv[]) {...

그렇게 되면, 사용자 코드가 정상적인 인자를 전달 받을 수 있게 된다. 

 

주요 개념

process_exec()에서 하는일

 

1. f_name을 tokenizing

“echo x y z”=>echo", "x", "y", "z

 

2. load()를 하여 ELF파일 로딩

파일시스템의 실행파일인 ELF 파일을 열어서 ELF파일의 코드와 데이터를 User의 Virtual memory에 복사한다.

 

3. setup_stack()으로 유저가 사용할 스택을 생성

User Virtual Memory의 맨 위쪽, 4KB 공간의 가장 끝(=가상주소의 제일 높은쪽)에서 아래방향으로 쌓이게 됨.

 

4. do_iret

Ring 0(커널모드) -> Ring1 (유저모드)로 전환

 

5. 유저프로그램 실행 시작

 

 

USER STACK 채우기

USER STACK은 주소가 위->아래로 작아지는 방향으로 스택이 push된다.

주어진 문자열 : %bin/ls –l foo bar

스택의 높은주소로부터 낮은주소로 쌓이는 요소들에 대해 나열해보겠다.

그전에 알아둬야 하는 개념은, 스택은 높은 주소->낮은주소로 쌓이고, 실제 실행시 코드는 낮은주소->높은주소로 읽는다.

 

1. 문자열, 실제 값들 

"%bin/ls" "–l" "foo" "bar"

로 tokenizing 된 token에 대해서 stack은 오른쪽에서 왼쪽방향 순서로 스택에 넣는다.

즉 "bar"~ "%bin/ls" 순으로 넣는것인데, 이는 나중에 code가 stack 값을 읽을때에는 낮은주소에서 높은주소 방향으로 읽기 때문이다.

그래야 바른 순서로 읽힌다. 

 

2. word align padding 

8바이트 정렬을 맞추기 위해 padding하는 과정이 들어가게된다.

그 이유는 cpu가 데이터를 8바이트 단위로 정렬된 상태로 읽을때 성능이 좋기 때문이다.

즉 위에서 문자열 실제 값들을 복사한 후에 argv[ ] 배열을 push 하기 전 스택포인터인 rsp를 8의 배수로 맞추는 padding작업을 한다.

 

padding이란, 정렬을 맞추거나 공간을 채우기 위해 의미 없는 데이터를 메모리에 추가해놓는 것이다.

 

3. argv[argc] : NULL포인터 삽입

argv[] 배열의 끝을 명시하기 위해 NULL포인터를 argv[argc]로 초기화하여 스택에 push한다.

 

4. argv[] 배열 시작주소

 

5. argc 값

argument 개수

 

6. Fake return address

main함수가 끝나면 return 함수를 0으로 줌으로써 프로그램이 종료되게 끔 함.

 

이렇게되면, 실제로 실행될때에는

return address -> argc -> argv[] 배열 시작주소 -> word align padding - > 문자열 실제 값 
순으로 실행된다. 

int main(int argc, char *argv[]) {...

 

 

_if , 인터럽트 프레임이란?

Interrupt frame이란 CPU 레지스터 상태를 저장해놓은 구조체이다.

user program을 실행하거나 되돌릴 때 사용된다.(Context save)

인터럽트 프레임의 레지스터 의미

RIP 다음에 실행할 명령어 주소
RSP 스택 포인터
RDI, RSI, RAX, ... 함수 인자, 계산 중간값 등
RFLAGS 플래그 (인터럽트 허용 여부 등)
CS, SS 코드/스택 세그먼트 (권한 레벨 포함)

 

인터럽트 프레임은 커널 스택에 위치한다.

ABI (컴파일된 프로그램이 OS와 CPU에서 실행될 수 있도록 정한 규약)에 따라, 

RDI  <- argc

RSI  <- argv 

...

으로 레지스터 값에 저장된다. 

 

'프로젝트 > pintOs' 카테고리의 다른 글

[pintOs]Process Termination Message  (2) 2025.06.02