1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

32ビットARMアセンブリのMOV命令で使える即値の仕組みを理解する

Last updated at Posted at 2025-10-14

初めに

ARMのMOV命令で使用できる即値には制限があります。
8ビット値0x000xFFを偶数ビット分左にずらして表せる数しか即値として使用ができません。
今回は実際にアセンブリでMOVを使用するコードを書き、動作を検証します。

※即値制限を説明しているサイトは沢山あるのですが、例が無く理解が難しかったので実際に自分で見てみることにしました。

コンパイル及び逆アセンブルのコマンド

### ARM上のLinuxで実行する場合

as -o test.o test.s
ld -o test test.o
objdump -d test > test.asm

### X86上のLinuxで実行する場合

arm-none-eabi-as -mcpu=arm7tdmi -o test.o test.s
arm-none-eabi-ld -Ttext=0x00000000 -o test.elf test.o
arm-none-eabi-objdump -d test.elf > test.asm

コード

0x000xFF0回ずらすとして考えるので自ずと全て使用が出来ます。

test.s
.global _start
_start:
    MOV r0, #0xFF
    MOV r2, #0x7F
    MOV r3, #0
    MOV r0, #0xFF000000
    MOV r1, #0xA5000000
    B .
test.asm
test.elf:     file format elf32-littlearm


Disassembly of section .text:

00000000 <_start>:
   0:	e3a000ff 	mov	r0, #255	; 0xff
   4:	e3a0207f 	mov	r2, #127	; 0x7f
   8:	e3a03000 	mov	r3, #0
   c:	e3a004ff 	mov	r0, #-16777216	; 0xff000000
  10:	e3a014a5 	mov	r1, #-1526726656	; 0xa5000000
  14:	eafffffe 	b	14 <_start+0x14>

考察

MOV r0, #0xFF000000

この命令の機械語はe3a004ffとなります。
これを2進数にすると11100011101000000000010011111111
e3a004ffを表す部分は下位12ビット010011111111です。
このうち下位8ビット11111111が8ビット値0xFFを表しており、上位4ビット0100はずらす回数を表しています。
0100は3なので3×2=6、つまり0xFFを6ビット分左にずらすと0xFF000000が表現できます。

MOV r1, #0xA5000000

同じく機械語はe3a014a5
これを2進数にすると11100011101000000001010010100101
下位12ビット=010010100101
12ビットのうち、
上位4ビット=0100=6回ずらす
下位8ビット=10100101=0xA5
0xA5を左に6ビットずらすと0xA5000000となります。

MOVが使用できない例

8ビット値をずらすことで表現できない値は、コンパイルするとエラーが出ます。

test.s
.global _start
_start:
    MOV r1, #0x12345678
    B .
test@test-ThinkPad-X280:~/kaihatsu/armtest$ arm-none-eabi-as -mcpu=arm7tdmi -o test.o test.s
test.s: Assembler messages:
test.s:3: Error: invalid constant (12345678) after fixup

この場合はLDR命令を使うことで解決ができます

LDR命令

MOV命令で指定できない即値

e51f1000内で32ビットの値を持たず、メモリ上に置いた32ビットの値を指定するだけなので、MOVの様に制限されず任意の値を即値として指定することができます。

test.s
    .global _start
_start:
    LDR     r1, =0x12345678
    B       .
test.asm
test.elf:     file format elf32-littlearm


Disassembly of section .text:

00000000 <_start>:
   0:	e51f1000 	ldr	r1, [pc, #-0]	; 8 <_start+0x8>
   4:	eafffffe 	b	4 <_start+0x4>
   8:	12345678 	.word	0x12345678

MOV命令で指定できる即値

LDR命令を使用したとしてもMOVで使用可能な数値の場合はアセンブラが自動的にMOV命令を生成します。

test.s
test@test-ThinkPad-X280:~/kaihatsu/armtest$ cat test.s
    .global _start
_start:
    LDR     r1, =0xFF
    B       .
test.asm
test.elf:     file format elf32-littlearm


Disassembly of section .text:

00000000 <_start>:
   0:	e3a010ff 	mov	r1, #255	; 0xff
   4:	eafffffe 	b	4 <_start+0x4>

[追記]
上位16ビットと下位16ビットに分けて格納する方法もあります。
ARM 32ビットでMOVW/MOVTによる即値代入とLDR命令の挙動を検証

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?