Software Básico - Bruno Müller

125
CI064 - Software Básico Bruno Müller Junior 12 de Março de 2012

description

Software Básico - Bruno Müller

Transcript of Software Básico - Bruno Müller

  • CI064 - Software Bsico

    Bruno Mller Junior

    12 de Maro de 2012

  • 2

  • Prefcio

    Como professor do departamento de informtica da UFPR, ministrei vrias discipli-nas na rea de sistemas, como Construo de Compiladores, Sistemas Operacionais,Arquitetura de Computadores e Circuitos Lgicos.

    Uma caracterstica comum a estas disciplinas a dificuldade de expor todo o con-tedo no nmero de horas destinado a cada uma.

    Observei que alguns tpicos destas disciplinas exigem conhecimentos prvios dosalunos, conhecimentos que no so apresentados formalmente. Exemplos incluem cha-madas ao sistema1, chamadas a procedimentos, uso da heap, uso de registradores e me-mria, execuo dos programas. Alm disto, programas de transformao de formatosde arquivos, com montadores, ligadores, compiladores e carregadores, assim como osseus formatos, tambm no so abordados.

    Por esta razo, o professor de cada disciplina se v obrigado a ministrar estes con-ceitos, utilizando um tempo precioso do curso, e apresentando somente uma visodaqueles conceitos de acordo com o enfoque daquela disciplina.

    Como resultado, aqueles conceitos so fragmentados em partes que nem sempreso consistentes nas cabeas dos alunos.

    Para ensinar estes conceitos de uma forma mais consistente, o departamento de in-formtica da UFPR criou a disciplina Software Bsico. Esta disciplina foi ministradapor mim por vrios anos, e este livro a compilao das minhas notas de aula.

    A disciplina aborda a camada de software mais prxima ao hardware, e explicaconceitos que so implementados parcialmente no hardware e como isto usado emsofware.

    Para tal, usa-se a linguagem assembly para desenvolver aplicativos. Esta linguagemno padronizada: cada CPU tem o seu conjunto de instrues, e uma linguagemparticular teria de ser escolhida. A nossa opo foi o assembly dos processadores dafamlia x86 (para 32 bits), uma vez que a maior parte do parque computacional dodepartamento de informtica da UFPR composto por computadores com esta CPU.

    Para uma viso mais completa, o livro tambm explica o que so programas execu-tveis, interpretados, emuladores, alm de biblitecas estticas, compartilhadas e din-micas.

    Desde que esta disciplina foi implantada, o tempo dispendido nas demais discipli-nas de sistemas foi diminudo (o que no quer dizer que sobra tempo), e seu nvel deaprendizado dos alunos mostrou-se mais consistente.

    1system calls

    3

  • 4Organizao do LivroO livro est organizado em duas partes:

    Primeira Parte: Linguagem assembly da famlia x86. A linguagem assembly uti-lizada para exemplificar alguns dos conceitos de linguagens de programao,de sistemas operacionais e de arquitetura de computadores como, por exemplo,uso de registradores, memria, interrupes, chamadas ao sistema e de procedi-mento. As ferramentas (software) que utilizei so: so:

    as (montador assembly do gnu) ald ( assembly language debugger)

    Uma opo ao ald o gdb (gnu debugger)Segunda Parte: software de base (compiladores, ligadores, montadores e carregado-

    res), os formatos intermedirios dos arquivos que eles geram (arquivos objeto,arquivos executveis, arquivos fonte).

  • Contedo

    I Traduo e Execuo de Programas 9

    1 A Seo de Cdigo e de Dados 151.1 Esqueleto de programas em assembly . . . . . . . . . . . . . . . . . 161.2 Expresses Aritmticas . . . . . . . . . . . . . . . . . . . . . . . . . 191.3 Comandos Repetitivos . . . . . . . . . . . . . . . . . . . . . . . . . 221.4 Traduo da construo While . . . . . . . . . . . . . . . . . . . . . 251.5 Comandos Condicionais . . . . . . . . . . . . . . . . . . . . . . . . 271.6 Vetores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 301.7 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30

    2 A Seo da Pilha 332.1 Modelo de Chamadas de Procedimento . . . . . . . . . . . . . . . . 332.2 Implementao do Modelo em Uma Arquitetura . . . . . . . . . . . . 34

    2.2.1 Sem Parmetros e sem Variveis Locais . . . . . . . . . . . . 352.2.2 Sem Parmetros e com Variveis Locais . . . . . . . . . . . . 372.2.3 Com Parmetros e com Variveis Locais . . . . . . . . . . . . 392.2.4 Parmetros passados por Referncia e com Variveis Locais . 392.2.5 A funo main da linguagem C . . . . . . . . . . . . . . . . 412.2.6 Chamadas Recursivas . . . . . . . . . . . . . . . . . . . . . 442.2.7 Uso de Bibliotecas . . . . . . . . . . . . . . . . . . . . . . . 48

    2.3 Aspetos de Segurana . . . . . . . . . . . . . . . . . . . . . . . . . . 48

    3 Chamadas de Sistema 513.1 A analogia do parquinho . . . . . . . . . . . . . . . . . . . . . . . . 513.2 Acrescentando a CPU . . . . . . . . . . . . . . . . . . . . . . . . . . 523.3 Acresentando perifricos e dispositivos de hardware . . . . . . . . . . 533.4 Interrupes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54

    3.4.1 Interrupo de Hardware . . . . . . . . . . . . . . . . . . . . 543.4.1.1 Registrando o driver . . . . . . . . . . . . . . . . . 543.4.1.2 Disparando o driver correto . . . . . . . . . . . . . 553.4.1.3 Exemplo . . . . . . . . . . . . . . . . . . . . . . . 56

    3.4.2 Interrupo de Sofware . . . . . . . . . . . . . . . . . . . . . 563.5 Os drivers nativos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 573.6 Questes de segurana . . . . . . . . . . . . . . . . . . . . . . . . . 57

    5

  • 6 CONTEDO

    3.7 As chamadas ao sistema no Linux . . . . . . . . . . . . . . . . . . . 593.7.1 Conjunto de servios . . . . . . . . . . . . . . . . . . . . . . 59

    4 A Seo BSS 614.1 Heap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 654.2 Exerccios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66

    II Software Bsicos 67

    5 Software Bsicos 71

    6 Formatos de Programa 756.1 Linguagem de alto nvel . . . . . . . . . . . . . . . . . . . . . . . . 756.2 Linguagem assembly . . . . . . . . . . . . . . . . . . . . . . . . . . 766.3 Linguagem de Mquina . . . . . . . . . . . . . . . . . . . . . . . . . 78

    6.3.1 Linguagem de Mquina - Arquivo executvel . . . . . . . . . 786.3.2 Linguagem de Mquina - Arquivo objeto . . . . . . . . . . . 79

    6.3.2.1 Bibliotecas . . . . . . . . . . . . . . . . . . . . . . 806.3.2.2 Bibliotecas Estticas . . . . . . . . . . . . . . . . . 806.3.2.3 Bibliotecas Compartilhadas . . . . . . . . . . . . . 826.3.2.4 Bibliotecas Dinmicas . . . . . . . . . . . . . . . . 83

    6.4 O Programa Ligador . . . . . . . . . . . . . . . . . . . . . . . . . . 866.4.1 Arquivos objeto com um nico segmento . . . . . . . . . . . 866.4.2 Arquivos objeto com mais de um segmento . . . . . . . . . . 906.4.3 Detalhes Importantes . . . . . . . . . . . . . . . . . . . . . . 906.4.4 Exemplo Prtico . . . . . . . . . . . . . . . . . . . . . . . . 916.4.5 Ligadores para objetos compartilhados . . . . . . . . . . . . 956.4.6 Ligadores para objetos dinmicos . . . . . . . . . . . . . . . 96

    6.5 O Programa Carregador . . . . . . . . . . . . . . . . . . . . . . . . . 976.5.1 Carregadores que copiam os programas em memria fsica sem

    relocao . . . . . . . . . . . . . . . . . . . . . . . . . . . . 976.5.2 Carregadores que copiam os programas em memria fsica com

    relocao . . . . . . . . . . . . . . . . . . . . . . . . . . . . 996.5.3 Carregadores que copiam os programas em memria virtual . 99

    6.5.3.1 Executveis com Bibliotecas Estticas . . . . . . . 1006.5.3.2 Executveis com Bibliotecas Compartilhadas . . . . 1006.5.3.3 Executveis com Bibliotecas Dinmicas . . . . . . 101

    6.5.4 Emuladores e Interpretadores. . . . . . . . . . . . . . . . . . 1016.5.4.1 Emuladores . . . . . . . . . . . . . . . . . . . . . 1016.5.4.2 Interpretadores . . . . . . . . . . . . . . . . . . . . 102

    A Formatos de Instruo 105A.1 Modos de Endereamento . . . . . . . . . . . . . . . . . . . . . . . . 106A.2 Registrador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106A.3 Imediato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107

  • CONTEDO 7

    A.4 Endereamento Direto . . . . . . . . . . . . . . . . . . . . . . . . . 107A.5 Endereamento Indireto . . . . . . . . . . . . . . . . . . . . . . . . . 108A.6 Endereamento Indexado . . . . . . . . . . . . . . . . . . . . . . . . 108

    B MMX 111B.1 Como verificar a presena do MMX . . . . . . . . . . . . . . . . . . 111B.2 Exemplo de aplicao paralela . . . . . . . . . . . . . . . . . . . . . 112

    C Memria Virtual 115C.1 Overlay . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115C.2 Paginao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116

    C.2.1 MMU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121

  • 8 CONTEDO

  • Parte I

    Traduo e Execuo deProgramas

    9

  • 11

    Nesta parte do livro ser descrito o que acontece ao longo do tempo de vida de umprocesso2, ou seja, desde que ele inicia sua execuo at ele terminar ou ser cancelado.

    A forma de execuo de um programa depende fundamentalmente do processador edo sistema operacional adotado. Como existem vrios processadores e vrios sistemasoperacionais, uma combinao deles foi adotada e todos os exemplos utilizados seguemesta combinao.

    Como processador foi escolhida a famlia de processadores x86 para 32 bits, tam-bm conhecido como IA32. Grande parte dos computadores disponveis comercial-mente utlizam este processador, o que garante maior facilidade para reproduzir a exe-cuo dos programas descritos no livro.

    Como sistema operacional foi escolhido o linux. Esta escolha se deve a vriosfatores, dos quais destacamos:

    1. o cdigo fonte do sistema operacional pode ser obtido e estudado;

    2. o formato dos arquivos objeto e executveis, assim como o modelo de execuo livre e bem documentado (formato ELF3).

    A execuo de programas ser analisada em um nvel prximo CPU, e por estarazo, os programas usados para apresentar o modelo de execuo foram desenvolvidosem linguagem assembly. O assembly utilizado em todos os exemplos do livro foramcodificados, montados e ligados em um sistema operacional linux 2.6.38, distribuioubuntu 11.04.

    O sistema operacional linux apresenta tambm algumas vantagens didticas, umavez que um programa em execuo recebe uma grande quantidade de memria virtual(4 gigabytes para mquinas de 32 bits), onde os endereos no variam de uma execuopara outra.

    A forma de mapear os endereos da memria virtual para a memria fsica docomputador ocorre atravs de um mecanismo chamado paginao.

    A figura 1 mostra um programa em execuo em memria (virtual). Observe queo programa em execuo composto por vrias partes (chamadas sees): seo text,data, bss, stack, e reas de uso exclusivo do sistema operacional.

    A partir da figura, possvel ver que um programa em execuo recebe 4 Gigaby-tes de memria virtual para trabalhar. Nem toda esta memria pode ser acessada li-vremente pelo processo, como por exemplo o espao na parte de baixo, e o espao naparte de cima:

    0x00000000 e 0x08048000 ((134.512.640)10 bytes, um pouco mais de 128Mby-tes;

    0xBFFFFFFF e 0xFFFFFFFF ((1.073.741.824)10 bytes, ou 1Gbytes).

    Com isso, do espao virtual de 4Gbytes citado acima, cada programa pode usar, naprtica, um pouco menor, um pouco menos de 3Gbytes.

    2processo o termo usado para referenciar um programa em execuo.3Executable and Linkable Format

  • 12

    Figura 1: Programa em execuo na memria virtual (formato ELF)

    Alm destas duas reas, o processo tambm no pode acessar a rea entre a seobss e a stack. Se o processo tentar acessar qualquer destas trs reas, o programaser cancelado por tentativa de acesso a endereo invlido, resultando na simpticamensagem Segmentation Fault.

    Cada seo ser abordada em captulos diferentes do livro. O captulo 1 descrevea seo de cdigo (text), e de dados globais (data). O captulo 2 descreve como oprograma em execuo utiliza a pilha para implementar chamadas de procedimento,assim como alocar espao para parmetros e variveis locais. O captulo 4 descrevecomo alocar espao para variveis dinmicas. Por fim, o captulo 3 descreve como oprocesso pode acessar recursos (como por exemplo arquivos) que no esto em suarea de endereamento virtual utilizando chamadas de sistema.

    O mtodo de apresentao baseia-se na traduo de pequenos programas que estona linguagem C para programas assembly dos IA32 com funcionalidade equivalenteaos programas em C.

    importante destacar os termos com funcionalidade equivalente. Isto significadizer que o programa assembly produzir os mesmos resultados que o programa Cgeraria, porm no obrigatoriamente com os mesmos comandos, e nem com os mesmosendereos de variveis. Alm disso, se o programa em C for compilado, o cdigogerado pode apresentar diferenas significativas.

    Programas assembly so programas com muitas linhas de cdigo, e quase sempredifceis de serem compreendidos por seres humanos (ou pelo menos pela maioria de-les). Este livro no tem a inteno de ensinar a linguagem assembly, e os exemplos soapresentados unicamente para descrever o que ocorre durante a execuo de programas.

    Por esta razo, no objetivo do livro entrar em muitos detalhes e muito menosde apresentar o conjunto completo de instrues contido na famlia IA324. Ser des-

    4o que seria desumano, pois existem algumas centenas de instrues com formato de tamanhos diferentes.

  • 13

    crito somente um subconjunto mnimo de instrues para os fins propostos pelo livro.Este subconjunto exclui vrias instrues e formatos de instruo, sendo que algunsprogramas so mais longos do que poderiam ser.

    Este subconjunto no apresentado de uma vez, mas sim de forma incremental.Cada exemplo inclui alugumas instrues ao conjunto apresentado at aquele mo-mento, seguindo o modelo de [Kow83].

  • 14

  • Captulo 1

    A Seo de Cdigo e de Dados

    Este captulo descreve a seo do programa em execuo que contm as instruesdo programa, chamada de seo de texto ou text. Incidentalmente tambm descreve aalocao de variveis globais (seo de dados ou data), finalizando com vetores.

    A parte do programa em execuo abordado por este captulo est destacado nafigura 1.1. Esta figura representa a rea virtual de um programa em execuo, e algunsdetalhes devem ser destacados:

    Como este livro baseia-se em mquinas de 32 bits, o espao de endereamentovai do endereo 0x00000000 (em baixo) at o endereo0xFFFFFFFF (emcima). So 4 giga bytes.

    a rea de cdigo comea no endereo virtual 0x08048000, e as instrues socopiadas do arquivo executvel para esta rea.

    a rea de dados comea logo acima da rea de cdigo. O incio desta seono fixo como a rea de cdigo, e depende do tamanho desta. Quanto maioro tamanho da rea de cdigo, mais alto ser o endereo de incio da seo dedados.

    O captulo est organizado da seguinte forma: a seo 1.1 apresenta o modelo deum programa em assembly, um esqueleto de programa assembly. Este esqueleto recheado nas sees seguintes. A seo 1.2 descreve como traduzir expressesaritmticas utilizando variveis globais. A seo 1.3 apresenta o funcionamento de co-mandos de desvio de fluxo em linguagem assembly, enquanto que a seo 1.4 mostracomo traduzir comandos do tipo while. A seo 1.5 descreve como traduzir coman-dos condicionais do tipo if-then e if-then-else). Para finalizar, a seo 1.6contm um exemplo que combina comandos repetitivos e condicionais que trabalhamsobre vetores em assembly.

    15

  • 16 CAPTULO 1. A SEO DE CDIGO E DE DADOS

    Figura 1.1: Programa em execuo na memria virtual - rea de texto e dados globais(formato ELF)

    1.1 Esqueleto de programas em assemblyEste captulo apresenta um programa escrito em linguagem C, semelhante ao algo-ritmo 35), cuja nica funo terminar graciosamente. O programa tem poucos co-mandos, e o objetivo mostrar o esqueleto de um programa traduzido de C para as-sembly, e posteriormente alguns aspectos da execuo de programas. A traduo doalgoritmo 1 apresentada em 2.

    main ( int argc, char** argv);1{2

    return 13;3}4

    Algoritmo 1: Arquivo prog1.c

    No algoritmo 1, o nico comando o da linha 3, return 13. Este comandofinaliza o programa, e retorna o nmero 13, que pode ser visto atravs do comandoecho $? digitado no terminal.

    A traduo acima no literal, uma vez que o main uma funo e deveria ter sidotraduzida como tal (como ser visto no captulo sobre traduo de funes). Porm, uma traduo vlida, uma vez que a funcionalidade do programa assembly equivale funcionalidade do programa em C.

    Programas em assembly so divididos em sees, e o programa traduzido contmduas sees. A seo .data contm as variveis globais do programa (como este pro-grama no usa variveis globais, esta seo est vazia) enquanto que a seo .textcontm os comandos a serem executados quando o programa for colocado em execu-

  • 1.1. ESQUELETO DE PROGRAMAS EM ASSEMBLY 17

    .section .data1

    .section .text2

    .globl _start3_start:4

    movl $1, %eax5movl $13, %ebx6int $0x807

    Algoritmo 2: Arquivo prog1.s

    o.A linha 4 do algoritmo 2 contm um rtulo, ou seja, um nome associado a um

    endereo. Na sintaxe do assembly que estamos usando (como em vrios outros), ortulo sempre um conjunto de caracteres e letras terminadas por dois pontos ( :).

    O rtulo _start especial e deve sempre estar presente. Ele corresponde aoendereo da primeira instruo do programa que ser executada, e deve ser declaradacomo global (linha 3). As demais instrues sero executadas na seqncia.

    Os comandos necessrios para gerar o arquivo executvel esto descritos a seguir:

    > as prog1.s -o prog1.o> ld prog1.o -o prog1> ./prog1> echo \$?13

    A execuo no mostra o que ocorre durante a execuo. Para tal, utilizaremoso programa ald (assembly language debugger), para executar o programa, passo apasso1

    Considere a figura ??. Esta figura mostra esquematicamente um computador. Ostrs blocos correspondem CPU, memria e dispositivos perifricos de I/O. Estes trsblocos esto ligados pelo barramento, que usado para a comunicao destes trs blo-cos.

    Para simplificar as coisas, considere que a memria contm o processo em execu-o, e s ele.

    A execuo do programa que est na memria envolve um ciclo:

    1. busca da prxima instruo. A CPU indica qual o endereo da memria quecontm a prxima instruo a ser executada. A memria retorna o contedodaquela posio de memria, ou seja, a instruo.

    2. decodificao da instruo. Ao chegar na CPU, a instruo est em um formatobinrio, e a CPU deve descobrir qual a instruo presente. Este processo chamado de decodificao de instruo.

    3. execuo da instruo. A CPU executa a instruo.1Tambm pode ser usado o gdb (gnu debugger), que muito mais poderoso e com muitas funcionali-

    dades a mais. Tantas que podem desviar o foco do leitor.

  • 18 CAPTULO 1. A SEO DE CDIGO E DE DADOS

    Os dois primeiros passos do ciclo implicam em usar o barramento para que a CPUe a memria possam se comunicar.

    Dentro da CPU existem estruturas de armazenamento de dados chamados registra-dores. A quantidade, tamanho e nome dos registradores so particulares de cada CPU.Alguns registradores so de propsito geral (podem ser usados livremente) e outros sode propsito especfico.

    No caso dos processadores da famlia IA32, os principais registradores de propsitogeral so: eax, ebx, ecx e edx. Alguns dos registradores de propsito especfico soeip (contm o endereo da prxima instruo), esp (contm o endereo do topo dapilha) e ebp (auxiliar para acesso aos registros de ativao.

    Existem vrios outros registradores, porm para manter um enfoque minimalista,este livro s ir trabalhar com estes.

    Para ver o ciclo de execuo de instrues em ao, deve-se usar o simulador ald.O primeiro passo , na linha de prompt, digitar ald, e depois das mensagens inici-ais digitar load prog1. Isto far com que o programa indicado seja colocado namemria para iniciar a simulao da execuo.

    A primeira instruo est para ser executada, porm o simulador no a mostra. Paravisualiz, necessrio indicar um ponto de parada (breakpoint). A sequncia abaixoindica o resultado que eu obtive:

    > ald> Assembly Language Debugger 0.1.5aCopyright (C) 2000-2003 Patrick Alken

    ald> load "prog1"prog1: ELF Intel 80386 (32 bit), LSB - little endian, Executable, Version 1 (Current)ald> stepeax = 0x00000001 ebx = 0x00000000 ecx = 0x00000000 edx = 0x00000000esp = 0xFF864DF0 ebp = 0x00000000 esi = 0x00000000 edi = 0x00000000ds = 0x0000002B es = 0x0000002B fs = 0x00000000 gs = 0x00000000ss = 0x0000002B cs = 0x00000023 eip = 0x08048059 eflags = 0x00000202

    Flags: IF

    08048059 BB0D000000 mov ebx, 0xdald>

    Comandos executados dentro do ald:

    load prog1: carrega o arquivo executvel prog1 para o simulador.

    step: executa uma nica instruo. Esta instruo ser aquela contida no ende-reo do rtulo _start.

    Aps o step, a instruo executada (movl $1, %eax), que copia a constante$1, para dentro de %eax (veja o valor de %eax aps o step).

    Observe que aps o step, o valor de todos os registradores so impressos (eax,ebx, ecx, edx, esp, ebp, esi, edi, ds, es, fs, gs, ss, cs,eip, eflags).

    Vamos usar a prxima instruo para mostrar o ciclo de execuo:

  • 1.2. EXPRESSES ARITMTICAS 19

    Busca de instruo a prxima instruo est indicada na ltima linha 08048059BB0D000000 mov ebx, 0xd2. O primeiro campo indica o endereo daprxima instruo. o mesmo valor que est contido em %eip. O segundocampo indica o padro binrio daquela instruo, e o terceiro campo indica ainstruo assembly contida naquele padro binrio. normalmente aqui que o%eip alterado para apontar para a prxima instruo.

    Decodificao da instruo O padro binrio citado acima (que neste exemplo BB0D000000) que contm a instruo a ser executada. Dentro deste padro esto contidas asinformaes sobre o que deve ser executado (copiar uma constante para o re-gistrador), qual a constante (0xd16 = 1010) a ser copiada e qual o registradordestino %ebx.

    Execuo A instruo executada.

    Cada vez que se digita step no simulador, este ciclo se repete, e as instrues doprograma so executadas uma a uma.

    Um comando importante do ald o examine. Este comando imprime o con-tedo da memria virtual do processo a partir do endereo indicado.

    Como exemplo, considere o comanod examine 0x08048059 (valor correntede %eip). A impresso que obtive mostrada abaixo:...

    ald> examine 0x08048059Dumping 64 bytes of memory starting at 0x08048059 in hex08048059: BB 0D 00 00 00 CD 80 00 2E 73 79 6D 74 61 62 00 .........symtab.08048069: 2E 73 74 72 74 61 62 00 2E 73 68 73 74 72 74 61 .strtab..shstrta08048079: 62 00 2E 74 65 78 74 00 00 00 00 00 00 00 00 00 b..text.........08048089: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

    Este endereo inicia com os valores hexadecimais 0xBB 0D 00 00, que corres-ponde exatamente ao padro hexadecimal da instruo movl 10, %ebx.

    Como este livro mostra o que ocorre em tempo de execuo, em especial na espaovirtual de endereamento, o comando examine passa a ser muito til.

    1.2 Expresses AritmticasEsta seo mostra como traduzir para assembly os programas escritos em linguagem Cque contm somente expresses aritmticas que usam variveis globais.

    O algoritmo 3 um programa em linguagem C que utiliza duas variveis globais (ae b). Estas variveis so somadas e o resultado colocado para o usurio (na varivelde ambiente $? do shell).

    2Observe que a ordem dos parmetros est invertida quando comparada com o programa. Isto ocorreporque h dois tipos de formado de programas assembly para os IA32: o formato Intel e o formato AT&T. Oprograma foi escrito obedecendo o formato AT&T (prprio para o montador as, desenvolvido pelo mesmogrupo que implementou o programa gcc (gnu), enquanto que o ald apresenta comandos no formato Intel.Ambos os formatos so equivalentes, e a maior diferena entre eles a ordem dos parmetros. Os programasque apresentaremos neste texto esto sempre no formato AT&T.)

  • 20 CAPTULO 1. A SEO DE CDIGO E DE DADOS

    int a, b;1main ( int argc, char** argv);2

    {3a=6;4b=7;5a = a+b;6return a;7

    }8Algoritmo 3: Arquivo prog2.c

    .section .data1a: .int 02b: .int 03

    .section .text4

    .globl _start5_start:6

    movl $6, a7movl $7, b8movl a, %eax9movl b, %ebx10addl %eax, %ebx11movl $1, %eax12int $0x8013

    Algoritmo 4: Arquivo prog2.s

  • 1.2. EXPRESSES ARITMTICAS 21

    O algoritmo 4 corresponde ao programa assembly equivalente ao programa C doalgoritmo 3.

    O primeiro aspecto a ser levantado como as variveis globais a e b foramdeclaradas no programa assembly (linhas 2 e 3 do algoritmo 4, ou seja, como rtulos(veja a definio de rtulo na pgina 17).

    Estes dois rtulos foram declarados na seo .data. Quando o programa for co-locado em execuo, sero reservados dois espaos de inteiro (para isto o .int daslinhas 2 e 3 do algoritmo 4). O parmetro que vem aps o .int indica o valor inicialda varivel, que no caso zero.

    Para deixar este ponto mais claro, vamos verificar como o programa ser executado.Aps montar e ligar o programa, obteremos o arquivo executvel prog2. Vamos utilizarnovamente o simulador ald e analisar a segunda instruo (linha 8).

    0804807E C705A090040807000000 mov dword [+0x80490a0], 0x7O primeiro valor impresso, 0804807E, corresponde ao endereo onde est loca-

    lizada esta instruo enquanto que C705A090040807000000 corresponde ao c-digo da instruo, e operandos, decodificados ao lado (mov dword [+0x80490a0],0x7). Ao ser executada, esta instruo ir colocar a constante 0x7 no endereo0x80490a0.

    Ao examinar o algoritmo 4, consta-se que esta instruo em cdigo de mquinacorresponde instruo da linha 8, ou seja, movl $7, b.

    Desta forma, possvel deduzir que, em tempo de execuo, o endereo de b 0x80490a0.

    Como ser visto adiante, quem define o endereo de a e de b o ligador, e noo montador e nem o carregador. Para comprovar isso, observe o resultado abaixo, docontedo do arquivo objeto (gerado pelo montador).> objdump prog2.o -S

    prog2.o: file format elf32-i386

    Disassembly of section .text:

    00000000 :0: c7 05 00 00 00 00 06 movl $0x6,0x07: 00 00 00a: c7 05 04 00 00 00 07 movl $0x7,0x4

    11: 00 00 0014: a1 00 00 00 00 mov 0x0,%eax19: 8b 1d 04 00 00 00 mov 0x4,%ebx1f: 01 c3 add %eax,%ebx21: b8 01 00 00 00 mov $0x1,%eax26: cd 80 int $0x80

    Compare este resultado com o contedo do arquivo executvel (gerado pelo ligador):

    > objdump -S prog2prog2: file format elf32-i386

    Disassembly of section .text:

  • 22 CAPTULO 1. A SEO DE CDIGO E DE DADOS

    08048074 :8048074: c7 05 9c 90 04 08 06 movl $0x6,0x804909c804807b: 00 00 00804807e: c7 05 a0 90 04 08 07 movl $0x7,0x80490a08048085: 00 00 008048088: a1 9c 90 04 08 mov 0x804909c,%eax804808d: 8b 1d a0 90 04 08 mov 0x80490a0,%ebx8048093: 01 c3 add %eax,%ebx8048095: b8 01 00 00 00 mov $0x1,%eax804809a: cd 80 int $0x80

    Em especial, examine a instruo movl $6, a. No arquivo objeto, temos // movl $0x6,0x0 en-quanto que no arquivo executvel, temos movl $0x6,0x804909c. No arquivo objeto, a referncia aosmbolo a zero (0x0), que s uma referncia. Algo como um aviso ao ligador: este smbolo deveser alocado no primeiro endereo disponvel da regio de dados. Quando o ligador gera o executvel, eleobserva isso e aloca este smbolo no endereo virtual disponvel na seo de dados, ou seja, 0x804909c.J o smbolo b no arquivo objeto est indicado para ser alocado em $0x4, ou seja, quatro bytes depoisde a. O ligador ento aloca-o em 0x80490a0 = 0x804909c + 0x4.

    Os processadores da famlia IA32 definem tamanhos para os tipos fundamentais de dados, em especial:bytes (8 bits), words (16 bits), double words (32 bits) quadwords (64 bits) e double quadwords (128 bits).

    Alis, o termo varivel em assembly diferente do termo utilizado em linguagens de programaofortemente tipadas (como Pascal), onde cada varivel de um tipo e deve passar por alguma operaoespecial para ser convertida para outro tipo. Nestas linguagens, uma varivel do tipo inteiro no pode sersomada a uma varivel real (apesar de ambas ocuparem 32 bits).

    J no caso de assembly, as variveis no esto associados a nenhum tipo (.int indica que deve ser alocadoespao necessrio para um inteiro, ou seja, 32 bits). Isto significa que tanto a quanto b podem ser usadascom instrues sobre .int, words, etc. Nem o montador nem o ligador fazem checagem de tipo - isto responsabilidade do programador (e volta e meia do uma grande dor de cabea).

    Outro ponto importante que a instruo de soma utilizada, addl, soma o contedo de dois registra-dores (neste caso %eax e %ebx, jogando o resultado em %ebx. Esta operao soma dois inteiros de 32 bitscom ou sem sinal. O caso de haver overflow (em qualquer um dos dois casos) indicado no registradorEFLAGS.

    Para outros tipos, formatos de somas, e outras instrues para operaes aritmticas, veja [Int04b].

    1.3 Comandos RepetitivosComandos repetitivos so aqueles que permitem que um conjunto de instrues seja repetido at que umadeterminada condio ocorra. Em linguagens de alto nvel, normalmente so divididos em comandos do tiporepeat e comandos do tipo while. Um repeat indica que o conjunto de instrues pode ser repetido deum a vrias vezes, enquanto que um while indica que o conjunto de instrues pode ser repetido de zero avrias vezes. A forma de operao destas construes est apresentada na figura 1.2.

    H tambm a construo do tipo for, que indica que um conjunto de instrues deve ser repetido umdeterminado nmero de vezes (figura 1.3). Esta construo semelhante ao comando while, porm acrescidade uma varivel de controle e de:

    1. um comando para iniciar a varivel de controle antes do primeiro teste;

    2. um comando para acrescentar a varivel de controle de um aps a execuo da seqncia de coman-dos especificada;

    3. que a expresso verifica se o valor da varivel de controle ultrapassou o limite.

    Em linguagens assembly, estas construes no esto presentes, o nosso prximo passo descrevercomo traduzir comandos de alto nvel para comandos de baixo nvel. Esta traduo feita automa-ticamente pelos compiladores, mas nem sempre so exatamente como descritas aqui principalmente paramelhorar o desempenho.

  • 1.3. COMANDOS REPETITIVOS 23

    Figura 1.2: Funcionalidade das construes while e repeat.

    Figura 1.3: Funcionalidade da construo for.

  • 24 CAPTULO 1. A SEO DE CDIGO E DE DADOS

    Com as instrues descritas at aqui, seria impossvel repetir o funcionamento de comandos repetitivos.Afinal, todas as instrues vistas at aqui indicam (implicitamente) que a instruo seguinte a prxima aser executada.

    Para tal, existem instrues assembly especficas que desviam o fluxo de execuo indicando o destinopara onde desviar usando rtulos. Como exemplo, considere o algoritmo 5, que incrementa o valor em %eaxde um at ultrapassar o valor de %ebx. Este programa tem trs rtulos (_start, loop, fim_loop) eduas instrues de desvio (jg e jmp), que esto para desvia se maior (jump if greater) e desvio incondici-onal (jump) respectivamente.

    O rtulo _start, como j vimos, indica o local onde a execuo do programa deve iniciar. O rtuloloop indica o ponto de incio do lao e o rtulo fim_loop indica o ponto de sada do lao, que serexecutada assim que a condio de trmino for atingida.

    .section .text1

    .globl _start2_start:3

    movl $0, %eax4movl $10, %ebx5

    loop:6cmpl %ebx, %eax7jg fim_loop8add $1, %eax9jmp loop10

    fim_loop:11movl $1, %eax12int $0x8013

    Algoritmo 5: Arquivo rot_e_desvios.s

    Alm das instrues de desvio, o programa apresenta um outro comando novo: cmpl. Esta instruocompara o SEGUNDO argumento com o primeiro (no caso, %eax com %ebx) colocando o resultado emum bit de um registrador especial (EFLAGS). Este registrador afetado por vrios tipos de instruo, econtm informaes sobre a ltima instruo executada, como por exemplo se ocorreu overflow aps umasoma.

    Os bits deste registrador podem ser testados individualmente, e no caso da operao jump if greater,verifica se o bit ZF (zero flag) igual a zero e se SF=OF (SF=Sign Flag e OF=Overflow Flag). Para maisdetalhes sobre o funcionamento do EFLAGS, veja [Int04a].

    Observe que se alguma outra instruo for colocada entre a comparao (cmpl) e o desvio os bits doEFLAGS podem sero afetados por esta nova instruo. Isto implica dizer que a instruo de desvio jg deveser colocada imediatamente aps a instruo cmpl.

    Outras instrues de desvio que sero utilizadas ao longo deste livro so:

    jge (jump if greater or equal), jl (jump if less), jle (jump if less or equal), je (jump if equal), jne (jump if not equal).Assim como a instruo jg, as instrues acima tambm funcionam analisando os bits de EFLAGS.Outro aspecto importante a ser destacado neste programa que ele segue a funcionalidade do comando

    for. Compare o programa com a figura 1.3, e observe que no desenho, o fim do loop atingido quando acondio for falsa (ou seja, quando a varivel de controle no mais menor ou igual ao limite). No programaacima, o teste se a condio de fim de loop foi atingida (ou seja, que a varivel de controle maior do queo limite).

  • 1.4. TRADUO DA CONSTRUO WHILE 25

    Como exerccio, simule a execuo do programa acima, prestando ateno a registrador EIP (extendedinstrucion pointer). Fiz isto em meu simulador, e obtive o seguinte resultado:

    %eip instruo (hexa) instruo1 08049074 B800000000 movl 0x0, %eax2 08049079 BB0A000000 movl 0xa, %ebx3 0804907E 39D8 cmpl %eax, %ebx4 08049080 7F05 jg fim_loop5 08049082 83C001 addl %eax, 0x16 08049085 EBF7 jmp loop7 0804907E 39D8 cmpl %eax, %ebx8 08049080 7F05 jg fim_loop9 08049082 83C001 addl %eax, 0x110 08049085 EBF7 jmp loop

    . . . . . . . . .

    Cada linha contm exatamente uma instruo. A coluna da esquerda indica a ordem de execuo dasinstrues. A coluna %eip indica o endereo da instruo, e a terceira coluna indica o contedo daquele en-dereo (a instruo em hexadecimal). A ltima coluna mostra o cdigo mnemnico da instruo hexadecimalindicada.

    Desta forma, a primeira instruo executada estava no endereo 0x08049074 (endereo do rtulo_start). A instruo contida naquele endereo movl 0x0,%eax, cujo cdigo de mquina (em hexa-decimal), 0xB800000000.

    Como esta instruo ocupa cinco bytes, a prxima instruo dever estar localizada em 0x08049074+ 0x00000005 = 0x08049079. Este o valor de %eip ao longo da execuo desta instruo (o %eipsempre aponta para a prxima instruo na seqncia). Para calcular o endereo da prxima instruo, bastasomar o endereo da instruo corrente com o tamanho desta instruo.

    Esta lgica de funcionamento quebrada quando ocorre um desvio. Observe o que ocorre aps ainstruo jmp loop. A instruo seguinte est no endereo 0x0804907E, que no coincidentemente omesmo endereo do rtulo loop. Este endereo determinado em tempo de ligao (ou seja, pelo ligador),e pode ser observado no cdigo executvel (verifique com o comando objdump).

    Com este exemplo possvel verificar na prtica que rtulos so utilizados para indicar endereos quetem alguma importncia para o programa.

    1.4 Traduo da construo WhileA traduo de uma construo while segue o fluxo de execuo apresentado na figura 1.2, onde os desviosno fluxo so substitudos por comandos de desvio em assembly e os pontos de entrada dos desvios sosubstitudos por rtulos.

    Como exemplo, considere os algoritmos 6 e 7.

    main ( int argc, char** argv)1{2. . .3while ( E )4

    {5C1, C2, . . . Cn;6

    }7. . .8}9

    Algoritmo 6: Comando while (Linguagem de alto nvel).

  • 26 CAPTULO 1. A SEO DE CDIGO E DE DADOS

    .section .text1

    .globl _start2_start:3. . .4

    while:5Traduo da Expresso (E)6jFALSO fim_while7Traduo dos Comandos (C1, C2, . . . Cn)8jmp while9

    fim_while:10. . .11

    Algoritmo 7: Traduo do comando while da figura 6 para assembly.

    As instrues do algoritmo 7 que esto em negrito correspondem s instrues que do a funcionalidadedo comando while (ou seja, os comandos que implementam a repetio de comandos at que a expressoseja falsa).

    Os comandos que precedem o while (os pontilhados da linha 3 do algoritmo 6) so traduzidos na seqn-cia em que aparecem, e esto representados na linha 4 do algoritmo 7. De forma anloga se traduz oscomandos de sucedem o while.

    Quando o incio do while encontrado (linha 4 do algoritmo 6), arquivo assembly recebe um rtulowhile:, que indica o incio da construo. Em seguida, traduz-se a expresso, e o fluxo ser desviadopara o rtulo fim_while (linhas 5-7 do algoritmo 7) se o resultado da expresso for falso. O desvio dalinha 6 (jFALSO) deve ser substituda por algum dos comandos de desvio (vrios destes so apresentados napgina 24).

    Os comandos que compe o while (linha 6 do algoritmo 6) so traduzidos para assembly na seqenciaem que aparecem. Aps o ltimo destes comandos, a traduo apresenta uma instruo de desvio incondi-cional (linha 9 do algoritmo 7) para o rtulo while (linha 4). Isto significa que a instruo seguinte a serexecutada aquela contida no rtulo while (traduo da expresso).

    Como exemplo de traduo de um programa completo, considere os algoritmos 8 e 9.

    int i, a;1main ( int argc, char** argv)2{3

    i=0; a=0;4while ( i

  • 1.5. COMANDOS CONDICIONAIS 27

    .section .data1i: .int 02a: .int 03.section .text4.globl _start5_start:6movl $0, i7movl $0, a8movl i, %eax9while:10

    cmpl $10, %eax11jge fim_while12movl a, %ebx13addl %eax, %ebx14movl %ebx, a15addl $1, %eax16movl %eax, i17jmp while18

    fim_while:19movl $1, %eax20int $0x8021Algoritmo 9: Traduo do programa while.c (algoritmo 8) para assembly.

    memria mais lento do que o acesso a registradores, mais eficiente mapear as variveis em registradorese minimizar os acessos memria.

    Desta forma, podemos construir um programa equivalente ao programa contido no algoritmo 9 ao consi-derar que i est mapeado no registrador %eax e que a est mapeado no registrador %ebx. Desta forma,podemos eliminar as linhas 2, 3, 6, 7, 8, 12, 14 e 16, para obter o algoritmo 10. Este programa equivalenteao programa do algoritmo 9, porm como ele s acessa registradores, mais rpido.

    Um dos desafios da traduo de programas escritos em linguagens de alto nvel para programas emlinguagem assembly maximizar a quantidade de variveis mapeadas em registradores, e com isso melhoraro desempenho do programa. Os compiladores so capazes de fazer esta tarefa muito bem, porm o resultadofinal depende muito da quantidade de registradores que esto disponveis na arquitetura alvo. Por esta razo,a maior parte dos processadores modernos so projetados com um grande nmero de registradores, uma vezque quando o nmero de registradores pequeno (como por exemplo nos processadores da famlia x86 ques tem oito registradores de propsito geral), a tendncia que programas que usam muitas variveis tenhamum desempenho inferior daquele obtido em processadores com muitos registradores. importante observarque cada vez mais incomum encontrar programas teis que usam poucas variveis.

    Uma soluo freqente para melhorar o desempenho dos processadores anexar uma memria super-rpida, bem prxima CPU (ou at dentro), chamada de memria cache, cuja capacidade de armazenamentode dados muito superior capacidade de armazenamento de dados do processador e o tempo de acessono muito maior do que o acesso a registradores. Porm o inconveniente o custo, que muito superior memria convencional. Por esta razo, as memrias cache so normalmente pequenas.

    1.5 Comandos CondicionaisAs linguagens de programao apresentam normalmente pelo menos dois tipos de comandos condicionais:if-then e if-then-else. Se a expresso testada for verdadeira, a seqncia de comandos contida nos

  • 28 CAPTULO 1. A SEO DE CDIGO E DE DADOS

    .section .text1

    .globl _start2_start:3movl $0, %eax4while:5

    cmpl $10, %eax6jge fim_while7movl a, %ebx8addl %eax, %ebx9addl $1, %eax10jmp while11

    fim_while:12Algoritmo 10: Traduo do programa while.c (algoritmo 9) sem acessos me-mria.

    comandos assembly relativos ao then deve ser executada, enquanto que se a condio for falsa, a seqnciade comandos do else deve ser executada (se houver else, obviamente). Os comandos do then e elseno podem ser executados consecutivamente - ou executa um ou outro, mas nunca os dois.

    O modelo de um comando condicional em C apresentado no algoritmo 11 e o arquivo assemblycorrespondente apresentado no algoritmo 12.

    main ( int argc, char** argv)1{2. . .3if ( E )4

    {5Cthen1, Cthen2, . . . Cthenn;6

    }7else8

    {9Celse1 , Celse2, . . . Celsem ;10

    }11. . .12}13

    Algoritmo 11: Comando If-Then-Else (Linguagem de alto nvel).

    A traduo segue os moldes apresentados na estrutura repetitiva. A execuo depende do resultadoda expresso. Se a expresso for verdadeira, a seqncia de instrues incluir as linhas 5, 6, 7 e 12. Sea expresso for falsa, a seqncia seguir as linhas 9, 10, 11, 12. No primeiro caso, sero executados oscomandos then e no segundo os comandos relativos a else. No h nenhuma forma de se executar oscomandos relativos a then e else, como manda o comando if.

    Como exerccio, traduza o algoritmo 13 para assembly, monte e execute o programa atravs do ald.Em seguida, altere os valores das variveis para que a execuo siga a outra alternativa. A idia com esteexerccio se familiarizar com todo o processo de gerao do programa executvel, com o fluxo de execuo,e principalmente com o modelo de memria virtual que adotada no linux (endereo dos rtulos da seo.data e da seo .text, endereo de incio do programa, etc.).

  • 1.5. COMANDOS CONDICIONAIS 29

    .section .text1

    .globl _start2_start:3. . .4

    Traduo da Expresso (E)5jFALSO else6Traduo dos Comandos do then (Cthen1, Cthen2, . . . Cthenn; )7jmp fim_if8

    else:9Traduo dos Comandos do else (Celse1, Celse2, . . . Celsen; )10

    fim_if:11. . .12

    Algoritmo 12: Traduo do comando if-then-else do algoritmo 11 para assembly.

    int a, b;1main ( int argc, char** argv)2{3

    a=4; b=5;4if (a>b) {5

    a=a+b;6return a;7

    }8else9{10

    a=a-b;11return a;12

    }13}14

    Algoritmo 13: Exemplo para traduo.

  • 30 CAPTULO 1. A SEO DE CDIGO E DE DADOS

    1.6 VetoresPara finalizar o captulo, esta seo apresenta um exemplo que combina comandos condicionais e repetitivos.Para aprofundar o conhecimento da seo de dados, este exemplo utiliza um vetor, e descreve as formas deacessar este tipo de informao na memria virtual.

    O programa apresentado no algoritmo 14, e contm um vetor (fixo) de dados. Este programa retornaem $? o valor do maior elemento do vetor. A varivel maior armazena sempre este valor a cada iterao.

    O vetor no tem um nmero fixo de elementos. Para determinar o fim do vetor usa-se um sentinela, ouseja, um elemento do vetor com valor fixo (no caso, zero). Alm disso, pressupe-se que existe pelo menosum elemento no vetor alm do sentinela.

    int data_items[]={3, 67, 34, 222, 45, 75, 54, 34, 44, 33, 22, 11, 66, 0};1int i, int maior;2main ( int argc, char** argv)3{4

    maior = data_items[0];5for (i=1; data_items[i] != 0; i++)6{7

    if (data_items[i] > maior)8maior = data_items[i];9

    }10return (maior);11

    }12Algoritmo 14: Arquivo vetor.c

    A traduo deste programa apresentada no algoritmo 15, e as novidades so:1. a forma de criar um vetor com valores fixos. Basta list-los lado a lado na seo data, ao lado do

    rtulo associado quele vetor (veja a linha 4 do algoritmo 15.2. a forma de referenciar cada elemento do vetor: movl data_items(, %edi, 4), %ebx.

    Este comando usa uma forma de endereamento especial, chamado endereamento indexado (vejaapndice A.6).

    1.7 Exerccios1. Proponha uma forma de traduo para os comandos for, switch e do .. while.2. Altere o algoritmo15 para ordenar o vetor.

  • 1.7. EXERCCIOS 31

    .section .data1i: .int 02maior: .int 03data_items: .int 3, 67, 34, 222, 45, 75, 54, 34, 44, 33, 22, 11, 66, 04.section .text5.globl _start6_start:7movl $0, %edi8movl data_items(, %edi, 4), %ebx9movl $1, %edi10loop:11movl data_items(, %edi, 4), %eax12cmpl $0, %eax13je fim_loop14cmpl %ebx, %eax15jle fim_if16movl %eax, %ebx17fim_if:18addl $1, %edi19jmp loop20fim_loop:21movl $1, %eax22int $0x8023

    Algoritmo 15: Arquivo vetor.s

  • 32 CAPTULO 1. A SEO DE CDIGO E DE DADOS

  • Captulo 2

    A Seo da Pilha

    A seo da pilha (stack) armazena informaes sobre chamadas de procedimento (parmetros, informaessobre contexto e variveis locais).

    A idia de armazenar estas informaes em uma pilha originria da linguagem de programao Algol601. Antes desta linguagem todas as variveis eram globais e no havia procedimentos. Expoentes destapoca foram as linguagens Fortran e Cobol, que posteriormente foram adaptadas para comportar procedi-mentos.

    Antes de detalhar o tema, necessrio compreender o que ocorre em uma chamada de procedimento, ouseja, o modelo utilizado para implementar chamadas de procedimento em praticamente todas as linguagensde programao atuais.

    A figura 2.1 mostra a parte do programa em execuo que ser abordado neste captulo, que correspondeao intervalo 0xbfffffff e o valor atual do registrador %esp. Existem instrues assembly para valoresna pilha e para retir-los de l que sero abordados na seqncia.

    2.1 Modelo de Chamadas de ProcedimentoEm termos abstratos, o modelo de chamadas de procedimento (independente de sistema operacional e dearquitetura de computador), assemelha-se ao modelo de folhas de papel como descrito a seguir (baseadoem [Kow83]).

    Quando um programa colocado em execuo, uma grande folha de papel (digamos uma folha emformato A2) colocada sobre uma mesa. Nesta folha, escrevemos (por exemplo no canto superior esquerdo)o nome de todas as variveis globais do programa. O valor de iniciao da varivel normalmente indefinido,e qualquer atribuio a esta varivel se sobrepe ao valor que consta naquela folha.

    Cada vez que um procedimento chamado, uma folha de papel menor (por exemplo, formato A5) colocada sobre as demais (ou somente sobre a primeira) e nela escrito o nome do procedimento e todasa variveis (parmetros e variveis locais) relativas quele procedimento. Assim como ocorre nas variveisglobais, as atribuies a variveis descritas naquela folha se sobrepe, ou seja, no alteram o valor anterior(ou em outras folhas).

    Atravs deste modelo fica mais fcil compreender o que ocorre quando da execuo de um procedimentorecursivo. Em cada chamada recursiva, as variveis a serem acessadas so somente aquelas da folha de papelno topo da pilha (parmetros e variveis locais daquele procedimento) ou primeira folha de papel (variveisglobais).

    Cada nova chamada de procedimento (ou seja, cada nova instncia da recurso), uma nova folha depapel colocada sobre as anteriores, de tal forma que quando a execuo de uma determinada instncia da

    1As referncias no so definitivas, mas a idia aparentemente oriunda dos estudos do pesquisadoralemo Friedrich L. Bauer, que tambm trabalhou no desenvolvimento da linguagem, no uso da pilha paraclculos de expresses aritmticas e lgicas. Ele at ganhou um prmio de pioneirismo da IEEE ( IEEEComputer Society Pioneer Award) em 1988 pelo seu trabalho.

    33

  • 34 CAPTULO 2. A SEO DA PILHA

    Figura 2.1: Programa em execuo na memria virtual - rea da pilha (formato ELF)

    recurso chegar ao fim, a folha de papel associada a ele (a folha de papel no topo) dever ser eliminada ea folha de papel anterior (ou seja, da instncia recursiva anterior) sero utilizados, e as variveis voltam ater o valor que tinham antes de iniciar a instncia que foi finalizada (excesso feita a variveis passadas porreferncia, claro).

    Considere a linguagem C. Quando uma varivel referenciada no programa, o primeiro lugar onde estavarivel deve ser procurada na folha de papel do topo. Se no estiver l, deve ser procurada na folha devariveis globais e se no estiver l tambm, a varivel no existe. Este trabalho no realizado em tempode execuo, mas sim em tempo de compilao, e isso explica o erro comum que gera uma mensagem deerro indicando que uma determinada varivel no foi declarada.

    2.2 Implementao do Modelo em Uma ArquiteturaO modelo genrico apresentado na seo anterior implementado de formas diferentes dependendo do con-junto Linguagem de programao/Sistema Operacional/CPU. Esta seo descreve uma possvel implemen-tao para o conjunto Linguagem C/Linux/x86. Existem outras possveis implementaes, como a que utlizada pelo compilador gcc, onde os endereos das variveis locais e dos parmetros so um pouco dife-rentes.

    O primeiro aspecto importante a ser lembrado que os endereos das variveis e dos procedimentosso definidas em tempo de compilao. Os endereos dos procedimentos podem ser fixos (so associadosa rtulos), o que no pode ser feito para as variveis de cada folha de papel. Estas variveis devem seracessadas indicando a folha de papel onde ela est contida. Desta forma, cada folha de papel deve sernumerada e quando nos referirmos a uma determinada varivel devemos dizer o nmero da folha de papelonde ela est embutida e qual a varivel em questo.

    Alis, j est na hora de utilizarmos o nome correto para as folhas de papel. Para um processo emexecuo, cada folha de papel chamada de registro de ativao2 .

    Um registro de ativao (figura 2.2) instanciado sempre na rea da pilha, e basicamente compostopor trs partes:

    parmetros: local onde reservado espao para as variveis que correspondem aos parmetros de umprocedimento.

    2Em ingls activation register. Porm tambm referenciado como frame register, stack register, entreoutros.

  • 2.2. IMPLEMENTAO DO MODELO EM UMA ARQUITETURA 35

    Figura 2.2: Registro de Ativao.

    informaes gerenciais: esta rea armazena basicamente o endereo da instruo de retorno e o valoranterior do registrador que indica o registro de ativao anterior, mas pode armazenar ainda outrasinformaes.

    variveis locais: espao para as variveis do procedimento.

    A seguir descrevemos como montar (e desmontar) os registros de ativao para cada procedimento emtempo de execuo. Observe que os comandos devem ser calculados em tempo de compilao, porm oefeito destas instrues (que implementam o registro de ativao) s poder ser visto em tempo de execuo.

    A seo 2.2.1 descreve os registros de ativao sem parmetros e sem variveis locais. A seo 2.2.2acrescenta as variveis locais ao modelo da seo anterior e a seo 2.2.3 acrescenta os parmetros ao mo-delo. A seo2.2.4 descreve parmetros passados por referncia e a seo 2.2.5 descreve alguns aspectos dafuno main da linguagem C. Para finalizar, a seo 2.2.6 apresenta um exemplo de uma funo recursiva,que usa todos os conceitos apresentados e a seo 2.2.7 mostra como utilizar as funes disponveis embibliotecas, em especial na libc.

    2.2.1 Sem Parmetros e sem Variveis LocaisDe acordo com o modelo da figura 2.2, o registro de ativao de um programa que no tem parmetros e nemvariveis locais s contm as informaes gerenciais. Estas informaes, no caso da nossa arquitetura-alvocorresponde ao endereo de retorno (ou seja, o endereo que o programa deve retornar quando finalizar aexecuo do procedimento) e o valor de um determinado registrador (%ebp) que usado para acessar asvariveis locais e os parmetros, mas que neste exemplo no usado para nada.

    Para exemplificar como montar o registro de ativao neste caso, considere o algoritmo 16, traduzidopara assembly no algoritmo 17.

    Este programa apresenta dois novos pares de instrues assembly: pushl e popl, call e ret. O parpushl e popl insere e retira valores genricos da pilha, enquanto que call e ret insere e retira endereosda pilha.

  • 36 CAPTULO 2. A SEO DA PILHA

    int a, b;1int soma ( )2{3

    return (a+b);4}5main ( int argc, char** argv)6{7

    a=4;8b=5;9b = soma();10return (b);11

    }12Algoritmo 16: Programa sem parmetros e sem variveis locais.

    .section .data1A: .int 02B: .int 03.section .text4.globl _start5soma:6

    pushl %ebp7movl %esp, %ebp8movl A, %eax9movl B, %ebx10addl %eax, %ebx11movl %ebx, %eax12popl %ebp13ret14

    _start:15movl $4, A16movl $5, B17call soma18movl %eax, %ebx19movl $1, $eax20int $0x8021

    Algoritmo 17: Traduo do programa do algoritmo 16.

  • 2.2. IMPLEMENTAO DO MODELO EM UMA ARQUITETURA 37

    Comearemos descrevendo o par pushl e popl. A instruo pushl empilha ovalor contido no registrador indicado, e equivalente s seguintes operaes: (1) subl $4, %esp e (2)movl registrador, (%esp). J a instruo popl faz a operao inversa, ouseja: movl (%esp), e addl $4, %esp. Observe que, como a pilha cresce parabaixo, necessrio decrementar %esp para inserir um elemento e incrementar para retir-lo.

    O par call e ret anlogo, porm ao invs de empilhar/desempilhar o valor de um registrador qual-quer, ele empilha/desempilha o valor do registrador %eip (instruction pointer), que indica qual o endereoda prxima instruo a ser executada.

    Desta forma, a instruo call tem efeito equivalente a executar as instrues pushl%eip seguido de jmp , enquanto que ret tem efeito equivalente a popl %eip. Estas duasinstrues so a base para a chamada de procedimento, uma vez que o endereo da instruo que seriaexecutada aps a chamada empilhado com a instruo call e desempilhado e jogado em %eip na ltimainstruo do procedimento, e este ser o endereo da prxima instruo a ser executada.

    A funo retorna um nmero inteiro, e este valor retornado em %eax. Este o padro para o x86, po-rm outras arquiteturas podem indicar outras formas. Para entender melhor como funciona todo o processo,acompanhe a execuo do programa assembly usando o simulador.

    2.2.2 Sem Parmetros e com Variveis LocaisUm aspecto que ainda no foi levantado corresponde s instrues das linhas 7, 8, e 13 do algoritmo 17.Estas instrues salvam e atualizam o valor do registrador %ebp. O endereo contido neste registradorsempre aponta para o mesmo local do registro de ativao corrente. Ao entrar em um novo procedimento,sempre necessrio salvar o valor atual de %ebp e ao sair necessrio restaur-lo. A razo disso que esteregistrador usado para acessar as variveis locais e as variveis que correspondem aos parmetros.

    Observe que:1. so sempre empilhadas duas informaes gerenciais

    2. %ebp sempre aponta para uma mesma posio no registro de ativao (logo abaixo do endereo deretorno e logo acima da primeira varivel local, se esta existir).

    Como as variveis locais esto sempre logo abaixo do valor indicado por %ebp, indica-se o endereodelas usando %ebp como referncia. Como exemplo, suponha que um programa contenha trs variveislocais inteiras. Ento o endereo destas variveis ser: %ebp-4, %ebp-8 e %ebp-12. Para tal, necessrioprimeiro abrir espao para elas. Como exemplo, considere o algoritmo 18, cujo cdigo asssembly estindicado no algoritmo 19.

    int a, b;1int soma ( )2{3

    int x, y;4x=a;5y=b;6return (x+y);7

    }8main ( int argc, char** argv)9{10

    a=4;11b=5;12b = soma();13return (b);14

    }15Algoritmo 18: Programa sem parmetros e com variveis locais.

  • 38 CAPTULO 2. A SEO DA PILHA

    .section .data1A: .int 02B: .int 03.section .text4.globl _start5_start:6soma:7

    pushl %ebp8movl %esp, %ebp9subl $8, %esp10movl A, %eax11movl %eax, -4(%ebp)12movl B, %eax13movl %eax, -8(%ebp)14addl -4(%ebp), %ebx15movl -8(%ebp), %eax16addl $8, %esp17popl %ebp18ret19

    _start:20movl $4, A21movl $5, B22call soma23movl %eax, %ebx24movl $1, $eax25int $0x8026

    Algoritmo 19: Traduo do programa do algoritmo 18.

  • 2.2. IMPLEMENTAO DO MODELO EM UMA ARQUITETURA 39

    No algoritmo 19, os endereos das variveis locais x e y so -4(%ebp) e -8(%ebp) respectivamente,e o espao para estas variveis aberto logo no incio do procedimento ao subtrair 8 de %esp, quatro bytespara x e quatro para y (lembre-se que a pilha cresce para baixo). O valor de %esp restaurado ao fim doprocedimento, e importante destacar que como ele foi alocado DEPOIS de %ebp ter sido empilhado, ele liberado ANTES de restaurar %ebp.

    importante destacar que todas as CPUs modernas (que eu conheo) tem registradores especficos paralidar com o acesso de variveis em registros de ativao. As CPUs x86 chamam este registrador de basepointer, enquanto que as CPUs MIPS chamam de frame register. Por vezes, o nome no to significativoquanto estas duas CPUs.

    Algumas CPUs chamam este registrador de frame pointer (fp), e outros usam nomes mais ou menossignificativos.

    2.2.3 Com Parmetros e com Variveis LocaisQuando um procedimento tem parmetros, eles devem ser empilhados ANTES de chamar o procedimento(antes do call), porm a ordem em que os parmetros devem ser empilhados pode variar de uma linguagempara outra. Na linguagem Pascal, o padro que a ordem de empilhamento deve ser a mesma em que os pa-rmetros aparecem, enquanto que na linguagem C, a ordem invertida, ou seja, o primeiro parmetro (aqueleque aparece primeiro aps o () o ltimo a ser empilhado, o segundo o penltimo e assim por diante. Omotivo para esta ordem (que no natural, diga-se de passagem) est relacionado com a implementao defunes que tem um nmero varivel de argumentos, como por exemplo printf e scanf, onde o primeiroargumento (o string) indica quantos parmetros foram (ou deveriam ter sido) empilhados.

    Como estamos seguindo o padro utilizado na linguagem C, adotaremos o segundo modelo. Comoexemplo, considere o algoritmo 20, e sua verso assembly no algoritmo 21.

    int a, b;1int soma ( int x, int y)2{3

    int z;4z = x + y;5return (z);6

    }7main ( int argc, char** argv)8{9

    a=4;10b=5;11b = soma(a, b);12return (b);13

    }14Algoritmo 20: Programa com parmetros e com variveis locais.

    A diferena deste programa com relao aos anteriores que os parmetros foram empilhados antesda instruo call linhas 20 e 21 na ordem inversa quela em que que aparecem. Os parmetros aparecemacima das informaes gerenciais. Como 4(%ebp) corresponde ao endereo de retorno, os endereos dosparmetros x e y so 8(%ebp) e 12(%ebp) respectivamente. O programa tambm apresenta uma varivelglobal que est localizada em -4(%ebp).

    2.2.4 Parmetros passados por Referncia e com Variveis LocaisOs parmetros da seo anterior foram passados por valor, ou seja, o valor foi copiado para a pilha. Isto fazcom que a varivel utilizada na chamada do procedimento no tenha o seu valor alterado quando do retorno.

  • 40 CAPTULO 2. A SEO DA PILHA

    .section .data1A: .int 02B: .int 03.section .text4.globl _start5_start:6soma:7

    pushl %ebp8movl %esp, %ebp9subl $4, %esp10movl 8(%ebp), %eax11addl 12(%ebp), %eax12movl %eax, -4(%ebp)13addl $4, %esp14popl %ebp15ret16

    _start:17movl $4, A18movl $5, B19pushl B20pushl A21call soma22addl $8, %esp23movl %eax, %ebx24movl $1, $eax25int $0x8026

    Algoritmo 21: Traduo do programa do algoritmo 20.

  • 2.2. IMPLEMENTAO DO MODELO EM UMA ARQUITETURA 41

    Porm, por vezes interessante que a varivel que corresponde ao parmetro seja alterada durante aexecuo da funo. Para satisfazer este tipo de necessidade, muitas linguagens de programao usam oconceito de varivel passada por referncia. Na linguagem Pascal, um parmetro passado por referncia precedido pela palavra reservada var.

    A linguagem C, usada neste texto, no contm este tipo de construo, porm prov mecanismos paraque o programador crie uma construo anloga.

    A idia bsica que o valor a ser empilhado na chamada no uma cpia do valor a ser passado,porm uma cpia do endereo da varivel. Toda vez que a varivel for acessada, deve ser indicado o deseja-se acessar o valor apontado por aquele parmetro e no o parmetro em si. Como exemplo, considere oalgoritmo 23.

    int a, b;1void troca ( int* x, int* y)2{3

    int z;4z = *x;5x = *y;6y = z;7

    }8main ( int argc, char** argv)9{10

    a=1;11b=2;12troca (&a, &b);13exit (0);14

    }15Algoritmo 22: Programa com parmetros passados por referncia e com vari-veis locais.

    Neste algoritmo, a funo troca recebe dois parmetros, x e y e os troca. Ao final do programaprincipal, a ter o valor 2 e b ter o valor 1. Alguns aspectos merecem destaque:

    1. na chamada do procedimento troca (&a, &b) o smbolo & antes de uma varivel indica quedeve ser empilhado o endereo desta varivel e no o seu valor.

    2. a funo void troca ( int* x, int* y) indica que os dois parmetros so apontadores,ou seja, contm os endereos das variveis a serem acessadas. Por esta razo, o comando z = *x;diz que o valor indicado pelo endereo contido em x deve ser copiado para z.

    Dadas estas explicaes, fica mais simples indicar a traduo do programa acima (algoritmo 23).O programa assembly reflete as idias apresentadas anteriormente:

    1. A chamada da funo (troca (&a, &b)) empilha os endereos das variveis (linhas 25 e 26).2. Os acessos aos parmetros so traduzidos da seguinte forma: A construo *, corresponde a

    duas instrues: movl , %registrador1, movl (%registrador1), %registra-dor2. Como exemplo de traduo de *x, temos as instrues 15 e 16 do algoritmo 23.

    Esperamos que a presente seo tenha esclarecido como e quando usar as construes & e*, que so de uso misterioso para todos os programadores iniciantes na linguagem C.

    2.2.5 A funo main da linguagem CCada linguagem de programao define um local para iniciar o programa. Na linguagem C, este local o procedimento main. At este momento, associamos este procedimento ao rtulo start, que indica o

  • 42 CAPTULO 2. A SEO DA PILHA

    .section .data1A: .int 02B: .int 03.section .text4.globl _start5troca:6pushl %ebp7movl %esp, %ebp8subl $4, %esp9movl 8(%ebp), %eax10movl (%eax), %ebx11movl %ebx, -4(%ebp)12movl 12(%ebp), %eax13movl (%eax), %ebx14movl 8(%ebp), %eax15movl %ebx, (%eax)16movl -4(%ebp), %ebx17movl 12(%ebp), %eax18movl %ebx, (%eax)19addl $4, %esp20pop %ebp21ret22_start:23movl $1, A24movl $2, B25pushl $B26pushl $A27call troca28addl $8, %esp29movl $0, %ebx30movl $1, %eax31int $0x8032

    Algoritmo 23: Traduo do algoritmo 22.

  • 2.2. IMPLEMENTAO DO MODELO EM UMA ARQUITETURA 43

    local onde um programa assembly tem incio. Porm as coisas no ocorrem desta forma, e esta seo irapresentar alguns dos detalhes que envolvem a funo main da linguagem C.

    Para comear, a funo main uma funo que tem dois argumentos: um inteiro (argc) e um vetorde endereos (argv). O parmetro argc indica quantos argumentos foram includos na linha de comandoque chamou o programa. Como exemplo, considere o comando programa arg1 arg2 arg3. Quandoeste programa entrar em execuo, argc ser empilhado com o valor 4 (pois so quatro palavras digitadas),e os valores de argv sero os seguintes: argv[0]=programa, argv[1]=arg1, argv[2]=arg2,argv[3]=arg3.

    Conforme o modelo de execuo, estes parmetros esto na pilha e podem ser acessados a partir de%ebp, e assim o . Porm, isto leva a duas outras perguntas:

    P Quem foi que colocou estes valores na pilha?

    R o sistema operacional, mais especificamente o carregador de programas. Ele quem organiza o espaovirtual de execuo de programas, e entre vrias outras tarefas, coloca os argumentos da linha decomando na pilha antes de liberar o programa para execuo. importante destacar que em linux, ocarregador faz isto para TODOS os programas, independente da linguagem em que foi desenvolvido(a linguagem C tem o mecanismo descrito acima para acessar estas informaes, e outras linguagenstem outros mecanismos).

    P Onde ficam e como so organizados estes parmetros?

    R Ficam na pilha, e para acessar argc a partir de um programa assembly basta usar 8(%ebp), como fizemosem todos os demais procedimentos

    Para exemplificar, considere o algoritmo 24. Vamos execut-lo no simulador ald, onde podemos analisarcuidadosamente alguns aspectos de sua execuo.

    .section .text1

    .globl _start2pushl %ebp3movl %esp, %ebp4movl 4(%ebp), %eax5movl 8(%ebp), %ebx6movl 12(%ebp), %ebx7movl 16(%ebp), %ebx8movl $1, %eax9int $0x8010

    Algoritmo 24: Programa que acessa os parmetros da funo main.

    O programa basicamente armazena o valor de argc em %eax e depois armazena os parmetros argv[0],argv[1] e depois argv[2] em %ebx.

    Porm, este procedimento especial, pois no tem de endereo de retorno. Afinal, quem colocaparmetros e o endereo de retorno na pilha o procediemento chamador. Como no h procedimentochamador, somente foram empilhados os parmetros, e por esta razo, o seu registro de ativao diferente detodos os outros. No lugar onde estaria o endereo de retorno, est argc, onde estaria argc est argv[1],e assim por diante.

    No procedimento que corresponde ao _start e somente nele, os endereos dos parmetros so osseguintes:

  • 44 CAPTULO 2. A SEO DA PILHA

    parmetro endereo lxicoargc 4(%ebp))argv[0] 8(%ebp))argv[1] 12(%ebp))argv[2] 16(%ebp))argv[3] 20(%ebp)). . . . . .

    Considere que o programa do algoritmo 24 chama-se imprArgs, e queremos execut-lo da seguinteforma:

    > ./imprimeArgs XXX YYY ZZZ

    Porm ao invs de execut-lo na linha de comando, fazemos isso no simulador ald. Para colocar ar-gumentos no programa, aps entrar no simulador, digite set args XXX YY ZZZ e load . Ao longo da execuo, verifique os valores que so colocados em %ebx e examine aquelas po-sies de memria (comando examine). Em minha mquina, os valores so, na ordem: 0xBFFFF976,0xBFFFF97F e 0xBFFFF983. Estes endereos podem variar de mquina para mquina. Quando executeio programa no simulador, e examinei o contedo de argv[0], obtive o seguinte resultado:

    ald> examine 0xBFFFF976Dumping 64 bytes of memory starting at 0xBFFFF976 in hexBFFFF976: 69 6D 70 72 41 72 67 73 00 58 58 58 00 59 59 59 imprArgs.XXX.YYYBFFFF986: 00 5A 5A 5A 00 4D 41 4E 50 41 54 48 3D 3A 2F 75 .ZZZ.MANPATH=:/u

    O endereo inicial a ser impresso 0xBFFFF976 (argv[0]). Este endereo contm o primeiro bytedo nome do meu programa (imprArgs) seguido de um byte zero, que indica fim desta cadeia de caracteres.O endereo seguinte 0xBFFFF97F(argv[1]), que corresponde ao primeiro byte do primeiro argumento(XXX), e assim por diante. Observe que todas as cadeias de caracteres indicadas por argv terminam emzero.

    Um fato curioso no dump de memria acima o que vem depois do ltimo argumento do programa:MANPATH=. . .. Esta uma varivel de ambiente, e todas as variveis de ambiente so listadas em seqnciaaps o ltimo parmetro (por exemplo, HOME, PWD, etc.. Com este mecanismo, qualquer programa, quandoem execuo, contm uma fotografia do valor das variveis de ambiente tinham quando ele foi executado.Para encontrar o valor de uma varivel de ambiente, basta procurar pelo nome dela a partir fim da lista deargumentos (neste caso, ZZZ). Os programadores C podem obter o valor destas variveis de ambiente atravsda funo getenv.

    2.2.6 Chamadas RecursivasPara finalizar o estudo sobre o funcionamento de chamadas de procedimento, esta seo apresenta um exem-plo de um programa recursivo. A idia fixar todos os conceitos apresentados sobre chamadas de procedi-mento, em especial a forma com que os registros de ativao so empilhados para um mesmo procedimento(ou seja, como a implementao de vrias folhas de papel sobrepostas que correspondem a um mesmoprocedimento).

    O algoritmo 25 contm todos estes elementos. Ele calcula o fatorial de um nmero (no caso, de 4).Existem maneiras muito mais elegantes e muito mais eficientes para implementar um programa que calculao fatorial, porm este programa foi implementado desta maneira (at certo ponto confusa) para incluir par-metros passados por referncia, parmetros passados por valor e variveis locais (observe que a varivel r desnecessria).

    A traduo do algoritmo 25 apresentada no algoritmo 26.Os aspectos importantes a serem destacados neste algoritmo so os seguintes:

    a forma de inserir o endereo de x na pilha (linhas 44 a 46). a forma de acessar o valor de x (atravs do endereo que est na pilha (*x): linhas 27 e 28. os passos para a chamada recursiva (linhas 21 a 25).

  • 2.2. IMPLEMENTAO DO MODELO EM UMA ARQUITETURA 45

    void fat ( int* res, int n)1{2

    int r;3if (n

  • 46 CAPTULO 2. A SEO DA PILHA

    .section .data1

    .section .text2

    .globl _start3fat:4

    pushl %ebp5movl %esp, %ebp6subl $4, %esp7movl 12(%ebp), %eax8movl $1, %ebx9cmpl %eax, %ebx10jl else11movl 8(%ebp), %eax12movl $1, (%eax)13jmp fim_if14

    else:15movl 12(%ebp), %eax16subl $1, %eax17pushl %eax18pushl 8(%ebp)19call fat20addl $8, %esp21movl 8(%ebp), %eax22movl (%eax), %eax23movl 12(%ebp), %ebx24imul %ebx, %eax25movl %eax, -4(%ebp)26movl -4(%ebp), %eax27movl 8(%ebp), %ebx28movl %eax, (%ebx)29

    fim_if:30addl $4, %esp31popl %ebp32ret33

    _start:34pushl %ebp35movl %esp, %ebp36subl $4, %esp37pushl $438movl %ebp, %eax39subl $4, %eax40pushl %eax41call fat42addl $8, %esp43movl -4(%ebp), %ebx44movl $1, %eax45int $0x8046

    Algoritmo 26: Traduo do Algoritmo 25

  • 2.2. IMPLEMENTAO DO MODELO EM UMA ARQUITETURA 47

    A figura 2.3 detalha o contedo de um registro de ativao. Observe que %ebp aponta para o endereode memria que contm o valor de %ebp do registro de ativao anterior. Nesta figura, fica mais fcil deperceber qual o endereo relativo a %ebp dos parmetros e das variveis locais.

    A figura 2.4 mostra uma srie de registros de ativao empilhados, como seria na execuo do programarecursivo tratado nesta seo. Cada registro de ativao est representado com uma cor diferente. Da es-querda para a direita, a figura mostra como os registros de ativao so colocados na pilha a cada chamadade procedimento. A configurao mais equerda obtida no procedimento main, a configurao direitacorresponde chamada de fat(4), e esquerda desta, correspode a fat(3), e assim por diante at fat(1).

    O objetivo desta figura ressaltar os valores de %ebp ao longo do tempo. Ele sempre aponta para oregistro de ativao corrente, no endereo exato onde est guardado o registro de ativao do procedimentoanterior a este. As setas indicam a lista encadeada de valores de %ebp.

    A figura mostra que o registrador %ebp aponta para ltimo registro de ativao colocado na pilha. Oendereo apontado por ele o local onde o valor anterior de %ebp foi salvo (veja figura 2.3). O valor antigode %ebp aponta para outro registro de ativao (imediatamente acima). Este, por sua vez, aponta para oregistro de ativao anterior, e assim por diante. O ltimo registro de ativao corresponde ao procedimentomain conforme destacado na figura.

    Figura 2.4: Registros de ativao do procedimento fat ao longo das chamadas recur-sivas.

    Como exerccio, indique:

    1. quais instrues assembly so responsveis pelo empilhamento e pelo desempilhamento de cadacampo do registro de ativao.

  • 48 CAPTULO 2. A SEO DA PILHA

    2. preencha os valores das variveis do programa em C nos campos relacionados com as variveis nafigura 2.4.

    2.2.7 Uso de BibliotecasOs programas apresentados at o momento ou no imprime os resultados, ou os coloca em uma varivel deambiente. Agora descreveremos como trabalhar com funes desenvolvidas externamente, mais especifica-mente com as funes disponveis na libc, em especial as funes printf e scanf.

    Para utilizar estas duas funes, so necessrios dois cuidados:

    1. Dentro do programa assembly, empilhar os procedimentos como descrito neste captulo.2. Ao ligar o programa, necessrio incluir a prpria libc. Como faremos a ligao dinmica, neces-

    srio incluir a biblioteca que contm o ligador dinmico.

    Para exemplificar o processo, considere o algoritmo 27, e sua traduo, o programa28.

    main (int argc, char** argv)1{2

    int x, y;3scanf ("Digite dois numeros %d %d ", &x, &y);4printf("Os numeros digitados foram %d %d \n ", x, y);5

    }6Algoritmo 27: Uso de printf e scanf.

    Como pode ser observado, a traduo literal. Empilha-se os parmetros e em seguida h a chamadapara as funes printf e scanf.

    > as psca.s -o psca.o> ld psca.o -o psca -lc -dynamic-linker /lib/ld-linux.so.2> ./psca> Digite dois nmeros: 1 2> Os numeros digitados foram 1 2

    As funes printf e scanf no esto implementadas aqui, e sim na biblioteca libc, disponvel em/usr/lib/libc.a (verso esttica) e /usr/lib/libc.so (verso dinmica). Como mais conveniente utilizar a bibli-oteca dinmica, usaremos esta para gerar o programa executvel.

    A opo -dynamic-linker /lib/ld-linux.so.2 indica qual o ligador dinmico que ser oresponsvel por carregar a biblioteca libc, indicada em -lc, em tempo de execuo.

    2.3 Aspetos de SeguranaA pilha j foi alvo de ataques, e foi considerada um ponto vulnervel em sistemas Unix (e conseqentementelinux). Esta falha de vulnerabilidade era conseqncia da implementao de famlia de funes getc,getchar, fgetc, que no verificam violaes do espao alocado para as variveis destino.

    Como exemplo, veja o algoritmo 29.A primeira coisa interessante que ao compilar este programa, surge uma mensagem curiosa:

    > gcc get.c/tmp/ccaXi9xy.o: In function main:get.c:(.text+0x1f): warning: the gets function is dangerous and should not be used.

    O aviso que a funo gets perigosa e que no deve ser usada. O porqu deste perigo que ela noverifica os limites do vetor (que no caso tem cinco bytes). Para demonstrar o problema, veja o que ocorrecom a execuo onde a entrada de dados maior do que o tamanho do vetor:

  • 2.3. ASPETOS DE SEGURANA 49

    .section .data1str1: .string "Digite dois nmeros: "2str2: .string "%d %d"3str3: .string "Os numeros digitados foram %d %d \n"4.section .text5.globl _start6_start:7

    pushl %ebp8movl %esp, %ebp9subl $8, %esp10pushl $str111call printf12addl $4, %esp13movl %ebp, %eax14subl $8, %eax15pushl %eax16movl %ebp, %eax17subl $4, %eax18pushl %eax19pushl $str220call scanf21addl $12, %esp22pushl -8(%ebp)23pushl -4(%ebp)24pushl $str325call printf26addl $12, %esp27movl $1, %eax28int $0x8029

    Algoritmo 28: Traduo do Algoritmo 27

    main ( int argc, char** argv);1{2

    char s[5];3gets (s); printf("}4

    Algoritmo 29: O perigoso gets

  • 50 CAPTULO 2. A SEO DA PILHA

    > ./get12345678901234567890

    Observe que foram digitados 10 caracteres, e eles foram armazenados (com sucesso) no vetor. Eviden-temente eles no cabem no espao alocado para eles, e podem sobreescrever outras variveis.

    Estas variveis so alocadas na pilha, e o primeiro artigo que citou esta vulnerabilidade foi no artigopostado na internet Smashing The Stack For Fun And Profit de Aleph One.

    Este ataque ocorre quando o usurio entra com uma quantidade de dados muito maior do que o tamanhoda varivel, sobreescrevendo outros dados na pilha, como o endereo de retorno do registro de ativaocorrente.

    Se os dados digitados inclurem um trecho de cdigo (por exemplo, o cdigo de /usr/bin/sh) ser injetadoum trecho de cdigo na pilha. O prximo passo envolve o comando assembly ret. Se antes desta instruocontiver o endereo do cdigo injetado, ento o cdigo injetado ser executado.

    Agora, vamos analisar o que ocorreria na injeo em um processo que executa como super-usurio,como por exemplo, o ftp em linha de comando.

    Se o cdigo injetado for o sh, o usurio no s executar a shell, mas a executar como super-usurio!Mais do que simples conjecturas, este mtodo foi usado (e com sucesso) durante algum tempo. Para

    mais detalhes, veja [JDD+04].Desde a publicao do artigo e da deteco da falha de segurana, foram criados mecanismos para evitar

    este tipo de invaso, pode ser visto na execuo do algoritmo 29, com maior quantidade de dados.

    ./get10101010101010101010101010110*** stack smashing detected ***: ./get terminated======= Backtrace: =========...

  • Captulo 3

    Chamadas de Sistema

    No modelo ELF, um programa em execuo no pode acessar nenhum recurso externo sua memria virtual.Alis, existem regies dentro de sua prpria rea virtual que o programa tambm no pode acessar, comopde ser visto na figura 1.

    Porm, praticamente todos os processo precisam acessar dados que esto fora de sua rea virtual, comoarquivos, eventos do mouse e teclados, entre vrias outras.

    No ELF, o mecanismo que permite acessar estes recursos utiliza chamadas ao sistema (system calls).Este captulo descreve o que so e como funcionam as chamadas ao sistema no linux em especial em

    mquinas x86. Como o conceito de chamadas ao sistema ser universal, tambm apresentamos o modelo quefoi adotado no MS-DOS. O objetivo mostrar que as chamadas ao sistema, se mal utilizadas, podem causarsrios problemas ao computador.

    Explicar o que so e como funcionam as chamadas ao sistema na prtica envolve conhecimentos maioresde hardware, e para manter uma abordagem mais leve, apresentamos algumas analogias.

    A primeira analogia descrita na seo 3.1, e explica os modos de execuo de um processo, usurio esupervisor. Em seguida, a seo 3.2 acrescenta CPU e a seo 3.3 acrescenta os perifricos (dispositivos dehardware) analogia.

    Com a analogia completa, a seo3.4 explica como as coisas ocorrem na prtica em uma arquitetura.Em seguida, a seo 3.6 apresenta uma outra forma de implementar as chamadas ao sistema (MS-DOS), erelata alguns problemas que podem ser gerados com esta implementao. Por fim, a seo 3.7 apresenta aschamadas ao sistema no linux.

    3.1 A analogia do parquinhoUma analogia que eu gosto de usar a de que um processo em execuo em memria virtual semelhante auma criana dentro de uma caixa de areia em um parquinho de uma creche.

    Imagine uma creche onde as crianas so colocadas em reas delimitadas para brincar, uma criana porrea. Normalmente isto acontece em creches, onde estas reas so caixas de areia.

    Porm nesta analogia, ao contrrio do que ocorre me creches, cada criana confinada a uma nica rea,no podendo sair dali para brincar com outras crianas.

    Agora, considere uma criana brincando em uma destas reas. O que ela tem para brincar aquilo queexiste naquela caixa de areia. Ali, ela pode fazer o que quiser: jogar areia para cima, colocar areia na boca(e outras coisas que prefiro no descrever).

    Tudo o que a criana fizer naquela caixa ter conseqncias unicamente para ela, ou seja, no afeta ascrianas em outras caixas de areia.

    Normalmente, s h uma criana por caixa de areia. Quando a criana terminar de brincar, a caixa deareia destruda. Para cada criana que quiser brincar mas no estiver em uma caixa de areia, uma novacaixa ser construda para ela, possivelmente usando areia de caixas destrudas anteriormente.

    51

  • 52 CAPTULO 3. CHAMADAS DE SISTEMA

    Porm, importante garantir que as lembranas deixadas por uma criana no sejam passadas paraoutras crianas. Uma forma de fazer isso, esterilizando todo o material das caixas de areia destrudas, comopor exemplo esterilizando a areia utilizada.

    Quem faz esta tarefa a tia, que aqui conhecida como supervisora. Alis, bom destacar que isto que se espera de uma creche bem conceituada: que cuide da sade das crianas. Voc deixaria seu filhoem um parquinho onde a supervisora negligencia a sade das crianas?

    Esta supervisora tambm responsvel por outras tarefas, como atender s requisies das crianas pordispositivos externos.

    Suponha que existem brinquedos para as crianas usarem nas caixas de areia: baldinho, regador, etc..Como as crianas no podem sair de sua caixa de areia, elas tem de pedir o brinquedo para a supervisora.

    A supervisora recebe o pedido, e procura por algum brinquedo disponvel. Eventualmente ir encontrar(nem que seja tirando outra caixa de areia onde est outra criana), porm antes de passar para a criana quesolicitou, deve primeiramente higienizar o brinquedo para que lembranas deixadas pela primeira crianano possam ser usadas pela segunda criana.

    Nesta analogia, temos que:

    crianas e supervisora so os processos;

    crianas tem uma rea restrita de ao, enquanto que a supervisora tem uma rea de atuao quasetotal;

    cada caixa de areia a memria virtual de um processo.

    os brinquedos so recursos, como por exemplo dados de arquivo, de teclado, de mouse, etc.. Ou seja:so os objetos que um processo no pode acessar porque esto fora de sua memria virtual;

    os pedidos e devolues de recursos externos so executados atravs das chamadas ao sistema (systemcalls).

    Um detalhe importante que crianas e supervisores, apesar de serem processos atuam em modosdiferentes. Enquanto uma criana s pode acessar a sua caixa de areia e as coisas que estiverem l dentro, asupervisora pode acessar qualquer caixa de areia, os espaos entre as caixas de areia e at fora delas (comopor exemplo, em sua sala particular). Estes dois modos so conhecidos como modo protegido (para ascrianas) e modo supervisor (para a supervisora).

    Assim, as chamadas ao sistema so basicamente requisies que o processos fazem ao sistema operaci-onal por recursos externos sua rea virtual. Para acessar qualquer coisa que estiver fora de sua rea virtual,o processo deve fazer uma chamada ao sistema.

    3.2 Acrescentando a CPUNa analogia da seo anterior, todos os processos (crianas e supervisora) podem trabalhar em paralelo,ou seja, duas crianas podem brincar em suas caixas de areia simultaneamente.

    Porm, em uma arquitetura real, somente os processo que esto usando a CPU que esto ativos. Osdemais esto em espera.

    Para explicar isso na analogia do parquinho, vamos introduzir um pouco de magia.Uma moradora vizinha no gosta do barulho que as crianas fazem quando esto brincando. Para azar

    de todos, ela uma bruxa malvada que invocou uma maldio terrvel para silenciar todos.Esta maldio ilumina todo o parquinho com uma luz cinza que tranforma todos os atingidos em esttuas

    (inclusive a supervisora).Outra vizinha uma bruxa boazinha, que estranhando a falta de barulho, percebeu o que ocorreu. Ela

    no uma bruxa to poderosa quanto a bruxa malvada, e no pde reverter o feitio.Mesmo assim, conseguiu conjurar uma fadinha voadora, imune luz cinza. Quando ela sobrevoa uma

    criana (ou a supervisora) consegue despert-la por algum tempo usando uma luz colorida. Infelizmente,a fadinha s consegue acordar exatamente uma pessoa por vez.

    Por esta razo, a bruxa boazinha pediu para a fadinha no ficar muito tempo em uma nica pessoa, emudar de pessoa a pessoa para que todos pudessem brincar um pouco.

    Porm, a bruxa boazinha observou que a fadinha no pensava muito para escolher a prxima pessoapara acordar, e com isso ela acabava acordando somente um grupo pequeno de pessoas (e outras no eramsequer acordadas).

  • 3.3. ACRESENTANDO PERIFRICOS E DISPOSITIVOS DE HARDWARE 53

    Para encontrar uma alternativa mais justa, a bruxa boazinha pediu para que a fadinha sempre acordassea supervisora aps uma criana. A supervisora foi informada da situao, e foi incumbida de encontrar umaforma mais justa para encontrar a prxima criana para acordar.

    Toda vez que a fadinha acordava a supervisora, ela anotava qual a ltima criana acordada e escolhia aprxima a ser acordada de acordo com as suas anotaes. Em seguida, a fadinha ia acordar a criana indicadapela supervisora.

    Um outro problema que a fadinha no tinha relgio. Com isso, por vezes ficava tempo demais sobreuma criana antes de voltar supervisora, causando injustias.

    Para resolver este ltimo problema, a bruxa boazinha deu um pager fadinha, e instalou um relgio queativa o pager em intervalos regulares. Estes intervalos so chamados de quanta, e correspondem ao tempomximo que a fadinha fica sobre uma criana.

    Cada vez que o relgio ativa o pager, a fadinha acorda a supervisora e mostra o pager para ela. Lest indicado quem que o ativou (no caso, o relgio). Com esta informao, a supervisora sabe que deveexecutar uma tarefa especfica: escolher qual a prxima criana ser acordada. Quando fizer a escolha, afadinha vai at a criana indicada e a ilumina at que ocorra outra ativao do pager.

    Imagine agora que o intervalo do relgio de um minuto. Quando se passar uma hora, at 60 crianastero brincado. Deste ponto de vista, todas as crianas parecem ter brincado em paralelo. Na prtica, istoocorre em um computador. O intervalo de execuo de cada processo to pequeno, que em um segundo,dezenas de processos entram e saem de execuo, dando a iluso de paralelismo. A esta iluso se d o nomede pseudo-paralelismo.

    A fadinha que foi apresentada aqui corresponde CPU. A alternncia de processos (process switch)ocorre da forma sugerida aqui. Cada vez que o relgio bate, a CPU consulta o sistema operacional para queele indique qual o prximo processo a ser acordado. Existem vrios algoritmos para escolher qual o prximoprocesso a ser acordado, como por exemplo escolher o processo que est h mais tempo sem utilizar a CPU.

    3.3 Acresentando perifricos e dispositivos de hardwareUma outra entidade que ser estendida aquela que fornece os brinquedos. Imagine que do lado de forado parquinho existem vrios quiosques especializados em fornecer brinquedos. Um quiosque s guardabaldinhos, outro s regadores, e assim por diante. Quando uma criana chama a supervisora, ela podeespecificar qual o brinquedo que ela quer. Por exemplo, quero o baldinho azul turquesa, nmero 0xab00(sim, as crianas sabem hexadecimal). A supervisora anota o nmero envia uma mensagem para o quisquede baldinhos solicitando o baldinho correspondente. Em sua caderneta, a atendente tambm anota qual foi acriana que pediu por aquele baldinho.

    O atendente de cada quiosque meio lento, pois so dezenas de milhares de brinquedos em cadaquiosque (no me perguntem como eles cabem l). Cada quiosque tem uma fadinha prpria (ou seja, afadinha do parquinho no precisa ir at l para dar vida ao atendente pois ele nunca vira esttua).

    Se a supervisora ficar esperando pelo baldinho, ela no poder atender s demais requisies das cri-anas, causando grande consternao audvel (mesmo sendo de uma s criana por vez). Por esta razo,ela volta a atender as requisies do parquinho e espera que o atendente avise quando encontrar o que foisolicitado.

    Quando o atendente encontrar, ele precisa avisar supervisora que encontrou o que foi pedido. Para estetipo de situao, a fadinha foi equipada com um dispositivo que pode ser acionado pelo pelos atendentes dosquiosques: um pager. Ao perceber que o pager foi acionado, a fadinha vai at a supervisora e a acorda. Nopager tem o nmero do quiosque que enviou a mensagem. A supervisora procura em sua caderneta quempediu aquele dispositivo, e o coloca na caixa de areia correspondente.

    Como o mecanismo de pegar brinquedos pode ser diferente dependendo do quiosque (por exemplo, parapegar um baldinho usa-se um mecanismo diferente do que para pegar areia, ou gua), o nmero do quiosquej suficiente para que a supervisora saiba como pegar aquele brinquedo. O atendente nunca sai do quiosque,e por isso, um mensageiro dedicado quela tarefa usado para transportar o baldinho. Para cada quiosqueh um mensageiro especializado.

    Nesta verso estendida da analogia, temos que: as fadas corresponem CPU. Existem tantas fadas para dar vida ao parquinho quantas CPUs em uma

    mquina. os quiosques so os dispositivos perifricos (disco, teclado, mouse, etc.). Quase todos tem uma CPU

    dedicada a executar o que foi requisitado pela supervisora. Porm, eles no tem acesso ao parquinho.

  • 54 CAPTULO 3. CHAMADAS DE SISTEMA

    quando a requisio ao quiosque fica disponvel, o atendente ativa o pager, que em termos tcnicos chamados interrupo. Nos x86, a CPU sabe que houve uma interrupo quando o pino INTR) ativado.

    a supervisora um processo. Ela executa cdigo, e tem subrotinas dedicadas a tratar as requisiesdos dispositivos. Cada dispositivo pode ser tratado por um trecho de cdigo diferente, e uma formade acessar o trecho de cdigo correto atravs do nmero que aparece no pager. Aps perceber queo pino INTR foi ativado, a CPU pergunta quem mandou a interrupo, e o dispositivo respondecom o seu nmero.

    3.4 InterrupesA analogia da seo anterior bastante fiel ao que realmente ocorre em um computador para que os proces-sos conversem com os dispositivos. Esta conversa ocorre atravs das chamadas de sistema, e esta seodescreve o que realmente ocorre dentro de uma arquitetura. Cada arquitetura trata estes eventos de maneirasdiferentes, e aqui apresentaremos como funciona o modelo de tratamento das arquiteturas da famlia x86.

    A conversa entre um processo e os dispositivos externos envolve dois passos. O primeiro ocorrequando o processo solicita dados ao dispositivo, e o segundo ocorre quando o dispositivo coloca os dados narea virtual do processo.

    Por uma questo didtica, descreveremos inicialmente o segundo passo e depois o primeiro.A seo 3.4.1 explica como trazer os dados de um dispositivo externo (um quiosque) para dentro da rea

    virtual de endereamento de um processo (a caixa de areia). Esta ao executada utilizando um mecanismochamado de interrupo de hardware.

    Por fim, a seo 3.4.2 descreve as interrupes de sofware e uma delas em especial, aquela que executaas chamadas ao sistema.

    3.4.1 Interrupo de HardwareConsidere que um dispositivo de hardware terminou uma tarefa. Por exemplo, que o disco acabou de ler obloco de dados que lhe foi solicitado. Neste ponto, o dispositivo (no caso, disco) envia um sinal para a CPU.Nos computadores da faml