2

I am using https://github.com/sudar/Arduino-Makefile project with https://github.com/ladislas/Bare-Arduino-Project to compile my Arduino projects from Linux command line. I put as much as possible functionality to libraries for reuse (and use the same libraries from many projects too).

Now I had run to some problems and I am not sure, if I am using the language (C/wiring/...) properly, as a lot of #define macros are used. I think, that seeing the resulting code would help me greeatly in finding, wheather some specific lines are compiled into what I want them to be compiled. I am interested mainly in the library code, even if it would mean to dump full program together with all used standard libraries. (I can find my way in large files.)

I would prefere intermediate files, as I suppose they could contain more info than just dissassembled .HEX file, but if this assumption is not correct, and I can get the same from .HEX, than I can use that way as well.

Question: How to get intermediate files (Ideally both "plain C" after preprocessing all macros AND "plain ASM" after compiling the code) ideally with corresponding lines of original code as comments inside.

Subquestion: In the above, how to disable optimalisation as much as possible, to get the code more verbatim similar to original C (I know, that it would hurt both speed and size and I do not care - I just want to be sure compiler does undertand my code the same way as I myself and if not, then see, where I made mistakes)

Thanks for all suggestions :)

gilhad
  • 1,466
  • 2
  • 11
  • 20

2 Answers2

1

One method I've used for creating assembly listings for Arduino sketches when using the Arduino IDE is as follows:
• Click Verify to compile the sketch
• Locate the the temporary build directory
• Use avr-objdump with -CSI... switches to decode the ELF file

Here are some commands you can put into a shell file to automate that procedure, on a Linux system:

item=*.ino
[ -z "$item" ] && echo ino file not found && exit
BDIR=/tmp/$(ls -t /tmp | egrep -m1 build.*tmp)
BASE=$(basename $item .ino)
avr-objdump -CSI$PWD $BDIR/$BASE.cpp.elf > $BASE.ino.asm

The above assumes the current working directory (ie, $PWD) is the directory with the sketch in it; variable item is the sketch name; variable BASE is the basename of the sketch, with .ino stripped off; $BDIR is the most-recently-used temporary build directory (which, on Ubuntu Linux systems, has a path that starts with /tmp/build); and the resulting deassembly is placed in $BASE.ino.asm for viewing.

To try this manually, as you may need to do on systems where the above shell commands don't work, say

avr-objdump -CSIddd bbb/sss.cpp.elf > sss.ino.asm

in a shell or at a command console, replacing ddd with the sketch's source directory name; bbb with the temporary build directory's name; and sss with the sketch's name.


Edit 2: Using Sudar's Arduino Makefile probably is the best starting point for looking at source code that has been pre-processed, or that has been compiled (into assembly language). This makefile system is fairly easy to install and use.

When you have the makefile system installed and working, you can generate pre-processed code (code that's been run through the pre-processor to incorporate #include files and to expand macros) by adding the following line within a makefile:

CPPFLAGS += -E

The -E switch tells avr-gcc to stop after preprocessing. According to man gcc its effect is:

Stop after the preprocessing stage; do not run the compiler proper. The output is in the form of preprocessed source code, which is sent to the standard output.

To generate assembly language, add the following line within a makefile:

CPPFLAGS += -S

The -S switch tells avr-gcc to stop after compiling. According to man gcc its effect is:

Stop after the stage of compilation proper; do not assemble. The output is in the form of an assembler code file for each non-assembler input file specified. ... By default, the assembler file name for a source file is made by replacing the suffix .c, .i, etc., with .s.

If you are skilled at makefile writing, it may be possible to add a target with rules to generate assembly or pre-processed code for inspection. Actually, Sudar's Arduino Makefile appears to have assembly-listing targets and rules already (as below for .pde; others for .ino and .cpp) although I haven't gotten them to work:

# generated assembly
$(OBJDIR)/%.s: %.pde $(COMMON_DEPS) | $(OBJDIR)
        @$(MKDIR) $(dir $@)
        $(CXX) -x c++ -include $(ARDUINO_HEADER) -MMD -S -fverbose-asm $(CPPFLAGS) $(CXXFLAGS) $< -o $@

[I now see that Edgar Bonet has mentioned this too.]

James Waldby - jwpat7
  • 8,920
  • 3
  • 21
  • 33
1

You can get the generated assembly by passing the -S option to avr-g++. The makefile you are using has a rule for that, so you would just type

make build-*/my_file.s

to get the assembly for my_file.cpp.

For the pre-processed C++, you use the -E option. There is no rule for that in the makefile, so you will have to write yo own, or manually invoke the compiler. At a minimum:

avr-g++ -mmcu=my_mcu -E my_file.cpp > my_file.i

You may want to add -DF_CPU=... -DARDUINO=... just like the makefile does when compiling the same file.

Edgar Bonet
  • 45,094
  • 4
  • 42
  • 81