linker switch from thumb to arm mode even cortex m4 doesn't support it

Bug #1697255 reported by necwerk
18
This bug affects 3 people
Affects Status Importance Assigned to Milestone
GNU Arm Embedded Toolchain
New
Undecided
Unassigned

Bug Description

gcc version 5.4.1 20160919 (release) [ARM/embedded-5-branch revision 240496] (GNU Tools for ARM Embedded Processors)

We have problems in veneers for functions that is known from a symbol file. Veneers for other functions that exists in the elf file is ok. Maybe only the pie, position independent codes are affected. Let me show an example

I have an already done elf image let's call it applet.elf and I would like to create an independent binary file let's call it pie.elf that would be a pie, position independent code and it would use some functions from the applet.elf

first, I compiled applet.elf with -mthumb -mcpu=cortex-m4 -mno-thumb-interwork --just-symbols xprintf.txt

applet.elf contains printf function and xprintf.txt contains a symbol for xprintf function

xprintf.txt:
xprintf = 0x0809b575 ;

After this I compile the pie.elf that simple calls the printf and the xprintf functions with the following parameters:

-fpie -nostdlib -mthumb -mcpu=cortex-m4 -mno-thumb-interwork

Now let's see the generated code and the problems we have with radare but before this I show something

arm-none-eabi-objdump -t applet.elf | grep printf

0809b575 g *ABS* 00000000 xprintf
0809b55c g F .text 00000028 printf

I don't know what that zero means at xprintf if I call this function from applet.elf it works well but maybe this info will be useful later

ok let's see the disassembled code

0x00000000 80b5 push {r7, lr}
0x00000002 00af add r7, sp, 0
0x00000004 054b ldr r3, [pc, 20] ; (0x0000001c)
0x00000006 7b44 add r3, pc ; add 0x2e
0x00000008 1846 mov r0, r3
0x0000000a 00f011f8 bl 0x00000030 ; [1] call printf_veneer 0x00000030()
0x0000000e 044b ldr r3, [pc, 16] ; (0x00000020)
0x00000010 7b44 add r3, pc ; add 0x2c
0x00000012 1846 mov r0, r3
0x00000014 00f008e8 blx 0x00000028 ;[2] call xprintf_veneer 0x00000028()
0x00000018 00bf nop
0x0000001a 80bd pop {r7, pc}
0x0000001c 2e00 movs r6, r5
0x0000001e 0000 movs r0, r0
0x00000020 2c00 movs r4, r5
0x00000022 0000 movs r0, r0
0x00000024 0000 movs r0, r0
0x00000026 0000 movs r0, r0
0x00000028 04f01fe5 ; <UNDEFINED> 0xf004e51f ;[3] 0x00004a6a()
0x0000002c 75b5 push {r0, r2, r4, r5, r6, lr}
0x0000002e 0908 lsrs r1, r1, 32
0x00000030 5ff800f0 ldr.w pc, [pc] ; 0x00000034
0x00000034 d117 asrs r1, r2, 31
0x00000036 0a08 lsrs r2, r1, 32

0x00000038 7465 str r4, [r6, 84] ; string: test\n
0x0000003a 7374 strb r3, [r6, 17]
0x0000003c 0a00 movs r2, r1
0x0000003e 0000 movs r0, r0

0x00000040 7465 str r4, [r6, 84] ; string test2\n
0x00000042 7374 strb r3, [r6, 17]
0x00000044 320a lsrs r2, r6, 8
0x00000046 0000 movs r0, r0

As you can see the opcode of xprintf_veneer is wrong. Maybe the linker switch from thumb to arm mode even cortex m4 doesn't support it

Revision history for this message
necwerk (m8r-njfnr31) wrote :
Revision history for this message
necwerk (m8r-njfnr31) wrote :

as you can see test2_veneer compiled/linked as non-thumb code.

00008028 <__test1_veneer>:
    8028: f85f f000 ldr.w pc, [pc] ; 802c <__test1_veneer+0x4>
    802c: 08000015 .word 0x08000015

00008030 <__test2_veneer>:
    8030: f004 e51f ; <UNDEFINED> instruction: 0xf004e51f
    8034: f0000001 .word 0xf0000001

Revision history for this message
necwerk (m8r-njfnr31) wrote :

workaround: remove '*ABS*' section from applet.elf

in details:

arm-none-eabi-gcc -mthumb -mcpu=cortex-m4 -nostdlib -Wl,--just-symbols=symbols.txt -Wl,-Ttext=0x08000000 -o applet.elf main.c test1.c
arm-none-eabi-strip --remove-section='*ABS*' -w -K '*' applet.elf
arm-none-eabi-gcc -fpie -mthumb -mcpu=cortex-m4 -nostdlib -Wl,--just-symbols=applet.elf -Wl,--just-symbols=symbols.txt -o pie.elf pie.c
arm-none-eabi-objdump -M force-thumb -d pie.elf

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

Hi Necwerk,

I'm not sure the symbol being absolute is the problem here. From the dump you provided we can see that the symbol is not considered a function (no F flag) and has a size of 0 bytes (the 0 you mentionned). You need to indicate that this is a function (maybe by declaring the prototype of that function).

Please let me know whether this work.

Revision history for this message
necwerk (m8r-njfnr31) wrote :

How it can work in the second case?

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

What second case do you mean?

Revision history for this message
necwerk (m8r-njfnr31) wrote :

With my workaround

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

I'm not sure. What's the output of arm-none-eabi-objdump -t applet.elf after the strip command?

Revision history for this message
necwerk (m8r-njfnr31) wrote :

before and after the strip command:

+ arm-none-eabi-objdump -t applet.elf

applet.elf: file format elf32-littlearm

SYMBOL TABLE:
08000000 l d .text 00000000 .text
08000040 l d .rodata 00000000 .rodata
00000000 l d .comment 00000000 .comment
00000000 l d .ARM.attributes 00000000 .ARM.attributes
00000000 l df *ABS* 00000000 main.c
00000000 l df *ABS* 00000000 test1.c
08000038 l F .text 00000008 __test2_veneer
0801004e g .rodata 00000000 _bss_end__
0801004e g .rodata 00000000 __bss_start__
0800001c g F .text 00000016 test1
0801004e g .rodata 00000000 __bss_end__
0801004e g .rodata 00000000 __bss_start
08000000 g F .text 0000001c main
08010050 g .rodata 00000000 __end__
f0000000 g *ABS* 00000000 test2
0801004e g .rodata 00000000 _edata
08010050 g .rodata 00000000 _end
00080000 g .ARM.attributes 00000000 _stack
0801004e g .rodata 00000000 __data_start

+ arm-none-eabi-strip '--remove-section=*ABS*' -w -K '*' applet.elf
+ arm-none-eabi-objdump -t applet.elf

applet.elf: file format elf32-littlearm

SYMBOL TABLE:
08000000 l d .text 00000000 .text
08000040 l d .rodata 00000000 .rodata
00000000 l d .comment 00000000 .comment
00000000 l d .ARM.attributes 00000000 .ARM.attributes
08000038 l F .text 00000008 __test2_veneer
0801004e g .rodata 00000000 _bss_end__
0801004e g .rodata 00000000 __bss_start__
0800001c g F .text 00000016 test1
0801004e g .rodata 00000000 __bss_end__
0801004e g .rodata 00000000 __bss_start
08000000 g F .text 0000001c main
08010050 g .rodata 00000000 __end__
0801004e g .rodata 00000000 _edata
08010050 g .rodata 00000000 _end
00080000 g .ARM.attributes 00000000 _stack
0801004e g .rodata 00000000 __data_start

so in short. if the symbols imported from a symbols file specified at --just-symbols argument the linked output is fine. the problem is if the linker use a symbol from other elf file and that symbol is originally imported from an other symbol file.

Anyways I think the most important problem is that the linker want to switch to ARM instruction mode on an cortex m4 which is a totally invalid thing.

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

Hi,

While I agree this is bad design, GNU ld assumes the situation is a valid situation when deciding what veneer to choose. In this case, you are branching to something which is not marked as being a function and GNU ld do something stupid (choose a default veneer that does interworking) instead of giving an error. I suppose when you strip the symbol GNU ld will try to detect the type of the symbol instead of relying on what the symbol table says.

Revision history for this message
necwerk (m8r-njfnr31) wrote :

Can I mark an address as function in symbol file?

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

I don't think there is a syntax for that. Which is why I proposed declaring the prototype in the C file so an UNDEF function symbol will get generated in the hope that --just-symbols will just reuse that symbol and update its value.

Revision history for this message
necwerk (m8r-njfnr31) wrote :

Can I mark an address as function in symbol file? Anyways it works well if I'm importing that symbol from symbol file...

Revision history for this message
necwerk (m8r-njfnr31) wrote :

Where we could change the code to avoid the linker to switch arm mode if the target is cortex m4 that doesn't support the arm instruction set? elf32_arm_stub_a8_veneer_blx?

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

The change would be in arm_type_of_stub to return a different type of stub. However I don't think this should be done, only an error should be reported if the target is ARM and the device is a Cortex-M. Otherwise you could by mistake link in an ARM function and you wouldn't get any error until you run it.

Best regards.

Revision history for this message
necwerk (m8r-njfnr31) wrote :

Cortex-M doesn't support ARM instructions so this is why I don't understand why the linker can switch to ARM mode from THUMB.

And the following compiler flags passed:

CFLAGS += -mthumb
CFLAGS += -mcpu=cortex-m4
CFLAGS += -mtune=cortex-m4
CFLAGS += -mno-thumb-interwork

Revision history for this message
John (jjpenn) wrote :

Bumping this thread. Has any fix/patch been put in place for this issue. I just got hit with the same issue on a Cortex-M4, linking with the latest GCC version (GNU Tools for Arm Embedded Processors 7-2018-q2-update) against an ARM Holdings generated elf file. I am using -fpie which seems to cause this issue. The symbols from the ARM elf file are:
00006d31 0 FUNC GLOBAL DEFAULT ABS memcpy (using readelf)
00006d31 g F *ABS* 00000000 memcpy (using objdump)

and GCC generates the following veneer:
00512ccc <__memcmp_veneer>:
  512ccc: 4778 bx pc <--THIS IS BAD!
  512cce: 46c0 nop ; (mov r8, r8)
  512cd0: e59fc004 ldr ip, [pc, #4] ; 512cdc <__memcmp_veneer+0x10>
  512cd4: e08fc00c add ip, pc, ip
  512cd8: e12fff1c bx ip
  512cdc: ffb6b1ed .word 0xffb6b1ed

The first instruction causes the mode to switch from Thumb to ARM. As it has been stated before this is illegal.
There is nothing I can do except use -mlong-calls which bloats the code by nearly 10%.

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

Hi John,

From what I see this specific veneer should only be generated when branching/calling to Arm code *or* when the target supports Arm mode. Ie it shouldn't happen for a Thumb-only device. I'd need code and command-line option used to reproduce.

Best regards.

Revision history for this message
John (jjpenn) wrote : Re: [Bug 1697255] Re: linker switch from thumb to arm mode even cortex m4 doesn't support it
  • gcc_bug.zip Edit (26.8 KiB, application/x-zip-compressed; name="gcc_bug.zip")
Download full text (4.3 KiB)

Hi, sorry for the delay. I have attached a simple build. I also noticed I
can create the same issue using addresses that are far, without PIE.

Attached is the zip file.

On Thu, Nov 8, 2018 at 7:00 AM Thomas Preud'homme <email address hidden>
wrote:

> Hi John,
>
> >From what I see this specific veneer should only be generated when
> branching/calling to Arm code *or* when the target supports Arm mode. Ie
> it shouldn't happen for a Thumb-only device. I'd need code and command-
> line option used to reproduce.
>
> Best regards.
>
> --
> You received this bug notification because you are subscribed to the bug
> report.
> https://bugs.launchpad.net/bugs/1697255
>
> Title:
> linker switch from thumb to arm mode even cortex m4 doesn't support it
>
> Status in GNU Arm Embedded Toolchain:
> New
>
> Bug description:
> gcc version 5.4.1 20160919 (release) [ARM/embedded-5-branch revision
> 240496] (GNU Tools for ARM Embedded Processors)
>
> We have problems in veneers for functions that is known from a symbol
> file. Veneers for other functions that exists in the elf file is ok.
> Maybe only the pie, position independent codes are affected. Let me
> show an example
>
> I have an already done elf image let's call it applet.elf and I would
> like to create an independent binary file let's call it pie.elf that
> would be a pie, position independent code and it would use some
> functions from the applet.elf
>
> first, I compiled applet.elf with -mthumb -mcpu=cortex-m4 -mno-thumb-
> interwork --just-symbols xprintf.txt
>
> applet.elf contains printf function and xprintf.txt contains a symbol
> for xprintf function
>
> xprintf.txt:
> xprintf = 0x0809b575 ;
>
> After this I compile the pie.elf that simple calls the printf and the
> xprintf functions with the following parameters:
>
> -fpie -nostdlib -mthumb -mcpu=cortex-m4 -mno-thumb-interwork
>
> Now let's see the generated code and the problems we have with radare
> but before this I show something
>
> arm-none-eabi-objdump -t applet.elf | grep printf
>
> 0809b575 g *ABS* 00000000 xprintf
> 0809b55c g F .text 00000028 printf
>
> I don't know what that zero means at xprintf if I call this function
> from applet.elf it works well but maybe this info will be useful later
>
> ok let's see the disassembled code
>
> 0x00000000 80b5 push {r7, lr}
> 0x00000002 00af add r7, sp, 0
> 0x00000004 054b ldr r3, [pc, 20] ; (0x0000001c)
> 0x00000006 7b44 add r3, pc ; add 0x2e
> 0x00000008 1846 mov r0, r3
> 0x0000000a 00f011f8 bl 0x00000030 ; [1] call printf_veneer
> 0x00000030()
> 0x0000000e 044b ldr r3, [pc, 16] ; (0x00000020)
> 0x00000010 7b44 add r3, pc ; add 0x2c
> 0x00000012 1846 mov r0, r3
> 0x00000014 00f008e8 blx 0x00000028 ;[2] call xprintf_veneer
> 0x00000028()
> 0x00000018 00bf nop
> 0x0000001a 80bd pop {r7, pc}
> 0x0000001c 2e00 movs r6, r5
> 0x0000001e 0000 movs r0, r0
> 0x00000020 2c00 ...

Read more...

Revision history for this message
xintianzhang (zxtxin) wrote :

any update?

xintianzhang (zxtxin)
information type: Public → Public Security
information type: Public Security → Private Security
information type: Private Security → Public
To post a comment you must log in.
This report contains Public information  
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.