Registros de Ativação

Propaganda
Gerenciamento de Memória
Geração de Código
(Registros de Ativação)
Compiladores II
A memória é afetada pelo compilador e/ou
código fonte:
Código objeto gerado
Espaço para variáveis globais
Ativação de procedimentos
Alocação dinâmica
Von Neumann
dados/código na mesma memória
Código objeto
Fluxo de controle
if-else, while, for, switch
expressões, atribuições
parte da operação de chamada de funções
Espaço para globais
Reserva de espaço em segmento de
dados (DS no 8086)
Declaração de atributos de classe ou
instância (JVM)
1
Alocação dinâmica
Com (des)alocação explícita
malloc, sbrk, free
Sem controle explícito
Linguagens funcionais
Java
Necessita coleta de lixo (garbage collection)
Registros de Ativação
Funções em Ling. Prog. imperativas possuem variáveis
locais
Criadas no inicio da função
Destruídas quando a função acaba
Cada chamada (invocação) de uma função tem sua
instância própria de variáveis locais.
Chamadas recursivas forçam a existência simultânea de várias
instâncias
As funções retornam apenas depois do término de todas as
funções chamadas por ela, ou seja, um comportamento last-infirst-out (LIFO).
A pilha do sistema é a estrutura LIFO usada para guardar todas
as instanciações
A parte da pilha utilizada na chamada de uma função é
denominada stack frame ou registro de ativação
(activation record).
Pilha do sistema
Usada para armazenar variáveis locais de todas
as instâncias
Em geral, implementada como um array estático
(muito grande) e crescendo para as posições
iniciais da memória.
Push(r1)
Stack_pointer - -;
M[stack_pointer]=r1;
r1=Pop();
r1 = M[stack_pointer];
stack_pointer++;
Registro de ativação e pilha do sistema
Os registros de ativação são estruturas
complexas, pop/push não são suficientes
O stack frame é normalmente indexado à
uma posição da pilha e tratado como um
array
Assim, podemos fazer um push/pop de
todo registro de ativação
2
Registro de ativação e pilha do sistema
Ex. 8086 e família:
bp, sp (ebp,esp)
Frame Pointer é
chamado pela intel
de Base Pointer
Exemplo
Suponha que f(a1,a2) chama g(b1,b2,b3)
Originalmente temos para f
Registro de ativação e pilha do sistema
“Macro” pop/push
Guardar e restaurar o bp, base registro
ativação, também chamado de
push bp, [bp-sp]
pop bp, [bp+1]
Exemplo
Os argumentos de g são empilhados
(ainda no stack frame de f)
3
Exemplo
Cria-se o registro de g
Organização do registro
O compilador pode utilizar qualquer
esquema que lhe convier
Os fabricantes de CPU (ou SO) fornecem
padrões ou esquemas para os
compiladores
Calling conventions
Se todos compiladores utilizarem o mesmo
esquema, as funcões de um podem ser
utilizadas pelo outro
Essencial para utilização de bibliotecas do SO
Passagem de Parâmetros
Registradores são mais rápidos do que
memória
O compilador deve usar os registradores o
máximo possível
Ao invés de emplihar a1,a2,..,an, colocar
a1,a2 ,a3,a4 em registradores e a5,a6 ,.., an
na pilha
Registro de ativação
Registradores
Alguns parâmetros
Valor de retorno
Variáveis locais
Temporários
Stack frame
Variáveis passadas por referência
Variáveis de rotinas aninhadas
Variáveis cujo valor é muito grande (e.g.double)
Variáveis do tipo array
4
Registro de ativação
Em geral, o compilador inicialmente atribui
uma variável ao stack frame
Se possível passa a variável p/ registrador
Register allocation
Processo de atribuição de variáveis à
registradores
Calling convention
Quem salva os registradores:
• Função Chamadora
• Função Chamada
Buffer overflow attack
O stack parace da seguinte forma quando
myFunction é chamada:
Buffer overflow attack
Explora um problema comum em
linguagens (ou suas implementações)
Sem teste de limites para acceso em
arrays
void myFunction(char *str) {
void main(){
char bufferB[16];
char bufferA[256];
}
}
Buffer overflow attack
Como existem, potencialmente, 256 bytes
a serem copiados em bufferA
Previous
stack content
Previous
stack content
bufferA
bufferA
Return address
Return address
OS data
bufferB
OS data
16 bytes
strcpy(bufferB, str);
myFunction(bufferA);
256 bytes
bufferB
5
Buffer overflow attack
Se bem escolhido, o valor que será escrito no
endereço de retorno pode levar a execução de
um código mal intencionado
Pode, por exemplo, executar iniciar um shell
com parâmetro indicando um programa
e.g, sh /home/user/bad-guy/kidnap-code
Em geral, programas executando em root
O código a ser executado normalmente já está
no sistema
Buffer overflow attack
O endereço de retorno normalmente aponta
para dentro da área utilizada na chamada da
função explorad
Previous
stack content
bufferA
Return address
OS data
256 bytes
bufferB
Buffer overflow attack
Possíveis soluções
Checar limite de accesso em arrays
Tornar buffers não-executáveis
Incluir um “canary” em uma posição stack
próxima ao endereço de retorno
Antes de retornar, este valor é verificado. Se for
inválido, o programa aborta
Pode ser um checksum de um valor com um
endereço de retorno, ou seja, preservar esta palavra
e alterar o endereço de retorno também não ajuda
6
Download