arm cortex-m0 elf file issue - Page 1
Forum section: electronics / general

author: trampas
author_rank: Regular Contributor
timestamp: December 26, 2024, 09:53:58 pm
content: I noticed when I compiler my code with arm-none-eabi-gcc version 10.3.1 I am able to run and step through the code correctly. However if I use any version of the compiler newer segger ozone and vscode (cortex-debug) thinks the code comes from the wrong source file. The binary of the code is correct but it thinks code came from a different source file.I have fought this for a several days now and found that if I take the elf file that does not work and run `objdump -dlr` on it then the output is corrupt. Specifically the none working elf file produces:```build/debug/lora.elf: file format elf32-littlearmDisassembly of section .text:00000000 <exception_table>:getStackSize():D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:2440: ff 7f 00 20 95 04 00 00 61 05 00 00 a5 05 00 00 ... ....a..........getStackUsed():D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:2542c: 61 05 00 00 00 00 00 00 00 00 00 00 61 05 00 00 a...........a...D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:2573c: a5 08 00 00 61 05 00 00 b1 0b 00 00 6d 06 00 00 ....a.......m...D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:2504c: 61 05 00 00 61 05 00 00 61 05 00 00 61 05 00 00 a...a...a...a...D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:2675c: 61 05 00 00 79 07 00 00 9d 07 00 00 c1 07 00 00 a...y...........6c: e5 07 00 00 09 08 00 00 2d 08 00 00 61 05 00 00 ........-...a..._ZN10I2C_MASTER4syncEv():D:\Projects\SECA\LoRa\firmware/src/drivers/i2c_master/i2c_master.cpp:907c: 61 05 00 00 61 05 00 00 c9 09 00 00 09 0a 00 00 a...a..........._sfixed():D:\Projects\SECA\LoRa\firmware/src/drivers/i2c_master/i2c_master.cpp:908c: 49 0a 00 00 89 0a 00 00 c9 0a 00 00 61 05 00 00 I...........a...D:\Projects\SECA\LoRa\firmware/src/drivers/i2c_master/i2c_master.cpp:919c: 61 05 00 00 61 05 00 00 61 05 00 00 61 05 00 00 a...a...a...a..._ZN10I2C_MASTER9read_byteEPh():D:\Projects\SECA\LoRa\firmware/src/drivers/i2c_master/i2c_master.cpp:93ac: 61 05 00 00 00 00 00 00 a.......```Where the working elf file produces:```build/debug/lora.elf: file format elf32-littlearmDisassembly of section .text:00000000 <exception_table>:_sfixed():0: ff 7f 00 20 45 04 00 00 0d 05 00 00 4d 05 00 00 ... E.......M......2c: 0d 05 00 00 00 00 00 00 00 00 00 00 0d 05 00 00 ................3c: 55 08 00 00 0d 05 00 00 75 0b 00 00 09 06 00 00 U.......u.......4c: 0d 05 00 00 0d 05 00 00 0d 05 00 00 0d 05 00 00 ................5c: 0d 05 00 00 29 07 00 00 4d 07 00 00 71 07 00 00 ....)...M...q...6c: 95 07 00 00 b9 07 00 00 dd 07 00 00 0d 05 00 00 ................7c: 0d 05 00 00 0d 05 00 00 79 09 00 00 b9 09 00 00 ........y.......8c: f9 09 00 00 39 0a 00 00 79 0a 00 00 0d 05 00 00 ....9...y.......9c: 0d 05 00 00 0d 05 00 00 0d 05 00 00 0d 05 00 00 ................ac: 0d 05 00 00 00 00 00 00 ........```Note that the getStackSize(): function referenced in the first output does not exist in the binary, that is the function was never called and it was removed using `-ffunction-sections -fdata-sections ` and `-Wl,--gc-sections`.I figure since 10.3.1 version of compiler is 3 years old, that I am doing something wrong in my build process. That is I assume it is more likely a problem I have than a problem with gcc, like maybe I need a new compiler/linker option to clean up elf file correctly?Thanks

author: trampas
author_rank: Regular Contributor
timestamp: December 27, 2024, 12:26:19 am
content: From what I have been able to determine, with GCC 11 and later the unused functions (unused symbols in elf) are being mapped to address zero. That is gdb and objdump thinks all the unused functions are linked in at address zero and then seemly random picks out which function to show as source (maybe based on link order?). The net result is that when debugging with gdb based debugger the debugger can not resolve the true source file for the code, and will randomly pick which line of which random function it will show you during debug.I will keep you posted with any updates.

author: ataradov
author_rank: Super Contributor
timestamp: December 27, 2024, 12:28:42 am
content: GCC at some point switched to DWARF version 5, which may affect how tools understand debug information. So, this would be the first thing I check. And I think there is an option to force older versions.Although I don't know if it will be messed up to that extent.

author: ataradov
author_rank: Super Contributor
timestamp: December 27, 2024, 12:30:31 am
content: Quote from: trampas on December 27, 2024, 12:26:19 amThis would be really strange. But also, if you collect unused functions, then they would not be in the binary anyway.

author: trampas
author_rank: Regular Contributor
timestamp: December 27, 2024, 01:09:25 am
content: The did switch to dwarf 5 at the same time, I tried setting the system dwarf 4 and it had no change in results.The unused functions are not in the binary, but then gdb appears to think they exist in the binary and places them all at address 0x00. As such as I step through my code it will randomly jump to the incorrect source file into a random line of code. The binary is correct and runs, but trying to step through code it goes off into random places.As shown below in the objdump the getStackSize() function is not in the binary, but objdump thinks it exists at address 0x000 and shows it in the dump.build/debug/lora.elf: file format elf32-littlearmDisassembly of section .text:00000000 <exception_table>:getStackSize():D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:2440: ff 7f 00 20 95 04 00 00 61 05 00 00 a5 05 00 00 ... ....a..........getStackUsed():D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:2542c: 61 05 00 00 00 00 00 00 00 00 00 00 61 05 00 00 a...........a...D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:2573c: a5 08 00 00 61 05 00 00 b1 0b 00 00 6d 06 00 00 ....a.......m...D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:2504c: 61 05 00 00 61 05 00 00 61 05 00 00 61 05 00 00 a...a...a...a...

author: SiliconWizard
author_rank: Super Contributor
timestamp: December 27, 2024, 01:20:27 am
content: So, are you seeing that your linked ELF files contain code that should have been pruned by the linker to begin with?

author: trampas
author_rank: Regular Contributor
timestamp: December 27, 2024, 01:27:42 am
content: The elf file binary is correct. However it think some of the code is from random source files where the code is removed.For example the configure_clocks function is in startup_wlr089.c file. However the objdump and gdb thinks the code come from sercom.cpp, see below0000016c <configure_clocks>:D:\Projects\SECA\LoRa\firmware/src/drivers/sercom/sercom.cpp:10116c: b500 push {lr}16e: 4b98 ldr r3, [pc, #608] ; (3d0 <HEAP_SIZE+0x1d0>)170: 2280 movs r2, #128 ; 0x80D:\Projects\SECA\LoRa\firmware/src/drivers/sercom/sercom.cpp:105172: 0052 lsls r2, r2, #1174: 609a str r2, [r3, #8]D:\Projects\SECA\LoRa\firmware/src/drivers/sercom/sercom.cpp:106176: 4b97 ldr r3, [pc, #604] ; (3d4 <HEAP_SIZE+0x1d4>)178: 3afd subs r2, #253 ; 0xfdD:\Projects\SECA\LoRa\firmware/src/drivers/sercom/sercom.cpp:10717a: 609a str r2, [r3, #8]17c: 4a96 ldr r2, [pc, #600] ; (3d8 <HEAP_SIZE+0x1d8>)D:\Projects\SECA\LoRa\firmware/src/drivers/sercom/sercom.cpp:108The reason is that all the functions in sercom.cpp are not used as such they have been removed from binary. Objdump and gdb then assumes every function in sercom.cpp is actually placed in memory at 0x000. Since the configure_clocks() function is placed in memory at 0x16C gdb and objdump picked that the configure_clocks() function must be one of the functions in sercom.cpp. So as you step through the configure_clocks() code the debugger is showing random source files from sercom.cpp.

author: trampas
author_rank: Regular Contributor
timestamp: December 27, 2024, 01:31:56 am
content: Now if change my compiler toolchain to 10.3.1-2.2.1 and rebuild the same code, same make file, etc. Then gdb and objdump are correct.NOTE the code is different because it is using a different version of compiler, as such binary is different.configure_clocks():D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:321154: 4a8d ldr r2, [pc, #564] ; (38c <HEAP_SIZE+0x18c>)156: 6953 ldr r3, [r2, #20]158: 2440 movs r4, #64 ; 0x4015a: 4323 orrs r3, r415c: 6153 str r3, [r2, #20]D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:32315e: 4b8c ldr r3, [pc, #560] ; (390 <HEAP_SIZE+0x190>)160: 2200 movs r2, #0162: 615a str r2, [r3, #20]D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:324164: 6959 ldr r1, [r3, #20]166: 488b ldr r0, [pc, #556] ; (394 <HEAP_SIZE+0x194>)168: 4008 ands r0, r116a: 2180 movs r1, #128 ; 0x8016c: 00c9 lsls r1, r1, #316e: 4301 orrs r1, r0

author: trampas
author_rank: Regular Contributor
timestamp: December 27, 2024, 02:00:01 am
content: Here is another example with 11.2.1-1.1.1. When I compile with -O0 it seems to get the configure_clocks() function has correct source file:00000198 <configure_clocks>:configure_clocks():D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:306198: b580 push {r7, lr}19a: b082 sub sp, #819c: af00 add r7, sp, #0D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:31119e: 4bb1 ldr r3, [pc, #708] ; (464 <STACK_SIZE+0x64>)1a0: 2280 movs r2, #128 ; 0x801a2: 0052 lsls r2, r2, #11a4: 609a str r2, [r3, #8]D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:3121a6: 4bb0 ldr r3, [pc, #704] ; (468 <STACK_SIZE+0x68>)1a8: 2203 movs r2, #31aa: 609a str r2, [r3, #8]D:\Projects\SECA\LoRa\firmware/src/CMSIS/wlr089/source/gcc/startup_wlr089.c:3151ac: 4baf ldr r3, [pc, #700] ; (46c <STACK_SIZE+0x6c>)1ae: 685a ldr r2, [r3, #4]1b0: 4bae ldr r3, [pc, #696] ; (46c <STACK_SIZE+0x6c>)1b2: 2104 movs r1, #41b4: 430a orrs r2, r11b6: 605a str r2, [r3, #4]with compile option of -O1:0000016c <configure_clocks>:D:\Projects\SECA\LoRa\firmware/src/drivers/sercom/sercom.cpp:10216c: b500 push {lr}16e: 4b98 ldr r3, [pc, #608] ; (3d0 <HEAP_SIZE+0x1d0>)170: 2280 movs r2, #128 ; 0x80D:\Projects\SECA\LoRa\firmware/src/drivers/sercom/sercom.cpp:106172: 0052 lsls r2, r2, #1174: 609a str r2, [r3, #8]D:\Projects\SECA\LoRa\firmware/src/drivers/sercom/sercom.cpp:107176: 4b97 ldr r3, [pc, #604] ; (3d4 <HEAP_SIZE+0x1d4>)178: 3afd subs r2, #253 ; 0xfdD:\Projects\SECA\LoRa\firmware/src/drivers/sercom/sercom.cpp:10817a: 609a str r2, [r3, #8]17c: 4a96 ldr r2, [pc, #600] ; (3d8 <HEAP_SIZE+0x1d8>)D:\Projects\SECA\LoRa\firmware/src/drivers/sercom/sercom.cpp:10917e: 6853 ldr r3, [r2, #4]180: 2104 movs r1, #4182: 430b orrs r3, r1D:\Projects\SECA\LoRa\firmware/src/drivers/sercom/sercom.cpp:113184: 6053 str r3, [r2, #4]186: 2380 movs r3, #128 ; 0x80D:\Projects\SECA\LoRa\firmware/src/drivers/sercom/sercom.cpp:114188: 05db lsls r3, r3, #2318a: 789b ldrb r3, [r3, #2]

author: xvr
author_rank: Frequent Contributor
timestamp: December 27, 2024, 01:20:52 pm
content: May be you turn on LTO optimization in compilation process? It looks like that some functions was cross inlined from one file into another.

author: trampas
author_rank: Regular Contributor
timestamp: December 27, 2024, 01:40:04 pm
content: I tried with -flto and every other option I could think of. It appears this is a 'bug' in GCC 11 and later.Note I worked on this issue for several days, because the odds of finding a bug in GCC after almost 3 years that no one else found is low. However I suspect that few have large amounts of functions being removed with the '-ffunction-sections -fdata-sections -Wl,--gc-sections' who are also trying to step through code close to address zero.I did noticed that GCC 11 switched to DWARF 5, so I tried option to generate DWARF 4 but the elf had the same result. I also noticed a lot of work was done in GCC 11 for link time optimizations (LTO), however again nothing I could change with command line options.Again it only is a problem when you are using gdb to debug code, the binary is fine. As such I suspect many might have seen strange results and assumed it was an issue for them and never root caused to figure out the problem. Also many developers try to remove unused functions from source code, again reducing the chances of finding the problem.On a more interesting note, my google foo is not great as there is almost no terms I could search to help aid in this problem without finding other issues. For example 'gdb unused functions' talks about how find unused functions. Also equally as interesting is that there are few people, and hard to reach them, that would be able to duplicate the issue and help you resolve it. That is most embedded developers never get detailed in how the tools work, and the few that do are hard to come by.Finally there is the question about how do you duplicate this issue. That is I assume my objdump outputs being messed up is also why gdb is messed up. However if I have to create an example with gdb that shows error it is hard to do when you use gdb with hardware in the loop. So it has been an interesting learning experience.