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

Зачем использовать LDR поверх MOV (или наоборот) в сборке ARM?

Я просматриваю этот учебник: http://www.cl.cam.ac.uk/freshers/raspberrypi/tutorials/os/ok01.html

Первая строка сборки:

ldr r0,=0x20200000

второе:

mov r1,#1

Я думал, что ldr предназначено для загрузки значений из памяти в регистры. Но кажется, что = означает, что 0x20200000 - это значение, а не адрес памяти. Кажется, что обе строки загружают абсолютные значения.

4b9b3361

Ответ 1

Это трюк/ярлык. например,

ldr r0,=main

что произойдет, если ассемблер будет выделять слово данных рядом с инструкцией, но за пределами пути команды

ldr r0,main_addr
...
b somewhere
main_addr: .data main

Теперь добавьте этот трюк в константы/немедленно, esp те, которые не могут вписаться в немедленную инструкцию перемещения:

top:
add r1,r2,r3
ldr r0,=0x12345678
eor r1,r2,r3
eor r1,r2,r3
b top

собрать, а затем разобрать

00000000 <top>:
   0:   e0821003    add r1, r2, r3
   4:   e59f0008    ldr r0, [pc, #8]    ; 14 <top+0x14>
   8:   e0221003    eor r1, r2, r3
   c:   e0221003    eor r1, r2, r3
  10:   eafffffa    b   0 <top>
  14:   12345678    eorsne  r5, r4, #125829120  ; 0x7800000

и вы видите, что ассемблер добавил слово данных для вас и изменил ldr на родственник pc для вас.

теперь, если вы используете немедленное действие, которое вписывается в инструкцию mov, тогда, в зависимости от ассемблера, возможно, с помощью gnu, как я использую, он превратил его в mov для меня

top:
add r1,r2,r3
ldr r0,=0x12345678
ldr r5,=1
mov r6,#1
eor r1,r2,r3
eor r1,r2,r3
b top


00000000 <top>:
   0:   e0821003    add r1, r2, r3
   4:   e59f0010    ldr r0, [pc, #16]   ; 1c <top+0x1c>
   8:   e3a05001    mov r5, #1
   c:   e3a06001    mov r6, #1
  10:   e0221003    eor r1, r2, r3
  14:   e0221003    eor r1, r2, r3
  18:   eafffff8    b   0 <top>
  1c:   12345678    eorsne  r5, r4, #125829120  ; 0x7800000

Итак, это в основном ярлык для ввода текста, понимайте, что вы даете ассемблеру возможность найти место, чтобы придерживаться постоянной, что обычно делает хорошую работу, иногда жалуется, не уверен, что я видел, что он не в состоянии сделать это безопасно. Иногда вам нужен код .ltorg или .pool в коде, чтобы помочь ассемблеру найти место.

Ответ 2

Более короткий ответ, только от человека, который ближе к вашему уровню, надеется, что это поможет: в ARM инструкции имеют 32 бита. Некоторые биты используются для идентификации операции, некоторые для операндов, а в случае команды MOV некоторые доступны для немедленного значения (например, # 1).

Как вы видите здесь (стр. 33), для немедленного значения доступно только 12 бит. Вместо того, чтобы использовать каждый бит в качестве числа (от 0 до 2 ^ 12-1 ~ 4095), команда вычисляет ближайшее число, поворачивая правое (ROR) первые 8 бит на два раза, количество, указанное в последних 4 битах, То есть immediate = first 8 bits ROR 2*(last four bits).

Таким образом, мы можем достичь гораздо большего числа, чем просто 4096 (см. стр. 34 для краткого изложения возможных непосредственных действий).

На всякий случай, что наш номер не может быть преобразован в инструкцию, подобную предыдущей (257 не может быть выражен как 8 бит, повернутых два раза каждые 4 бита), тогда мы должны использовать LDR r0, = 257

В этом случае компилятор сохраняет номер 257 в памяти, рядом с программным кодом, поэтому его можно адресовать по отношению к ПК и загружать его из памяти, так же подробно объясняется в dwelch.

Примечание. Если вы следуете этому руководству, то при попытке "сделать" с mov r0, # 257 вы получите сообщение об ошибке, и вам придется вручную попробовать ldr r0, = 257.

Ответ 3

Как и другие ответы, я думаю, что могу упростить ответ.

ldr= Регистр LoaD

mov= MOVe

Оба эффективно делают одно и то же, но по-разному.

Разница во многом похожа на разницу между

#define CONST 5

и

int CONST = 5;

на языке C.

mov выполняется очень быстро, так как имеет сопутствующее значение, непосредственно сохраненное как часть инструкции (в 12-битном формате, описанном в ответе выше). Он имеет некоторые ограничения из-за того, как он сохраняет значение. Зачем? Поскольку

  • 12 бит недостаточно для хранения огромных чисел, таких как 32-разрядные адреса памяти.
  • Первые 8 бит ROR 2 * (последние 4 бита) не могут представлять только любое число, даже в 12-битном диапазоне.

ldr, с другой стороны, универсален (главным образом, из-за оптимизации компилятора). Он работает так (как показано в разобранной процедуре)

  • Если значение может быть представлено в 12-битном и первом 8 бит ROR 2 * (последние 4 бита) формате, тогда компилятор изменит его на mov, сопровождающее значение.

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

Я надеюсь, что это помогло.