현재 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을 구현하라고 주석처리 되어있음
저장시점: load
함수 내 set_stack
을 수행하고 나면 struct intr_frame if_
의 rsp
값에 stack top 주소가 들어온다.
이 rsp값을 낮춰가면서 stack에 데이터를 집어 넣는다.
나는 가이드라인과 조금 다르게 했는데 모든 인자크기의 합을 Round_up 해서 공간을 미리 확보하고, 시작지점부터 데이터를 삽입했기 때문에 높은 주소(마지막) 에 padding이 생긴다.
introduction 에서는 word-align이 추가되고 그 다음부터 argv의 실제 내용이 저장된다.
하지만 나는 마지막에 padding을 붙여서 align을 맞췄다.
현재 스택을 모두 넣은 상태에서 rsp 는 0x4747ffc8
이다.
gdb로 출력해본 결과 값이 잘 들어간걸 볼 수 있다.
(64bit 운영체제 기준이므로 하단의 x/12xg 0x4747ffc8 부분을 봐주길 바란다.)
부팅이 완료되고 args-single 을 실행하는 과정에서 에러가 발생한다.
system call!
이라는 출력과 함께 args-single onearg가 종료되었다고 나온다.
syscall_handler가 호출되었을 때 상태가 no_sti 인데
이 no_sti 의 내용을 확인할 수 없어서 멈춰있는 중이다.
argument passing 테스트 통과를 위해서는 syscall 중 일부분을 작성해두어야 한다.
sys_exit, sys_write 두 가지 이다.
이 두가지는 아래에 따로 기술하였다.
thread.c
다음와 같이 yield 하는 조건을 수정했더니 문제가 없어졌다. -> 문제 해결 방법이 아니다.
이 경우 main thread가 새로운 thread를 만들고 실행시켜야 하는데 yield 하지 않아서 main thread가 바로 종료되어 버린다.
이 때문에 새로 생성된 스레드는 실행되지 못하고 내가 삽입한 실행파일 args-single
이 실행되지 못한다.
확인된 원인은 thread_yield 에서 발생하는 assertion failed 이다.
ASSERT (!intr_context())
코드에서 실패하고 종료된다.
synch.c
코드에서 sema_up()
을 확인해보면 yield() 만 사용했다.
정확한 지점은 추적이 불가능하지만 external_interrupt 상황에서 yield를 수행할 경우 발생한다.
이를 막아주기 위해서 외부 인터럽트 상황일 때 intr_yield_on_return()
으로 해결해주었다.
원인은 찾지 못했다. call stack으로 추적할 수가 없었다.
이때 레지스터 상태를 보면 6E69732D 73677261
이라는 값이 들어있다.
hex값으로 보면 "args-sin" 이 뒤집어있는걸 볼 수 있는데 이때문에 string을 8byte 단위로 뒤집어서 넣어야 하나? 라는 생각을 잠깐했다.
너무 갔다고 생각했다.
%rsi
에는 argv[0]의 주소 값 이 들어가야 한다. 즉 rsp - 8
의 값이 들어가야 한다.
나의 코드 (process.c)
3시간은 쓴거같다.
꼭 한줄씩 문제가 생겼는데 test a b c
라는 입력이 들어왔으면 스레드의 이름을 test
로 해줘야 하기 때문이였다.
다음과 같이 스레드 생성에 필요한 이름을 파싱하기 위해 sub_file_name
을 만들었다.
strcspn
함수는 reject가 포함되지 않는 index 0 부터 시작하는 substring의 길이를 반환한다.
char 배열의 크기가 15인 이유는 pintOS 에서 파일이름의 길이가 최대 14였기 때문이다.
결과:
다른 팀원이 hex_dump 함수를 사용해서 편하게 작업하는보고 사용하면 좋겠다고 생각해서 작성한다.
process.c
주석처리한 첫줄을 보면 hex_dump를 이용해 아래와 같이 출력할 수 있다.
USERSTACK
이 중요하다. KERN_BASE
와 헷갈리지 말자!!
다음과 같이 gdb를 이용해서 값을 확인할 수 있다.