Save assembler files during building

I spent an hour to understand how I can save assembler “.S” files during building.
Probably, I don’t know the place where will be saved.

I tried next:

[env:uno]
platform = atmelavr
board = uno
framework = arduino
build_flags =
    -save-temps

but can’t find files.

I found filed in the root of the project but they don’t contain something useful. As I can see there is only string tables, I suppose debug table

CLion + macOs

Source:

#include <Arduino.h>
void setup() {
    pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
    digitalWrite(LED_BUILTIN, HIGH);
    delay(1000);
    digitalWrite(LED_BUILTIN, LOW);
    delay(100); 
}

S file

	.file	"main__.cpp"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__tmp_reg__ = 0
__zero_reg__ = 1
	.section	.gnu.lto_.profile.293fb85e1d98b8c9,"",@progbits
	.string	"x\234cc```\001bF\006\007A"
	.string	"\001\t"
	.ascii	"]"
	.text
	.section	.gnu.lto_.icf.293fb85e1d98b8c9,"",@progbits
	.string	"x\234cc``\340e@"
	.string	"&\206m7\366\3723n\355\375\373\224\217\001"
	.ascii	")N\005\343"
	.text
	.section	.gnu.lto_.jmpfuncs.293fb85e1d98b8c9,"",@progbits
	.string	"x\234cc``\270\303\200"
	.string	"L@\314\3028\205\231\361\303\316\245+\230\272\231\347030\3622nf\224a`<\300\310\310\013\304\f\f \351\255\355g6rA\244\031\031\267@\245\031!\322@S@JN-\376v\210\025\244\204\221\361\t\003\343V\250\232'\f`E,\214X\f\235\326z\350<;\304P\006\306mPi\210z\260\211sgL\374\313\t1\361\005;\343v\250\202\027\3548LDs\027\003"
	.ascii	"\2077.\332"
	.text
	.section	.gnu.lto_.inline.293fb85e1d98b8c9,"",@progbits
	.string	"x\234cc``pg@"
	.string	"&\006\0066>F\020\305\300\266@\036D10\363\200\205\031\031\370\2150%\030a\322(\034\006"
	.ascii	"z\373\002\215"
	.text
	.section	.gnu.lto_.pureconst.293fb85e1d98b8c9,"",@progbits
	.string	"x\234cc```\005b&\006\tF\t"
	.string	""
	.string	"\364"
	.ascii	"?"
	.text
	.section	.gnu.lto_setup.293fb85e1d98b8c9,"",@progbits
	.ascii	"x\234%\215\261KBa\024\305\317\371\256>\037\201\212s\376\003\022"
	.ascii	"\344\237\323(\341\324`\210\375\001\357\253\320g\344\020T\272"
	.ascii	"\274\301\206\320-D-\336\366\341,\r\256m\rM\022\r\256Y\367\323"
	.ascii	"\003?8\234{\357\271\001\200\245RR\016\025\nh\356\336\201\313"
	.ascii	"\320\220\336\330\220\210\f#\366\344A\270\210\277RS\031Y\225\033"
	.ascii	"trv\354\230\b\320W\2748e\005\272\3669\331>\346\203\314>\347\214"
	.ascii	"\001\250\346e\225uv\373\027[\267y\342\221\216\272\212\376\260"
	.ascii	"\0167b\274\273vX\263=\274/\354n\264(M\327\037\271\350\327\206"
	.ascii	"\211\260/Z\3029#?\370I\237\307\346V\0221\314\363\225e\215\346"
	.ascii	"\361rr\260\217\3107\226\023\021|\363jx\262+\363\352j\203~1@\361"
	.ascii	"\242U\2576N\317\316k\265\343z\263\211\177\2633H8"
	.text
	.section	.gnu.lto_loop.293fb85e1d98b8c9,"",@progbits
	.ascii	"x\234}\220=K\003A\020\206\347\335\275/\205 \326\346\017\244\321"
	.ascii	"\237\024$\225\205\022\364\007\334\372\021\222\240\205\202\236"
	.ascii	"\026'\234\210\230N\202F=?\340H%\"*\266v**xDA\260Kt\366V\260\221"
	.ascii	"\f\f;\314\354\373>\3038DT\007\3210\277#\234\220\004\261|M4\353"
	.ascii	"\t@\027\312\003\371\002>\226\344\252D\273\372\034\213\302\256"
	.ascii	"\342H\326;\216j$\b%Q\300\251\003\373(\020\177{h\366\326r\216"
	.ascii	"e\3728\200C\314\240\275;;Q\275\357\252J\322-\304\226CT\3439C"
	.ascii	"TBu)t5\237P\212J\364x!2\025[\305qz\357\372]\345\205\022\201d"
	.ascii	"\033\264\340\353\301G\274\323\020\2132\224\0029\034\"\317\255"
	.ascii	"V\365\2529hZ\300\021\362\241\224l\267\020\275\334\342\037;+`"
	.ascii	"&\341\330\330mn\254t\007\264\326\306\253\213X\213\235l\227\267"
	.ascii	"~\273\234\260\370\027\036T\3327\256\201\023N\377\340\357\375"
	.ascii	"\340g\006~\271\375\325\266\r\374\211pn\340\035\314E\237^\246"
	.ascii	"\325Qc _\210UC3\323\245\261\311\361\211\251bq\264T.\323\017\240"
	.ascii	"\254\206O"
	.text
	.section	.gnu.lto_.symbol_nodes.293fb85e1d98b8c9,"",@progbits
	.ascii	"x\234U\310\301\021@0\030D\341\267IF]T\366\007)@\021\252pvV\003"
	.ascii	"3\352\bar\340\260\363f\277\006\350\313p\031\203i\343\311\022"
	.ascii	"\273\"\027\246\237h\220\271W \306\266@\222\371\037\214\262\360"
	.ascii	"\005\217c\336\263\274B\255g\255\377\254?\035Y\334b\372\"\032"
	.text
	.section	.gnu.lto_.refs.293fb85e1d98b8c9,"",@progbits
	.string	"x\234cc```\004b\006"
	.string	""
	.string	"D"
	.ascii	"\b"
	.text
	.section	.gnu.lto_.decls.293fb85e1d98b8c9,"",@progbits
	.ascii	"x\234\215SOH\024Q\030\177\337<Wm\\3\"\302\303\036\242\213\206"
	.ascii	"\270St\361\026\321\241Ku\b\244K\240\303\356fK\353\3166;\026\326"
	.ascii	"\241\207%\225z\b\214\n\2424\202\312\254LK\323\362\317Zk\226\245"
	.ascii	"\225htP\324\n<hTx\020\363`\337{\363\306]\313\240\307|\363\315"
	.ascii	"{\337\367\3733\357\315\244\022BrR\bY\300\034\303X\302A1\367b"
	.ascii	"(\030\035\274N"
	.string	"\354\341\302\350\302\350\301\210c\274\302\030 \177\217\223@\bR\222b\214A\311\361B\326\024\311\021_\005w\nqi\253\340\206\244\207~\331G\245\207\001\351\341\317q\221BS\345\327\206\364j\n\036\025\226\200\317g;\0262\3559/\267\314L\325dRE<\277k\272\331\243z\3571{\244o!\320\n\324\341i\250\273\023\317\244\036\336\250|o\\\250M\203\\\365\026\357\213M\217\354\230\252dL\201\016P\341\tPh\003/bP\001\357\347\030\253`\261zF\263\tl\367\300V\017\201v\310\0255x\f\036x\004\270\202@T`\r\267G\350\004\214\003\272\001\333?\200L \302\236\203\230b\266\373\234%\260\357@\022\317\304\206\360'\305\241\023\227\314 \016Y\f\2339IA*\022\t]\366\343@q]4\255`X\341\001H2\375*eH:)\220\333|y\360|\273B\217\212\363\230\254n\232\314\310\276$6\231\261u"
	.ascii	"\305\033\345\036\022\350\204l\274\207SlTw_\305\330\232\315\365"
	.ascii	"\254~\222\305\226\256\273?2v\005A\233x\027<K\234\3103q\234\360"
	.ascii	"\024&P\274\0136#\262\262qf'=\013B\257}v\346\212[\262<uMr]\020"
	.ascii	"\024\335\t\212\356d\212\036Aqa~\264Y\24156\307\364\375\321\341"
	.ascii	"\314\024\3342\3615\240?\\\253\375|z,uy\255\027\304b\325\247\352"
	.ascii	".\327?^\356\205x\271\347 \337.>\376d\221\242/t\024\373r\267\340"
	.ascii	"N\025;Cy\017\304\022\276b\362K\205\270\360t\272e\266S\245\323"
	.ascii	"\266\247\007\367\026\037\252B?\307\261\364\263\261\271\342_["
	.ascii	"\333/\324_:\3527\352\346[S\245\372\257-\225\3549\360\016\350"
	.ascii	"Kh\3679\332\257\204\366\265\271\253\215\031\364\233\255=\372"
	.ascii	"a\340\240\003\316\025`n\374u\002\374\332\001\017\bp\337\322|"
	.ascii	",\013\177\317\365*(8\035\376\361\366Z\006N7\250\260\216W\353"
	.ascii	"\333:\024w\025\377\247\3363\346\312\026do\3617z\003\334\371 "
	.ascii	"\270\005\025fl\356\277\3362\227\225\334\334\277\242yH6\363\274"
	.ascii	"6j\372\264R=\030.*\362\372\"\021u\367\276\302M\273\362\362\266"
	.ascii	"m#ie\301\260UPd\355\321\n\243\0013\252\205\365\322\300\211\362"
	.ascii	"\250\346\215\204t\353\220a\226\006\r-\242\373\216\350%\201\250"
	.ascii	"f\031F\310w\030i\362u\2534\020\322\217\231\032\217`\330\027*"
	.ascii	"\363\007\264\250\345G2\357a\342\212\006\254\262H\326JQ\222\022"
	.ascii	"2\214HZ$\030\336k\370\003\373\377G\357\220\211\325\343\206y$"
	.ascii	"_7\375h\324\310\347r>\303\304\232\\\321v\332\231\253\372\321"
	.ascii	"R\271\333\037,\tZz\350\200\031\264\002\277\001\214\240x<"
	.text
	.section	.gnu.lto_.symtab.293fb85e1d98b8c9,"",@progbits
	.string	"setup"
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	"\275"
	.string	""
	.string	""
	.string	"loop"
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	"\277"
	.string	""
	.string	""
	.string	"pinMode"
	.string	""
	.ascii	"\002"
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	"\304"
	.string	""
	.string	""
	.string	"delay"
	.string	""
	.ascii	"\002"
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	"\310"
	.string	""
	.string	""
	.string	"digitalWrite"
	.string	""
	.ascii	"\002"
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	""
	.string	"\312"
	.string	""
	.string	""
	.text
	.section	.gnu.lto_.opts,"",@progbits
	.string	"'-fmath-errno' '-fsigned-zeros' '-ftrapping-math' '-fno-trapv' '-fno-openmp' '-fno-openacc' '-mn-flash=1' '-mmcu=avr5' '-Os' '-ffunction-sections' '-fdata-sections' '-flto' '-mn-flash=1' '-mno-skip-bug' '-fno-exceptions'"
	.text
	.comm	__gnu_lto_v1,1,1
	.comm	__gnu_lto_slim,1,1
	.ident	"GCC: (GNU) 7.3.0"
1 Like

You could do worse than to add build_flags=--save-temps to your platformio.ini file but this applies to any variant of the gcc compiler, possibly clang if that’s in use – but don;t quote me. If you use a different compiler, then the docs should have details of the various flags, and you should be able to add it accordingly.

On an Arduino, gcc is used. The option will fill your project directory with *.i files, *.ii files and *.s files. You can get rid of the first two if as you only appear interested in the assembly source files.

I find this method a minor pain in the rear! What I do if I ever need the assembly source for an ArduinoUno project is to compile in the usual manner – I tend mostly to use the command line:

## Compile ...
pio run

## Switch to location for elf file.
cd .pio/build/uno

## Check...
ls *.elf
firmware.elf

## Dump assembly with C source...
/home/norman/.platformio/packages/toolchain-atmelavr/avr/bin/objdump -S -d firmware.elf > firmeware.s

## Firmware.s is the assembly source for the whole project.

## Change back to project directory.
cd -

The -S option says to mix the C/C++ source in to output alongside the assembly code. The -d option says to disassemble executable sections only. You need to redirect to a file as output from objdump is always to stdout.

HTH

Cheers,
Norm.

Oh. My main mistake was that I didn’t check all parameters.

the option -flto generate useless assembler files and result should be observed after linking

There should be two leading hyphens in --save-temps.

1 Like

--save-temps=obj should put files next to objects.

But for some reason it doesn’t work:
C:\Users\dzidm\.platformio\packages\toolchain-gccarmnoneeabi\bin\arm-none-eabi-gcc.exe: error: unrecognized command line option '-save-temp=obj'; did you mean '-save-temps'?

It’s possible that the compiler options have changed in the last three years, but as far as I’ve found, it’s definitely --save-temps.

Cheers,
Norm.

(Let me preface that I am not really asking for a the solution, /unless it’s obvious and proven/, I am just documenting my experience. I spent too much time on this.)

--save-temps works, but two issues with it:

  1. generates files in the root workspace folder
  2. the assembly files were useless as @ namezys said

I tried your other method objdump -S -d firmware.elf > firmeware.s and it’s much better but still not great, especially for -O2 (I think), as it really clutters the output.

However it’s pretty good with my debug profile:

Ultimately, I was looking for something that would populate some register names with variable symbols, but I couldn’t make objdump to do it. I was hoping that -demangle or -disassembler-options arguments could do it but didn’t figure out how to use them and I have a feeling they wouldn’t do what I want.

The best looking disassembly I’ve got with Ghidra.


It does resolve some variable names and much more!, eg:

However I couldn’t figure out how to load C sources.
So I ended up using objdump -S to find source code line address and then navigated to the address in Ghidra to quickly debug a piece of code.


Aha, btw, the best looking assembly dump I experienced and was spoiled by, was for STM8 project with SDCC compiler:


It, by default!, generates assembly files next to objects. They include source code line position and beautifully substituted some of the registers with variable names.
It is so easy to work with, unlike gcc.

Ah, my apologies. I misunderstood. Sorry.

Yes, understood. The -O2 is doing some optimisation and this can seriously mess with your head when looking at the disassembly. This might help, and if not, please accept my further apologies in advance!

  • Execute a verbose compilation, I tend to use the command line but you can do it from VSCode also.
  • Copy and paste the compiler command line into a terminal session where the PlatformIO code is available on the path.
  • Edit out the “-Os” options and replace them with “-O0 -g”.
  • Execute the edited command line.
  • Run the linker command again, if necessary.

If you now run the disassembly using avr-objdump -S -d firmware.elf then you don;t get the optimisations.

It has to be done this way because the following doesn’t work for the Uno board and possibly other AVR microcontrollers which don’t have onboard debugging.

[env]
platform = atmelavr
framework = arduino
board = uno

[env:release]
; Nothing required here.

[env:debug]
build-unflags = -Os
build-flags = -O0 -g

It would be nice if it did work and it would save a lot of messing about. Setting build-type = debug also has no effect!

The Arduino IDE, version 2.x, has an option “Sketch->Optimize for Debugging” which also doesn’t work for the Uno boards, however, I have been able to make it work.

Cheers,
Norm.

1 Like