Computer Science › Como os Computadores Realmente Funcionam

C e Assembly

0 de 18
  1. Instruções Aritméticas e Lógicas

    `add`, `sub`, `imul`, `and`, `or`, `xor` e os deslocamentos operam diretamente sobre registradores ou memória, e `lea` (load effective address) calcula uma expressão aritmética de endereço sem nunca tocar a memória para a qual ela aponta.

    Ler →6 seções11 min
  2. Códigos de Condição e Desvios Condicionais

    `cmp` e `test` ligam silenciosamente as flags de zero, sinal, overflow e carry; `jcc`, `setcc` e `cmovcc` são as instruções que de fato as leem de volta. São exatamente as flags da ULA já vistas em hardware, agora conduzindo um controle de fluxo real.

    Ler →6 seções11 min
  3. Traduzindo o Controle de Fluxo: if, while e for

    Um compilador reduz todo `if`, `while` e `for` ao mesmo pequeno vocabulário de comparações e saltos condicionais, a tradução mecânica que o ACM/IEEE CS2013 nomeia diretamente como um resultado de aprendizagem central para a linguagem assembly.

    Ler →6 seções10 min
  4. O Espaço de Endereçamento do Processo

    Todo programa em execução enxerga seu próprio layout privado de memória (código, globais inicializadas e não inicializadas, um heap que cresce para cima e uma pilha que cresce para baixo), uma visão que o sistema operacional constrói, e não a RAM física bruta que a máquina de fato tem.

    Ler →6 seções12 min
  5. A Pilha e o Armazenamento Automático

    Uma região de memória LIFO que guarda as variáveis locais e a contabilidade de chamadas de toda função, crescendo para baixo um frame por vez e encolhendo automaticamente no instante em que uma função retorna. É exatamente a estrutura de hardware que deu nome ao TAD Pilha.

    Ler →6 seções11 min
  6. A Pilha de Execução do x86-64: call e ret

    `call` empilha o endereço de retorno e salta para a função chamada; `ret` desempilha esse mesmo endereço de volta para o ponteiro de instrução. É todo o mecanismo que um procedimento usa para devolver o controle a quem quer que o tenha invocado.

    Ler →6 seções10 min
  7. Stack Frames: Prólogo e Epílogo

    Uma sequência curta e fixa de instruções, o prólogo, reserva um frame para as variáveis locais de uma função na entrada, e um epílogo correspondente o desmonta antes de retornar, deixando a pilha exatamente como quem chamou a deixou.

    Ler →6 seções10 min
  8. A Convenção de Chamada System V AMD64

    O acordo exato e obrigatório que os compiladores no Linux/macOS seguem para que funções compiladas de forma independente consigam chamar umas às outras corretamente, definindo quais registradores levam os seis primeiros argumentos, qual leva o valor de retorno, quais uma função chamada pode sobrescrever livremente e como a pilha precisa ficar alinhada em cada chamada.

    Ler →6 seções12 min
  9. Projeto Final: do Código-Fonte em C a uma Chamada de Função Rastreada

    Uma pequena função recursiva em C compilada até o assembly x86-64 real e depois rastreada chamada por chamada, com todo ponteiro, stack frame e regra de convenção de chamada vistos nesta disciplina funcionando juntos para fazer a recursão, aceita por fé desde Programação e Pensamento Computacional, acontecer fisicamente.

    Ler →6 seções11 min
  10. Ponteiros: Endereços, Desreferência e o Operador de Endereço

    Um ponteiro é uma variável comum cujo valor por acaso é um endereço de memória. `&` pede a um objeto o seu endereço, `*` segue um endereço de volta até o objeto que mora lá, e todo acesso indireto em C se reduz a só esses dois operadores.

    Ler →6 seções11 min
  11. O Heap e a Alocação Dinâmica

    Memória pedida explicitamente em tempo de execução com `malloc` e liberada explicitamente com `free`, para dados cujo tamanho ou tempo de vida não pode ser preso a nenhuma chamada de função isolada. É o heap real para o qual a realocação por duplicação de um array dinâmico de fato recorre.

    Ler →6 seções11 min
  12. Bugs Comuns de Memória: Vazamentos, Double Free e Ponteiros Pendentes

    O gerenciamento manual de memória falha de três formas distintas e bem conhecidas (esquecer de liberar, que é um vazamento; liberar duas vezes, que é um double free; e usar memória depois de liberada, que é um ponteiro pendente / use-after-free), cada uma com seu próprio sintoma e sua própria correção.

    Ler →6 seções10 min
  13. void* e Código Genérico

    Um ponteiro sem tipo, que pode apontar para qualquer coisa, mas não pode ser desreferenciado como nada até receber uma conversão (cast). É o truque que `malloc`, `qsort` e `memcpy` usam para continuar genéricos numa linguagem sem templates.

    Ler →6 seções10 min
  14. Ponteiros para Função

    Um ponteiro cujo alvo é código executável, e não dados. É o mecanismo por trás de callbacks e tabelas de despacho numa linguagem que não tem funções de primeira classe próprias.

    Ler →6 seções10 min
  15. Structs, Unions e Layout de Memória

    Uma struct dispõe seus campos de forma contígua na ordem de declaração, com padding inserido pelo compilador para manter cada campo alinhado; uma union sobrepõe todos os membros no mesmo endereço inicial, um de cada vez.

    Ler →6 seções11 min
  16. Aritmética de Ponteiros e Decaimento de Arrays

    Somar 1 a um ponteiro o avança um elemento inteiro, e não um byte (a aritmética é escalada pelo tamanho do alvo), e em quase toda expressão o nome de um array decai silenciosamente para um ponteiro para o seu primeiro elemento.

    Ler →6 seções10 min
  17. Stack Smashing e Buffer Overflows

    Escrever além do fim de um buffer alocado na pilha não corrompe só uma variável vizinha. Levado longe o bastante, sobrescreve o próprio endereço de retorno salvo, o clássico primeiro passo para sequestrar o fluxo de controle de um programa.

    Ler →6 seções11 min

C e Assembly

Part of the Computer Science curriculum.

Sort
1

Registradores do x86-64 e Movimentação de Dados

16 registradores de uso geral de 64 bits, cada um com sub-porções endereçáveis de 32, 16 e 8 bits, entre os quais se move dados com `mov` e suas variantes com extensão de zeros ou de sinal. É o mesmo banco de registradores já construído com flip-flops, agora com seus nomes reais do x86-64.

2

Instruções Aritméticas e Lógicas

`add`, `sub`, `imul`, `and`, `or`, `xor` e os deslocamentos operam diretamente sobre registradores ou memória, e `lea` (load effective address) calcula uma expressão aritmética de endereço sem nunca tocar a memória para a qual ela aponta.

3

Códigos de Condição e Desvios Condicionais

`cmp` e `test` ligam silenciosamente as flags de zero, sinal, overflow e carry; `jcc`, `setcc` e `cmovcc` são as instruções que de fato as leem de volta. São exatamente as flags da ULA já vistas em hardware, agora conduzindo um controle de fluxo real.

4

Traduzindo o Controle de Fluxo: if, while e for

Um compilador reduz todo `if`, `while` e `for` ao mesmo pequeno vocabulário de comparações e saltos condicionais, a tradução mecânica que o ACM/IEEE CS2013 nomeia diretamente como um resultado de aprendizagem central para a linguagem assembly.

5

O Espaço de Endereçamento do Processo

Todo programa em execução enxerga seu próprio layout privado de memória (código, globais inicializadas e não inicializadas, um heap que cresce para cima e uma pilha que cresce para baixo), uma visão que o sistema operacional constrói, e não a RAM física bruta que a máquina de fato tem.

6

A Pilha e o Armazenamento Automático

Uma região de memória LIFO que guarda as variáveis locais e a contabilidade de chamadas de toda função, crescendo para baixo um frame por vez e encolhendo automaticamente no instante em que uma função retorna. É exatamente a estrutura de hardware que deu nome ao TAD Pilha.

7

A Pilha de Execução do x86-64: call e ret

`call` empilha o endereço de retorno e salta para a função chamada; `ret` desempilha esse mesmo endereço de volta para o ponteiro de instrução. É todo o mecanismo que um procedimento usa para devolver o controle a quem quer que o tenha invocado.

8

Stack Frames: Prólogo e Epílogo

Uma sequência curta e fixa de instruções, o prólogo, reserva um frame para as variáveis locais de uma função na entrada, e um epílogo correspondente o desmonta antes de retornar, deixando a pilha exatamente como quem chamou a deixou.

9

A Convenção de Chamada System V AMD64

O acordo exato e obrigatório que os compiladores no Linux/macOS seguem para que funções compiladas de forma independente consigam chamar umas às outras corretamente, definindo quais registradores levam os seis primeiros argumentos, qual leva o valor de retorno, quais uma função chamada pode sobrescrever livremente e como a pilha precisa ficar alinhada em cada chamada.

10

Projeto Final: do Código-Fonte em C a uma Chamada de Função Rastreada

Uma pequena função recursiva em C compilada até o assembly x86-64 real e depois rastreada chamada por chamada, com todo ponteiro, stack frame e regra de convenção de chamada vistos nesta disciplina funcionando juntos para fazer a recursão, aceita por fé desde Programação e Pensamento Computacional, acontecer fisicamente.

11

Ponteiros: Endereços, Desreferência e o Operador de Endereço

Um ponteiro é uma variável comum cujo valor por acaso é um endereço de memória. `&` pede a um objeto o seu endereço, `*` segue um endereço de volta até o objeto que mora lá, e todo acesso indireto em C se reduz a só esses dois operadores.

12

O Heap e a Alocação Dinâmica

Memória pedida explicitamente em tempo de execução com `malloc` e liberada explicitamente com `free`, para dados cujo tamanho ou tempo de vida não pode ser preso a nenhuma chamada de função isolada. É o heap real para o qual a realocação por duplicação de um array dinâmico de fato recorre.

13

Bugs Comuns de Memória: Vazamentos, Double Free e Ponteiros Pendentes

O gerenciamento manual de memória falha de três formas distintas e bem conhecidas (esquecer de liberar, que é um vazamento; liberar duas vezes, que é um double free; e usar memória depois de liberada, que é um ponteiro pendente / use-after-free), cada uma com seu próprio sintoma e sua própria correção.

14

void* e Código Genérico

Um ponteiro sem tipo, que pode apontar para qualquer coisa, mas não pode ser desreferenciado como nada até receber uma conversão (cast). É o truque que `malloc`, `qsort` e `memcpy` usam para continuar genéricos numa linguagem sem templates.

15

Ponteiros para Função

Um ponteiro cujo alvo é código executável, e não dados. É o mecanismo por trás de callbacks e tabelas de despacho numa linguagem que não tem funções de primeira classe próprias.

16

Structs, Unions e Layout de Memória

Uma struct dispõe seus campos de forma contígua na ordem de declaração, com padding inserido pelo compilador para manter cada campo alinhado; uma union sobrepõe todos os membros no mesmo endereço inicial, um de cada vez.

17

Aritmética de Ponteiros e Decaimento de Arrays

Somar 1 a um ponteiro o avança um elemento inteiro, e não um byte (a aritmética é escalada pelo tamanho do alvo), e em quase toda expressão o nome de um array decai silenciosamente para um ponteiro para o seu primeiro elemento.

18

Stack Smashing e Buffer Overflows

Escrever além do fim de um buffer alocado na pilha não corrompe só uma variável vizinha. Levado longe o bastante, sobrescreve o próprio endereço de retorno salvo, o clássico primeiro passo para sequestrar o fluxo de controle de um programa.