Язык ассемблера: попытайтесь понять небольшую функцию - PullRequest
12 голосов
/ 27 февраля 2010

для моей работы мне нужно обратить вспять то, что делает эта часть кода (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 ]

6 голосов
/ 27 февраля 2010

За исключением последних двух строк, это может быть что-то вроде следующего.
Пожалуйста, не бей меня, если я не на 100% прав.

Если
R0 - это p0 или p и
R1 равно n и
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;
}
4 голосов
/ 27 февраля 2010

Здесь комментируются инструкции построчно

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 голосов
/ 27 февраля 2010

Филипп предоставил несколько указателей, вам также необходимо ознакомиться с соглашением о вызовах ARM. (То есть, какой регистр (ы) содержит аргументы функции на входе и какое его возвращаемое значение.)

Из краткого прочтения я думаю, что этот код strnlen или что-то тесно с ним связанное.

1 голос
/ 27 февраля 2010

Мой ASM немного ржавый, поэтому, пожалуйста, не гнилые помидоры. Предполагая, что это начинается в sub_FFFF7B38:

Команда PUSH {LR} сохраняет регистр связи, который является специальным регистром, который содержит адрес возврата во время вызова подпрограммы.

ADDS устанавливает флаги (как CMN). Также ADDS R2, R0, #0 добавляет R0 к 0 и сохраняет в R2. (Исправление от Чарльза в комментариях)

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} восстанавливает предыдущий адрес возврата, который содержался в регистре ссылок до выполнения этого кода.

Редактировать - Пока я был в машине, творог объяснил, о чем я думал, когда пытался выписать свой ответ, и у меня не хватило времени.

1 голос
/ 27 февраля 2010

Как насчет этого: Набор инструкций для ARM

Некоторые подсказки / упрощенный асм

  • Push - кладет что-то в «стек» / память
  • Добавить - Обычно "добавить", как в +
  • Поп извлекает что-то из «стека» / памяти
  • CMP - это Short of Compare, который сравнивает что-то с чем-то другим.

X: или: Whatever: означает, что следующее является «подпрограммой». Вы когда-нибудь использовали "goto" в Java? На самом деле похоже на это.

Если у вас есть следующее (не обращайте внимания, если это правильный arm-asm, это просто pseduo):

PUSH 1
x:     
    POP %eax

Сначала он поместит 1 в стек, а затем вставит обратно в eax (что означает сокращение для расширенного топора, то есть регистр, в который можно поместить 32-битный объем данных)

Теперь, что тогда делает x:? Что ж, давайте предположим, что до этого есть 100 строк asm, тогда вы можете использовать команду «jump» для перехода к x:.

Это немного введение в асм. Упрощенный.

Попытайтесь понять приведенный выше код и изучите набор инструкций.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...