2017-02-28 1 views
0

배열에서 ARM 어셈블리에서 배열이 작동하는 방식을 알아 내려했지만, 난 그냥 압도당했습니다. 크기 20, 0, 1, 2 등의 배열을 초기화하고 싶습니다.ARM 어셈블리 배열

A[0] = 0 
A[1] = 1 

내가 올바르게 작성한 것을 인쇄하는 방법을 알지 못합니다. 이것은 내가 지금까지 가지고있는 것입니다 :

.data 
.balign 4  @ Memory location divisible by 4 
     string: .asciz "a[%d] = %d\n" 
     a:  .skip 80  @ allocates 20 
.text 
.global main 
.extern printf 

main: 
     push {ip, lr}  @ return address + dummy register 
     ldr  r1, =a   @ set r1 to index point of array 
     mov  r2, #0   @ index r2 = 0 
loop: 
     cmp  r2, #20   @ 20 elements? 
     beq  end    @ Leave loop if 20 elements 
     add  r3, r1, r2, LSL #2  @ r3 = r1 + (r2*4) 
     str  r2, [r3]  @ r3 = r2 
     add  r2, r2, #1  @ r2 = r2 + 1 
     b  loop   @ branch to next loop iteration 
print: 
     push {lr}   @ store return address 
     ldr  r0, =string  @ format 
     bl  printf   @ c printf 
     pop  {pc}   @ return address 

ARM은 충분히 혼란스럽고, 나는 잘못하고 있습니다. 아무도 내가 어떻게 더 잘 이해할 수있는 작품인지 이해할 수 있다면 도움이 될 것입니다.

+1

디버거를 사용하면 제대로 수행하는지 확인할 수 있습니다. 귀하의 배열 처리가 잘 보이지만 인쇄 부분이 잘못되었습니다. 플랫폼에서 printf를 사용하는 방법을 확인하십시오. –

+0

'str r2, [r3] @ r3 = r2' 코멘트가 잘못되었으므로 'r3'이 변경되지는 않지만 메모리 내용이 변경됩니다. 'r3' 값이 가리키는 주소. 또한'mov r2, # 0 @ index r2 = 0'은 약간의 ... 당신은'r2'를 인덱스와 값으로 사용하고 있습니다. 실제로는 좋지만 코멘트에서 단어 "인덱스"를 생략 할 것입니다. 'ldr r1, = a @ 배열의 ​​인덱스 포인트에 r1 설정'r1'은 인덱스가 아닌 (첫 번째 요소의) 배열 주소입니다. (나머지는 사미가 위에서 쓴 것처럼 배열 코드는 괜찮아 보이고 printf는 완전히 borked되며 디버거를 사용하여 메모리 내용을 확인하고 내용을 등록) – Ped7g

+0

단어 배열 또는 바이트 배열을 만들고 싶습니까? 당신은 단어의 배열을 만들었고 그것이 당신이 원한 것이라면 괜찮습니다. –

답변

0

printf에 문제가있는 경우 툴체인을 사용하여 호출 규칙이 무엇인지 확인한 다음이를 준수 할 수 있습니다.

00001008 <notmain>: 
    1008: e59f2010 ldr r2, [pc, #16] ; 1020 <notmain+0x18> 
    100c: e59f3010 ldr r3, [pc, #16] ; 1024 <notmain+0x1c> 
    1010: e5921000 ldr r1, [r2] 
    1014: e59f000c ldr r0, [pc, #12] ; 1028 <notmain+0x20> 
    1018: e5932000 ldr r2, [r3] 
    101c: eafffff8 b 1004 <printf> 
    1020: 0000903c andeq r9, r0, ip, lsr r0 
    1024: 00009038 andeq r9, r0, r8, lsr r0 
    1028: 0000102c andeq r1, r0, ip, lsr #32 

Disassembly of section .rodata: 

0000102c <.rodata>: 
    102c: 64255b61 strtvs r5, [r5], #-2913 ; 0xb61 
    1030: 203d205d eorscs r2, sp, sp, asr r0 
    1034: 000a6425 andeq r6, sl, r5, lsr #8 

Disassembly of section .bss: 

00009038 <b>: 
    9038: 00000000 andeq r0, r0, r0 

0000903c <a>: 
    903c: 

호출 규칙주는

#include <stdio.h> 
unsigned int a,b; 
void notmain (void) 
{ 
    printf("a[%d] = %d\n",a,b); 
} 

일반적 번째의 R0, R1에서 첫 번째 파라미터, R3 후 스택을 사용하도록 R2의 세번째. 여기에는 많은 예외가 있지만 printf 호출로 정상적으로 작동하는 컴파일러는 r0에 형식 문자열 주소가 필요하다는 것을 알 수 있습니다. a의 값은 r1과 r2의 각각 b의 값입니다.

귀하의 printf는 r0에 문자열을 가지고 있지만 해당 형식 문자열을 가진 printf 호출에는 3 개의 매개 변수가 필요합니다.

위의 코드는 꼬리 최적화를 사용하고 printf를 호출하여 호출하지 않고 반환했습니다. 당신은 정렬

push {r3,lr} 
... 
pop {r3,pc} 

에게 그것을 확실히 늘 유지하기 위해 푸시/팝을 유지하기 위해 신경 반드시 그나마 팔 규칙 요즘은 스택이 64 개 비트 경계에 정렬 할 선호, 그래서 당신은 어떤 레지스터를 넣을 수 있습니다 당신이 이것을하기 위해 상처를 주었을 때, 하류가 가정하는 것에 따라 그것을하지 않거나 해칠 수도 있습니다.

r1 (레이블 a)이 단어 정렬 주소라는 가정하에 설정 및 루프가 올바르게 작동해야합니다. 문자열을 엉망으로 만든다면 그렇지 않을 수도 있습니다. 배열을 정렬하기 위해 먼저 문자열을 넣거나 다른 정렬 문을 앞에 붙여야합니다. 단순히 코드 일 수있는 명령 세트 기능이 있지만 그대로 작동합니다.