首页 > 解决方案 > 如何在 ARM 程序集的自定义函数中使用 while 循环(或任何循环)?

问题描述

我正在尝试解决一个问题,我有一个从 10 到 50 的计数器。对于每个数字,我必须检查它是否是 8 的倍数(如果是,那么我将 0xffff 存储在 R3 中),或者它是否是3 的倍数(我将存储 0xbbbb)或者如果它是两者的倍数(我将 0xffbb 存储在 R3 中)。

为了检查数字是否是 3 的倍数,我的计划是从数字中减去 3,直到它达到 0 或小于 3。我正在努力弄清楚如何在自定义函数中使用循环。到目前为止,这是我的代码:

.section    .data
.balign 4
return_start:   .word 0
.balign 4
return_loop:    .word 0
.balign 4
return_8:   .word 0
.balign 4
return_3:   .word 0
.balign 4
return_3loop:   .word 0

.section    .text

.global _start
/* .func   _loop
.func   _multOf8
.func   _multOf3 */

_start:
    LDR R1, addr_return_start
    STR lr, [R1]

    mov r0, #10 /* Start with 10 */
    BL  _loop

    LDR lr, addr_return_start
    LDR lr, [LR]

_loop:
    add R0, #1  /* increment by 1 */
    MOV r3, #0 /* resetting r3 */
    CMP R0, #50 /* check if it is 50, if it is then go to the end */
    BEQ _end

    /* else check if it is a multple of 8 */
    BL  _multOf8
    /* check if it is a multiple of 3 */
    BL  _multOf3

    B   _loop

_multOf8:
    /* save LR */
    LDR R1, addr_return_8
    STR lr, [R1]

    AND r1, r0, #7
    CMP r1, #0
    MOVEQ r3, #0xffff   /* if it is a multiple of 8 */
    /* else return */
    LDR LR, addr_return_8
    LDR LR, [LR]
    BX LR

_multOf3:
    LDR R1, addr_return_3
    STR lr, [R1]

    /* if it is a multiple of 3 */
    /* will need to subtract it continuously? */
    PUSH R0
    BL  _3loop
    POP R0

    LDR LR, addr_return_3
    LDR LR, [lr]
    BX  lr

_3loop:
    LDR R1, addr_return_3loop
    STR lr, [R1]

_end:   B   _end

addr_return_start:  .word return_start

addr_return_loop:   .word return_loop

addr_return_8:  .word return_8

addr_return_3:  .word return_3

addr_return_3loop:  .word return_3loop

如您所见,在_multOf3我试图分支到_3loop. 问题是,我不知道如何处理LR以及如何从这个循环中返回。我觉得如果我要存储 LR,每次我们遍历循环时都会不断地覆盖它。

任何帮助将非常感激!请注意,我是 ARM 汇编的初学者。

标签: assemblyarm

解决方案


ARM 中的循环并不太复杂。有几种方法可以实现一个。通常,您需要留出一个寄存器作为循环计数器。下面的例子是一个递减循环。

_loop: /* R2 is the loop counter */

/* do stuff here */

subs R2,R2,#1   /* the S at the end sets the flags accordingly. If the result is zero,
                   the zero flag will be set and BNE will not branch.
BNE _loop
/* if R2 = 0, execution will fall through to here, otherwise it jumps back to the loop's start

递增循环需要额外的步骤,因为您需要将循环计数器的值与所需的端点进行比较:

_loop /* R2 is the loop counter */

/* do stuff here */

add R2,R2,#1   /* no need for S at the end, it does us no good here. */
CMP R2,#50     /* 50 was arbitrarily chosen for this example. */
BNE _loop      /* this just checks if they're not equal, for this example it's sufficient but 
               it's better to use BLS for signed numbers or BLO/BCC for unsigned */

推荐阅读