Pintos 내 process.c의 수행 과정에 대해 대략적으로 공부했으므로 이제는 구현을 진행해야 한다.
앞서 말했듯이 우리의 구현과제는 총 2개로 이루어진다.
[구현 과제]
1. 사용자에게 받은 인자 parsing
2. User Stack 내 인자 삽입
3. 쓰레드 이름 parsing(추가 구현)
이 모든 코드 작성은 process.c 내에서 일어나며 process_exec() 함수 내에서 1,2를 구현하면 된다.
Kaist 내 방침상 이후에 공부할 학생들을 위해 작성한 정답 코드를 올리는 것은 금지되어 있다.(내 코드가 정답인지는 모르겠지만...) 따라서, 의사 코드를 통해 작성을 진행하겠다.
1. 구현
- 사용자에게 받은 인자 Parsing
int process_exec (void *f_name) {
char *file_name = f_name;
bool success;
// 나누어진 인자를 단어 단위로 저장할 리스트 선언
...
/* 1. Modify Parsing file_name */
// strtok_r() 함수를 사용하여 ' '로 나누어진 첫번째 인자를 받을 변수와 남은 인자들을 저장할 변수를 선언한다.
// 반복문을 통해 인자들을 ' '로 모두 나누어 리스트에 저장한다.
// ex) args-single oneargs hello => arr[0] : args-single, arr[1] : oneargs, arr[2] : hello로 나뉘게 된다.
...
/* Start switched process. */
do_iret (&_if);
NOT_REACHED ();
}
사용자에게 받은 인자를 파싱하기 위해 strtok_r을 사용하여 특정 조건에 \0을 삽입함으로써 해당 단어만큼만 추출하게 해준다. 이렇게 나눠진 각각의 단어를 리스트에다가 저장해 놓는다.
- User Stack 내 인자 삽입
int
process_exec (void *f_name) {
char *file_name = f_name;
bool success;
// 나누어진 인자를 단어 단위로 저장할 리스트 선언
...
/* 1. Modify Parsing file_name */
// strtok_r() 함수를 사용하여 ' '로 나누어진 첫번째 인자를 받을 변수와 남은 인자들을 저장할 변수를 선언한다.
// 반복문을 통해 인자들을 ' '로 모두 나누어 리스트에 저장한다.
// ex) args-single oneargs hello => arr[0] : args-single, arr[1] : oneargs, arr[2] : hello로 나뉘게 된다.
...
/* We cannot use the intr_frame in the thread structure.
* This is because when current thread rescheduled,
* it stores the execution information to the member. */
struct intr_frame _if;
_if.ds = _if.es = _if.ss = SEL_UDSEG;
_if.cs = SEL_UCSEG;
_if.eflags = FLAG_IF | FLAG_MBS;
/* We first kill the current context */
process_cleanup ();
/* And then load the binary */
success = load (file_name, &_if);
/*2. Push User Stack*/
// argument_stack이라는 함수 선언 후 파싱한 인자가 담겨 있는 리스트, 인자 갯수, &_if.rsp 전달
// _if.R.rsi 선언
// _if.R.rdi 선언
/* If load failed, quit. */
palloc_free_page (file_name);
if (!success)
return -1;
/* 결과 확인 hex dump check */
hex_dump(_if.rsp, _if.rsp, USER_STACK - _if.rsp, true);
/* Start switched process. */
do_iret (&_if);
NOT_REACHED ();
}
파싱한 인자를 아래와 같은 구조로 스택에 쌓기 위해서 argument_stack이라는 함수를 사용하려고 한다.
만약 User Stack에 저장이 완료 되었다면 현재 인자의 갯수를 rdi에 현재 rsp의 주소 - 8 한 위치를 rsi에 저장해 줘야 한다.
- argument_stack 함수 구현
/* Push Argument Stack */
void argument_stack(char **parse ,int count , void **rsp){
// 1. Push Arguments
// 널 문자를 포함한 총 인자 갯수를 저장할 변수 선언
// 인자가 위치한 rsp 주소를 넣을 리스트 선언
// 1-1. Push character strings from left to write.
// 현재 *rsp 주소를 기준으로 이중 반복문을 통해 parsing한 인자를 하나씩 받으며 *rsp-1을 하면서 단어 하나씩 넣기
// 하나의 인자 저장이 끝나면 현재 rsp 주소 리스트에 삽입
// 1-2. Place padding if necessary to align it by 8 Byte.
// 현재 주소에서 *rsp -(8-(temp%8))
// 패딩을 위한 공간에 memset을 통해 0 저장;
// 1-3. Push start address of the character strings.
// rsp -8한 주소에 memest을 통해 0 저장
*rsp = *rsp - 8 ;
memset(*rsp, 0, sizeof(char *))
// memcpy를 통해 현재 각 인자의 시작주소가 저장되어 있는 *rsp 리스트 변수들을 *rsp-8 반복하며 저장
// 2. Push the address of the next instruction (return address)
// 마지막으로 가짜 return 함수를 만들기 위해 memset으로 *rsp-8 후 0 저장
}
위 스택 사진처럼 인자를 현재 rsp 위치에서 비트 수만큼 빼면서 데이터를 삽입해야 한다. 저장할 때는 위에서 아래로
스택에 저장할 때, 인자의 순서를 조심하자!! 만약 abc가 있다면 저장할 때는 c->b->a 순으로 저장을 해야 나중에 출력 시 현재 rsp 주소가 0x4747ffb8에 있기 때문에 a->b->c 로 빼면서 사용할 수 있다.
2. 구현 확인
pintos --gdb --fs-disk=10 -p tests/userprog/args-single:args-single -- -q -f run 'args-single onearg'
명령어로 해당 파일 실행 후 현재 User stack 쌓은 인자들이 제대로 있는지 확인
읽을 때는 아래에서부터 위로 읽으므로 해당 내용이 입력한 것과 반대로 저장된 것을 확인 할 수 있다.
'sw 사관학교 정글 > TIL' 카테고리의 다른 글
[정글 73일차] Project3 : Page Table & Virtual Memory (0) | 2023.05.10 |
---|---|
[정글 72일차] Project2 발표 및 Project3 발제 (0) | 2023.05.09 |
[정글 62일차] Project2 : Argument Parsing 호출 순서 및 코드 실행 방법 (0) | 2023.04.29 |
[정글 60일차] Project2 발제 (0) | 2023.04.29 |
[정글 59일차] Project1 : Priority Schedule2 (0) | 2023.04.29 |