210209 개발일지(64일차) - 운영체제(OS) 프로젝트 #2-1 : Argument Passing

고재개발·2021년 2월 9일
0

OS Project

목록 보기
11/28

Argument Passing은

  1. Argument를 나눠주는 띄어쓰기 별로 나눠주는 Argument Parsing과
  2. Parsing된 Argument들을 User stack 넘겨주는 Argument Passing의

두 기능을 포함한다고 할 수 있다.

Argument parsing

예를 들어, 아래와 같이
run 'args-single onearg'라는 명령이 터미널에 입력되면, run이란 명령어가 뒤에 입력되는 'args-single onearg'을 실행하는 것이라고 생각하면 된다.
argument[0]에 해당하는 args-single은 파일명이 될 것이고, onearg는 인자가 될 것이다.

process_exec() 함수 내에서 구현하면 된다.
아래 while문과 argument_stack() 함수를 주목하면 된다.
argument_stack() 함수는 구현해야 한다.

int process_exec(void *f_name)
{
    char *file_name = f_name;
    bool success;
    char *next_ptr;
    char *save_ptr = NULL;
    char *save_arg[128];
    int token_cnt = 1;
    save_ptr = strtok_r(f_name, " ", &next_ptr);
    save_arg[0] = save_ptr;

    while (save_ptr != NULL)
    {
        token_cnt++;
        save_ptr = strtok_r(NULL, " ", &next_ptr);
        save_arg[token_cnt - 1] = save_ptr;
        // printf("save_ptr : %s, %d\n", save_ptr, token_cnt);
        // printf("........ : %s, %d\n", save_arg[token_cnt-1], token_cnt);
    }

    /* 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);
    /* If load failed, quit. */

    if (!success)
        return -1;    

    // printf("%d", token_cnt);
    argument_stack(save_arg, token_cnt, &_if.rsp);

    _if.R.rdi = token_cnt - 1;
    _if.R.rsi = (uintptr_t *)_if.rsp + 1;

    // hex_dump(_if.rsp, _if.rsp, USER_STACK - _if.rsp, true);

    /* Start switched process. */
    do_iret(&_if);
    palloc_free_page(file_name); 
    NOT_REACHED();
}

Argument passing

위에서 parsing한 문자열들을 User stack 영역에 잘 쌓도록 넘겨준다.
argument_stack() 함수로 구현하여, 나타내볼 것이다.
USER_STACK이 정의되어 있어서 아래 표와 같은 결과값이 나온다.
명령어 예시 : /bin/ls -l foo bar

void argument_stack(char **parse, int count, void **rsp)
{
    char *word_address[128];
    int for_word_align = 0;

    //! 문자열 저장
    for (int i = count - 2; i > -1; i--)
    {
        for_word_align = for_word_align + strlen(parse[i]);

        for (int j = strlen(parse[i]); j > -1; j--)
        {
            *rsp = (char *)*rsp - 1;
            **(char **)rsp = parse[i][j];
        }
        word_address[i] = (char *)*rsp;

    }

    //! word_align 처리 
    *rsp = *(uintptr_t *)rsp & ~(uintptr_t)7;

    // argv[cnt+1]에 0(NULL) 추가
    *rsp = (uintptr_t *)*rsp - 1;
    **(uint64_t **)rsp = NULL;

    //!argv[0~cnt] 저장
    for (int i = count - 2; i > -1; i--)
    {
        *rsp = (uintptr_t *)*rsp - 1;
        **(uint64_t **)rsp = word_address[i];
    }

    //! return address 저장
    *rsp = (uintptr_t *)*rsp - 1;
    **(uint64_t **)rsp = 0;
}

argc(인자 수), argv[0]의 주소값 저장

추가적으로, 인자 수와 argv[0]의 주소값을 저장해줘야 한다.
process_exec() 함수에서 아래 두 줄을 추가해주면 된다.

int process_exec(void *f_name){
    ...
    _if.R.rdi = token_cnt - 1;
    _if.R.rsi = (uintptr_t *)_if.rsp + 1;
    ...
}

Argument passing을 시작으로, system call 내용들을 잘 구현해보자.
profile
고재개발

0개의 댓글