Сборка ARMv7 хранит значения в массиве

Я пытаюсь добавить введенный пользователем номер к каждому элементу массива. У меня все работало, пока я не понял, что исходный массив не обновляется. Просто, подумал я, просто сохраните значение обратно в массив и живите дальше. К сожалению, это не кажется таким уж простым.

Как следует из названия, я использую ARMv7 и пишу ассемблер. Я использовал это руководство, чтобы понимать основы и иметь хороший код для просмотра. Когда я запускаю приведенный здесь пример кода, он работает нормально: str r2, [r3] помещает все, что находится в r2, в то, на что указывает r3. Ниже приведена моя попытка сделать то же самое, что дает мне Signal 11 occurred: SIGSEGV (Invalid memory segment access) и Execution stopped at: 0x0000580C STR r3,[r5,#0]:

@ Loop and add value to all values in array regardless of array length
@ Setup loop
@ r4 comes from above and the scanf value, I've checked the registers and the value is correct
mov     r0, #0
ldr     r1, =array_b
ldr     r2, addrArr
loop:                   @ Start loop to add inputed number to every value in array
    add     r3, r2, r0
    ldr     r3, [r3]
    add     r3, r3, r4  @ Add input to each index in array

    add     r5, r2, r0  @ Pointer to location in array
    str     r3, [r5]    @ Put new value into array

    cmp     r0, r1      @ Check for end of array
    addne   r0, r0, #4  @ Not super necessary but it shows one of the cool things ARM can do, condition math
    bne     loop        @ Branch if not equal
    beq     doneLoop    @ Branch if equal

doneLoop:               @ End loop

Вот вары

.align  2
array:
    .word   0
    .word   1
    .word   2
    .word   3
    .word   4
    .word   5
    .word   6
    .word   7
.equ    array_b, .-array
addrArr:    .word array

Насколько я понимаю, str сначала берет источник, а затем - пункт назначения (что по какой-то причине отличается от других инструкций). Таким образом, r5 используется для вычисления того, где в массиве хранить значение, а r3 имеет значение из инструкции add. Я проверил, и значение в r5 является допустимым, то есть: это начало массива, а array_b имеет правильную длину (в данном случае 32). Я также пробовал делать =array вместо addrArr, но они дают одно и то же значение и одно и то же сообщение об ошибке.


person dlkulp    schedule 16.03.2015    source источник
comment
Кроме того, ваш код ужасно раздут. Я знаю, что это не ваша проблема, но я не могу не указать на это. Нет необходимости каждый раз добавлять базовый адрес вашего массива и индекс, просто сделайте это один раз. Используя правильные режимы адресации, вам даже не нужно делать это один раз, это делается автоматически процессором. Ваш цикл, вероятно, должен уместиться в 4 инструкции. Наконец, последняя инструкция beq ничего не делает.   -  person Bregalad    schedule 17.03.2015
comment
Я довольно новичок в этом, я хотел бы знать лучшие способы сделать это! Не могли бы вы привести быстрый пример или ссылку на где-нибудь, где говорится об этом?   -  person dlkulp    schedule 17.03.2015
comment
Да, эта страница кажется довольно хороший справочник о том, что ARM может сделать для режимов адресации, среди прочего   -  person Bregalad    schedule 17.03.2015


Ответы (1)


Это связано с тем, что исторически в системах существует два основных типа воспоминаний:

  • ПЗУ, память только для чтения, не может быть записана и может хранить только программу и постоянные данные
  • ОЗУ, оперативное запоминающее устройство, может быть как для чтения, так и для записи. Он используется для хранения переменных.

Многие системы не используют ПЗУ напрямую, вместо этого данные могут быть загружены с другой постоянной подложки, например, дискеты, ленты или жесткого диска в ОЗУ. Чтобы программа не записывала в оперативную память то, что не должна была быть записана, оперативную память можно разделить на несколько областей с помощью сегментированной памяти.

Не все системы имеют это, поэтому это действительно зависит от архитектуры. Если используется сегментированная память, это в основном заставляет процессор выходить из приложения, когда вы пытаетесь записать в сегмент ОЗУ, предназначенный только для чтения. Это именно то, что кажется вашей проблемой здесь.

Чтобы решить эту проблему, вы должны объявить свой массив, который является переменной и должен храниться в оперативной памяти, указав перед ним .data.

С другой стороны, ваши исполняемые инструкции должны быть помещены в сегмент только для чтения, отмеченный директивой ассемблера .text.

person Bregalad    schedule 16.03.2015
comment
gcc помещает код в .rodata? Почему я должен использовать .text вместо .rodata? - person dlkulp; 17.03.2015
comment
Сегменты описываются в скрипте компоновщика, роль которого состоит в том, чтобы сообщить компоновщику, какие разделы и где находятся в адресном пространстве. Я подозреваю, что gcc отделяет .rodata от .text для разделения кода и постоянных данных, но я не совсем уверен, поэтому могу ошибаться. Это может предотвратить ошибочное выполнение постоянных данных как кода, если сегментированные страницы поддерживают эту функцию. Вот то, что кажется хороший справочник по использованию скрипта компоновщика. - person Bregalad; 17.03.2015