Как использовать ветвление в цикле в ARM Assembly? - PullRequest
0 голосов
/ 19 ноября 2018

Моя программа создает 2d массив в памяти с .skip 1000.Затем он заполняет этот массив входом из stdin, используя этот цикл:

    @@loop to store message in array
    @outer for loop over rows
    MOV r0,#0 @r0 = i (row index)
msgrowloop:
    CMP r0,r2 @compare to nrows
    BEQ msgendrowloop

    @multiply/accumulate instruction
    MLA r7, r3, r0, r6 @calculates the address of the first element in each row

    @inner for loop over columns
    MOV r1,#0 @r1 = j (column index)
msgcolumnloop:
    CMP r1,r3 @compare to ncolumns
    BEQ msgendcolumnloop

    @@@store from stdin

    PUSH {r0-r4}
    BL getchar @branch & link to getchar - reads single character from stdin

    CMP r0,#-1 @check if we're at the end of file
    BEQ msgendrowloop @if so, exit loop

    MOV r8, r0 @move character to r8
    POP {r0-r4}

    @@@store from stdin end

    @store r8 in memory and increase r7 by one byte
    STRB r8,[r7],#1
    ADD r1,r1,#1 @j += 1
    B msgcolumnloop
msgendcolumnloop:
    ADD r0,r0,#1 @i += 1
    B msgrowloop
msgendrowloop:
    @rest of the program...

Теперь, используя это, я получаю ошибку сегментации, но если я изменю свою функцию stdin на эту:

PUSH {r0-r4}
BL getchar @branch & link to getchar - reads single character from stdin

CMP r0, #-1 @check if we are at end of file
MOV r8, r0 @move character to r8

POP {r0-r4}
BEQ msgendrowloop @exit loop when done

Вместо этого:

PUSH {r0-r4}
BL getchar @branch & link to getchar - reads single character from stdin

CMP r0,#-1 @check if we're at the end of file
BEQ msgendrowloop @if so, exit loop

MOV r8, r0 @move character to r8
POP {r0-r4}

Работает отлично.Логика здесь сбивает с толку, так как мой оригинальный код кажется логически обоснованным.

1 Ответ

0 голосов
/ 22 ноября 2018

Формализация комментариев выше в ответ:

Основная причина поведения, которое вы видите, заключается в том, что вторая форма вашей функции stdin не сохраняет указатель стека (его использование стека)не «сбалансирован»).PUSH {r0-r4} уравновешивается POP {r0-r4}, который восстанавливает указатель стека до значения, которое он имел при входе в блок, но если берется ветвь BEQ, то POP пропускается и операции стека не выполняются.более сбалансированныйЭто означает, что, когда другой бит кода извлекает данные из стека, ожидая найти вещи, которые он выдвинул ранее, он выводит неправильные значения.Скорее всего, есть всплывающее окно, в котором счетчик программ возвращается в виде функции, и он выводит бессмысленный адрес, а значит и segfault.

Хорошая идея - развить навыки с использованием отладчика, чтобы попытаться найти кореньпричина ошибки, как это для себя.Предполагая, что я прав в отношении причины segfault, основная процедура в этом случае будет

  1. Чтобы найти строку кода, которая генерирует segfault, которая, вероятно, выглядит примерно как POP {r4-r6,pc}
  2. Чтобы установить, беря указатель стека из r13 и просматривая стек в памяти, что значение, которое вставляется в pc, является недопустимым адресом ветвления
  3. Чтобы найти PUSH {r4-r6,lr}, который балансирует это POP, и удостоверится, что соответствующий адрес был передан в первую очередь
  4. Чтобы заметить, что указатель стека изменился в значении между концом PUSH и началомбалансировка POP (что не следует делать, если все операции промежуточного стека были правильно сбалансированы)
  5. Чтобы пройти по коду и попытаться найти источник дисбаланса стека.

Кроме того, обратите внимание на стандарт вызова процедур в ARM ABI .В двух словах:

  • r0-r3 используются для аргументов функций и возвращаемых значений;
  • r0-r3 и r12 являются "замкнутыми" и не могут полагатьсяони сохраняют свои значения в вызовах функций, поэтому лучше не использовать их для промежуточного хранения, если вам не нужно;
  • r4-r11 и lr (r14) «сохраняются при вызове»поэтому любая функция, которую вы пишете, должна сохранять их (но не обязательно сохранять r0-r3 или r12);
  • Стек должен быть выровнен по 8 байтов по границам единиц перевода, поэтому всегда полезно нажимать идобавьте четные числа регистров, чтобы не стать жертвой странного неопределенного поведения.Ваш звонок на getchar в настоящее время работает со смещенным стеком.
...