Assembly 破译汇编代码

Assembly 破译汇编代码,assembly,arm,Assembly,Arm,我刚才问了几个问题,关于某些助记符的含义,以及我收到的代码中的命令。我以前从未与Assembly合作过 以下是代码片段: traverse proc ldr r0, =21475234 push {r4, r5, lr} mov r4, r0 ldr r5, [r4] ldr r0, [r4, #4] bl traverse cmp r5, r0 it lt movlt r5

我刚才问了几个问题,关于某些助记符的含义,以及我收到的代码中的命令。我以前从未与Assembly合作过

以下是代码片段:

 traverse proc 
      ldr r0, =21475234
      push {r4, r5, lr}
      mov r4, r0
      ldr r5, [r4] 

      ldr r0, [r4, #4]
      bl traverse 
      cmp r5, r0 
      it lt 
      movlt r5, r0 

      mov r0,r5 
      pop {r4,r5,pc}  
  • 什么东西被加载到
    r5
    ?按照说明,是否将
    r4
    推入堆栈,加载
    r0
    中的值,然后加载
    r5

  • 什么加载到
    r0
    [r4,#4]
    是否指
    r4
    中第五位的数字

  • bl TRAVENSE
    既然我们已经在使用TRAVENSE函数,我们是否要将链接分支到同一个函数

  • 我不知道电脑的助记符是什么意思

  • transverse proc
    中的
    proc
    代表什么?在每个函数声明中都需要这样做吗

  • 提前谢谢各位,我还在想办法

    ldr r0, =21475234
    
    这是一个快捷方式,几乎是伪代码。各种各样的arm汇编程序都倾向于支持它

    可能打算这样使用

    ldr r0,=hello
    ldr r1,[r0]
    
    ...
    
    in some other file perhaps
    
    .globl hello
    hello:
       .word 0x1234
    
    基本上它意味着在等号后面加载对象的地址

    ldr r0,hello
    ...
    hello:
      .word 0x1234
    
    表示将标签hello处的数据值加载到r0中

    在C语言中是这样的

    //ldr r0,=hello
    unsigned int r0 = (unsigned int)&hello;
    //ldr r0,hello
    unsigned int r0 = hello;
    
    因为arm在很大程度上是一个固定长度的指令集,其中的指令大小等于或小于寄存器,所以当您使用数字作为项目地址而不是标签时,您无法加载任何所需的立即数

    ldr r0,=0x12345678
    
    编码为

    ldr r0,temp000
    ...
    temp000: .word 0x12345678
    
    将值0x12345678加载到r0中。汇编程序必须找到一个距离ldr足够近但不在执行路径内的位置来放置该数据字,有时会出现无法找到位置的错误

    所以

    将值21475234加载到r0中

    这一推 推送{r4,r5,lr} 在堆栈上保存r4、r5和返回寄存器lr。常用的调用约定表示,对于arm,您可以销毁r0-r3,但必须保留其他寄存器(这有一两个例外),因此要使用r4,我们必须保存它。我假设这是编译代码,不是手工编写的,或者是从编译代码调用的

    现在我们可以使用r4,它将值21475234复制到r4,r0和r4现在保持相同的值 mov r4,r0 当你在一个寄存器周围放上[括号]时,它基本上是寄存器间接寻址,而不是想要该寄存器的内容,寄存器的内容是你想要的内容的地址,所以这表示读取地址21475234处的值,并将该值保存在r5中

      ldr r5, [r4] 
    
    您是否删除了一些用于发布此问题的代码

    这表示读取地址21475234+4处的值,并将其保存在r0中

    ldr r0, [r4, #4]
    
    当立即数在括号内时,意味着将其添加到寄存器中,并使用从寄存器r4加4中的地址读取的地址

    ldr r0, [r4, #4]
    
    从添加r4+r5生成的地址读取

    ldr r0, [r4, r5]
    
    这与r4中的地址完全不同,从r4中读取,将值放入r0,然后将4添加到r4中

    ldr r0, [r4], #4
    
    这类似于C代码

    unsigned int r0 = *r4++;
    
    lr是链接寄存器r14,pc是程序计数器r15,当您更改r15时,它实际上是一个分支。当调用函数(procedure,proc)时,lr的推送保存了返回地址,这样您就可以在函数调用之后立即返回运行代码。为了做到这一点,您基本上需要将程序计数器更改为调用后的地址(bl=分支链接,它基本上是对某个地址的函数调用)。所以在arm中你可以推动lr和pop pc,所以这个

    pop {r4,r5,pc}
    
    是push的补充,它将r4和r5恢复到输入函数时的值,然后将返回地址弹出到程序计数器中,使程序分支到该地址

    遍历是过程(函数)的标签或名称。proc是过程的缩写。毫无疑问,汇编程序助记符比仅仅声明标签更专业。标签应该可以很好地工作,但是如果这样做的话,您可能会从汇编程序获得更多帮助。(在《每日集会》20多年的写作中,我从未找到这样做的理由,但也许其他人已经找到了)


    bl traverse,这是一个递归调用。不确定您是如何摆脱这一困境的,您发布了所有代码吗?

    这是一个不会终止的递归函数。这里有东西坏了。非常感谢你,德韦尔奇!你的回答对我的问题给出了详细而翔实的回答。天气确实晴朗了很多。然而,我还有一个问题。您提到LDR0,[r4,#4]将加载到r0中,r4+4的地址。由于r4在堆栈中,将+4添加到r4的地址会得到堆栈中r5的地址吗?我没有遗漏任何代码。这是一个用C编写的练习,然后用我们自己的话解释代码是如何工作的/程序的目的。再次感谢你的帮助,我很感激!r4是一个寄存器,它的副本在堆栈上。就像r0和r4一样,在这段代码中,在一段时间内保持相同的值。堆栈只是内存(一些位),寄存器是一些位,它们是分开的。将值放在堆栈上的目的是确保我们将r4放回完成函数时找到的方式,基本上我们不想触及堆栈上的值。绝对精彩。谢谢德韦尔奇:)
    pop {r4,r5,pc}