Das kann von vielem kommen. Unter anderem daher, dass der Compiler überhaupt nicht verpflichtet ist, irgendwas auf den Stack zu legen. Er kann die Werte auch alle in Registern halten, wenn ihm danach ist. Und da du var2 überhaupt nicht benutzt, sondern nur initialisierst, ist es sogar wahrscheinlich, dass diese Variable komplett wegoptimiert wird und damit im Programm gar nicht existiert.
Desweiteren ist es dem Compiler natürlich auch freigestellt, die Variablen auf dem Stack zu ordnen, wie er das will. Ob var2 nun über var1 oder darunter liegt, ob es direkt darunter liegt oder 42 Bytes dazwischen frei sind – das kannst du nicht wirklich beeinflussen.
Sehen wir uns den objdump mal an, der bei gcc -m32 rauskommt (mit einem printf statt des prints):
8048405: 66 c7 44 24 16 0a 00 mov WORD PTR [esp+0x16],0xa
804840c: 66 c7 44 24 1e 1e 00 mov WORD PTR [esp+0x1e],0x1e
8048413: 8d 44 24 16 lea eax,[esp+0x16]
8048417: 83 e8 04 sub eax,0x4
804841a: 89 44 24 18 mov DWORD PTR [esp+0x18],eax
804841e: 8b 44 24 18 mov eax,DWORD PTR [esp+0x18]
8048422: 8b 00 mov eax,DWORD PTR [eax]
8048424: 89 44 24 04 mov DWORD PTR [esp+0x4],eax
8048428: c7 04 24 d0 84 04 08 mov DWORD PTR [esp],0x80484d0
804842f: e8 9c fe ff ff call 80482d0 <printf@plt>
Erstmal werden also beide Variablen auf den Stack gelegt, da hast du sogar Glück. var1 liegt an [esp+0x16], var2 an [esp+0x1e]. Also liegt var2 hier mal über var1, dazwischen sind 6 Bytes Platz.
Dann wird die &var1 nach eax geladen, anschließend wird 4 abgezogen („&var1 - 2“ ist dank Pointerarithmetik das gleiche wie „(short *)((uintptr_t)&var1 - 4)“; es entspricht eben „&(&var1)[-2]“). Das heißt, eax zeigt dann auf [esp+12]. Da liegt nichts, also, undefinierte Daten. An 8048422 werden diese Daten dann geladen und im nächsten Befehl für printf bereitgelegt. Bei mir liegt da übrigens 63347.
Dein Problem hier ist also erstens die Pointerarithmetik (vermutlich willst du eher „&var1 - 1“) und zweitens die generelle Tatsache, dass nur der Compiler weiß, wie der Stack tatsächlich aussieht, also was überhaupt draufliegt, und wenn es da ist, wo es ist.
Mit -O3 ist das Ergebnis übrigens noch deutlich kürzer:
8048309: 8b 44 24 1a mov eax,DWORD PTR [esp+0x1a]
804830d: c7 04 24 b0 84 04 08 mov DWORD PTR [esp],0x80484b0
8048314: 89 44 24 04 mov DWORD PTR [esp+0x4],eax
8048318: e8 b3 ff ff ff call 80482d0 <printf@plt>
Hier weiß gcc gleich, dass es vollkommen egal ist, welche Werte var1 und var2 annehmen, weil die eh nie von Belang sind (da du mit der Pointerarithmetik sowieso aus dem Bereich von var1 rausgehst und es wie gesagt nicht definiert ist, ob du so auf var2 landest). Damit liest er einfach den Wert von irgendwo auf dem Stack ([esp+0x1a] deutet darauf hin, dass var1 somit an [esp+0x1e] liegen würde, wenn sein Wert denn relevant wäre) und gibt den aus.