Pintos_project2 - argument passing

2025. 9. 25. 11:29·Develop

Userprogram

사용자메모리접근

커널은 사용자가 제공한 포인터로 메모리 접근할 필요가 있다.
사용자가 NULL포인터, 매핑되지 않은 가상메모리, 커널영역메모리
에 대한 포인터를 제공하면 이를 오류로 판단하고

  1. 자원을 해제한다음
  2. 프로세스를 종료 해야한다.

유저프로그램의 모든영역에 해당하므로 포인터를 넘기는
시스템콜에는 적용해주도록 하자

코드

간단한 버전(통과는 함)

// pintos/userprogram/systemcall.c
static void check_address(const void *addr)
{
    if (addr == NULL || !is_user_vaddr(addr) || 
        pml4_get_page(thread_current()->pml4, addr) == NULL)
    {
        exit(-1); // 프로세스 강제 종료
    }
}
  1. if문에서 null, 커널영역, 페이지가 할당되었는지 판단
  2. 첫 1바이트만 검사하므로 완전한 검사는 아님

바이트마다 검사 + 커널영역으로 복사 후 사용

// pintos/userprogram/systemcall.c
bool copy_user_string(char *dst, const char *src, size_t max_len)
{
    for (size_t i = 0; i < max_len; i++)
    {
        /* 매 바이트 접근 전에 해당 주소가 사용자 영역인지 검사한다. */
        check_address(src + i);
        char c = src[i];
        dst[i] = c;
        /* NULL 문자를 만났다면 복사가 완료된 것. */
        if (c == '\0')
        {
            return true;
        }
    }
    /* 문자열이 최대 허용 길이 안에서 끝나지 않았음. */
    return false;
}

📌Argument Passing

주소 이름 데이터 타입
0x4747fffc argv[3][…] ‘bar\0’ char[4]
0x4747fff8 argv[2][…] ‘foo\0’ char[4]
0x4747fff5 argv[1][…] ‘-l\0’ char[3]
0x4747ffed argv[0][…] ‘/bin/ls\0’ char[8]
0x4747ffe8 워드 정렬 0 uint8_t[]
0x4747ffe0 argv[4] 0 char *
0x4747ffd8 argv[3] 0x4747fffc char *
0x4747ffd0 argv[2] 0x4747fff8 char *
0x4747ffc8 argv[1] 0x4747fff5 char *
0x4747ffc0 argv[0] 0x4747ffed char *
0x4747ffb8 반환 주소 0 void (*)()
- 워드정렬은 성능향상
- argv[argc] 는 규약
- 반환주소도 규약
### 인자전달이란??
커널영역에서는 사용자프로그램을 실행시킬때 인자들을
사용자영역 스택에 미리 세팅을 해주어야한다.

그래야 사용자모드로 넘어가서 사용자스택을 이용해 인자를
사용할 수 있다.

코드

process_exec() 함수에서 현재 스레드를 정리하고
프로그램을 로드할 때 추가해주면 된다.

필요한 과정은 arg_program arg1 arg2 arg3 이런식으로 입력명령이 들어오면

  1. 파싱한 후
  2. 유저메모리에 세팅
    해주면 된다.

파싱은 내장된 strtok_r 함수를 사용하면 되는데
원본 문자열에 영향이 가므로 재사용 할 거면 복사한 후 사용

유저메모리 세팅은 유저스택의 상단 포인터를 가지고,
위 표에 맞게 데이터를 적재하면 된다.

load 함수

// userprog/process.c

static bool load(const char *file_name, struct intr_frame *if_) // echo 1 2
{
    /* intr_frame은 유저프로그램을 
    시작하기전에 cpu 레지스터를 저장할 구조체 */
    (생략)
    uint64_t *addr[32]; // 인자를 저장할 문자열집합

    // addr에 인자를 저장하고 인자의 개수를 반환
    int argc = parse_args(file_name, addr);

    (생략)
    // 실행된 프로그램은 쓰기 작업 불가
    file_deny_write(file); 

    /* 유저스택 최상단 세팅 */
    if_->rip = ehdr.e_entry;

    // 유저스택에 데이터를 적재하는 함수
    setup_stack_args(if_, addr, argc);

    success = true;
    t->exec_file = file;

    // hex_dump를 이용해 디버깅. 
    print_dump(if_, 128);

    (생략)
    return success;
}

load 함수는 레지스터 및 페이지를 세팅하는 함수
이때 스택도 세팅

pars_args(cmdline, argv)

// "argument-test 1 2 3 4" → ["argument-test", "1", "2", "3", "4"]
static int parse_args(char *cmdline, char **argv)
{
    int argc = 0;
    char *token, *save_ptr;
    for (token = strtok_r(cmdline, " ", &save_ptr); token != NULL;
         token = strtok_r(NULL, " ", &save_ptr))
    {
        argv[argc++] = token;
    }
    return argc;
}

setup_stack_args(if, argv, argc)

static void setup_stack_args(struct intr_frame *if_, char **argv, int argc)
{
    uint8_t *ptr = (uint8_t *)if_->rsp; // 1바이트 단위 포인터
    uint64_t *addr[32];                 // 인자 최대 32개

    // 1. 문자열들 복사
    for (int i = argc - 1; i >= 0; i--)
    {
        int len = strlen(argv[i]);
        ptr -= (len + 1);
        memcpy(ptr, argv[i], len + 1);
        addr[i] = (uint64_t *)ptr;
    }

    ptr = (uint8_t *)((uintptr_t)ptr & ~0xF); // align

    ptr -= 8;
    *(uint64_t *)ptr = 0; // 마지막인자 0

    for (int i = argc - 1; i >= 0; i--)
    {
        ptr -= 8;
        *(uint64_t *)ptr = (uint64_t *)addr[i];
    }

    ptr -= 8;
    *(uint64_t *)ptr = 0; // fake address
    if_->R.rsi = (uint64_t)(ptr + 8);
    if_->R.rdi = argc;
    if_->rsp = (uint64_t)ptr;
}

'Develop' 카테고리의 다른 글

MessageQueue를 써야하는 이유 (+카프카 사용후기)  (0) 2026.01.02
node.js는 어떤식으로 동작할까?  (0) 2025.10.17
Pintos_project1 - Priority  (0) 2025.09.10
Pintos_project1 - Alarm Clock  (0) 2025.09.09
malloc lab-implicit list에 관하여 + 구현  (3) 2025.08.23
'Develop' 카테고리의 다른 글
  • MessageQueue를 써야하는 이유 (+카프카 사용후기)
  • node.js는 어떤식으로 동작할까?
  • Pintos_project1 - Priority
  • Pintos_project1 - Alarm Clock
sj-leeee
sj-leeee
배운것과 느낀것을 적는 공간입니다.
  • sj-leeee
    sj-leeee 님의 블로그
    sj-leeee
  • 전체
    오늘
    어제
    • 분류 전체보기 (23) N
      • LIFE (5)
      • Develop (17) N
  • 블로그 메뉴

    • 홈
    • 방명록
  • 링크

    • 깃허브
    • 이전블로그
  • 공지사항

  • 인기 글

  • 태그

    크래프톤
    heap
    정글
    싱글스레드
    MQ
    컴파일
    Pintos
    malloc
    AWS
    Kafka
    운영체제
    LinkedList
    git
    8주차
    node.js
    rbtree
    크래프톤정글
    krafton
    Algorithm
    Jungle
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
sj-leeee
Pintos_project2 - argument passing
상단으로

티스토리툴바