user14631: First we set fuse bits:
avrdude -c usbasp -p atmega328p -U lfuse:w:0xFF:m -U hfuse:w:0xDF:m -U efuse:w:0x07:m # same for atmega168

In the following examples we use the following commands to compile and burn all the programs:
avr-gcc -Os -mmcu=atmega328p -c -o serial.o serial.c
avr-ld -o serial.elf serial.o
avr-objcopy -O ihex serial.elf serial.hex
avrdude -c usbasp -p atmega328p -U flash:w:serial.hex

Let us burn the following program:
#define F_CPU 16000000UL
#include <avr/io.h>
void main (void) {
  DDRB |= (1<<PB5);
  PORTB |= (1<<PB5);
  while (1);
}

It makes the led to be on constantly. And it stays so for infinite period of time.
Then we burn the following program:
#define F_CPU 16000000UL
#define BAUD 9600
#include <avr/io.h>
char data = 0;
void main(void) {
  // Initialize USART:
  #include <util/setbaud.h> 
  UBRR0H = UBRRH_VALUE; // set the speed (Higher bit)
  UBRR0L = UBRRL_VALUE; // set the speed (Lower bit)
  UCSR0B |= (1<<RXEN0); // enable receiver
  UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00); // set mode (8N1)
  DDRB |= (1<<PB5); // enable output on pin PB5 (default led on arduino)
  while(1) {
    while(!(UCSR0A&(1<<RXC0))); // wait until a byte is received
    data = UDR0; // read it
    if (data) PORTB |= (1<<PB5); // set the led on
  }
}

Then we open a terminal (9600,8N1) and press several keys, until the led turns off.
Now we burn the first program again and the led is constantly blinking. The reason for this is that watchdog times gets started when we press the keys in terminal. But why and when WDT gets started? How to make so that it will not start?
It should be noted also that we can disable the blinking only with complete poweroff/poweron - only after that the led lights constantly without blinking, as necessary.
This happens on atmega168 and atmega328p, 100% reproducible.
avr-gcc version 4.8.1 avrdude version 6.1
NOTE: bootloader is not used at all.

user2881: WDT settings will remain unchanged, even after a reset. So the timer will keep running and therefore keep resetting the device. Which causes the blinking. Power cycling will clear the WDT settings.
PS I didn't read the code, as uncommented register writes are pretty much unreadable.

user14631: The problem code was reduced to this:
#define F_CPU 16000000UL
#include <avr/io.h>
char data;
void main(void) {
  UBRR0H = 0x00;
  UBRR0L = 0x67; // baud=9600
  UCSR0B = 0x10; // 00010000
  UCSR0C = 0x06; // 00000110
  DDRB |= (1<<PB5);
  PORTB |= (1<<PB5);
  while(1) {
    data = UDR0;
  }
}

This is the code which works:
#define F_CPU 16000000UL
#include <avr/io.h>
void main(void) {
  char data;
  UBRR0H = 0x00;
  UBRR0L = 0x67; // baud=9600
  UCSR0B = 0x10; // 00010000
  UCSR0C = 0x06; // 00000110
  DDRB |= (1<<PB5);
  PORTB |= (1<<PB5);
  while(1) {
    data = UDR0;
  }
}

But I don't know how to explain that char inside main makes the problem disappear...
EDIT
Just for the record, here are two more examples. The first example works with both compilation methods. The second example works only with the second compilation method. The examples differ only with that in the first direct code is used, and in the second it is used via functions.
#define F_CPU 16000000UL
#define BAUD 9600

#include <avr/io.h>
void main(void) {
  char data;
  #include <util/setbaud.h> 
  UBRR0H = UBRRH_VALUE;
  UBRR0L = UBRRL_VALUE;
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);
  UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
  DDRB = (1<<PB5);
  while (1) {
    PORTB ^= (1<<PB5);
    while(!(UCSR0A&(1<<RXC0)));
    data = UDR0;
    UDR0 = data;
    while(!(UCSR0A&(1<<TXC0)));
  }
}

#define F_CPU 16000000UL
#define BAUD 9600

#include <avr/io.h>
void serialSetup(void) {
  #include <util/setbaud.h> 
  UBRR0H = UBRRH_VALUE;
  UBRR0L = UBRRL_VALUE;
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);
  UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
}
void serialSend(char data) {
  UDR0 = data;
  while(!(UCSR0A&(1<<TXC0)));
}
char serialGet(void) {
  while(!(UCSR0A&(1<<RXC0)));
  return UDR0;
}
void main(void) {
  char data;
  serialSetup();
  DDRB = (1<<PB5);
  while (1) {
    PORTB ^= (1<<PB5);
    data = serialGet();
    serialSend(data);
  }
}


user4143: One thing that I found whilst experimenting with command line compilation is that for some strange reason no startup code was being linked with my code, so it all went completely screwy.
I finally tracked the problem down to a missing command line flag while linking.
First, you need to link with avr-gcc not avr-ld.  Second, you need to pass the -mmcu=atmega328p flag to the link command so that it knows which startup code to link in.
This is my complete command line sequence for compiling a simple blink program:
avr-gcc -g -mmcu=atmega328p -ffunction-sections -fdata-sections   -c -o blink.o blink.c
avr-gcc -mmcu=atmega328p -Wl,--gc-sections -o blink.elf blink.o 
avr-objdump -S blink.elf > blink.dis
avr-objcopy -O ihex -R .eeprom blink.elf blink.hex

You notice I'm making function and data sections too, and then garbage collecting the unused ones - good practice since it can very much reduce the size of your finished program.
I am doing this through a Makefile, which looks like this:
PREFIX=avr-
CC=${PREFIX}gcc
CXX=${PREFIX}g++
LD=${PREFIX}ld
AS=${PREFIX}as
OBJCOPY=${PREFIX}objcopy
OBJDUMP=${PREFIX}objdump

BIN=blink
MCU=atmega328p
OBJS=blink.o

CFLAGS=-g -mmcu=${MCU} -ffunction-sections -fdata-sections
CXXFLAGS=-g -mmcu=${MCU} -ffunction-sections -fdata-sections -fno-exceptions
LDFLAGS=-mmcu=${MCU} -Wl,--gc-sections

${BIN}.hex: ${BIN}.elf
    ${OBJCOPY} -O ihex -R .eeprom $< $@

${BIN}.elf: ${OBJS}
    ${CC} ${LDFLAGS} -o $@ $? 
    ${OBJDUMP} -S $@ > ${BIN}.dis

install: ${BIN}.hex
    avrdude -c usbasp -p ${MCU} -U flash:w:${BIN}.hex -qq

clean:
    rm -f *.o *.elf *.hex

fuses:
    avrdude  -c usbasp -p ${MCU} -U lfuse:w:0xff:m -U hfuse:w:0xd6:m -U efuse:w:0x05:m -qq


14631: <p>First we set fuse bits:</p>

<pre><code>avrdude -c usbasp -p atmega328p -U lfuse:w:0xFF:m -U hfuse:w:0xDF:m -U efuse:w:0x07:m # same for atmega168
</code></pre>

<p>In the following examples we use the following commands to compile and burn all the programs:</p>

<pre><code>avr-gcc -Os -mmcu=atmega328p -c -o serial.o serial.c
avr-ld -o serial.elf serial.o
avr-objcopy -O ihex serial.elf serial.hex
avrdude -c usbasp -p atmega328p -U flash:w:serial.hex
</code></pre>

<p>Let us burn the following program:</p>

<pre><code>#define F_CPU 16000000UL
#include &lt;avr/io.h&gt;
void main (void) {
  DDRB |= (1&lt;&lt;PB5);
  PORTB |= (1&lt;&lt;PB5);
  while (1);
}
</code></pre>

<p>It makes the led to be on constantly. And it stays so for infinite period of time.</p>

<p>Then we burn the following program:</p>

<pre><code>#define F_CPU 16000000UL
#define BAUD 9600
#include &lt;avr/io.h&gt;
char data = 0;
void main(void) {
  // Initialize USART:
  #include &lt;util/setbaud.h&gt; 
  UBRR0H = UBRRH_VALUE; // set the speed (Higher bit)
  UBRR0L = UBRRL_VALUE; // set the speed (Lower bit)
  UCSR0B |= (1&lt;&lt;RXEN0); // enable receiver
  UCSR0C |= (1&lt;&lt;UCSZ01)|(1&lt;&lt;UCSZ00); // set mode (8N1)
  DDRB |= (1&lt;&lt;PB5); // enable output on pin PB5 (default led on arduino)
  while(1) {
    while(!(UCSR0A&amp;(1&lt;&lt;RXC0))); // wait until a byte is received
    data = UDR0; // read it
    if (data) PORTB |= (1&lt;&lt;PB5); // set the led on
  }
}
</code></pre>

<p>Then we open a terminal (9600,8N1) and press several keys, until the led turns off.
Now we burn the first program again and the led is constantly blinking. The reason for this is that watchdog times gets started when we press the keys in terminal. But why and when WDT gets started? How to make so that it will not start?</p>

<p>It should be noted also that we can disable the blinking only with complete poweroff/poweron - only after that the led lights constantly without blinking, as necessary.</p>

<p>This happens on atmega168 and atmega328p, 100% reproducible.</p>

<p>avr-gcc version 4.8.1 avrdude version 6.1</p>

<p><strong>NOTE:</strong> bootloader is not used at all.</p>
 2881: <p>WDT settings will remain unchanged, even after a reset. So the timer will keep running and therefore keep resetting the device. Which causes the blinking. Power cycling will clear the WDT settings.</p>

<p>PS I didn't read the code, as uncommented register writes are pretty much unreadable.</p>
 14631: <p>The problem code was reduced to this:</p>

<pre><code>#define F_CPU 16000000UL
#include &lt;avr/io.h&gt;
char data;
void main(void) {
  UBRR0H = 0x00;
  UBRR0L = 0x67; // baud=9600
  UCSR0B = 0x10; // 00010000
  UCSR0C = 0x06; // 00000110
  DDRB |= (1&lt;&lt;PB5);
  PORTB |= (1&lt;&lt;PB5);
  while(1) {
    data = UDR0;
  }
}
</code></pre>

<p>This is the code which works:</p>

<pre><code>#define F_CPU 16000000UL
#include &lt;avr/io.h&gt;
void main(void) {
  char data;
  UBRR0H = 0x00;
  UBRR0L = 0x67; // baud=9600
  UCSR0B = 0x10; // 00010000
  UCSR0C = 0x06; // 00000110
  DDRB |= (1&lt;&lt;PB5);
  PORTB |= (1&lt;&lt;PB5);
  while(1) {
    data = UDR0;
  }
}
</code></pre>

<p>But I don't know how to explain that char inside main makes the problem disappear...</p>

<p><strong>EDIT</strong>
Just for the record, here are two more examples. The first example works with both compilation methods. The second example works only with the second compilation method. The examples differ only with that in the first direct code is used, and in the second it is used via functions.</p>

<pre><code>#define F_CPU 16000000UL
#define BAUD 9600

#include &lt;avr/io.h&gt;
void main(void) {
  char data;
  #include &lt;util/setbaud.h&gt; 
  UBRR0H = UBRRH_VALUE;
  UBRR0L = UBRRL_VALUE;
  UCSR0B = (1&lt;&lt;RXEN0)|(1&lt;&lt;TXEN0);
  UCSR0C = (1&lt;&lt;UCSZ01)|(1&lt;&lt;UCSZ00);
  DDRB = (1&lt;&lt;PB5);
  while (1) {
    PORTB ^= (1&lt;&lt;PB5);
    while(!(UCSR0A&amp;(1&lt;&lt;RXC0)));
    data = UDR0;
    UDR0 = data;
    while(!(UCSR0A&amp;(1&lt;&lt;TXC0)));
  }
}
</code></pre>



<pre><code>#define F_CPU 16000000UL
#define BAUD 9600

#include &lt;avr/io.h&gt;
void serialSetup(void) {
  #include &lt;util/setbaud.h&gt; 
  UBRR0H = UBRRH_VALUE;
  UBRR0L = UBRRL_VALUE;
  UCSR0B = (1&lt;&lt;RXEN0)|(1&lt;&lt;TXEN0);
  UCSR0C = (1&lt;&lt;UCSZ01)|(1&lt;&lt;UCSZ00);
}
void serialSend(char data) {
  UDR0 = data;
  while(!(UCSR0A&amp;(1&lt;&lt;TXC0)));
}
char serialGet(void) {
  while(!(UCSR0A&amp;(1&lt;&lt;RXC0)));
  return UDR0;
}
void main(void) {
  char data;
  serialSetup();
  DDRB = (1&lt;&lt;PB5);
  while (1) {
    PORTB ^= (1&lt;&lt;PB5);
    data = serialGet();
    serialSend(data);
  }
}
</code></pre>
 4143: <p>One thing that I found whilst experimenting with command line compilation is that for some strange reason no startup code was being linked with my code, so it all went completely screwy.</p>

<p>I finally tracked the problem down to a missing command line flag while linking.</p>

<p>First, you need to link with <code>avr-gcc</code> not <code>avr-ld</code>.  Second, you need to pass the <code>-mmcu=atmega328p</code> flag to the link command so that it knows which startup code to link in.</p>

<p>This is my complete command line sequence for compiling a simple blink program:</p>

<pre><code>avr-gcc -g -mmcu=atmega328p -ffunction-sections -fdata-sections   -c -o blink.o blink.c
avr-gcc -mmcu=atmega328p -Wl,--gc-sections -o blink.elf blink.o 
avr-objdump -S blink.elf &gt; blink.dis
avr-objcopy -O ihex -R .eeprom blink.elf blink.hex
</code></pre>

<p>You notice I'm making function and data sections too, and then garbage collecting the unused ones - good practice since it can very much reduce the size of your finished program.</p>

<p>I am doing this through a Makefile, which looks like this:</p>

<pre><code>PREFIX=avr-
CC=${PREFIX}gcc
CXX=${PREFIX}g++
LD=${PREFIX}ld
AS=${PREFIX}as
OBJCOPY=${PREFIX}objcopy
OBJDUMP=${PREFIX}objdump

BIN=blink
MCU=atmega328p
OBJS=blink.o

CFLAGS=-g -mmcu=${MCU} -ffunction-sections -fdata-sections
CXXFLAGS=-g -mmcu=${MCU} -ffunction-sections -fdata-sections -fno-exceptions
LDFLAGS=-mmcu=${MCU} -Wl,--gc-sections

${BIN}.hex: ${BIN}.elf
    ${OBJCOPY} -O ihex -R .eeprom $&lt; $@

${BIN}.elf: ${OBJS}
    ${CC} ${LDFLAGS} -o $@ $? 
    ${OBJDUMP} -S $@ &gt; ${BIN}.dis

install: ${BIN}.hex
    avrdude -c usbasp -p ${MCU} -U flash:w:${BIN}.hex -qq

clean:
    rm -f *.o *.elf *.hex

fuses:
    avrdude  -c usbasp -p ${MCU} -U lfuse:w:0xff:m -U hfuse:w:0xd6:m -U efuse:w:0x05:m -qq
</code></pre>
