2010-02-26 13 views
12

para mi trabajo, necesito revertir lo que está haciendo esta porción del código (ARM9). Soy un desarrollador de Java & Realmente no entiendo esta parte del código relacionado con una sola función.Lenguaje ensamblador: intente comprender una función pequeña

Por supuesto que estoy pidiendo ayuda porque el código original no está más disponible. ¿Alguien puede ayudarme a saber qué está haciendo este código con un pequeño algoritmo en cualquier idioma? Sería bueno. Lo he intentado por muchas horas sin resultados.

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} 

Respuesta

1

¿Qué tal esto: Instruction set for ARM

Algunos consejos/asm simplicifed

  • Push - Pone algo en la "pila"/memoria
  • Add - Solemos "añadir", como en +
  • Pop retrea algo de la "pila"/Memoria
  • CMP: no se puede comparar, lo que compara algo con otra cosa.

X: o: Whatever: significa que la siguiente es una "subrutina". ¿Has usado alguna vez "goto" en Java? Similar a eso en realidad.

Si usted tiene los siguientes (ignorar si es correcto el brazo-asm es sólo pseduo):

PUSH 1 
x:  
    POP %eax 

Primero pondría 1 en la pila y luego hacer estallar de nuevo en eax (que es la abreviatura de ax extendido, que es un registro donde puede poner datos de 32 bits)

Ahora, ¿qué hace el x: hacer entonces? Bien, supongamos que hay 100 líneas de asm antes de eso también, entonces podrías usar una instrucción de "salto" para navegar a x:.

Esa es una pequeña introducción a asm. Simplificado.

Intente comprender el código anterior y examine el conjunto de instrucciones.

+0

Entiendo push, add, cmp, jmp pero todavía entiendo el propósito del código. – mada

2

Filip ha proporcionado algunos consejos, también debe leer sobre la convención de llamadas ARM. (Es decir, qué registro (s) contiene la función argumentos en la entrada y cuál es su valor de retorno.)

De una lectura rápida, creo que este código es strnlen o algo estrechamente relacionado con él.

+0

El código es exactamente strnlen y me sorprende que solo lo haya dicho y su respuesta no haya sido modificada. –

6

A excepción de las dos últimas líneas, podría ser algo como lo siguiente.
No me pegues si no soy 100% correcto.

Si
R0 es p0 o p y
R1 es n y
R2 es el valor temporal (editado; principio pensé: i o la dirección de p0[i])
R3 es el valor temporal

.

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? 

o en 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; 
} 
+0

@Curd - Creo que te acercaste mucho más de lo que estaba pensando y no creo que pueda superar tu respuesta. +1 –

+0

R2 es un registro temporal también. 'ADDS R2, R0, # 0' sobrescribe' R2' antes de ser leído. 'R2' solo guarda el valor original de' R0', no es un índice así que ¿no debería ser 'p0'? También 'CC' es la condición de" llevar claro ", no llevar conjunto, (ver' CS' más adelante). –

+0

@ Charley Bailey: (1) En cuanto a R2, tiene razón. Editaré mi respuesta de manera efectiva. (2) Sí, CC es "Carry Clear" y CS es "Carry Set", pero ARM usa la bandera Carry para subracción/comparación al revés, como cabría esperar (y otras arquitecturas lo hacen). Entonces, cuando estoy hablando de "llevar" en el comentario, no refleja el bit real de la bandera de ARM, sino si hubo un préstamo o no. Gracias por sus correcciones. – Curd

1

Mi ASM es un poco oxidado, así que no hay tomates podridos por favor. Suponiendo que esto comienza en sub_FFFF7B38:

El comando PUSH {LR} conserva el registro de enlace, que es un registro especial que contiene la dirección de retorno durante una llamada de subrutina.

ADDS establece las banderas (como CMN). También ADDS R2, R0, #0 agrega R0 a 0 y almacena en R2. (Corrección de Charles en los comentarios)

LDRB R3, [R2] se está cargando el contenido de R2 en la memoria principal en lugar de un registro, al que hace referencia R3. LDRB solo carga un solo byte. Los tres bytes no utilizados en la palabra se ponen a cero al cargarse. Básicamente, obtener R2 fuera de los registros y en custodia (tal vez).

CMP R3, #0 realiza una resta entre los dos operandos y establece los indicadores de registro, pero no almacena un resultado. Esas banderas conducen a ...

BEQ loc_FFFF7B521, que significa "Si la comparación anterior era igual, ir a loc_FFFF7B521" o if(R3 == 0) {goto loc_FFFF7B521;}

Así que si R3 no es cero, entonces el comando SUBS R1, #1 resta uno de R1 y establece una bandera.

BCC loc_FFFF7B52 hará que la ejecución salte a loc_FFFF7B52 si se establece el indicador de acarreo.

(SNIP)

Por último, POP {LR} restaura la dirección de retorno anterior, que se celebró en el registro de enlace antes de que este código ejecutado.

Editar - Mientras estaba en el coche, Curd deletreó casi lo que estaba pensando cuando estaba tratando de escribir mi respuesta y se quedó sin tiempo.

+0

'ADDS' establece las banderas (como' CMN' sería). También 'ADDS R2, R0, # 0' agrega' R0' a 0 y almacena en 'R2', no agrega' R0' y 'R2'. –

+0

@Charles - No pude encontrar el comando 'ADDS' en ninguno de mis propios documentos (todos x86), ni tampoco lo vi en el sitio web provisto por Fillip. Gracias por la corrección. :) –

+0

'S' es solo un sufijo,' ADDS' no es una instrucción separada. Puede sufrir cualquier instrucción aritmética con 'S' para obtener los indicadores establecidos. –

4

Estas son las instrucciones de línea comentada por la línea

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. 

Así que en el código C muy básico:

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; 
} 

Adición de algunas estructuras de control para deshacerse de los 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; 
} 

Edit: Ahora que mi c onfusion sobre el bit de acarreo y SUBS ha sido aclarado esto tiene más sentido.

simplificar:

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

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

    return r0 - r2; 
} 

En palabras, esto es encontrar el índice del primer NUL en los primeros r1 caracteres del puntero de cadena de por r0, o volver r1 si ninguno.

+1

En su segundo ejemplo, no es 'while (r1-- == 0)' sino 'while (r1--! = 0)'. Así que su ejemplo final es, de hecho, lo que realmente hace, en otras palabras, es un 'strlen' de longitud limitada. –

+0

@Andrew McGregor: Cambié si! =, Goto fin a while ==. Estoy bastante seguro de que esta es una transformación correcta. Pasé un tiempo desconcertando esto ya que parecía estar mal. ¿Estás completamente seguro de que lo arruiné? –

+0

La bandera de transporte de ARM está invertida; es un bit no transable, por lo que subs seguido por bcc significa rama si la resta no dio cero –

Cuestiones relacionadas