Question

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?

Was it helpful?

Solution

The GNU assembler does not require an octothorpe before an immediate operand for ARM assembly code. Your impression is incorrect.

OTHER TIPS

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top