The GNU assembler does not require an octothorpe before an immediate operand for ARM assembly code. Your impression is incorrect.
Is the hash required for immediate values in ARM assembly?
-
08-10-2022 - |
Frage
I've been working on reading through some different arm assembly code generated by gcc, and I came across something that I haven't been able to find in the spec.
movw r0, #39784
movt r0, 1
Obviously the first one is moving the value 39784 into the bottom 16bits or r0, but the movt's operand of '1' is odd because it doesnt have the hash before it, and I was under the impression that immediate values required the hash. Is it somehow optional in certain situations? or am I missing something magical?
Lösung
Andere Tipps
GNU gas
behavior for ARMv7 depends on .syntax
The docs say https://sourceware.org/binutils/docs-2.26/as/ARM_002dInstruction_002dSet.html#ARM_002dInstruction_002dSet :
Two slightly different syntaxes are support for ARM and THUMB instructions. The default, divided, uses the old style where ARM and THUMB instructions had their own, separate syntaxes. The new, unified syntax, which can be selected via the .syntax directive, and has the following main features:
- Immediate operands do not require a # prefix.
and https://sourceware.org/binutils/docs-2.26/as/ARM_002dChars.html#ARM_002dChars says:
Either '#' or '$' can be used to indicate immediate operands.
For ARMv8 #
is always optional
https://sourceware.org/binutils/docs-2.26/as/AArch64_002dChars.html#AArch64_002dChars documents:
The '#' can be optionally used to indicate immediate operands.
Test
Ubuntu 16.04, Binutils 2.26.1.
v7.S:
/* These fail */
mov r0, 1
mov r0, 0x1
/* These work */
mov r0, #1
mov r0, #0x1
mov r0, $1
mov r0, $0x1
.syntax unified
mov r0, 1
mov r0, #1
mov r0, 0x1
mov r0, #0x1
mov r0, $1
mov r0, $0x1
v8.S:
mov x0, 1
mov x0, #1
mov x0, 0x1
mov x0, #0x1
Assemble:
arm-linux-gnueabi-as v7.S
aarch64-linux-gnu-as v8.S
Outcome: v8 suceeds, v7 fails on the divided
lines without #
:
v7.S:1: Error: immediate expression requires a # prefix -- `mov r0,1'
v7.S:2: Error: immediate expression requires a # prefix -- `mov r0,0x1'
TODO
Hmmm, but there are some v7 instructions for which #
is actually optional, e.g. there are no errors for movw
and movt
:
movw r0, 1
movt r0, 0x1
but there are errors for:
movw r0, $1
movt r0, $0x1
ARM reference manual
The ARMv8-fb manual has assembly/disassembly recommentations/requirements in itself, at C1.2 "Structure of the A64 assembler language":
The A64 assembly language does not require the # character to introduce constant immediate operands, but an assembler must allow immediate values introduced with or without the # character. Arm recommends that an A64 disassembler outputs a # before an immediate operand.
Personal recommendation
Use .syntax unified
in your v7 code, and never use #
on any literal on either v7 or v8.
Unified syntax is newer and better, and those #
and $
signs are just more code noise.
The Linux kernel agrees with me: https://github.com/torvalds/linux/blob/v4.19/arch/arm/include/asm/unified.h#L23