When I look at the official Arm specifications,
!
Causes the instruction to write a modified value back to <Rn> . If ! is omitted, the instruction does not change <Rn> in this way.
This is how the function is explained, yet the ASL Code is as follows,
if ConditionPassed() then
n = UInt(Rn); registers = '00000000':register_list;
if BitCount(registers) < 1 then UNPREDICTABLE;
wback = (registers<n> == '0');
address = R[n];
for i = 0 to 7
if registers<i> == '1' then
R[i] = MemA[address,4];
address = address + 4;
if wback && registers<n> == '0' then R[n] = R[n] + 4*BitCount(registers);
So the only logical thing would be to use wback for the purpose, yet it doesn't seem to add up when I examine the general structure.
It is documented in the arm documentation.
Initially it looks strange if you are used to the w bit and so that might lead you to check the armv7-m, armv7-ar, so of course go back to the original arm arm
! Causes base register writeback, and is not optional.
You can also try it and see what an assembler thinks of it
.cpu cortex-m0
.thumb
ldm r1,{r2}
ldm r1!,{r2}
arm-none-eabi-as so.s -o so.o
so.s: Assembler messages:
so.s:4: Warning: this instruction will write back the base register
line 4 being the one without the !
Disassembly of section .text:
00000000 <.text>:
0: c904 ldmia r1!, {r2}
2: c904 ldmia r1!, {r2}
Upon further inspection it is not a bug in the documentation though
LDM <Rn>,<registers> <Rn> included in <registers>
so test that
.cpu cortex-m0
.thumb
ldm r1,{r1}
ldm r1!,{r1}
so.s: Assembler messages:
so.s:5: Warning: this instruction will not write back the base register
line 5 being the one with the !
Disassembly of section .text:
00000000 <.text>:
0: c902 ldmia r1, {r1}
2: c902 ldmia r1, {r1}
Which is also stated in the psuedocode from the arm documentation:
if wback && registers<n> == ‘0’ then R[n] = R[n] + 4*BitCount(registers);
so this is not encoded as a bit as in the larger instructions, this is implied based on the presence of rn in the register list.
Now go back to the original arm arm
Operand restrictions
If the base register <Rn> is specified in <registers>, the final value of <Rn> is the loaded value (not the written-back value).
so even in the original it is not written back. and if you test it gnu assembler knows this as well with similar messages
.cpu arm7tdmi
.thumb
ldm r1,{r1}
ldm r1!,{r1}
arm-none-eabi-as so.s -o so.o
so.s: Assembler messages:
so.s:5: Warning: this instruction will not write back the base register
Disassembly of section .text:
00000000 <.text>:
0: c902 ldmia r1, {r1}
2: c902 ldmia r1, {r1}
This is perhaps an intentional thing in the armv4 days as they were trying to operate as an IP company and a number of the UNPREDICTABLE RESULTS, and other such things were actually predictable and were how they tested to see if you had stolen a core. It would not surprise me if the way this was written in the original arm arm docs was also something to catch folks making clones.