Compare commits

..

5 commits
main ... main

4 changed files with 211 additions and 44 deletions

View file

@ -80,40 +80,3 @@ As datas e tópicos podem mudar de acordo com o desenrolar do curso!
Ao final do curso, será fornecido um certificado de conclusão mediante a Ao final do curso, será fornecido um certificado de conclusão mediante a
apresentação de um projeto final. apresentação de um projeto final.
* Inscrições e forma de pagamento
- *Inscrições:* até 27 de junho de 2025
- *Valor parcelado:* R$300,00 (em até 6x)
- *À vista no PIX:* R$270,00 (10% de desconto)
* Como se inscrever
** 1. Realize o pagamento pela forma escolhida
- *PIX (com desconto):* cursos@blauaraujo.com
- *Parcelamentos:* [[https://link.picpay.com/p/17500877656850385526c47][link de pagamento (PicPay)]]
** 2. Envie um e-mail com seus dados
*Destinatário:* cursos@blauaraujo.com
*Informações (obrigatórias):*
- Comprovante de pagamento
- Nome completo
- E-mail de contato
- CPF ou CNPJ
- Endereço postal completo com CEP
Esses dados são necessários para a emissão da nota fiscal.
** 3. Aguarde a resposta
Seu e-mail será respondido em até 24h para confirmar sua inscrição e dar algumas
informações sobre o início das aulas. Você também receberá a nota fiscal eletrônica
no e-mail informado.
* Outras informações e casos especiais
Envie um e-mail para cursos@blauaraujo.com ou me procure no [[https://t.me/blau_araujo][Telegram]].

View file

@ -6,7 +6,11 @@
* 0 -- Introdução à linguagem Assembly (NASM) * 0 -- Introdução à linguagem Assembly (NASM)
[[./aula-00.org][Texto]] | [[#][Vídeo]] - [[./aula-00.org][Texto]]
- [[https://youtu.be/NsFUbSoz12c][Vídeo #0: Sobre o curso]]
- [[https://youtu.be/LUuNAMezDOM][Vídeo #1: O que é Assembly]]
*Conteúdo:*
- O que é Assembly - O que é Assembly
- Linguagem dependente da arquitetura - Linguagem dependente da arquitetura
@ -21,7 +25,10 @@
* 1 -- Arquitetura de computadores * 1 -- Arquitetura de computadores
[[./aula-01.org][Texto]] | [[#][Vídeo]] - [[./aula-01.org][Texto]]
- [[https://youtu.be/nW1OrIisvV0][Vídeo #2: Arquiteturas]]
*Conteúdo:*
- Modelo de von Neumann - Modelo de von Neumann
- Arquiteturas x86 - Arquiteturas x86

View file

@ -4,6 +4,11 @@
#+options: toc:3 #+options: toc:3
*Vídeos relacionados:*
- [[https://youtu.be/NsFUbSoz12c][Sobre o curso]]
- [[https://youtu.be/LUuNAMezDOM][O que é Assembly]]
* Objetivos * Objetivos
- Apresentar as características e os elementos básicos da linguagem Assembly. - Apresentar as características e os elementos básicos da linguagem Assembly.
@ -12,6 +17,110 @@
- Aprender as instruções e diretivas essenciais para começar a programar. - Aprender as instruções e diretivas essenciais para começar a programar.
- Criar executar um primeiro programa em Assembly. - Criar executar um primeiro programa em Assembly.
* Máquina de Turing
No começo do século 20, surge uma questão no campo da matemática: até onde
seria possível solucionar problemas seguindo estritamente um conjunto de
regras fixas estabelecidas em um /algoritmo/?
#+begin_quote
*Nota:* em matemática, /algoritmos/ são sequências finitas de ações executáveis
que visam obter soluções para determinados tipos de problema.
#+end_quote
Nos anos 1930, o matemático Alan Turing estava trabalhando em um problema de
lógica formal (campo que estuda a estrutura de enunciados e suas regras). Como
parte do que estava tentando demonstrar, ele precisava encontrar uma forma
geral para descrever como algoritmos poderiam ser implementados e executados
mecanicamente.
A partir disso, ele formulou o conceito matemático de uma máquina abstrata que
manipularia automaticamente os símbolos em uma fita de acordo com uma tabela
de regras: a sua /a-machine/ (de /"automatic machine"/), mais tarde chamada de
/Máquina de Turing/ por seu orientador de doutorado -- termo que utilizamos
até hoje.
Então, a Máquina de Turing é um modelo matemático que descreve um dispositivo
muito simples que seria capaz de expressar computações arbitrárias e, com
isso, explorar as propriedades e as limitações da computação mecânica.
#+begin_quote
*Nota:* /modelos matemáticos computacionais/ são modelos que descrevem como a
saída de uma função matemática é computada a partir de uma dada entrada.
#+end_quote
Turing descreveu a imagem física de sua máquina como consistindo de...
- Uma fita dividida em células contendo símbolos ou espaços vazios;
- Um cabeçote para ler e escrever símbolos na fita;
- Um registrador de estados, para armazenar o estado corrente de um conjunto
finito de estados possíveis;
- Uma tabela de instruções que, dado o estado atual e o que estiver sendo
lido na fita, diz à máquina o que fazer na sequência.
Por exemplo:
#+begin_example
Estado atual: q1
Fita:
┌───┬───┬───┬───┬───┬───┬───┐
│ ␣ │ 1 │ 1 │ 0 │ ␣ │ ␣ │ ␣ │
...└───┴───┴───┴───┴───┴───┴───┘...
Cabeçote
Regra:
Se (q1, 0) -> escreva 1, mova para a direita, mude estado para q2
#+end_example
*Ilustração moderna:* [[https://www.youtube.com/watch?v=E3keLeMwfHY][vídeo de Mike Davey]]
Esse modelo simples, apesar de abstrato, revelou-se poderoso o suficiente para
representar qualquer cálculo que possa ser feito por um algoritmo. Contudo,
a computação sequencial das células de uma fita é lenta demais para aplicações
práticas modernas. Mesmo assim, a máquina que Turing descreveu tornou-se uma
das principais inspirações para a construção das /unidades de processamento/,
utilizadas nos computadores até os nossos dias.
** Uma longa fita de bits
Na computação moderna, os nossos programas ainda podem ser vistos como uma
fita contendo uma longa sequência de bits (valores binários =0= e =1=). Mas,
diferente da máquina de Turing:
- Os bits são armazenados na memória principal do computador, onde podem ser
acessados de forma aleatória e quase instantânea;
- Em vez de símbolos individuais por célula e uma tabela de estados, os bits
são interpretados em blocos de tamanho fixo, expressando as instruções
que a CPU deve executar e os dados envolvidos nessas operações;
- A tabela de estados agora está incorporada nos processadores na forma de
um conjunto fixo de instruções específico de cada CPU, conhecido como ISA
(/Instruction Set Architecture/).
Portanto, /escrever um programa/ significa, em essência, representar, nessa
longa fita de bits, os códigos relativos aos dados e instruções que uma
máquina em particular será capaz de interpretar e executar. Isso é o que
chamamos de /código de máquina/ (ou, popularmente, /linguagem de máquina/) e,
em vários momentos da história da computação, os programas foram escritos
desta forma.
Obviamente, escrever diretamente o código de máquina é um processo demorado,
tedioso e propenso a erros. Por isso, já nos anos 1950, começaram a ser
criados programas dedicados à tradução de representações simbólicas de
instruções para as representações binárias do código de máquina. Na prática,
o que esses programas fazem é utilizar as representações simbólicas como um
"manual de instruções" para montar o código de máquina correspondente -- daí
serem chamados de /montadores/ (ou /assemblers/, em inglês).
Vale observar que, inicialmente, essas representações simbólicas não eram
escritas em arquivos de texto como fazemos hoje. Em geral, os códigos das
instruções e dados eram registrados fisicamente, em fitas ou cartões
perfurados, que depois eram lidos por máquinas. Assim, uma /linguagem de
montagem/ (/assembly language/) já existia, mas ainda se passava por uma longa
fase onde o processo de escrita de programas era manual e bastante sujeito
a erros mecânicos e operacionais.
* O que é Assembly * O que é Assembly
Assembly é uma linguagem de programação que oferece formas de representar, em Assembly é uma linguagem de programação que oferece formas de representar, em
@ -162,7 +271,7 @@ quantos bytes quisermos, em qualquer endereço, desde que tenhamos permissão
do sistema. do sistema.
#+end_quote #+end_quote
** Por que aprender Assembly? * Por que aprender Assembly?
*** Entendimento do funcionamento de computadores *** Entendimento do funcionamento de computadores
@ -434,7 +543,7 @@ Quando escrevemos programas em NASM que serão ligados com outros módulos,
como bibliotecas externas ou arquivos objeto, nós precisamos informar ao como bibliotecas externas ou arquivos objeto, nós precisamos informar ao
editor de ligações quais símbolos devem ser /exportados/ para esses módulos editor de ligações quais símbolos devem ser /exportados/ para esses módulos
e quais devem ser /importados/ de outros lugares. No NASM, isso é feito com e quais devem ser /importados/ de outros lugares. No NASM, isso é feito com
as diretivas =global= (importação) e =extern= (exportação). as diretivas =global= (exportação) e =extern= (importação).
No GNU/Linux, especialmente quando não usamos uma linguagem de mais alto No GNU/Linux, especialmente quando não usamos uma linguagem de mais alto
nível (como C), nós precisamos especificar manualmente o ponto de entrada nível (como C), nós precisamos especificar manualmente o ponto de entrada
@ -738,7 +847,7 @@ imul destino, origem (resultado em destino)
imul destino, origem, imediato (resultado em destino) imul destino, origem, imediato (resultado em destino)
#+end_example #+end_example
- Multiplica =origem= pelo valor de =imediato= e armazena o resultado em =origem=. - Multiplica =origem= pelo valor de =imediato= e armazena o resultado em =destino=.
- Se o resultado exceder a capacidade de =destino=, apenas os bytes mais - Se o resultado exceder a capacidade de =destino=, apenas os bytes mais
baixos serão armazenados (não há extensão de registradores). baixos serão armazenados (não há extensão de registradores).
- Afeta as flags =CF= e =OF= no caso de estouro da capacidade de =destino=. - Afeta as flags =CF= e =OF= no caso de estouro da capacidade de =destino=.
@ -1249,19 +1358,20 @@ instalados no seu sistema:
- Um editor de código da sua preferência (Vim, Emacs, Geany, etc) - Um editor de código da sua preferência (Vim, Emacs, Geany, etc)
- =git= - =git=
- =nasm= - =nasm= e =ndisasm=
- =gcc= - =gcc=
- =as= - =as=
- =ld= - =ld=
- =gdb= - =gdb=
- =readelf= - =readelf=
- =objdump= - =objdump=
- =objcopy=
- =nm= - =nm=
- =ldd= - =ldd=
- =hexedit= - =hexedit=
- =xxd= (geralmente instalado com o editor Vim) - =xxd= (geralmente instalado com o editor Vim)
No Debian, a maioria deles é instalada com os comandos: No Debian e derivados, a maioria deles é instalada com os comandos:
#+begin_example #+begin_example
sudo apt update sudo apt update

87
docs/prefixo-rex.org Normal file
View file

@ -0,0 +1,87 @@
* Prefixos REX na arquitetura Intel 64 (x86-64)
O prefixo REX é um byte opcional usado no modo 64 bits para:
- Acessar registradores estendidos (~r8r15~)
- Usar operandos de ~64~ bits
- Estender campos ~ModR/M~, ~SIB~ ou ~opcode~
** Formato geral do prefixo REX (1 byte)
#+begin_example
Bits: 7 6 5 4 | 3 | 2 | 1 | 0
0 1 0 0 W R X B
#+end_example
| Bit | Nome | Função |
|-----+------+--------------------------------------------------------------------|
| ~74~ | ~0100~ | Identifica o byte como prefixo REX |
| ~3~ | ~W~ | ~1~ = operandos de ~64~ bits |
| ~2~ | ~R~ | Estende o campo ~Reg~ no byte ~ModR/M~ |
| ~1~ | ~X~ | Estende o campo ~Index~ no byte ~SIB~ |
| ~0~ | ~B~ | Estende o campo ~Base~ no ~ModR/M~, ~SIB~ ou campo ~reg~ em certos opcodes |
** Tabela dos 16 prefixos REX possíveis (~0x400x4F~)
| Hex | Binário | ~W~ | ~R~ | ~X~ | ~B~ | Significado resumido |
|------+----------+---+---+---+---+-------------------------------------------------|
| ~0x40~ | ~01000000~ | ~0~ | ~0~ | ~0~ | ~0~ | Sem extensão nem ~64~-bit |
| ~0x41~ | ~01000001~ | ~0~ | ~0~ | ~0~ | ~1~ | ~B = 1~ (extensão do campo Base) |
| ~0x42~ | ~01000010~ | ~0~ | ~0~ | ~1~ | ~0~ | ~X = 1~ (extensão do campo Index) |
| ~0x43~ | ~01000011~ | ~0~ | ~0~ | ~1~ | ~1~ | ~X = 1~, ~B = 1~ |
| ~0x44~ | ~01000100~ | ~0~ | ~1~ | ~0~ | ~0~ | ~R = 1~ (extensão do campo Reg) |
| ~0x45~ | ~01000101~ | ~0~ | ~1~ | ~0~ | ~1~ | ~R = 1~, ~B = 1~ |
| ~0x46~ | ~01000110~ | ~0~ | ~1~ | ~1~ | ~0~ | ~R = 1~, ~X = 1~ |
| ~0x47~ | ~01000111~ | ~0~ | ~1~ | ~1~ | ~1~ | ~R = 1~, ~X = 1~, ~B = 1~ |
| ~0x48~ | ~01001000~ | ~1~ | ~0~ | ~0~ | ~0~ | ~W = 1~ (operandos de ~64~ bits) |
| ~0x49~ | ~01001001~ | ~1~ | ~0~ | ~0~ | ~1~ | ~W = 1~, ~B = 1~ |
| ~0x4A~ | ~01001010~ | ~1~ | ~0~ | ~1~ | ~0~ | ~W = 1~, ~X = 1~ |
| ~0x4B~ | ~01001011~ | ~1~ | ~0~ | ~1~ | ~1~ | ~W = 1~, ~X = 1~, ~B = 1~ |
| ~0x4C~ | ~01001100~ | ~1~ | ~1~ | ~0~ | ~0~ | ~W = 1~, ~R = 1~ |
| ~0x4D~ | ~01001101~ | ~1~ | ~1~ | ~0~ | ~1~ | ~W = 1~, ~R = 1~, ~B = 1~ |
| ~0x4E~ | ~01001110~ | ~1~ | ~1~ | ~1~ | ~0~ | ~W = 1~, ~R = 1~, ~X = 1~ |
| ~0x4F~ | ~01001111~ | ~1~ | ~1~ | ~1~ | ~1~ | ~W = 1~, ~R = 1~, ~X = 1~, ~B = 1~ (todas as extensões) |
** Observações
- O prefixo REX só é válido no modo 64 bits.
- Pode ser necessário mesmo com operandos de 32 bits se registradores estendidos
forem usados.
** Exemplo de desmontagem
#+begin_example
48 89 c8 => mov rax, rcx
#+end_example
Nesse caso:
- ~48~: É o prefixo REX com ~W = 1~, ~R = 0~, ~X = 0~, ~B = 0~ (operandos de 64 bits).
- ~89~: OpCode ~mov r/m, reg~ (como primeiro operando é ~r/m~, temos que ver o byte ModR/M).
- ~c8~: Byte ModR/M, onde...
#+begin_example
Bits: 7 8 | 5 4 3 | 2 1 0
modo | origem | destino
c8 → 11 | 001 | 000
regs | rcx | rax
#+end_example
Portanto... ~48 89 c8 => mov rax, rcx~
** Tabela de registradores no byte ModR/M
O modo ~11~ indica que os dois operandos estão em registradores. Os 3 bits
dos campos ~reg~ e ~r/m~ indicam os registradores, com ou sem extensão via
prefixo ~REX~.
| Código | Reg. | ~REX.R~ ou ~REX.B~ |
|--------+------+----------------|
| ~000~ | ~rax~ | ~r8~ |
| ~001~ | ~rcx~ | ~r9~ |
| ~010~ | ~rdx~ | ~r10~ |
| ~011~ | ~rbx~ | ~r11~ |
| ~100~ | ~rsp~ | ~r12~ |
| ~101~ | ~rbp~ | ~r13~ |
| ~110~ | ~rsi~ | ~r14~ |
| ~111~ | ~rdi~ | ~r15~ |