Das Beispiel von oben hab ich mal durchdebuggt. Es geht so, wie man sich das vorstellt. Die Funktionen werden richtig aufgerufen, Stack richtig aufgebaut/abgebaut und Argumente korrekt übergeben.
Der String steht danach dort, wo er soll, und das Programm kehrt friedlich zurück nach main.

Das lcd_gotoxy und lcd_write hab ich rausgeworfen (hab ich net).

Also ist der Fehler dort, oder der Wurm ist wirklich beim Speicherverbrauch oder im Rest deines Programms.

Das kleine Progrämmchen (nur main, foo, lcd_printf_xy_p und die Lib-Funcs) brauchen mit -O2 schon über 0x700 (Dez ca. 1800) Bytes an Flash!!!
vsprintf scheint ca 60 Bytes an SRAM zu brauchen.

Check mal durch, ob das wirklich alles reinpasst bei dir.