2017-02-28 12 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'をインデックスと値の両方として使用していますが、実際は素晴らしいですが、コメントから単語 "index"を省略します。 'ldr r1、= a @配列のインデックスポイントにr1をセットする' r1'はインデックスではなく(最初の要素の)配列のアドレスです。 (上記のようにサミが書いたように、配列コードはokと思われ、printfは完全にボルケージされており、デバッガを使ってメモリの内容をチェックし、内容を登録します) – 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); 
} 

は、一般的に第二R1のR0の最初のパラメータ、R3は、スタックを使用するようにR2の第三です。これには多くの例外がありますが、printf呼び出しで正常に動作するコンパイラは、r0に書式文字列のアドレスが必要です。 aの値はr1とr2のそれぞれのbの値です。

printfの文字列はr0ですが、その書式文字列を含むprintf呼び出しには3つのパラメータが必要です。

上記のコードでは、tail最適化を使用してprintfを呼び出して呼び出したのではなく、分岐して返しました。腕大会、これらの日は、あなたには、いくつかのレジスタを置くことができるので、あなたは、必ずしもそれは確かに文句を言わない

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

そのアライメントを維持するために、プッシュ/ポップに保つために気にいけない、スタックは64ビット境界に配置することを好みますあなたがこれをするのを傷つけます、下流が何を仮定しているかに応じて、それをしないことを傷つけるかもしれないし、しないかもしれません。

セットアップとループは、r1(ラベルa)が単語アライメントされたアドレスであると仮定すると、うまく機能するはずです。あなたがあなたの文字列を混乱させるならば、それはそうかもしれないし、そうでないかもしれません。文字列を最初に置くか、配列の整列を保証するために別の整列文を置いてください。単純にコードを実行できる命令セット機能がありますが、そのまま機能しているようです。

関連する問題