Почему я не могу переместить #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 нет инструкций для большого пальца (пока).

Другие вопросы по тегам