汇编语言:尝试理解一个小函数

时间:2010-02-26 22:17:55

标签: assembly arm

对于我的工作,我需要反转这部分代码(ARM9)正在做的事情。我是一个java开发者&我真的不明白这部分与单个函数相关的代码。

当然,我正在寻求帮助,因为原始代码不再可用。任何人都可以帮助我知道这个代码在任何高级语言中使用小算法做了什么?这会很好。我已经尝试了很多个小时没有结果。

sub_FFFF7B38
    PUSH    {LR}
    ADDS    R2, R0, #0
    LDRB    R3, [R2]
    CMP     R3, #0
    BEQ     loc_FFFF7B52
    SUBS    R1, #1
    BCC     loc_FFFF7B52

loc_FFFF7B46:
    ADDS    R0, #1
    LDRB    R3, [R0]
    CMP     R3, #0
    BEQ     loc_FFFF7B52
    SUBS    R1, #1
    BCS     loc_FFFF7B46

loc_FFFF7B52:
    SUBS    R0, R0, R2
    POP     {R1}

5 个答案:

答案 0 :(得分:6)

除最后两行外,它可能如下所示 如果我不是100%正确,请不要打我。

如果
R0p0p
R1n
R2是临时值(已编辑;首先我认为:i或地址p0[i]
R3是临时值

sub_FFFF7B38
          PUSH {LR}           ; save return address
          ADDS R2, R0, #0     ; move R0 to R2
          LDRB R3, [R2]       ; load *p0
          CMP R3, #0          ; if *p0==0 
          BEQ loc_FFFF7B52    ; then jump to loc_FFFF7B52 
          SUBS R1, #1         ; decrement n
          BCC loc_FFFF7B52    ; if there was a borrow (i.e. n was 0): jump to loc_FFFF7B52


loc_FFFF7B46:
          ADDS R0, #1         ; increment p
          LDRB R3, [R0]       ; load *p
          CMP R3, #0          ; if *p==0
          BEQ loc_FFFF7B52    ; jump to loc_FFFF7B52
          SUBS R1, #1         ; decrement n
          BCS loc_FFFF7B46    ; if there was no borrow (i.e. n was not 0): jump to loc_FFFF7B46


loc_FFFF7B52:
          SUBS R0, R0, R2     ; calculate p - p0
          POP {R1}            ; ??? I don't understand the purpose of this
                              ; isn't there missing something?

或在C:

int f(char *p0, unsigned int n)
{
  char *p;

  if (*p0==0 || n--==0)
    return 0;

  for(p=p0; *++p && n>0; n--)
  {
  }
  return p - p0;
}

答案 1 :(得分:4)

以下是逐行评论的说明

sub_FFFF7B38
    PUSH    {LR}          ; save LR (link register) on the stack
    ADDS    R2, R0, #0    ; R2 = R0 + 0 and set flags (could just have been MOV?)
    LDRB    R3, [R2]      ; Load R3 with a single byte from the address at R2
    CMP     R3, #0        ; Compare R3 against 0...
    BEQ     loc_FFFF7B52  ; ...branch to end if equal
    SUBS    R1, #1        ; R1 = R1 - 1 and set flags
    BCC     loc_FFFF7B52  ; branch to end if carry was clear which for subtraction is
                          ; if the result is not positive

loc_FFFF7B46:
    ADDS    R0, #1        ; R0 = R0 + 1 and set flags
    LDRB    R3, [R0]      ; Load R3 with byte from address at R0
    CMP     R3, #0        ; Compare R3 against 0...
    BEQ     loc_FFFF7B52  ; ...branch to end if equal
    SUBS    R1, #1        ; R1 = R1 - 1 and set flags
    BCS     loc_FFFF7B46  ; loop if carry set  which for subtraction is
                          ; if the result is positive

loc_FFFF7B52:
    SUBS    R0, R0, R2    ; R0 = R0 - R2
    POP     {R1}          ; Load what the previously saved value of LR into R1
                          ; Presumably the missing next line is MOV PC, R1 to
                          ; return from the function.

所以在非常基本的C代码中:

void unknown(const char* r0, int r1)
{
    const char* r2 = r0;
    char r3 = *r2;
    if (r3 == '\0')
        goto end;
    if (--r1 <= 0)
        goto end;

loop:
    r3 = *++r0;
    if (r3 == '\0')
        goto end;
    if (--r1 > 0)
        goto loop;

end:
    return r0 - r2;
}

添加一些控制结构以摆脱goto s:

void unknown(const char* r0, int r1)
{
    const char* r2 = r0;
    char r3 = *r2;

    if (r3 != '\0')
    {
        if (--r1 >= 0)
        do
        {
             if (*++r0 == '\0')
                 break;
        } while (--r1 >= 0);
    }

    return r0 - r2;
}

编辑:现在我对进位位和SUBS的混淆已被清除,这更有意义。

简化:

void unknown(const char* r0, int r1)
{
    const char* r2 = r0;

    while (*r0 != '\0' && --r1 >= 0)
        r0++;

    return r0 - r2;
}

简而言之,这是找到NUL字符串指针的第一个r1字符中的第一个r0的索引,如果没有,则返回r1

答案 2 :(得分:2)

Filip提供了一些指针,您还需要阅读ARM调用约定。 (也就是说,哪个寄存器包含条目上的函数参数以及它的返回值。)

从快速阅读中我认为这段代码是strnlen或与之密切相关的东西。

答案 3 :(得分:1)

这个怎么样:Instruction set for ARM

一些提示/简化asm

  • 推送 - 将某些内容放在“堆栈”/内存
  • 添加 - 在+
  • 中使用“添加”
  • Pop从“堆栈”/ Memory
  • 中撤回了一些内容
  • CMP - 缺少比较,比较其他东西。

X:或:Whatever:表示以下是“子程序”。曾经在Java中使用过“goto”吗?与实际情况类似。

如果您有以下内容(忽略它是否正确arm-asm它只是pseduo):

PUSH 1
x:     
    POP %eax

首先它会将1放在堆栈上,然后将其弹回到eax(这是扩展ax的缩写,这是一个可以放置32位数据的寄存器)

现在,x:做了什么?那么我们假设在此之前有100行asm,那么你可以使用“jump”指令导航到x:

这是对asm的一点介绍。简化。

尝试理解上面的代码并检查指令集。

答案 4 :(得分:1)

我的ASM有点生锈,所以请不要吃烂番茄。假设从sub_FFFF7B38开始:

命令PUSH {LR}保留链接寄存器,这是一个特殊寄存器,用于在子程序调用期间保存返回地址。

ADDS设置标志(如CMN会)。此外,ADDS R2, R0, #0R0添加到0并存储在R2中。 (评论中Charles的更正)

LDRB R3, [R2]正在将R2的内容加载到主内存而不是R3引用的寄存器中。 LDRB仅加载一个字节。加载时,字中三个未使用的字节归零。基本上,将R2从寄存器中取出并保存(可能)。

CMP R3, #0在两个操作数之间执行减法并设置寄存器标志,但不存储结果。那些旗帜导致......

BEQ loc_FFFF7B521,表示“如果之前的比较相同,请转到loc_FFFF7B521”或if(R3 == 0) {goto loc_FFFF7B521;}

因此,如果R3不为零,则SUBS R1, #1命令会从R1中减去一个并设置一个标记。

如果设置了进位标志,

BCC loc_FFFF7B52将导致执行跳转到loc_FFFF7B52

(剪辑)

最后,POP {LR}恢复在执行此代码之前在链接寄存器上保留的上一个返回地址。

编辑 - 当我在车里时,当我试图写出我的答案并且没时间用完时,Curd阐述了我的想法。