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

Bug #1697255 reported by necwerk on 2017-06-11
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
GNU ARM Embedded Toolchain
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

necwerk (m8r-njfnr31) wrote :
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

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

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.

necwerk (m8r-njfnr31) wrote :

How it can work in the second case?

What second case do you mean?

necwerk (m8r-njfnr31) wrote :

With my workaround

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

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.

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.

necwerk (m8r-njfnr31) wrote :

Can I mark an address as function in symbol file?

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.

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...

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?

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.

To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers

Bug attachments