2016-10-14 3 views
0

현재 사용자에게 정수 값을 묻는 메시지가 화면에 출력되는 ci20 컴퓨터의 작은 프로그램을 작업 중입니다.어셈블리 ci20에서 사용자 입력 프롬프트 표시 오류

내 현재 코드

.data 

prompt: 
.asciiz "Please enter an integer: " 
message: 
.asciiz "\nValue entered: " 

.text 
.global main 

main: 
    addiu $sp, $sp, -4 # push stack 
    sw $ra, ($sp)  # save return address 

    addi $v0, $0, 4 
    la $a0, prompt 
    syscall   # printing prompt 

    addi $v0, $0, 5 
    syscall   # get user input 

    move $t0, $v0  # save input in $t0 
    move $a0, $v0 
    addi $v0, $0, 1 # Not sure if this is right to print message 
    la $a0, message # Not sure if this is right to print message 
    syscall 

    lw $ra, ($sp)  # restoring $sp 
    addiu $sp, $sp, +4 # release the stack space used for $sp 

내가 독방 감금 오류를 얻을 프로그램을 실행하려고 그 이유는 확실하지 않다. 어떤 도움이나 제안이라도 대단히 감사하겠습니다.

답변

3

편집 : 어떤 이유로 든이 코드는 ci20 컴퓨터에서 테스트되었습니다.

이 리눅스가 무엇입니까? 그런 다음 MARS 시스템 호출을 사용할 수 없으면 Linux syscalls를 찾아야합니다. 그런 다음 인수는 Linux에서 유효하지 않으므로 명령어의 첫 번째 부분 인 syscall을 segfaulting 할 것입니다.


는 "프롬프트"당신은 v0 = 1, a0 = message 같은 시스템 콜에 대한 인수를 설정 "메시지"를 표시 ... v0 = 4, a0 = prompt로 설정 인수 syscall을 사용하여 표시합니다.

MARS 인 경우 v0 = 1은 "인쇄 정수"이므로 a0은 "메시지"문자열 주소가 아닌 정수 여야합니다. .. 아마도 v0 = 4 및 v0 = 1 (인수 a0은 "메시지"이고 특정 호출에 대해서는 사용자 정수)와 함께 syscall을 두 번 호출하려고합니다.

어쨌든이 중 어느 것도 segfault가 아닙니다. segfault는 코드 끝에 addiu $sp, $sp, +4으로 끝나거나 ra으로 돌아 가지 않고 syscall "exit"함수를 호출하는 끝 부분에서 발생합니다 (코드 시작 부분에 ra을 저장하면 exit보다 반환하기를 원하는 것처럼 보입니다). 그러나 그것은 당신에게 달렸습니다). 따라서 임의의 명령어 (초기화되지 않은 메모리 컨텐츠)를 통해 실행이 계속됩니다.

어쨌든이, 당신은 그것을 통해 디버거 단계에서이 코드가 명령에 의한 명령, 다음은 세그먼테이션 폴트 (segfault) 위치를 정확히 말할 수있을 것입니다 방법 부하 파악해야하고, segfaulting 명령 전에 레지스터의 내용은 무엇 이었습니까 . 코드가 segfaults이고 어디 까지나 알지 못하는 경우에는 노력이 부족하다는 것을 보여줍니다.

(면책 조항 : 나는 MIPS 어셈블리를 결코하지 않았다, 그래서 대부분 작동하고 뭔가를 간과 할 수 어떻게 추측하고있어)


편집에 대한 syscall, 어쩌면이 힌트가 너무 도움이 될 것입니다?

syscall CPU의 모든 멋진 기능을 수행하는 마법 명령이 아닙니다. 그냥 처리기 루틴으로 이동합니다.

해당 핸들러 코드는 OS에 의해 설정됩니다. SO의 MIPS 어셈블리 목록의 대부분은 Linux와 완전히 다른 처리기가있는 MARS 또는 SPIM을 대상으로합니다.

그래서 Linux ABI에서 MIPS를 연구하고 거기에서 syscall이 어떻게 사용되는지 알아보아야합니다. 그리고 리눅스 시스템 콜 테이블을 찾으십시오. 아마도 x86 문서가 많이 나올 것입니다. 따라서 이것을 v0/a0/... ABI로 변환해야합니다.

계속 MARS 예제를 따라갈 수 있지만 모든 OS 상호 작용을 조정해야하며 모든 것에 대한 대안을 찾을 수는 없습니다.예를 들어 숫자를 출력하는 것은 리눅스에서 사용할 수 없습니다. 너 자신에 의해 ASCII 문자열로 숫자 값을 변환해야합니다. ('0'을 더하면 한자리 숫자가 충분합니다. 9보다 큰 숫자의 경우 10의 각 지수에 대해 숫자를 계산하고 ASCII 문자로 변환하여 일부 버퍼에 저장해야합니다.), 그리고 나서 sys_write/etc와 함께 문자열을 출력하십시오. (또는 일부 libc와 링크하여 C 라이브러리의 sprintf과 같은 함수 호출).

+0

네, 리눅스 읽기/쓰기 시스템 호출은 파일 디스크립터 (예 : stdin은 0, stdout은 1), 버퍼 주소와 바이트 수를 취해야합니다. –

+0

응답 @ Ped7g에 감사드립니다. 나는 gdb를 돌리는 Linux 기반의 머신 인 ci20 머신에서이 프로그램을 실행하고 있습니다. gdb 디버거를 통해 실행할 때 오류가 발생하지 않으므로 오류가 발생하는 이유를 혼동하지 않습니다. – TurtleMan

+0

@ TurtleMan 그럼 인수는 segfault만큼 독성이 없지만 리눅스가 아닌 syscall에 MARS 인수를 사용하고 있습니다. 웹에서 간단히 살펴보면,'v0' ='4' (sys_write),'a0' ='1' (파일 설명자 stdout),'a1' ='prompt' (주소 .ascii 문자열),'a2' ='25' (.ascii 문자열의 길이)'syscall'. 짧은 코드에서 먼저 이것을 시도해보십시오 ... 오, 그리고'v0' ='1'은 sys_exit입니다 (종료 코드로'a0' 값을 가짐). 아마 a0 = 123과'echo $? '를 사용하여 종료 코드가 123인지 확인하기 위해 첫 번째 코드로 테스트하십시오. – Ped7g