Can the compiler be set to output the Assembly that would be used?

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.

1 Like

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.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 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"
        .section        .text._Z20do_some_computationsiii,"ax",@progbits
        .align  4
        .global _Z20do_some_computationsiii
        .type   _Z20do_some_computationsiii, @function
        .file 1 "src\\main.cpp"
        .loc 1 3 0
        entry   sp, 32
        .loc 1 4 0
        mull    a2, a2, a3
        .loc 1 5 0
        addi.n  a2, a2, 3

So now it used mull and addi with a constant 3.


This is my platformio.ini which gets me the avr assembly code files

platform = atmelavr
board = nanoatmega328
framework = arduino

; keep asm .s, .i and .ii files in source dir (need to clean manually)
build_flags = 

; Serial Monitor options
monitor_speed = 115200
1 Like

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! :wink:

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 = 

The obj option is documented here.