Here is a simple program in C:
int main() {
int a = 5;
int b = 7;
int c = a + b;
return 0;
}
If you compile it with gcc -m32 -S -O0 -o main.s main.c
under Linux, you'll get something like this
.file "main.c"
.text
.globl main
.type main, @function
main:
.LFB0:
/* %ebp is a Base Pointer Register */
pushl %ebp
movl %esp, %ebp
/* Here we reserve space for our variables */
subl $16, %esp
/* a's address is %ebp - 4 */
movl $5, -4(%ebp)
/* b's address is %ebp - 8 */
movl $7, -8(%ebp)
/* a + b */
movl -8(%ebp), %eax
movl -4(%ebp), %edx
addl %edx, %eax
/* c's address is %ebp - 12 */
movl %eax, -12(%ebp)
/* return 0 */
movl $0, %eax
leave
ret
As you can see, in this case, variables' addresses are calculated as offsets of a base pointer of a function. If you enable optimisations, variables' values may be stored in registers.