Extremis
Assembly

Extremis

RISC-V 어셈블리로 작성된 RPG 어드벤처

( 도대체 누가 .iris를 커밋할 수 없도록 프로그래밍한 걸까? )

RISC-V 32비트 어셈블리로 작성된 텍스트 기반 RPG로, QEMU를 통해 시뮬레이션됩니다.

"우주는 내가 더 나은 일, 예를 들어 인생을 사는 것 같은 걸 하지 못하게 하기로 결정한 모양이다."

의존성

  • riscv32-elf-as — RISC-V 어셈블러
  • riscv32-elf-ld — RISC-V 링커
  • qemu-riscv32 — RISC-V 사용자 모드 에뮬레이터

Arch Linux에서:

sudo pacman -S riscv64-elf-binutils qemu-user

빌드 및 실행

make build   # 어셈블 및 링크하여 main.bin 생성
make run     # 빌드 + qemu-riscv32로 실행
make debug   # -strace 플래그로 실행하여 시스템 콜 확인

프로젝트 구조

Extremis/
├── main.s                      # 진입점 (_start), run_chapter_1 호출
├── src/
│   ├── include/
│   │   └── function.s          # startF / endF 스택 프레임 매크로
│   ├── engine/
│   │   ├── print.s             # print  — null 종료 문자열 하나 출력 (a0)
│   │   └── utils.s             # printl — 문자열 목록 출력 (a0=테이블 주소, a1=개수)
│   ├── chapters/
│   │   └── chapter_1.s         # 1장 로직; 인트로 문자열 로드 후 printl 호출
│   └── dialogue/
│       └── intro.s             # 인트로 시퀀스용 문자열 데이터
└── build/                      # 컴파일된 .o 파일 (src/ 구조 반영)

아키텍처

엔진은 QEMU 사용자 모드 에뮬레이션을 통해 Linux ABI를 대상으로 하는 순수 RISC-V 32비트 어셈블리입니다.

스택 프레임 규칙

모든 함수는 src/include/function.sstartF / endF 매크로를 사용하여 ra, s0, s1, s2를 스택에 저장하고 복원합니다:

startF    # push: 16바이트 할당, ra/s0/s1/s2 저장
...
endF      # pop:  ra/s0/s1/s2 복원, 16바이트 해제
ret

시스템 콜

경고: RARS/MARS 환경 호출 번호는 qemu-riscv32에서 작동하지 않습니다. 이 프로젝트는 Linux RISC-V ABI 시스템 콜 번호를 사용합니다.

시스템 콜 번호는 a7에 넣고 ecall로 호출합니다. 반환값은 a0로 돌아옵니다.

출력

용도 RARS a7 Linux a7 a0 a1 a2 참고사항
문자열 출력 4 64 1 (stdout fd) buf 주소 길이 Linux는 null에서 멈추지 않음 — 바이트 길이 전달
문자 출력 11 64 1 문자 buf 1 문자를 메모리에 저장 후 주소 전달
정수 출력 1 정수 Linux에 해당 없음; 문자열로 변환 후 출력
16진수 정수 출력 34 정수 Linux에 해당 없음; 직접 변환 필요
부호 없는 정수 출력 36 정수 Linux에 해당 없음; 직접 변환 필요

입력

용도 RARS a7 Linux a7 a0 a1 a2 참고사항
문자열 읽기 8 63 0 (stdin fd) buf 주소 최대 바이트 Linux는 개행 문자를 포함한 원시 바이트 반환
문자 읽기 12 63 0 buf 주소 1 a0 = 읽은 바이트 수; 문자는 buf에 저장
정수 읽기 5 Linux에 해당 없음; 문자열 읽어서 파싱

프로세스

용도 RARS a7 Linux a7 a0 참고사항
종료 10 93 RARS는 a0 무시; Linux는 종료 상태로 읽음
종료(코드) 17 93 종료 코드 Linux exit_group

메모리

용도 RARS a7 Linux a7 a0 반환값 참고사항
할당 (sbrk) 9 214 바이트 (RARS) / 새 brk 주소 (Linux) a0 = 할당된 블록 시작 주소 Linux brk는 다르게 작동 — 크기가 아닌 새 상한값 설정

파일 I/O

용도 RARS a7 Linux a7 a0 a1 a2 a3 참고사항
파일 열기 13 56 dirfd (-100=CWD) 파일명 주소 플래그 모드 Linux는 openat 사용
파일 읽기 14 63 fd buf 주소 최대 바이트 읽은 바이트 수 반환
파일 쓰기 15 64 fd buf 주소 바이트 수 쓴 바이트 수 반환
파일 닫기 16 57 fd 성공 시 0 반환

시간

용도 RARS a7 Linux a7 a0 a1 참고사항
시간 30 113 클록 ID (1=REALTIME) timespec* buf RARS는 lo/hi를 a0/a1로 분할 반환; Linux는 buf에 구조체 작성
대기 32 115 클록 ID timespec* RARS는 a0에 밀리초 사용; Linux는 구조체로 clock_nanosleep 사용

콘텐츠 추가

  • 새로운 대화 문자열은 src/dialogue/에 추가합니다.
  • 새로운 챕터는 src/chapters/에 추가하고, 필요한 챕터 파일에서 .include로 포함시킵니다.
  • Makefile은 src/ 아래의 모든 .s 파일을 자동으로 찾습니다 (src/include/ 제외).