"branch" instruction encoding

Asked by jdobry

I compare code generated by 4.6 2012q4 and 4.7 2013q2 and I found significant difference on assembler branch instruction encoding.

Code from 2012q4 looks like:
D100 bne test
                         nop
                  test:

But code from 2013q2 like
F0408001 bne test
                         nop
                  test:

Differnece is clear: old version use encoding T1 and new version encoding T3 (instruction "BNE.W" in "BNE" place)
Why new version create bigger code than previous? It make problems with compare and branch instruction CBZ/CBNZ because it have max +128 range (64 or less instructions). Code can be compiled on old version, on new compilation fail "Error: branch out of range" because many instructions inside CBZ skip area are significantly bigger.

Is it problem on this GCC port or in GCC generally?

Question information

Language:
English Edit question
Status:
Answered
For:
GNU Arm Embedded Toolchain Edit question
Assignee:
No assignee Edit question
Last query:
Last reply:

This question was reopened

Revision history for this message
Joey Ye (jinyun-ye) said :
#1

I just tried a small C case and it does use short encoding for beq. If will be very helpful if you can share:
- Small pieces of source code. (.c or .s)
- Options to invoke compiler
- Compiler versions (4.7 2013q2 hasn't been released yet. Did you mean 2013q1?)

Thanks - Joey

Revision history for this message
jdobry (jdobry) said :
#2

File test.S:
  .syntax unified
  .text
  .thumb
  b test
  nop
test:

Compilation:
arm-none-eabi-gcc -c test.S -o test.o -Wa,-alh

Result with 4.6 2012q4:
   1 # 1 "test.S"
   1 .syntax unified
   0
   0
   2 .text
   3 .thumb
   4 0000 00E0 b test
   5 0002 C046 nop
   6 test:

Result with 4.7 2013q1
   1 # 1 "test.S"
   1 .syntax unified
   0
   2 .text
   3 .thumb
   4 0000 00F001B8 b test
   5 0004 C046 nop
   6 test:

Without directive ".syntax unified" it works fine, but I need it.

PS: version is 4.7 2013q1 own compilation. I don't know why but compilation result of gcc-arm-none-eabi-4_7-2013q1-20130313-src.tar.bz2 is package gcc-arm-none-eabi-4_7-2013q2-20130514-win32.exe

Revision history for this message
Joey Ye (jinyun-ye) said :
#3

Thanks for reporting this.

Reproduced and it is binutils version update that brings this change. Need more time to figure out what happened and decide if it is expected.

Before final conclusion, a easy workaround is using explicitly b.n in your case:

      b.n test
      nop
test:

- Joey

Revision history for this message
Joey Ye (jinyun-ye) said :
#4

Now I think it expected behavior. To avoid 4 byte branch all the time, you can name your local labels as ".L", which is how compiler generated code works. See following example:

test.S:
main:
.Lmain:
    b .Lmain
    b main

test.o:
   0: e7fe b.n 0 <main>
   2: f7ff bffe b.w 0 <main>

- Joey

Revision history for this message
jdobry (jdobry) said :
#5

Many thanks for answer. Both solutions works.

It made another question: is it expected behavior for next versions/generations of GCC compiler?

Revision history for this message
Joey Ye (jinyun-ye) said :
#6

I think it expected behavior for future version too.

On Tue, May 21, 2013 at 3:41 PM, jdobry <
<email address hidden>> wrote:

> Question #228850 on GCC ARM Embedded changed:
> https://answers.launchpad.net/gcc-arm-embedded/+question/228850
>
> Status: Answered => Open
>
> jdobry is still having a problem:
> Many thanks for answer. Both solutions works.
>
> It made another question: is it expected behavior for next
> versions/generations of GCC compiler?
>
> --
> You received this question notification because you are an answer
> contact for GCC ARM Embedded.
>

Revision history for this message
jdobry (jdobry) said :
#7

Thanks for informations.

Revision history for this message
jdobry (jdobry) said :
#8

Sorry for re-open. But this behavior is in conflict to ARM architecture reference manual. If both encoding are available, compiler must select a 16-bit encoding.
I personally don't have problem with this behavior, but it need clarification.

Quotation from ARM architecture reference manual (ARM DDI 0406C.b ID072512 chapter A8.2):

Specifies optional assembler qualifiers on the instruction. The following qualifiers are defined:
.N Meaning narrow, specifies that the assembler must select a 16-bit encoding for the
instruction. If this is not possible, an assembler error is produced.
.W Meaning wide, specifies that the assembler must select a 32-bit encoding for the
instruction. If this is not possible, an assembler error is produced.
If neither .W nor .N is specified, the assembler can select either 16-bit or 32-bit encodings. If both
are available, it must select a 16-bit encoding.

Revision history for this message
Joey Ye (jinyun-ye) said :
#9

Please refer to http://sourceware.org/bugzilla/show_bug.cgi?id=12532 for reason why this change was made.

I don't think current assembler breaks "If both are available, it must select a 16-bit encoding.". In case of global symbol, 16-bit encoding isn't available due to possible symbol preemption.

Thanks - Joey

Revision history for this message
jdobry (jdobry) said :
#10

OK. But why it works differently without ".syntax unified" ?

I don't thing that it is global label without ".globl" export. This mean, that compiler do not pass this jump distance to linker and calculate it itself. Problem with R_ARM_THM_JUMP11 relocation can't happen.

For global symbols in different ".section" on same ASM file it's clear why it isn't possible use short version of branch.

Can you help with this problem?

Provide an answer of your own, or ask jdobry for more information if necessary.

To post a message you must log in.