I want to try and see what some code is doing at the assembly level but I am unsure on how to get Platform IO to output an Assembly file.
The platform I am compiling for is the ESP32.
Any suggestions are welcome.
I want to try and see what some code is doing at the assembly level but I am unsure on how to get Platform IO to output an Assembly file.
The platform I am compiling for is the ESP32.
Any suggestions are welcome.
Disassembling the whole firmware will result in a ton of assembly, but you can still do it. PIO builds you the firmware.elf
(which has some symbol information in it). So you can use the xtensa-esp32-elf-objdump
program of your C:\Users\<user>\.platformio\packages\toolchain-xtensa32\bin
package to disassemble that, or one specific file.
E.g. main.cpp
#include <Arduino.h>
int do_some_computations(int a, int b, int c) {
return a*b+c;
}
void setup() {
Serial.begin(115200);
Serial.println("Output: " + String(do_some_computations(1,2,3)));
}
void loop() { }
Then build it
>pio run
Linking .pio\build\esp32\firmware.elf
Building .pio\build\esp32\firmware.bin
Retrieving maximum program size .pio\build\esp32\firmware.elf
Checking size .pio\build\esp32\firmware.elf
esptool.py v2.6
Advanced Memory Usage is available via "PlatformIO Home > Project Inspect"
DATA: [ ] 4.7% (used 15436 bytes from 327680 bytes)
PROGRAM: [== ] 16.6% (used 217693 bytes from 1310720 bytes)
============================================= [SUCCESS] Took 16.54 seconds =============================================
And disassemble it…
C:\Users\Maxi\Documents\stackoverflow_testing>"C:\Users\Maxi\.platformio\packages\toolchain-xtensa32\bin\xtensa-esp32-elf-objdump.exe" -C -d .pio\build\esp32\firmware.elf
.pio\build\esp32\firmware.elf: file format elf32-xtensa-le
[...]
You can selectively disassemble one object file (but then it isn’t aware of the other object files yet before linking)
C:\Users\Maxi\Documents\stackoverflow_testing>"C:\Users\Maxi\.platformio\packages\toolchain-xtensa32\bin\xtensa-esp32-elf-objdump.exe" -C -d .pio\build\esp32\src\main.cpp.o
[..]
Disassembly of section .text._Z20do_some_computationsiii:
00000000 <do_some_computations(int, int, int)>:
0: 004136 entry a1, 32
3: 822230 mull a2, a2, a3
6: 224a add.n a2, a2, a4
8: f01d retw.n
So you can see here how return a*b+c;
is implemented via first multiplying the first and second argument register (a2
, a3
) into the second argument register, to which then the third argument register a4
is added. a1
is the stackpointer and a2
doubles as one return register (see The ESP8266 and ABI Interface - Linux/Xtensa, XTensa reference)
You can also add the GCC option
build_flags = -S
to the platformio.ini
(docs), which will make GCC output the assembly. So now all the .pio\build\esp32\*.o
files will actually be assembler output files
So if I e.g. change the function to return a*b+3;
recompile and read the file I get
C:\Users\Maxi\Documents\stackoverflow_testing>cat .pio\build\esp32\src\main.cpp.o
.file "main.cpp"
.text
.Ltext0:
.section .text._Z20do_some_computationsiii,"ax",@progbits
.align 4
.global _Z20do_some_computationsiii
.type _Z20do_some_computationsiii, @function
_Z20do_some_computationsiii:
.LFB2430:
.file 1 "src\\main.cpp"
.loc 1 3 0
.LVL0:
entry sp, 32
.LCFI0:
.loc 1 4 0
mull a2, a2, a3
.LVL1:
.loc 1 5 0
addi.n a2, a2, 3
retw.n
So now it used mull
and addi
with a constant 3.
This is my platformio.ini which gets me the avr assembly code files
[env:nanoatmega328]
platform = atmelavr
board = nanoatmega328
framework = arduino
; keep asm .s, .i and .ii files in source dir (need to clean manually)
build_flags =
-save-temps
-fverbose-asm
; Serial Monitor options
monitor_speed = 115200
Thanks for the contribution @schaloule, but the OP was after:
as opposed to your AVR specific answer. I’m sure this may come in handy though if someone is after AVR info and comes across this thread though!
I’d like to say thanks very much to @schaloule, those flags work splendidly for ESP32 as well. I would like to add a suggestion for others visiting here… which is to use the obj option on save-temps (then the temporary files don’t go into the top level folder)…
build_flags =
-save-temps=obj
-fverbose-asm
The obj option is documented here.