0

There's this piece of Keil assembly code in Valvano's book (3.3.3 Memory Access Instruction):

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

The first line LDR R5, PAaddr gets translated by the assembler to

LDR R5, [PC, #16]

where the #16 represents the number of bytes between the MOV R6, #0x55 and the DCD definition.

I can't understand how the #16 came about. According to 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 summary, STR takes twice as many cycles as MOV's so I would intuitively guess STR's instruction size is double of what MOV is (or 4-bytes). DCD just stores the value to the ROM, so it can't be any bigger than MOV. If I sum up the instruction size in bytes (2 for MOV, 4 for STR, and perhaps a 1 or 2 for DCD), I should get 7 or 8 bytes between the second to the last instruction, or a #7 or #8 jump from PC instead.

KMC
  • 19,548
  • 58
  • 164
  • 253
  • you need to provide the disassembly for a question like this. – old_timer Jul 25 '20 at 12:58
  • this is all well documented by arm (instruction set documentation by arm not assembly language documentation). – old_timer Jul 25 '20 at 12:59
  • @old_timer I looked into it but it wasn't there either. In the [Arm Instruction Set Reference](https://static.docs.arm.com/100076/0100/arm_instruction_set_reference_guide_100076_0100_00_en.pdf) it says MOV instruction takes 16-bits on page C2-61, but STR (page C2-142) provides no information on its instruction size. – KMC Jul 25 '20 at 13:16
  • That is still not the correct document you need the arm architectural reference manual for the architecture in question which you find from the technical reference manual for the core (which you get from the chip vendor doc for the chip), pretty much the only arm docs you need, have not found much use for any other arm docs, and there are some arm docs you should avoid as they cause more problems than they solve. – old_timer Jul 25 '20 at 13:19
  • assembly language docs are not going to tell you about the instruction set encoding, or at least not in this case. – old_timer Jul 25 '20 at 13:20
  • which encoding is used IS driven by the assembler in questions assembly language and as a result the size and alignments from there which govern the distance between items for pc relative addressing, docs are not often going to cover this you have to sometimes just try it and see what the assembler encodes. – old_timer Jul 25 '20 at 13:30
  • I just started reading my first book on ARM (Valvano Vol.1) so I haven't dug that deep into the tool chain to figure things out. But regardless, most (if not all?) Thumb2 should have instruction each no bigger than 32bits/4bytes [what do we mean by instruction size?](https://stackoverflow.com/questions/19656586/what-do-we-mean-by-instruction-size). The last three instructions should take no more than 4 x 3 = 12 bytes. That #16 make no sense. But it's a fairly established textbook on its fifth edition so I assume that's not an error but more so my (mis)understanding somewhere – KMC Jul 25 '20 at 13:49
  • TM4C123 launchpad – KMC Jul 25 '20 at 13:50
  • From ti "ARM® Cortex™-M4F-based" and that document will tell you ARMv7-m architecture, which describes the instruction set used by the cortex-m4 core in the ti chip – old_timer Jul 25 '20 at 13:52
  • I don't get it... shouldn't I be reading ARM documentation on Thumb instruction, which is what I'm doing now? TI chip is just an implementation of the core – KMC Jul 25 '20 at 14:06
  • to get to the documentation for an arm core, you first have to discover what core is in your chip so you start with the chip, it says cortex-m4 that takes you to the TRM for the cortex-m4 which says it is armv7-m based and that document you see the architecture including the instruction set. – old_timer Jul 25 '20 at 14:43
  • in this case you start with the board documentat, which sends you to a chip, that doc sends yot to core then that to architecture. – old_timer Jul 25 '20 at 14:44

1 Answers1

1

I don't have Kiel handy but doesn't really matter, you didn't provide enough information (what is your target architecture/core) and not all of this is well documented by arm.

So generic thumb

.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.

So ALIGN(0x00+2,4) = 0x04. 0x08 - 4 = 4 = one word. So 1 word 0x4D01 the 01 is the immediate.

.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

ALIGN(0x02+2,4) = 0x4. 0x08 - 0x04 = 0x04, one word 0x4D01 encoding.

.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

No change, but

.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

and

.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

ALIGN(0x02+2,4) = 0x04. 0x0C-0x04 = 0x08, 2 words, 0x4D02 encoding.

You can do the same things with Kiel's assembly language vs gnu shown above.

It's not your job to count unless you are writing your own assembler (or trying to create your own machine code for some other reason).

In any case simply read the ARM architecture documentation for the architecture in question. Compare that to the output of a debugged assembler for further clarification as needed.

Edit

From the early/original ARM ARM

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

this one makes more sense IMO.

When in doubt go back to the old/original-ish ARM ARM.

Most(ish) recent 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;

But that covers T1, T2 and A1 encodings in one shot, making it the most confusing.

In any case, they describe what is going on with the encoding as well as overall size of each of the instructions.

halfer
  • 19,824
  • 17
  • 99
  • 186
old_timer
  • 69,149
  • 8
  • 89
  • 168