Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Recursion L手臂装配中的诅咒示例_Recursion_Assembly_Arm_Cortex M3_Cortex M - Fatal编程技术网

Recursion L手臂装配中的诅咒示例

Recursion L手臂装配中的诅咒示例,recursion,assembly,arm,cortex-m3,cortex-m,Recursion,Assembly,Arm,Cortex M3,Cortex M,有人能给我举个例子,说明在ARM组装中,仅使用此处列出的指令(用于可视化)如何进行递归吗 我试图为这个类做一个递归斐波那契函数和阶乘函数。我知道递归是一个调用函数的函数,但我不知道如何在ARM中模拟它 如果链接不起作用,我将使用visUAL,我只能使用以下说明: 莫夫 MVN 药品不良反应 LDR 加 模数转换器 潜艇 SBC RSB RSC 及 提高采收率 比克 奥尔 LSL LSR ASR 罗尔 RRX 化学机械抛光 CMN TST 特克 LDR LDM 扫描隧道显微镜 B 基本法 填满

有人能给我举个例子,说明在ARM组装中,仅使用此处列出的指令(用于可视化)如何进行递归吗

我试图为这个类做一个递归斐波那契函数和阶乘函数。我知道递归是一个调用函数的函数,但我不知道如何在ARM中模拟它

如果链接不起作用,我将使用visUAL,我只能使用以下说明:

  • 莫夫
  • MVN
  • 药品不良反应
  • LDR
  • 模数转换器
  • 潜艇
  • SBC
  • RSB
  • RSC
  • 提高采收率
  • 比克
  • 奥尔
  • LSL
  • LSR
  • ASR
  • 罗尔
  • RRX
  • 化学机械抛光
  • CMN
  • TST
  • 特克
  • LDR
  • LDM
  • 扫描隧道显微镜
  • B
  • 基本法
  • 填满
  • 结束
这不会为R4加载较旧的值,因此每次函数调用自身时,R4都会加倍

    ;VisUAL initializess all registers to 0 except for R13/SP, which is -16777216

    MOV     R4, #0
    MOV     R5, #1

    MOV     r0, #4

    MOV     LR, #16             ;tells program to move to 4th instruction


FIB


    STMDB   SP!, {R4-R6, LR}    ;Stores necessary values on stack (PUSH command)
    LDR     R4, [SP]            ;Loads older value for R4 from memory
    ADD     R4, R4, R5          ;Adds R5 to R4
    STR     R4, [SP], #8        ;stores current value for R4 to memory
    MOV     R5, R4              ;Makes R5 = R4


    CMP     R4, #144            ;If R4 >= 144:
    BGE     POP                 ;Branch to POP

    MOV     PC, LR              ;Moves to STMDB(PUSH) statement

POP
    LDMIA   SP!, {R4-R6, LR}    ;Pops registers off stack
    END                         ;ends program

您需要使用stack、STMDB和LDMIA指令。在具有“统一”符号的真实ARM工具上,它们还具有助记符PUSH和POP

Fibonnaci和阶乘不是很好的例子,因为它们不“需要”递归。但让我们假装他们有。我会选择斐波那契,因为你没有MUL指令!?您希望执行以下操作:

START
   MOV R0, #6
   BL FIB
   END ; pseudo-instruction to make your simulator terminate

FIB                                 ; int fib(int i) {
   STMDB SP!, {R4,R5,R6,LR}         ;   int n, tmp;
   MOV R4, R0                       ;   n = i;
   CMP R0, #2                       ;   if (i <= 2) {
   MOV R0, #1                       ;     return 1;
   BLE FIB_END                      ;   }
   SUB R0, R4, #2                   ;   i = n-2;
   BL FIB                           ;   i = fib(i);
   MOV R5, R0                       ;   tmp = i;
   SUB R0, R4, #1                   ;   i = n-1;
   BL FIB                           ;   i = fib(i);
   ADD R0, R0, R5                   ;   i = i + tmp;
FIB_END                             ;   return i;
   LDMIA SP!, {R4,R5,R6,PC}         ;  }
开始
MOV R0,#6
BL-FIB
终止使模拟器终止的伪指令
小谎;int fib(int i){
STMDB SP!,{R4,R5,R6,LR};int n,tmp;
MOV R4,R0;n=i;

CMP R0,#2;如果(i其他递归函数:

unsigned int so ( unsigned int x )
{
    static unsigned int z=0;
    z+=x;
    if(x==0) return(z);
    so(x-1);
    return(z);
}
构建/分解

arm-none-eabi-gcc -O2 -c Desktop/so.c -o so.o
arm-none-eabi-objdump -D so.o


00000000 <so>:
   0:   e92d4010    push    {r4, lr}
   4:   e59f4034    ldr r4, [pc, #52]   ; 40 <so+0x40>
   8:   e5943000    ldr r3, [r4]
   c:   e3500000    cmp r0, #0
  10:   e0803003    add r3, r0, r3
  14:   e5843000    str r3, [r4]
  18:   1a000002    bne 28 <so+0x28>
  1c:   e1a00003    mov r0, r3
  20:   e8bd4010    pop {r4, lr}
  24:   e12fff1e    bx  lr
  28:   e2400001    sub r0, r0, #1
  2c:   ebfffffe    bl  0 <so>
  30:   e5943000    ldr r3, [r4]
  34:   e8bd4010    pop {r4, lr}
  38:   e1a00003    mov r0, r3
  3c:   e12fff1e    bx  lr
  40:   00000000    
一堆像是一个迪克西杯托,可能在你的时代之前。一个杯托,你把一个杯子拉下来,下一个和其余的杯子留在杯托里,你可以把一个推回去

因此,堆栈是函数的临时存储,在杯子上写入一个数据项,然后将其推入支架(从调用者处保存r4)写入另一个项目并将其推入支架(lr,调用者的返回地址).我们在这里每个函数只使用两个项目,因此每个函数我可以向上推两个杯子到保持架中,每次调用函数我都会得到两个新的和唯一的存储位置来存储本地信息。当我退出函数时,我将两个杯子从保持架中拉出,并使用它们的值(并丢弃它们).这在某种程度上是递归的关键,堆栈为每个调用提供了新的本地存储,与以前对同一函数的调用不同,如果不需要任何其他返回地址的话(尽管做了一些更简单的递归示例,但在优化时,它不够聪明,基本上不需要循环)

ldr rd,[rn]认为他brakets说的是该地址的项目,所以在rn中读取地址处的内存,并将该值保存在rd中

str rd,[rn]一条arm指令出错,其余的第一个参数是等号的左边(加上r1,r2,r3 r1=r2+r3,ldr r1,[r4]r1=[r4])。这一条是向后的[rn]=rd将rd中的值存储到地址r4描述的内存位置,一级间接寻址

stmdb sp!表示在执行任何操作之前,先将堆栈指针减量为列表中寄存器数量的4字节倍,然后将第一个编号最低的寄存器写入[sp+0],然后写入[sp+4]旁边依此类推,最后一个值将比sp的起始值小四个。!表示函数在sp为递减值的情况下结束。您可以使用ldm/stm进行堆栈推送和弹出操作以外的操作。例如memcpy,但这是另一回事


所有这些都在infocenter.arm.com的arm文档中,您应该已经有了这些文档(arm体系结构参考手册,如果您没有阅读过,armv5是首选的第一本)。

模拟调用自己?
BL yourself
。保存并恢复
LR
。简单。显示伪代码(或C)对于你正在尝试做的事情,以及你遇到的困难。用C写一个非常简单的递归例子,大约总共五行。编译和反汇编,看看产生了什么。如果你遵循C EABI,那么你只需简单地编写代码,而不必这样做,就可以完成了。@Jester抱歉,我已经添加了我到目前为止所做的事情。我不知道w C或除Python 3以外的任何高级语言。@old_timer抱歉,我不懂C。我只懂Python 3。在调试器中单步执行您的代码,这样您就可以看到寄存器值是如何变化的。您的
stmdb
/
ldmia
指令看起来是正确的,推动一些regs+LR并弹出相同的regs+PC返回。我不认为您的不过,返回值是正确的。我认为您正在更新一个被破坏的计数器。请注释您的代码;我不知道您希望它如何工作,只是它不工作。(但实际上,使用调试器单步执行应该可以解决问题。)Fibonacci和Factorial作为递归的例子也一直困扰着我。特别是在asm中,它很容易忽略要点,而不是实际保存/恢复局部变量,而是最终实现一个带有一系列返回的常规循环。(特别是在x86上,
call
ret
已经使用堆栈,这与RISC机器不同,在RISC机器上,您可以在非叶函数中手动保存LR。)真正困扰我的是递归显然效率较低,尤其是对于Fib。IMO二叉树遍历将是一个更好的例子,除非你需要一个数据结构。@PeterCordes现在我正试图想出一个很好的简单递归函数,它确实需要堆栈上下文,并且不能优化为迭代或尾部调用。我想不出来谢谢!我已经试着按照你说的做了,但我还是真的迷路了。我不知道我做错了什么,但我认为这与STMDB和LDMIA指令有关。我以前从未对堆栈做过任何事情,所以这对我来说都是新鲜事。@NickHollinghurst:顺序树遍历仍然是我的目标。Inst
Disassembly of section .bss:

00000000 <z.4099>:
   0:   00000000    
arm-none-eabi-ld -Ttext=0x1000 -Tbss=0x2000 so.o -o so.elf
arm-none-eabi-ld: warning: cannot find entry symbol _start; defaulting to 0000000000001000
arm-none-eabi-objdump -D so.elf

so.elf:     file format elf32-littlearm


Disassembly of section .text:

00001000 <so>:
    1000:   e92d4010    push    {r4, lr}
    1004:   e59f4034    ldr r4, [pc, #52]   ; 1040 <so+0x40>
    1008:   e5943000    ldr r3, [r4]
    100c:   e3500000    cmp r0, #0
    1010:   e0803003    add r3, r0, r3
    1014:   e5843000    str r3, [r4]
    1018:   1a000002    bne 1028 <so+0x28>
    101c:   e1a00003    mov r0, r3
    1020:   e8bd4010    pop {r4, lr}
    1024:   e12fff1e    bx  lr
    1028:   e2400001    sub r0, r0, #1
    102c:   ebfffff3    bl  1000 <so>
    1030:   e5943000    ldr r3, [r4]
    1034:   e8bd4010    pop {r4, lr}
    1038:   e1a00003    mov r0, r3
    103c:   e12fff1e    bx  lr
    1040:   00002000    

Disassembly of section .bss:

00002000 <z.4099>:
    2000:   00000000    
arm-none-eabi-gcc -O2 -c -mcpu=mpcore Desktop/so.c -o so.o
arm-none-eabi-objdump -D so.o

so.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <so>:
   0:   e92d4010    push    {r4, lr}
   4:   e59f402c    ldr r4, [pc, #44]   ; 38 <so+0x38>
   8:   e3500000    cmp r0, #0
   c:   e5943000    ldr r3, [r4]
  10:   e0803003    add r3, r0, r3
  14:   e5843000    str r3, [r4]
  18:   1a000001    bne 24 <so+0x24>
  1c:   e1a00003    mov r0, r3
  20:   e8bd8010    pop {r4, pc}
  24:   e2400001    sub r0, r0, #1
  28:   ebfffffe    bl  0 <so>
  2c:   e5943000    ldr r3, [r4]
  30:   e1a00003    mov r0, r3
  34:   e8bd8010    pop {r4, pc}
  38:   00000000 
so:
    push    {r4, lr}
    @ z += x
    ldr r4, zptr
    ldr r3, [r4]
    add r3, r0, r3
    str r3, [r4]
    @ if x==0 return z
    cmp r0, #0
    beq l30
    @ so(x - 1)
    sub r0, r0, #1
    bl so
    ldr r3, [r4]
l30:
    @ return z
    mov r0, r3
    pop {r4, pc}
zptr: .word z

.section .bss
z: .word 0

arm-none-eabi-as so.s -o so.o
arm-none-eabi-objdump -D so.o

so.o:     file format elf32-littlearm


Disassembly of section .text:

00000000 <so>:
   0:   e92d4010    push    {r4, lr}  (stmdb)
   4:   e59f4024    ldr r4, [pc, #36]   ; 30 <zptr>
   8:   e5943000    ldr r3, [r4]
   c:   e0803003    add r3, r0, r3
  10:   e5843000    str r3, [r4]
  14:   e3500000    cmp r0, #0
  18:   0a000002    beq 28 <l30>
  1c:   e2400001    sub r0, r0, #1
  20:   ebfffff6    bl  0 <so>
  24:   e5943000    ldr r3, [r4]

00000028 <l30>:
  28:   e1a00003    mov r0, r3
  2c:   e8bd8010    pop {r4, pc}  (ldmia)

00000030 <zptr>:
  30:   00000000    

Disassembly of section .bss:

00000000 <z>:
   0:   00000000    
push {r4,lr}  which is a pseudo instruction for stmdb sp!,{r4,lr}

Lr is the r14 which is the return address look at the bl instruction
branch and link, so we branch to some address but lr (link register) is 
set to the return address, the instruction after the bl.  So when main or some other function calls so(4);  lets assume so is at address 0x1000 so the program counter, r15, pc gets 0x1000, lr will get the value of the instruction after the caller so lets say that is 0x708.  Lets also assume the stack pointer during this first call to so() from main is at 0x8000, and lets say that .bss is at 0x2000 so z lives at address 0x2000 (which also means the value at 0x1030, zptr is 0x2000.

We enter the function for the first time with r0 (x) = 4.

When you read the arm docs for stmdb sp!,{r4,lr} it decrements before (db)  so sp on entry this time is 0x8000 so it decrements for the two items to 0x7FF8, the first item in the list is written there so

0x7FF8 = r4 from main
0x7FFC = 9x 0x708 return address to main

the ! means sp stays modified so sp-0x7ff8

then ldr r4,zptr  r4 = 0x2000
ldr r3,[r4] this is an indirect load so what is at address r4 is read to 
put in r3 so r3 = [0x2000] = 0x0000 at this point  the z variable.

z+=x;  add r3,r0,r3  r3 = r0 + r3 = 4 + 0 = 4
str r3,[r4]  [r4] = r3, [0x2000] = r3 write 4 to 0x2000

cmp r0,#0   4 != 0

beq to 28 nope, not equal so no branch

sub r0,r0,#1   r0 = 4 - 1 = 3

bl so  so this is so(3); pc = 0x1000 lr = 0x1024

so now we enter so for the second time with r0 = 3

stmdb sp!,{r4,lr}

0x7FF0 = r4 (saving from so(4) call but we dont care its value even though we know it)
0x7FF4 = lr from so(4) = 0x1024
sp=0x7FF0
ldr r4,zptr r4 = 0x2000
ldr r3,[r4] r3 = [0x2000] = 4
add r3,r0,r3  r3 = 3 + 4 = 7
str r3,[r4]  write 7 to 0x2000
cmp r0,#0 3 != 0
beq 0x1028 not equal so dont branch
sub r0,r0,#1   r0 = 3-1 = 2
bl so  pc=0x1000 lr=0x1024

so(2)

stmdb sp!,{r4,lr}
0x7FE8 = r4 from caller, just save it
0x7FEC = lr from caller, 0x1024
sp=0x7FE8
ldr r4,zprt  r4=0x2000
ldr r3,[r4]  r3 = read 7 from 0x2000
add r3,r0,r3  r3 = 2 + 7 = 9
str r3,[r4]  write 9 to 0x2000
cmp r0,#0  2 != 0
beq 0x1028  not equal so dont branch
sub r0,r0,#1  r0 = 2 - 1 = 1
bl 0x1000 pc=0x1000 lr=0x1024

so(1)

stmdb sp!,{r4,lr}
0x7FE0 = save r4
0x7FE4 = lr = 0x1024
sp=0x7FE0
ldr r4,zptr r4=0x2000
ldr r3,[r4]  r3 = read 9 from 0x2000
add r3,r0,r3  r3 = 1 + 9 = 10
str r3,[r4]  write 10 to 0x2000
cmp r0,#0  1 != 0
beq 0x1028  not equal so dont branch
sub r0,r0,#1  r0 = 1 - 1 = 0
bl 0x1000  pc=0x1000 lr=0x1024

so(0)

stmdb sp!,{r4,lr}
0x7FD8 = r4
0x7FDC = lr = 0x1024
sp = 0x7FD8
ldr r4,zptr  r4 = 0x2000
ldr r3,[r4]  r3 = read 10 from 0x2000
add r3,r0,r3  r3 = 0 + 10 = 10
str r0,[r4]  write 10 to 0x2000
cmp r0,#0  0 = 0  so it matches
beq 0x1028 it is equal so we finally take this branch
mov r0,r3  r0 = 10
ldmia sp!,{r4,pc}
increment after
r4 = [sp+0] = [0x7FD8] restore r4 from caller
pc = [sp+4] = [0x7FDC] = 0x1024
sp += 8 = 0x7FE0
(branch to 0x1024)(return from so(0) to so(1))
ldr r3,[r4]  read 10 from 0x2000
mov r0,r3  r0 = 10
ldmia sp!,{r4,pc}
r4 = [sp+0] = [0x7FE0] restore r4 from caller
pc = [sp+4] = [0x7FE4] = 0x1024
sp += 8 = 0x7FE8
(branch to 0x1024)(return from so(1) to so(2))
ldr r3,[r4]  read 10 from 0x2000
mov r0,r3  r0 = 10
ldmia sp!,{r4,pc}
r4 = [sp+0] = [0x7FE8] restore r4 from caller
pc = [sp+4] = [0x7FEC] = 0x1024
sp += 8 = 0x7FF0
(branch to 0x1024)(return from so(2) to so(3))
ldr r3,[r4]  read 10 from 0x2000
mov r0,r3  r0 = 10
ldmia sp!,{r4,pc}
r4 = [sp+0] = [0x7FF0] restore r4 from caller
pc = [sp+4] = [0x7FF4] = 0x1024
sp += 8 = 0x7FF8
(branch to 0x1024)(return from so(3) to so(4))
ldr r3,[r4]  read 10 from 0x2000
mov r0,r3  r0 = 10
ldmia sp!,{r4,pc}
r4 = [sp+0] = [0x7FF8] restore r4 from caller (main()'s r4)
pc = [sp+4] = [0x7FFC] = 0x708
sp += 8 = 0x8000
(branch to 0x708)(return from so(4) to main())

and we are done.