Если не вникать в регистры и тонкости адресации, то переменные хранятся в памяти по определённым адресам. В этом вся их суть.
Имя переменной существует только на уровне языка программирования. Хотя это зависит от языка. В скриптовых языках, например, имя также хранится в памяти, но это уже нюансы. В компилируемом языке имя переменной нужно только для наглядности и понимания логики программы, и во время компиляции это имя превращается в адрес.
Готовая скомпилированная программа (например, exe-шник) выполняется процессором, который ни о каких переменных не в курсе. Для процессора просто есть инструкции по типу записать по такому-то адресу такое-то значение и т.п.
К слову, языки программирования составлены так, чтобы быть удобными и читаемыми для человека. Машине такой формат не очень удобен. Поэтому текст программы переводится в машинный код (либо в байт-код в случае скриптовых языков), и только затем исполняется на более низком уровне. Таким образом, сам язык программирования ничего не делает и не понимает. Это просто набор правил того, как описать свои алгоритмы. Программист пишет программу, потому эту программу скармливает компилятору (или интерпретатору), переводя её в код, и затем уже с кодом работает процессор. Как-то так.
Чтобы реально разобраться, нужно познакомиться с ассемблером. Имхо, очень полезно пройтись по основам ассемблера в начале, чтобы потом уже с пониманием подойти к изучению более высокоуровневых языков программирования.