2017-10-09 23 views
0

단순히 콘솔의 입력에서 문자열을 읽으려고합니다. xspim을 실행하고 있지만 가상 모드를 사용할 수없는 베어 모드로 실행해야합니다. 온라인에서 찾은 많은 것들이 의사 명령어로 수행하는 방법입니다. 내가 읽는 모든 문서에서 "la"명령어를 사용하여 $ a0에 문자열을 저장한다고했지만, 그 명령어는 사용할 수 없습니다. 나는 그 가르침이 번역되는 것에 대해 읽었고, 효과적으로 "lui"와 "ori"로 바뀌었다. 나를 던지고있는 부분은 첫 번째 데이터 위치 (항상 0x 1000 0000)와 문자열의 첫 번째 바이트 주소 사이의 바이트 수를 입력해야한다는 것입니다. 내 문자열의 첫 번째 바이트가 무엇인지 확실하지 않습니다. RISC 기계맨손으로 실행중인 MIPS에서 정적 데이터 주소를 얻는 방법 (의사 명령어 없음)

.globl main 
.globl done 
.globl convert 

.data 
prompt: .asciiz "Enter a decimal number, to quit type 'quit':" #45 
result: .asciiz "The number you entered is " #72 
input: .space 64 

.text 
convert: 


main:  addi $v0, $0, 4   #Print prompt to enter number 
      lui $a0, 0x1000   #Address of prompt 
      syscall     #Display prompt 

      addi $v0, $0, 8   #Setting up syscall to read in string 
      lui $at, 4097 
      ori $a0, $at, input  #Where I want my string to be stored 
      addi $a1, $0, 64  #How long my string will be 
      syscall     #Syscall to read in string 
+0

스택 (입력 버퍼 용)을 사용하여 문제를 해결할 수 있습니다. –

답변

0

일반적으로 어셈블러 + 링커는 두 부분으로 분할 주소를 지원하므로 주소는 링크 타임 상수로하지 조립 시간을 가지고, 그래서 당신은 lui $reg, upper(input)ori $reg, $reg, lower(input)을 작성할 수 있습니다 여기에 내가 가진거야. 예를 들어

, 당신은 보면 MIPS gcc's assembly output on Godbolt (gcc -O3 -S, 링크 된 바이너리를 분해하지) : bar는 오프셋 lw에서 대신 전체 주소를 생성 같은 주소의 LO 절반을 사용

int my_global; 
int *foo() { return &my_global; } 
    lui  $2,%hi(my_global) 
    j  $31 
    addiu $2,$2,%lo(my_global) # branch-delay slot (SPIM doesn't have a branch-delay slot, but real MIPS does) 

int bar() { return my_global; } 
    lui  $2,%hi(my_global) 
    lw  $2,%lo(my_global)($2) 
    j  $31 
    nop 

    .section  .bss,"aw",@nobits 
    .align 2 
    .type my_global, @object 
    .size my_global, 4 
my_global: 
    .space 4 

공지 것을

로드 명령어에서 0의 오프셋을 사용하는 것입니다.


유용한 최적화 당신이 개 주소를 알고있는 경우는 같은 64K 블록이 다른 ori 낮은 반 상수와 같은 lui 결과를 재사용하는 것입니다에 있습니다. 나는 이것이 귀하의 데이터를위한 경우라고 생각합니다. Mars guarantees that syscall preserves all registers except the result; 나는 SPIM이 같다고 가정한다.


수동 (당신을 도울 수있는 링커없이)을해야 할 경우

은 다음 네, 당신은 당신의 데이터의 절대 주소를 알아야합니다.

귀하의 경우에는 CRT 시작 코드 또는 .data 섹션에 데이터를 입력하는 코드가 없습니다. .data 섹션 의 자료는 실행 파일의 데이터 세그먼트 시작 부분에이므로 prompt: 주소는 0x1000 0000입니다.

패딩이나 정렬을 요청하지 않았으므로 아무 것도 얻을 수 없습니다. 데이터는 함께 포장 된 출력으로 조합됩니다. (C와는 달리, char prompt[45], result[];은 연속적이라는 보장이 없습니다.)

SPIM을 사용하지 않았지만 result-promptinput-prompt으로 쓸 수 있기를 바랍니다.

main: 
     addi $v0, $0, 4   #Print prompt to enter number 
     lui $a0, 0x1000   #Address of prompt 
     syscall     #Display prompt 

     # $a0 still holds 0x1000 << 16 
     addui $a0, $a0, input-prompt  #buffer address 
     addi $a1, $0, 64     # length 

     addi $v0, $0, 8   #syscall 8 = read string 
     syscall     #read_string(input, 64) 

     addui $t0, $a0, 0  # copy pointer to input 
     addui $a0, $a0, result - input # offset pointer again to point to the output message. 

또는 대신에 다른 레지스터에 포인터를 복사

, 당신은 액세스 input[]에 사용 모든 lb/ sb 오프셋 (offset)에 input-result를 추가하여 최적화 할 수 있습니다.