Подтвердить что ты не робот

Язык ассемблера: попытайтесь понять небольшую функцию

для моей работы, мне нужно отменить то, что делает эта часть кода (ARM9). Im java developper, и я действительно не понимаю эту часть кода, связанную с одной функцией.

Конечно, я прошу помощи, потому что исходный код недоступен. Кто-нибудь может помочь мне узнать, что делает этот код с алгоритмом smal на любом высоком языке? Это было бы хорошо. Я пробовал много часов без каких-либо результатов.

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}
4b9b3361

Ответ 1

За исключением двух последних строк, это может быть что-то вроде следующего. Пожалуйста, не ударяйте меня, если я не на 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;
}

Ответ 2

Вот инструкции, прокомментированные по строке

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, если не существует.

Ответ 3

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

С быстрым чтением я думаю, что этот код является strnlen или чем-то близким к нему.

Ответ 4

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

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

  • Push - помещает что-то в "Stack" /Memory
  • Добавить - Обычная "добавить", как в +
  • Pop возвращает что-то из "стека" / "Память"
  • CMP - отсутствует в сравнении, что сравнивает что-то с чем-то другим.

X: или: Whatever: означает, что следующая "подпрограмма". Когда-либо использовались "goto" в Java? Как и на самом деле.

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

PUSH 1
x:     
    POP %eax

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

Теперь, что делает X:? Предположим, что до этого есть 100 строк asm, тогда вы можете использовать "переход" для перехода к X:.

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

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

Ответ 5

Моя 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, если установлен флаг переноса.

(snip)

Наконец, POP {LR} восстанавливает предыдущий обратный адрес, который был сохранен в реестре ссылок до выполнения этого кода.

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