pintOS project 2 - argument passing

c4fiber·2023년 12월 28일
0

SW사관학교 정글7기

목록 보기
43/49

왜? (목적)

현재 file_name 은 인자를 포함한 형태 “test a b c” 이다.
filesys 를 통해서 file을 읽어들여야 하는데 공백을 기준으로 파일명 (예시에서는 "test")를 분리해야 한다.

이를 parsing 해서 실행 파일은 test, 인자로 a, b, c 를 넘겨주도록 해야함.


어떻게? (방법)

process.c 파일의 process_exec 를 보면 elf 파일을 load 하는 과정이 있다.

load 함수는 process.c 파일에 정의되어 있으며 최하단에 보면 TODO 로 argument passing을 구현하라고 주석처리 되어있음


input arguments into stack

저장시점: load 함수 내 set_stack 을 수행하고 나면 struct intr_frame if_rsp 값에 stack top 주소가 들어온다.

이 rsp값을 낮춰가면서 stack에 데이터를 집어 넣는다.

참고용 pintOS docs 내용

내가 삽입한 arguments의 상태

나는 가이드라인과 조금 다르게 했는데 모든 인자크기의 합을 Round_up 해서 공간을 미리 확보하고, 시작지점부터 데이터를 삽입했기 때문에 높은 주소(마지막) 에 padding이 생긴다.

introduction 에서는 word-align이 추가되고 그 다음부터 argv의 실제 내용이 저장된다.
하지만 나는 마지막에 padding을 붙여서 align을 맞췄다.

gdb로 메모리 상태를 출력해본 결과

현재 스택을 모두 넣은 상태에서 rsp 는 0x4747ffc8 이다.
gdb로 출력해본 결과 값이 잘 들어간걸 볼 수 있다.
(64bit 운영체제 기준이므로 하단의 x/12xg 0x4747ffc8 부분을 봐주길 바란다.)


발생한 에러 목록

process_exec, load 수정 후 "system call!" 에러

부팅이 완료되고 args-single 을 실행하는 과정에서 에러가 발생한다.

system call! 이라는 출력과 함께 args-single onearg가 종료되었다고 나온다.

syscall_handler가 호출되었을 때 상태가 no_sti 인데
이 no_sti 의 내용을 확인할 수 없어서 멈춰있는 중이다.

argument passing 테스트 통과를 위해서는 syscall 중 일부분을 작성해두어야 한다.
sys_exit, sys_write 두 가지 이다.

  • exit: 종료하면서 특정 문구를 출력해야함
  • write: user level에서 콘솔에 출력할 수 없으므로 system call을 구현해야함

이 두가지는 아래에 따로 기술하였다.


user program이 실행되지 않고 테스트가 종료되는 경우

thread.c

다음와 같이 yield 하는 조건을 수정했더니 문제가 없어졌다. -> 문제 해결 방법이 아니다.
이 경우 main thread가 새로운 thread를 만들고 실행시켜야 하는데 yield 하지 않아서 main thread가 바로 종료되어 버린다.
이 때문에 새로 생성된 스레드는 실행되지 못하고 내가 삽입한 실행파일 args-single 이 실행되지 못한다.

(임시 해결 방법) solved: thread_create 에서 yield 방법 변경

확인된 원인은 thread_yield 에서 발생하는 assertion failed 이다.
ASSERT (!intr_context()) 코드에서 실패하고 종료된다.

synch.c 코드에서 sema_up() 을 확인해보면 yield() 만 사용했다.
정확한 지점은 추적이 불가능하지만 external_interrupt 상황에서 yield를 수행할 경우 발생한다.

이를 막아주기 위해서 외부 인터럽트 상황일 때 intr_yield_on_return() 으로 해결해주었다.


intr 0x0d General Protection exception

원인은 찾지 못했다. call stack으로 추적할 수가 없었다.

해결시도 1: 8byte 단위로 뒤집어주기 -> 실패

이때 레지스터 상태를 보면 6E69732D 73677261 이라는 값이 들어있다.

hex값으로 보면 "args-sin" 이 뒤집어있는걸 볼 수 있는데 이때문에 string을 8byte 단위로 뒤집어서 넣어야 하나? 라는 생각을 잠깐했다.

너무 갔다고 생각했다.

해결 완료 - 인자를 잘못넣었다.

%rsi 에는 argv[0]의 주소 값 이 들어가야 한다. 즉 rsp - 8 의 값이 들어가야 한다.

나의 코드 (process.c)

3시간은 쓴거같다.


exit(status_code) 를 수행하면 이를 출력해주어야 한다.


스레드를 생성할 때 이름을 제대로 집어넣지 못했다.

꼭 한줄씩 문제가 생겼는데 test a b c 라는 입력이 들어왔으면 스레드의 이름을 test 로 해줘야 하기 때문이였다.

다음과 같이 스레드 생성에 필요한 이름을 파싱하기 위해 sub_file_name 을 만들었다.

strcspn 함수는 reject가 포함되지 않는 index 0 부터 시작하는 substring의 길이를 반환한다.
char 배열의 크기가 15인 이유는 pintOS 에서 파일이름의 길이가 최대 14였기 때문이다.

결과:


번외: hex_dump 를 이용해 확인하는 방법

다른 팀원이 hex_dump 함수를 사용해서 편하게 작업하는보고 사용하면 좋겠다고 생각해서 작성한다.

process.c

주석처리한 첫줄을 보면 hex_dump를 이용해 아래와 같이 출력할 수 있다.
USERSTACK 이 중요하다. KERN_BASE 와 헷갈리지 말자!!

다음과 같이 gdb를 이용해서 값을 확인할 수 있다.

profile
amazing idiot

0개의 댓글