assembly ARM汇编嵌套循环

busg9geu  于 2023-10-19  发布在  其他
关注(0)|答案(3)|浏览(111)

我是ARM汇编语言的新手,我知道如何制作一个简单的for循环,但是,当我试图将to概念应用于嵌套循环时,我对如何设置它感到非常困惑。我想知道是否有一个规则设置循环一般?也许我可以用这个规则来做一个嵌套循环?
举个例子,如果我有一个用C写的简单的嵌套循环代码,像下面这样,在汇编中会是什么样子?我真的很感激详细的解释,谢谢!

for(int i = 0; i < a; i++){
  for(int j = 0; j < b; j++){
  int sum = 0;
    for(k = 0; k < c; k++){
      for( l = 0; l < d; l++){
        int temp1 = i+k;
        int temp2 = j+k;
      }
    }
  }
}
fkaflof6

fkaflof61#

对于两个嵌套循环,我通常会这样做。* 请记住,在这段代码中,i(外循环计数器)将是R0,j(内循环计数器)将是R1。R2用于计算内外循环上的循环数。

AREA        myCode, CODE, READONLY
            ENTRY
            EXPORT __main
                
__main
            
            MOV     R2, #0
            
            MOV     R0, #2      ; ** outer loop (loop 1) counter initialization ** 
LOOP1       CBZ     R0, STOP    ; if (R0 == 0 && R1 == 0) then branch to somewhere. (I'm just ending program here)
            ; between outer and inner loop
            ; could do anything but I'm just incrementing R2
            ADD     R2, R2, #1
            
            MOV     R1, #3      ; ** inner loop (loop 2) counter initialization **
LOOP2       CBZ     R1, CNTULP1
            ; code inside of inner loop will be here
            ; could do anything but I'm just incrementing R2
            ADD     R2, R2, #1

; Notice) when you need to continue loop2 => branch to CNTULP2. else if you wanted to continue loop1 => branch to CNTULP1
;           and when you wanted to break loops => branch out of them for example branch to STOP 
CNTULP2     ; continue loop2 (inner loop) 
            SUB     R1, R1, #1  ; decrement inner loop counter
            B       LOOP2

CNTULP1     ; continue loop1 (outer loop)
            SUB     R0, R0, #1  ; decrement outer loop counter
            B       LOOP1

STOP        B       STOP
            END
1sbrub3j

1sbrub3j2#

这和一个循环没有什么不同,你只是把它们嵌套起来。与C或其他语言相同(为每个循环使用不同的变量/寄存器,以便它们可以无干扰地嵌套)。

something holds i (register or memory)
something holds a (register or memory)

i = 0;
loop0:
   get i
   get a
   compare i and a
   if signed greater than or equal jump to loop0_done
   do stuff
   get i
   increment i
   jmp to loop0
loop0_done:

你也可以这样设计它:

something holds i (register or memory)
something holds a (register or memory)

i = 0;
loop0:
   get i
   get a
   compare i and a
   if signed greater than or equal jump to loop0_done
   do stuff
   get i
   increment i
loop0_mid:
   get a
   compare i and a
   if signed less than jump to loop0

假设a和B作为r 0和r1传入。我们希望此代码遵循正常的arm调用约定。

for(int i = 0; i < a; i++){
  for(int j = 0; j < b; j++)
    do stuff
  }
}

push {r4,r5,r6,r7}
;@ A loop
mov r4,#0 ;@ i
mov r5,r0 ;@ a
mov r7,r1 ;@ b
b a_loop_mid
a_loop:

  mov r6,#0 ;@ j
  b b_loop_mid
b_loop:

    do stuff

    add r6,#1
b_loop_mid:
    cmp r6,r7
    blt b_loop

  add r4,#1
  a_loop_mid
  cmp r4,r5
  blt a_loop

pop {r4,r5,r6,r7}

两个循环看起来一样,只是使用了不同的寄存器/变量:

mov r4,#0 ;@ i
mov r5,r0 ;@ a
b a_loop_mid
a_loop:

    do stuff

  add r4,#1
  a_loop_mid
  cmp r4,r5
  blt a_loop

mov r6,#0 ;@ j
  b b_loop_mid
b_loop:

    do stuff

    add r6,#1
b_loop_mid:
    cmp r6,r7
    blt b_loop

然后把它们放在巢里现在你要用完寄存器了,所以有些东西需要放在堆栈上,所以访问b可能是

ldr r1,[sp,#12]

并且不需要烧录寄存器R7。
同样,对于计数为n的循环,但循环中没有使用计数变量,那么您可以根据指令集,也许保存一条或几条指令。有多个arm指令集,因此,

add this,#1
cmp this,that
blt somewhere

可以在循环中保存指令

subs this,#1
bne somewhere

你需要正确地初始化它,

for(i=0;i<a;++)

a是5,那么我会数0,1,2,3,4,5个数所以你可以数5,4,3,2,1,5个东西

this=a
label:
...
subs this,#1
bne label

并在循环中保存该指令
一些arm指令集有一个cbz和cbnz(比较和分支,如果为零或如果不为零)
所以

sub this,#1
cbnz label

没有真实的储蓄。有些指令集(不是arm)有一个递减,如果不为零则跳转

this = a
label:

djnz this, label

保存另一条指令。
如果你使用典型的arm调用约定链接编译后的代码,那么r 0-r3是易失的,而r4以上的大多数是非易失的(你必须保留它们)。这意味着,如果你想在循环中调用另一个函数,那么这个函数可能会扰乱r 0-r3,所以你不能在调用边界上将它们用作循环的一部分。
如果r 0中有a

mov r2,#0
a_loop:
   bl somewhere
   cmp r2,r0
   blt a_loop

这有两个问题,r2和r 0都可以在某处函数中改变,所以比较和东西可能会被弄乱。
这样做

mov r2,r0
a_loop:
   bl somewhere
   subs r2,#1
   bne a_loop

对于这个循环,只有r2是混乱的,但是如果在这个代码之后需要r 0中的a值,则可能已经被破坏。这就是为什么对于简单的东西,你可能会看到这个

push {r4,...}
mov r4,r0
...
pop {r4,...}

保存调用者r4,然后在此函数中使用r4保存a值。或最差情况

push {r0,...}
ldr rn,[sp,??]  read a
pop {r0,...}

其中SP偏移量是基于堆栈上有多少填充物以及R 0值落在何处来确定的。或者使用一个堆栈框架和引用。
归根结底,嵌套循环与其他语言没有什么不同。你必须有不干扰其他嵌套循环的循环变量。你的循环完全在外部循环中。

lsmepo6l

lsmepo6l3#

Just decrement and branch conditionally.
//PROCESS STRING
ldr r0,=Stg0    //load r0 with address of string
ldr r1,=StgLen  //load ADDRESS of string len
ldr r1,[r1]     //load r1 with len of string
nxtchr:
  ldrb r2,[r0],#1  //get next byte of string & auto-increment pointer
  ???              //do something to the char
  subs r1,#1       //decrement r1. the instruction is subs, not sub!
  bne nxtchr       //branch if not zero
THE subs & bne PAIR DUPE THE FUNCTIONALITY OF THE X86 LOOP INSTRUCTION

相关问题