CBZ CBNZ instruction usage in inline assembly

Asked by Danielius


I am trying to compile the following inline assembly.
I am compiling for cortex-m4 (stm32f407 device).
I tried different toolchain version, all give the same result.

__ASM volatile
  "ldr r2, =0x42418234\n\t"
  "ldr.w r3, [r2, #0]\n\t" //load TXE bit value using bit band register
  "cbnz r3, label1\n\t"

     : // no output
     : [ptr] "r" (buf_ptr),
       [ptr_end] "r" (buf_end)
     : "cc", "r2","r3"

and I am getting an error:
/tmp/ccOYDN40.s: Assembler messages:
/tmp/ccOYDN40.s:397: Error: branch out of range
make: *** [src/com_proc.o] Error 1
src/subdir.mk:81: recipe for target 'src/com_proc.o' failed

I am aware that CBNZ can only branch within 4_130 bytes, which I think is the case in my code.
replacing "cbnz r3, label1\n\t" with
"cmp r3, #0\n\t"
"bne label1\n\t"

works fine.

I am not sure what I am doing wrong with cbnz instruction?

Question information

English Edit question
GNU Arm Embedded Toolchain Edit question
No assignee Edit question
Solved by:
Last query:
Last reply:
Revision history for this message
Tejas Belagod (belagod-tejas) said :

CB{N}Z can only branch forward in the range of 0 to 126. See ARMv7-M ARM ARM section A7.7.21.

Revision history for this message
Danielius (danielius-bil) said :


Thats right. CBNZ has a limited branche range.
Wcich in my case it should be fine, as I am only branching 4 bytes back.

But it does not compile no matther what, even If I insert additional 'nop' instructions between the label1 and cbnz.

Could this be a bug in arm gcc toolchain?..


Revision history for this message
Thomas Preud'homme (thomas-preudhomme) said :

Hi Danielus,

In case it wasn't clear, cb(n)z is only capable of branching *forward* by up to 126 bytes. It *cannot* branch backward which is what you are trying to do.

Best regards.

Revision history for this message
Danielius (danielius-bil) said :

Hi Thomas,

Oh I see,
Sorry, my bad.
Thanks for the explanation.