O conceito de “variáveis locais”, como estamos habituados em linguagens de programação de mais alto nível, não tem equivalência direta em assembly.
IMPORTANTE: Todos os códigos em assembly compartilhados nessa série omitem verificações e, para fins de simplicidade, não estão otimizados.
Na prática, o desafio é determinar, dentre as alternativas disponíveis, a forma mais eficiente para armazenar e recuperar, de alguma forma, dados na memória tornando-os acessíveis para processamento pelo código. Escolhas infelizes geralmente implicam em performance mais pobre.
#include <iostream>
int summarize(const int value)
{
	auto result = 0;
	for (auto i = 1; i <= value; i++)
	{
		result += i;
	}
	return result;
}
int main() {
	std::cout << "summarize(10) = " << summarize(10) << std::endl;
}
O mais eficiente costuma ser utilizar os registradores do processador. Embora eles tenham pouca capacidade, estão montados fisicamente junto ao processador o que torna sua velocidade de acesso imbatível.
Os compiladores geralmente utilizam os registradores para, por exemplo, armazenar valores de contadores e acumuladores em loops.
	.model flat,c
        .code
summarize_ proc
	push ebp
	mov ebp, esp
	push ebx
	xor eax, eax    ; result = 0;
	mov ebx, 1
	mov ecx,[ebp+8] ; ecx = value
	jmp check_for_is_complete
for_body:
        add eax, ebx
	inc ebx
check_for_is_complete:
	cmp ebx, ecx
	jg finish
	jmp for_body
finish:
	pop ebx
	pop ebp
	ret
summarize_ endp
	end 
Importante que lembremos que os registradores que utilizamos em nossas funções são os mesmos disponíveis para todo o código. Dependendo da convenção adotada, alguns registradores podem ser voláteis ou não-voláteis. Registradores não-voláteis devem ter seu valor restaurado sempre antes da função retornar (como ebx e ebp no exemplo). Registradores voláteis podem ter seus valores modificados livremente.
Outra alternativa comum é alocar espaço na stack para acomodar o valor das variáveis.
#include <iostream>
int summarize(const int a, const int b)
{
	const auto max = (a > b) ? a : b;
	const auto min = (a < b) ? a : b;
	return (max * (max + 1) - (min - 1) * min) / 2;
}
int main() {
	std::cout << "summarize(10) = " << summarize(100, 1) << std::endl;
}
Quando utilizamos a stack para armazenar os valores de variáveis locais, é comum “reservar” espaço logo no início da função (trecho de código conhecido como prólogo) e garantir que o espaço alocado seja liberado no final da função (trecho de código conhecido como epílogo).

A prática comum é colocar os valores das variáveis locais logo após o registrador ebp. Dessa forma, parâmetros para as funções são acessados com deslocamentos positivos e variáveis são acessadas com deslocamentos negativos.
	.model flat,c
        .code
summarize_ proc
	push ebp
	mov ebp, esp
	sub esp, 8		; allocating space on the stack for two integers
	
	mov eax,[ebp+8]		; eax = 'a'
        mov ecx,[ebp+12]	; ecx = 'b'
	cmp eax, ecx
	jle aIsMax
	mov [ebp - 8], eax	; max = a
	jmp resume_1
aIsMax:
	mov [ebp - 8], ecx	; max = b
resume_1:
	cmp eax, ecx
	jge aIsMin
	mov [ebp - 4], eax	; min = a
	jmp resume_2
aIsMin:
	mov [ebp - 4], ecx	; min = b
resume_2: 
	mov eax, [ebp - 8]  ; eax = max
	add eax, 1
	imul eax, [ebp - 8]
	mov ecx, [ebp - 4]  ; ecx = min
	sub ecx, 1
	imul ecx, [ebp - 4]
	sub eax, ecx
	cdq
	sar eax, 1
	mov esp, ebp  ; releasing local storage space
	pop ebp
	ret
summarize_ endp
	end 
Obviamente, nada disso é relevante quando estamos escrevendo código em Java, C++ ou C#. Por sorte, os compiladores fazem um ótimo trabalho escondendo esses “detalhes” do nosso dia a dia.
Objetos complexos, armazenados na heap, tem apenas seus endereço armazenado localmente (também em registradores ou na stack).
 
								