如何计算指令之间的字节数

How to count number of bytes between instructions

Valvano的书(3.3.3 Memory Access Instruction)中有这段Keil汇编代码:

; Keil Syntax
LDR R5, PAaddr
MOV R6, #0x55
STR R6, [R5]
;outside of execution
PAaddr DCD 0x400043FC

第一行 LDR R5, PAaddr 被汇编器翻译成

LDR R5, [PC, #16]

其中 #16 表示 MOV R6, #0x55DCD 定义之间的字节数。

我不明白 #16 是怎么来的。根据 Keil's ARM and Thumb Instructions, MOV is a 16-bit instruction (hence 2-bytes). I can't find the instruction size for STR or DCD, but from reading ARM's instruction set summarySTR 的周期是 MOV 的两倍,所以我直觉地猜测 STR 的指令大小是 MOV 的两倍(或 4 个字节)。 DCD只是把值存入ROM,所以不能比MOV大。如果我以字节为单位总结指令大小(MOV 为 2,STR 为 4,DCD 可能为 1 或 2),我应该在第二条指令到最后一条指令之间得到 7 或 8 个字节,或者 #7 或 #8改为从 PC 跳转。

我手边没有 Kiel,但这并不重要,您没有提供足够的信息(您的目标是什么 architecture/core),而且 arm 并未详细记录所有这些信息。

拇指太一般了

.thumb
LDR R5, PAaddr
MOV R6, #0x55
STR R6, [R5]
.align
PAaddr: .word 0x400043FC
Disassembly of section .text:

00000000 <PAaddr-0x8>:
   0:   4d01        ldr r5, [pc, #4]    ; (8 <PAaddr>)
   2:   2655        movs    r6, #85 ; 0x55
   4:   602e        str r6, [r5, #0]
   6:   46c0        nop         ; (mov r8, r8)

00000008 <PAaddr>:
   8:   400043fc    .word   0x400043fc

The immediate offset added to the Align(PC, 4) value of the instruction to form the address. Permitted values are multiples of four in the range 0-1020 for encoding T1.

所以对齐(0x00+2,4) = 0x04。 0x08 - 4 = 4 = 一个字。所以 1 字 0x4D01 01 是立即数。

.thumb
nop
LDR R5, PAaddr
MOV R6, #0x55
STR R6, [R5]
.align
PAaddr: .word 0x400043FC


00000000 <PAaddr-0x8>:
   0:   46c0        nop         ; (mov r8, r8)
   2:   4d01        ldr r5, [pc, #4]    ; (8 <PAaddr>)
   4:   2655        movs    r6, #85 ; 0x55
   6:   602e        str r6, [r5, #0]

00000008 <PAaddr>:
   8:   400043fc    .word   0x400043fc

对齐(0x02+2,4) = 0x4。 0x08 - 0x04 = 0x04,一个字0x4D01编码。

.cpu cortex-m3
.thumb
LDR R5, PAaddr
MOV R6, #0x55
STR R6, [R5]
.align
PAaddr: .word 0x400043FC

Disassembly of section .text:

00000000 <PAaddr-0x8>:
   0:   4d01        ldr r5, [pc, #4]    ; (8 <PAaddr>)
   2:   2655        movs    r6, #85 ; 0x55
   4:   602e        str r6, [r5, #0]
   6:   bf00        nop

00000008 <PAaddr>:
   8:   400043fc    .word   0x400043fc

没有变化,但是

.cpu cortex-m3
.syntax unified
.thumb
LDR R5, PAaddr
MOV R6, #0x55
STR R6, [R5]
.align
PAaddr: .word 0x400043FC

Disassembly of section .text:

00000000 <PAaddr-0x8>:
   0:   4d01        ldr r5, [pc, #4]    ; (8 <PAaddr>)
   2:   f04f 0655   mov.w   r6, #85 ; 0x55
   6:   602e        str r6, [r5, #0]

00000008 <PAaddr>:
   8:   400043fc    .word   0x400043fc

.cpu cortex-m3
.syntax unified
.thumb
nop
LDR R5, PAaddr
MOV R6, #0x55
STR R6, [R5]
.align
PAaddr: .word 0x400043FC

Disassembly of section .text:

00000000 <PAaddr-0xc>:
   0:   bf00        nop
   2:   4d02        ldr r5, [pc, #8]    ; (c <PAaddr>)
   4:   f04f 0655   mov.w   r6, #85 ; 0x55
   8:   602e        str r6, [r5, #0]
   a:   bf00        nop

0000000c <PAaddr>:
   c:   400043fc    .word   0x400043fc

对齐(0x02+2,4) = 0x04。 0x0C-0x04 = 0x08,2个字,0x4D02编码。

你可以用 Kiel 的汇编语言和上面显示的 gnu 做同样的事情。

除非您正在编写自己的汇编程序(或出于其他原因尝试创建自己的机器代码),否则计算不是您的工作。

无论如何,只需阅读相关体系结构的 ARM 体系结构文档即可。将其与调试汇编程序的输出进行比较,以便根据需要进一步说明。

编辑

来自early/originalARM ARM

address = (PC[31:2] << 2) + (immed_8 * 4)
Rd = Memory[address, 4]

这个在我看来更有意义。

如有疑问,请返回 old/original-ish ARM ARM。

最近的 ARM ARM

if ConditionPassed() then
  EncodingSpecificOperations(); NullCheckIfThumbEE(15);
  base = Align(PC,4);
  address = if add then (base + imm32) else (base - imm32);
  data = MemU[address,4];
  if t == 15 then
    if address<1:0> == ‘00’ then LoadWritePC(data); else UNPREDICTABLE;
  elsif UnalignedSupport() || address<1:0> == ‘00’ then
    R[t] = data;
else // Can only apply before ARMv7
  if CurrentInstrSet() == InstrSet_ARM then
    R[t] = ROR(data, 8*UInt(address<1:0>));
  else
    R[t] = bits(32) UNKNOWN;

但这一次涵盖了 T1、T2 和 A1 编码,因此最令人困惑。

在任何情况下,它们都描述了编码的情况以及每条指令的总体大小。