By default, all unknown non-option arguments on the avr-gcc command-line (i. e., all filename arguments that don't have a suffix that is handled by avr-gcc) are passed straight to the linker. Thus, all files ending in .o (object files) and .a (object libraries) are provided to the linker.

System libraries are usually not passed by their explicit filename but rather using the -l option which uses an abbreviated form of the archive filename (see above). avr-libc ships two system libraries, libc.a, and libm.a. While the standard library libc.a will always be searched for unresolved references when the linker is started using the C compiler frontend (i. e., there's always at least one implied -lc option), the mathematics library libm.a needs to be explicitly requested using -lm. See also the entry in the FAQ explaining this.

Conventionally, Makefiles use the make macro LDLIBS to keep track of -l (and possibly -L) options that should only be appended to the C compiler command-line when linking the final binary. In contrast, the macro LDFLAGS is used to store other command-line options to the C compiler that should be passed as options during the linking stage. The difference is that options are placed early on the command-line, while libraries are put at the end since they are to be used to resolve global symbols that are still unresolved at this point.

Specific linker flags can be passed from the C compiler command-line using the -Wl compiler option, see above. This option requires that there be no spaces in the appended linker option, while some of the linker options above (like -Map or --defsym) would require a space. In these situations, the space can be replaced by an equal sign as well. For example, the following command-line can be used to compile foo.c into an executable, and also produce a link map that contains a cross-reference list in the file foo.map:

$ avr-gcc -O -o foo.out -Wl,-Map=foo.map -Wl,--cref foo.c

Alternatively, a comma as a placeholder will be replaced by a space before passing the option to the linker. So for a device with external SRAM, the following command-line would cause the linker to place the data segment at address 0x2000 in the SRAM:

$ avr-gcc -mmcu=atmega128 -o foo.out -Wl,-Tdata,0x802000

See the explanation of the data section for why 0x800000 needs to be added to the actual value. Note that the stack will still remain in internal RAM, through the symbol __stack that is provided by the run-time startup code. This is probably a good idea anyway (since internal RAM access is faster), and even required for some early devices that had hardware bugs preventing them from using a stack in external RAM. Note also that the heap for malloc() will still be placed after all the variables in the data section, so in this situation, no stack/heap collision can occur.

In order to relocate the stack from its default location at the top of interns RAM, the value of the symbol __stack can be changed on the linker command-line. As the linker is typically called from the compiler frontend, this can be achieved using a compiler option like

-Wl,--defsym=__stack=0x8003ff

The above will make the code use stack space from RAM address 0x3ff downwards. The amount of stack space available then depends on the bottom address of internal RAM for a particular device. It is the responsibility of the application to ensure the stack does not grow out of bounds, as well as to arrange for the stack to not collide with variable allocations made by the compiler (sections .data and .bss).