I am aware that my response comes after ~2 years since this question has been asked, but I belive that there's still no correct, in-depth answer.
Let us begin with a little bit of theory:
When you invoke GCC, it normally does preprocessing, compilation, assembly and linking. The “overall options” allow you to stop this process at an intermediate stage. For example, the -c option says not to run the linker. Then the output consists of object files output by the assembler.
Other options are passed on to one stage of processing. Some options control the preprocessor and others the compiler itself. Yet other options control the assembler and linker; most of these are not documented here, since you rarely need to use any of them.
source: GCC Online Docs
LDFLAGS
Extra flags to give to compilers when they are supposed to invoke the linker, ‘ld’, such as -L. Libraries (-lfoo) should be added to the LDLIBS variable instead.
source: GNU make Manual
As you can see, it is up to GCC (I will call it this way to distinguish from actual compiler; you can find it beeing called C compiler frontend or simply compiler though) which options will be passed to which tools and it appears that -On
option isn't passed to the linker (you can check it by giving -v
option to GCC). So invoking GCC without this option when it is supposed to do only the linking is OK.
The real problem is that you don't provide -mmcu=dev
option to GCC when linking. It is therefore unable to find proper crt*.o
file (C RunTime) and tell the linker to link it in; your application ends up without any initialization code.
So please note that you must include -mmcu=dev
in LDFLAGS or pass it to GCC regardless of what it is meant to do (preprocessing/compilation/assemblation/linking). I've already seen a couple of makefiles without this option in LDFLAGS on the Internet, so beware.
Now it's time for some practice -- assuming that your source is in test.c
file, issue the following commands (on linux):
avr-gcc -mmcu=attiny13a -DF_CPU=1200000 -Wall -O1 -c -o testO1.o test.c
avr-gcc -mmcu=attiny13a -DF_CPU=1200000 -Wall -Os -c -o testOs.o test.c
avr-gcc -o testO1_nodev.elf testO1.o
avr-gcc -v -o testOs_nodev.elf testOs.o > testOs_nodev.log 2>&1
avr-gcc -v -mmcu=attiny13a -o testOs_correct.elf testOs.o > testOs_correct.log 2>&1
I left only necessary options + -Wall
, for ATtiny13a you need -mmcu=attiny13a
instead of -mmcu=attiny13
.
Let's take a look at testOs_nodev.log
and testOs_correct.log
. Issue the following command:
diff testOs_nodev.log testOs_correct.log
and you will see something like:
2c2
< Reading specs from /usr/lib/gcc/avr/5.2.0/device-specs/specs-avr2
---
> Reading specs from /usr/lib/gcc/avr/5.2.0/device-specs/specs-attiny13a
10,12c10,12
< LIBRARY_PATH=/usr/lib/gcc/avr/5.2.0/:/usr/lib/gcc/avr/5.2.0/../../../../avr/lib/
< COLLECT_GCC_OPTIONS='-v' '-o' 'testOs_nodev.elf' '-specs=device-specs/specs-avr2'
< /usr/lib/gcc/avr/5.2.0/collect2 -plugin /usr/lib/gcc/avr/5.2.0/liblto_plugin.so \
-plugin-opt=/usr/lib/gcc/avr/5.2.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccqBjM6T.res \
-plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lm -plugin-opt=-pass-through=-lc \
-o testOs_nodev.elf -L/usr/lib/gcc/avr/5.2.0 -L/usr/lib/gcc/avr/5.2.0/../../../../avr/lib \
testOs.o --start-group -lgcc -lm -lc --end-group
---
> LIBRARY_PATH=/usr/lib/gcc/avr/5.2.0/avr25/tiny-stack/:\
/usr/lib/gcc/avr/5.2.0/../../../../avr/lib/avr25/tiny-stack/:\
/usr/lib/gcc/avr/5.2.0/:/usr/lib/gcc/avr/5.2.0/../../../../avr/lib/
> COLLECT_GCC_OPTIONS='-v' '-o' 'testOs_correct.elf' '-specs=device-specs/specs-attiny13a' \
'-mmcu=avr25' '-msp8'
> /usr/lib/gcc/avr/5.2.0/collect2 -plugin /usr/lib/gcc/avr/5.2.0/liblto_plugin.so \
-plugin-opt=/usr/lib/gcc/avr/5.2.0/lto-wrapper -plugin-opt=-fresolution=/tmp/ccV919rY.res \
-plugin-opt=-pass-through=-lgcc -plugin-opt=-pass-through=-lm -plugin-opt=-pass-through=-lc \
-plugin-opt=-pass-through=-lattiny13a -mavr25 -o testOs_correct.elf \
/usr/lib/gcc/avr/5.2.0/../../../../avr/lib/avr25/tiny-stack/crtattiny13a.o \
-L/usr/lib/gcc/avr/5.2.0/avr25/tiny-stack -L/usr/lib/gcc/avr/5.2.0/../../../../avr/lib/avr25/tiny-stack \
-L/usr/lib/gcc/avr/5.2.0 -L/usr/lib/gcc/avr/5.2.0/../../../../avr/lib testOs.o \
--start-group -lgcc -lm -lc -lattiny13a --end-group
(I broke a few lines to make it readable)
The difference is that without -mmcu=dev
option GCC defaults to use avr2 specs file and doesn't link any CRT file.
Examine object files (*.o
) and output files (*.elf
) using avr-objdump:
avr-objdump -xd testOs_nodev.elf
You will notice that *_nodev.elf
files don't contain correct information about architecture (avr instead of avr:25) nor any startup code (compare testOs_correct.elf
with testOs_nodev.elf
). The code section seems to a verbatim copy of what was supplied in object file.
If any part of my elaboration seems unclear or needs extra explanation, feel free to ask (comment).