【问题标题】:ARM Assembly ArraysARM 汇编数组
【发布时间】:2017-07-19 02:37:15
【问题描述】:

我试图弄清楚数组在 ARM 汇编中是如何工作的,但我不知所措。我想将一个大小为 20 的数组初始化为 0、1、2 等等。

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 让我很困惑,我不知道我做错了什么。如果有人能帮助我更好地理解这是如何工作的,将不胜感激。

【问题讨论】:

  • 使用调试器,你会看到你做的是否正确。您的数组处理看起来不错,但打印部分是错误的。检查如何在您的平台中使用 printf。
  • str r2, [r3] @ r3 = r2 注释错误,不是r3 会改变,而是内存内容会改变。在r3 值指向的地址。 mov r2, #0 @ index r2 = 0 也有点……您将 r2 用作索引和值,这实际上很好,但我会在评论中省略“索引”一词。 ldr r1, =a @ set r1 to index point of array r1 是数组(第一个元素)的地址,而不是索引。 (其余如 Sami 上面写的,数组代码看起来没问题,printf 完全无用,使用调试器检查内存内容和寄存器内容)
  • 您是要创建单词数组还是字节数组?你做了一个单词数组,如果这是你想要的,那很好。
  • 查看这些指令 ldr r2,[r1,r3] 甚至更好的 ldr r2,[r1],#4 的详细信息,看看它们是否/如何帮助简化这个循环。

标签: arrays assembly arm armv8


【解决方案1】:

这对于想了解如何在 arm 汇编 语言中为数组分配内存 的其他人可能会有所帮助 这是一个添加对应数组元素并存储在第三个数组中的简单示例。

.global  _start

_start:
      MOV R0, #5              
      LDR R1,=first_array     @ loading the address of first_array[0]
      LDR R2,=second_array    @ loading the address of second_array[0]
      LDR R7,=final_array     @ loading the address of final_array[0]
      MOV R3,#5               @ len of array
      MOV R4,#0               @ to store sum
check: 
      cmp R3,#1               @ like condition in for loop for i>1
      BNE loop                @ if R3 is not equal to 1 jump to the loop label
      B _exit                 @ else exit
loop:
      LDR R5,[R1],#4          @ loading the values and storing in registers and base register gets updated automatically R1 = R1 + 4 
      LDR R6,[R2],#4          @ similarly
      add R4,R5,R6         
      STR R4,[R7],#4          @ storing the values back to the final array 
      SUB R3,R3,#1            @ decrment value just like i-- in for loop
      B check
_exit:
      LDR R7,=final_array     @ before exiting checking the values stored 
      LDR R1, [R7]            @ R1 = 60 
      LDR R2, [R7,#4]         @ R2 = 80
      LDR R3, [R7,#8]         @ R3 = 100
      LDR R4, [R7,#12]        @ R4 = 120
      MOV R7, #1              @ terminate syscall, 1
      SWI 0                   @ execute syscall

.data
first_array:  .word 10,20,30,40  
second_array: .word 50,60,70,80 
final_array:  .word 0,0,0,0,0

【讨论】:

    【解决方案2】:

    如前所述,您的 printf 有问题,您可以使用工具链本身查看调用约定是什么,然后遵守。

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

    给予

    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:   
    

    调用约定一般是r0中的第一个参数,r1中的第二个参数,r2中的第三个参数直到r3然后使用堆栈。这有很多例外,但我们可以在这里看到,通常使用 printf 调用正常工作的编译器想要 r0 中格式字符串的地址。 r1 和 r2 中 a 的值,然后 b 的值。

    您的 printf 在 r0 中有字符串,但使用该格式字符串的 printf 调用需要三个参数。

    上面的代码使用了尾部优化和分支到 printf 而不是调用它并从它返回。如今的 arm 约定更喜欢堆栈在 64 位边界上对齐,因此您可以放置​​一些寄存器,您不必关心在 push/pop 上保留以保持对齐

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

    这样做当然不会伤害您,不这样做可能会或可能不会伤害取决于下游的假设。

    假设 r1(标签 a)是字对齐地址,您的设置和循环应该可以正常工作。如果你弄乱了你的字符串,它可能会也可能不会,应该先放一个然后是字符串,或者在 a 之前放另一个对齐语句以确保数组对齐。有指令集功能可以简化代码,但看起来功能不变。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-04-23
      • 1970-01-01
      • 2012-08-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-25
      • 1970-01-01
      相关资源
      最近更新 更多