3
\$\begingroup\$

I have done an instruction trace while trying to find a bug on a Cortex M3. There is one part of the command I cannot understand.

STRB R1, [R3], #+0x01

According to ARM documentation, this stores a byte in R1.

I would think that R3 gets stored into R1, but I cannot figure out what the #+0x01 does.

I have seem this notation elsewhere in my trace, and while I understand #0x01, I cannot figure out what the "+" does to a literal. What does "#+0x01" mean ?

Below is a screenshot of my instruction trace taken from Seggar's Ozone. enter image description here

\$\endgroup\$
  • \$\begingroup\$ As @ChrisStratton said, the link you provide is not to the STRB instruction. The instruction syntax you provide does not appear to be a valid syntax (the offset should be inside the square brackets). Do you know what the plus sign usually means if it is the first character in a literal value? \$\endgroup\$ – Elliot Alderson Jul 26 '18 at 16:29
  • \$\begingroup\$ @ElliotAlderson I do not. \$\endgroup\$ – Frankie Jul 26 '18 at 16:45
  • \$\begingroup\$ @ElliotAlderson I am assuming that Seggar is displaying the trace data correctly and that the syntax is correct. \$\endgroup\$ – Frankie Jul 26 '18 at 16:49
  • \$\begingroup\$ This is not the syntax of the ARMASM, but I assume that different assemblers can have a slightly different syntax. \$\endgroup\$ – Eugene Sh. Jul 26 '18 at 16:56
  • 1
    \$\begingroup\$ Here you go: segger.com/support/instruction-sets/arm/strb Third line under "Arm syntax (wide, v4T)" \$\endgroup\$ – Eugene Sh. Jul 26 '18 at 16:58
3
\$\begingroup\$

Updated

As pointed out by @ChrisStratton in comments, the answer below ignored the fact that the processor in use does not support the 4-byte ARM instruction set, and only runs "Thumb" code. Based on this information, and the fact that the debugger shown in the question is apparently decoding 4-byte instructions (based on how the addresses increment for each instruction), it would appear that the debugger is misconfigured. There should be a setting to force it to disassemble code as thumb instructions; this needs to be enabled when working with Cortex M3 processors.

I've left the original answer below as it answers the question as asked (how to interpret the particular instruction being reported by the debugger), but it should be noted that this instruction does not occur in your code, and is only being displayed because of the incorrect configuration of the debugger.

Original answer

You're misreading the ARM documentation. The instruction is:

STRB reg1, [reg2], #offset

where the offset is a flexible offset.

The meaning of this instruction is that the contents of reg1 are stored in memory at the address reg2 + offset. In this case, R1 is stored at the byte at the address 1 higher than the address pointed to by R3.

To help understand this, note that ARM is (predominantly) a load/store processor architecture, which is to say that it distinguishes between operations that move data to memory ("store register", abbreviated in the mnemonic as STR), from memory ("load register", abbreviated as LDR) and other operations which (generally) use registers only and not memory (albeit with exceptions because ARM isn't a pure load/store architecture). References to either "load" or "store" are always dealing with memory, and are always dealing with it in those directions. An instruction that copies data from one register to another wouldn't be given such a name (in fact in ARM that would be MOV for move).

As an aside, the link you provided is to the wrong section of the ARM documentation. That describes the instructions available in the "ARM Thumb" instruction set, but your program appears to be using the traditional full ARM instruction set ("Thumb" programs have 2 bytes per instruction, whereas your program has 4 bytes per instruction, judging by the addresses displayed in the debugger output). The correct section is the one that starts here. (striking this section out as it is completely incorrect)

\$\endgroup\$
  • \$\begingroup\$ Apparently there are some 32-bit thumb2 instructions but they don't show up in the Cortex M3 reference manual. We really need to see the opcodes. @old_timer likely has a point about the post-increment - it would make sense for memset() to be writing to an incrementing location and checking for the end. However this is not how gcc's thumb memset works... could be Keil's or IARs or something special. \$\endgroup\$ – Chris Stratton Jul 26 '18 at 21:31
  • \$\begingroup\$ Thumb 2 has a mix of 16-bit and 32-bit instructions. \$\endgroup\$ – immibis Jul 26 '18 at 23:35
3
\$\begingroup\$

Without the original opcodes, it's not possible to say with full confidence if this sequence is being accurately decoded.

However, one possibility which would be legitimate on a Cortex M3 would be this 32-bit Thumb-2 instruction as decoded by arm-none-eabi-objdump:

f803 1b01   strb.w  r1, [r3], #1

This is of the type which ARM Holdings calls "Thumb syntax (wide, v6T2)" and an alternate formatting more closely matching your debugger's view would be:

STRB    Rt, [Rn], #-255…255

In this case, the low byte of the value in r1 would be stored to the address in r3, and then r3 would be (as first pointed out by @old_timer) incremented by 1.

This is a rather plausible meaning, as the debug trace makes it appear that this is part of the implementation of the memset() function, which fills memory with a byte value.

If this were the case, then the actual pseudo-code would be something like:

//r0=memset(r0, r1, r2)
  Copy target address from r0 to working register r3
  Add length in r2 to target address in r0 or r3 and save in r2
another:
  if r3 equals r2 goto end
  store byte from r1 to address in r3, then increment r3 by one byte
  goto another
end:
  return instruction, with the un-incremented target address in r0

As a further note, the range of increment for this instruction is +/- 255 units, where the unit in this case is a byte. A whole byte of the 32-bit instruction is available for storing the magnitude of the offset, while the sign is stored separately.

The copy of the base address from r0 to r3 is necessary because memset() must return the unmodified base address - and conveniently, in the same r0 in which it was passed.

\$\endgroup\$
  • \$\begingroup\$ It not only increments the register after each store but also adds the value as an offset. So r1 is stored at r3+1 and the resulting address is written back to r3. \$\endgroup\$ – Goswin von Brederlow Nov 19 '18 at 15:53
  • \$\begingroup\$ A register "increment" is an operation which by definition alters the stored value. However your interpretation of the overall instruction is incorrect. In this case the offset is outside of the brackets, so it is "post indexed" which is to say that the store is to the address referenced by the old value of the index register. You are thinking instead of the case of a pre-indexed store, which in this instruction set is indicated by an offset inside the brackets. In C terms this is [i++] while you are thinking of [++i]. \$\endgroup\$ – Chris Stratton Nov 19 '18 at 16:25
  • \$\begingroup\$ Ups, you are right. I was thinking of strltb r0, [r3, #1]! \$\endgroup\$ – Goswin von Brederlow Nov 22 '18 at 21:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.