Почему я не могу переместить #1001 на r5 на руке?
У меня есть RPi4, и я пытаюсь написать код на ассемблере для цикла 1000 раз. Код работает нормально, когда я устанавливаю меньшее количество циклов, но когда я пытаюсь установить его 1001,gcc
говорит:
loop.s: Assembler messages:
loop.s:15: Error: invalid constant (3e9) after fixup
Вот код:
.data
ms3: .asciz "%d\n"
.text
.global main
.extern printf
main:
push {ip, lr}
mov r1, #0
mov r5, #1001
loop1000:
push {r1}
ldr r0, =ms3
bl printf
pop {r1}
add r1, #1
cmp r1, r5
bne loop1000
pop {ip, pc}
1 ответ
Языки ассемблера определяются инструментом, а не целью, поэтому решения и точный синтаксис для инструкций различаются. Вы упомянули gcc, который подразумевает ассемблер gnu, хотя gcc, на который подается ассемблер, является еще одним языком ассемблера gnu arm
При использовании ассемблера gnu псевдо-инструкция ldr = будет пытаться использовать оптимальную инструкцию, если это возможно, в противном случае она будет выполнять загрузку относительно компьютера. Если вам нужен полный контроль, используйте только ldr = для ярлыков (очевидно, что это было изначально задумано)
.cpu arm7tdmi
ldr r5,=1001
ldr r5,=0x00990000
ldr r5,=0x00990099
ldr r5,=0x90000009
.thumb
.cpu cortex-m0
ldr r5,=1001
.cpu cortex-m3
ldr r5,=1001
movw r5,#1001
ldr r5,=0x00990099
.align
Disassembly of section .text:
00000000 <.text>:
0: e59f5018 ldr r5, [pc, #24] ; 20 <.text+0x20>
4: e3a05899 mov r5, #10027008 ; 0x990000
8: e59f5014 ldr r5, [pc, #20] ; 24 <.text+0x24>
c: e3a05299 mov r5, #-1879048183 ; 0x90000009
10: 4d03 ldr r5, [pc, #12] ; (20 <.text+0x20>)
12: f240 35e9 movw r5, #1001 ; 0x3e9
16: f240 35e9 movw r5, #1001 ; 0x3e9
1a: f04f 1599 mov.w r5, #10027161 ; 0x990099
1e: bf00 nop
20: 000003e9 andeq r0, r0, r9, ror #7
24: 00990099 umullseq r0, r9, r9, r0
начиная с середины вашего вопроса.
10: 4d03 ldr r5, [pc, #12] ; (20 <.text+0x20>)
1001 (0x3e9) не вписывается в 8-битную команду немедленного действия, без вращения, в инструкции большого пальца mov. поэтому, используя ldr =, ассемблер создал относительную для компьютера нагрузку, которая имеет свои плюсы и минусы.
Расширение thumb2 доступно только на некоторых процессорах, которые поддерживают немедленные изменения большего размера.
12: f240 35e9 movw r5, #1001 ; 0x3e9
Он даже может делать такие странные вещи.
1a: f04f 1599 mov.w r5, #10027161 ; 0x990099
и ldr =, и прямое использование movw привели к одной и той же инструкции (как и ожидалось).
12: f240 35e9 movw r5, #1001 ; 0x3e9
16: f240 35e9 movw r5, #1001 ; 0x3e9
В комментариях была некоторая путаница (всем нужно прочитать документацию, а не только OP)
0: e59f5018 ldr r5, [pc, #24] ; 20 <.text+0x20>
4: e3a05899 mov r5, #10027008 ; 0x990000
8: e59f5014 ldr r5, [pc, #20] ; 24 <.text+0x24>
c: e3a05299 mov r5, #-1879048183 ; 0x90000009
Режим arm не может делать то, что 0x00990099, но он может выполнять 8 ненулевых битов, повернутых на четной границе 0x00990000 и 0x90000009, но не 0x000001FE, 0x102 и так далее.
arm использует 32-битные инструкции и, как и mips и другие, ограничено в возможном количестве немедленных битов, оставляя место для кода операции из-за отсутствия лучшего термина. thumb - 16 бит, поэтому для немедленной обработки доступно гораздо меньше места. Расширения thumb2 добавляют дополнительные инструкции, которые занимают 2x16 бит, но не могут использовать кодировку руки в целом, но по какой-то причине не используют ту же непосредственную схему, которую вы видите в инструкциях руки, поэтому у вас есть эта вещь отражения и сдвига, а не просто сдвиг вещь.
Все это есть в документации по arm, которую вы должны иметь рядом с собой при написании / изучении языка ассемблера.
Язык ассемблера определяется инструментом (ассемблером), а не целью, поэтому ожидается, что gnu ассемблер, kiel, ARMasm и другие будут иметь разные языки ассемблера (в основном в области без инструкций), и они это делают. То же самое для любой другой цели (x86, mips и т. Д.). Это общее правило, что обычно не существует стандартизированных языков ассемблера, и уж тем более не для основных наборов инструкций.
Утверждение, что трюк ldr rx,=label/address с gnu ассемблером привел к оптимальной инструкции, но это псевдокод, а не настоящая инструкция, и поэтому не ожидается, что он вообще будет поддерживаться на некоторых ассемблерах, а некоторые, которые его поддерживают, могут буквально реализовать относительную нагрузку на компьютер, а не оптимизировать (в пределах возможностей, которые могут иметь параметр командной строки для включения / отключения оптимизации).
Вы созданы для большого пальца, а для большого пальца вы ограничены немедленным 8-битным без сдвига. Если ваш процессор также поддерживает thumb2, вы можете указать ассемблеру эту командную строку или в коде, и он сгенерирует оптимизированную инструкцию и / или вы можете указать инструкцию напрямую. Если thumb2 не поддерживается, вы можете либо напрямую создать относительную нагрузку на компьютер.
mov r5,hello
...
hello: .word 1001
или используйте ldr equals, или используйте несколько инструкций 3 со сдвигом влево 8 или с 0xE9, и тому подобное.
РЕДАКТИРОВАТЬ
Только для Джейка...
.thumb
.cpu cortex-m0
ldr r5,=1001
.cpu cortex-m3
ldr r5,=1001
.align
arm-none-eabi-as --version
GNU assembler (GNU Binutils) 2.34
Copyright (C) 2020 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `arm-none-eabi'.
00000000 <.text>:
0: 4d01 ldr r5, [pc, #4] ; (8 <.text+0x8>)
2: f240 35e9 movw r5, #1001 ; 0x3e9
6: bf00 nop
8: 000003e9 andeq r0, r0, r9, ror #7
для armv6m (и armv4t, armv5t, armv6, current armv8ms) вы не можете использовать movw, что и подразумевалось в сообщении об ошибке OP.
Для armv7, armv7m вы можете, и инструкция ldr генерирует это, вместо того, чтобы постоянно изменять ваш код в зависимости от того, что вы сразу же выберете, если вы используете ассемблер gnu, тогда ldr equals - лучший способ.
arm-none-eabi-gcc --version
arm-none-eabi-gcc (GCC) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00000000 <.text>:
0: 4d01 ldr r5, [pc, #4] ; (8 <.text+0x8>)
2: f240 35e9 movw r5, #1001 ; 0x3e9
6: bf00 nop
8: 000003e9 andeq r0, r0, r9, ror #7
Теперь, хотя загрузка ассемблера через gcc является еще одним языком ассемблера, он, как и ожидалось, генерирует идеальную инструкцию при использовании ldr equals. Где вы можете использовать movw, он работает, где вы не можете - нет, но давайте попробуем это.
.thumb
.cpu cortex-m0
ldr r5,=1001
.cpu cortex-m3
movw r5,#1001
.align
Претензий нет. Те же результаты.
Пробуем ваше предложение:
.thumb
.cpu cortex-m0
movw r5,#1001
.cpu cortex-m3
movw r5,#1001
.align
arm-none-eabi-gcc so.s -c -o so.o
so.s: Assembler messages:
so.s:6: Error: selected processor does not support `movw r5,#1001' in Thumb mode
и теперь вам нужно переписать свой код. movw - не лучшее решение.
EDIT2 для OP.
нижняя строка, краткий ответ... Причина, по которой вы получили это сообщение, заключается в том, что вы не можете сгенерировать немедленную инструкцию mov для большого пальца с этим непосредственным значением, потому что вы увидите в документации по руке у вас не так много бит. Если, когда вы сказали rapi 4, вы имели в виду raspberry pi 4, который является armv8, который поддерживает aarch32 (armv7-a), который поддерживает расширения thumb2 (который post armv6-m включает movw)
.thumb
ldr r5,=1001
.align
Используйте ldr equals, чтобы найти оптимальную инструкцию
arm-none-eabi-as -march=armv7a so.s -o so.o
arm-none-eabi-objdump -D so.o
so.o: file format elf32-littlearm
Disassembly of section .text:
00000000 <.text>:
0: f240 35e9 movw r5, #1001 ; 0x3e9
а затем используйте это напрямую, если хотите
.thumb
ldr r5,=1001
movw r5,#1001
.align
Disassembly of section .text:
00000000 <.text>:
0: f240 35e9 movw r5, #1001 ; 0x3e9
4: f240 35e9 movw r5, #1001 ; 0x3e9
Если это действительно Raspberry Pi 4, вам понадобится справочное руководство по архитектуре armv7-ar, чтобы охватить материал aarch32, и справочное руководство по архитектуре armv8 (не 8m), чтобы охватить материал aarch64. И другой набор инструментов gnu, так как это совершенно другой набор инструкций (aarch64-независимо-что угодно против руки-что-нибудь-что угодно). И в aarch64 нет инструкций для большого пальца (пока).