Я не хочу, чтобы это был исключительный ответ, но он предлагает больше информации, а также предлагает неудобное решение для использования только одной инструкции ldr.
При использовании этого двухэтапного метода ldr ассемблер фактически добавляет еще 4 байта данных после вашего кода! Даже в разделе .text эти 4 байта являются фактическим адресом вашей переменной .data. Затем первая инструкция ldr фактически указывает на этот адрес, затем вы используете следующую ldr для использования реального адреса. Как обсуждалось в tangrs, этот двойной указатель может быть способом убедиться, что ваши переменные/константы доступны, особенно если раздел .data находится дальше (64 КБ в моем последнем запуске).
Глядя на пример кода правильного способа сделать это:
.text
.global _start
_start:
ldr r0, =x
ldr r0, [r0]
mov r7, #1
swi #0
nop
.data
x: .word 0xf0f0f0f0
Ассемблер ДЕЙСТВИТЕЛЬНО производит это:
00010074 <_start>:
10074: e59f000c ldr r0, [pc, #12] ; 10088 <_start+0x14>
10078: e5900000 ldr r0, [r0]
1007c: e3a07001 mov r7, #1
10080: ef000000 svc 0x00000000
10084: e1a00000 nop ; (mov r0, r0)
10088: 0002008c andeq r0, r2, ip, lsl #1
Disassembly of section .data:
0002008c <x>:
2008c: f0f0f0f0 ; <UNDEFINED> instruction: 0xf0f0f0f0
Первый ldr указывает на 12 байтов после счетчика программ (считается текущей инструкцией + еще восемь). Это указывает на адрес 0x10088 (как указано в objdump), который указывает на инструкцию andeq (не настоящую инструкцию в данном контексте). На самом деле это адрес 0x0002008c, который указывает на наш правильный адрес в разделе .data для нашей переменной x. Теперь, когда у нас есть адрес нашей переменной в r0, мы можем использовать ldr для этого адреса, чтобы получить реальное значение. Примечательно, однако, что хотя второй операнд в исходном файле для обеих этих инструкций ldr выглядит очень по-разному, машинная кодировка используется для одной и той же кодировки ldr; они оба являются LDR Immediate (хотя первый вариант ldr также считается LDR Literal, это просто LDR Immediate с жестко закодированным значением «Rn» в «1111», что в любом случае является просто регистром компьютера).
Имея все это в виду, хотя это и неудобно, мы можем придумать способ просто использовать форму LDR Immediate (Literal) один раз. Все, что нам нужно сделать, это убедиться, что мы получили правильное непосредственное значение (смещение), которое соответствует нашим реальным данным. Легче сделать, чем сказать:
.text
.global _start
_start:
ldr r0, [pc, #8]
mov r7, #1
swi #0
nop
x: .word 0xf0f0f0f0
Помимо необходимости использовать только одну инструкцию LDR для достижения того же результата, в этой версии исходного кода есть еще одно тонкое отличие: нет раздела .data. Это можно сделать с помощью раздела данных, но это поместит наши данные в гораздо более высокий адрес, что сделает наше смещение настолько большим, что нам, возможно, придется использовать дополнительные инструкции только для того, чтобы получить правильное смещение. Еще одно замечание связано с тем, что это находится в разделе .text (r-x), вы не можете использовать для него str по умолчанию. Это очень небольшой барьер, просто используйте опцию -N для ld, и ваш раздел .text теперь будет rwx. Я уверен, что последнее предложение разозлит богов stackoverflow, иди ко мне;)
person
XlogicX
schedule
15.11.2018