conteúdo da aula 3
This commit is contained in:
parent
95ad4cc85b
commit
9780039c11
2 changed files with 434 additions and 45 deletions
|
@ -15,10 +15,10 @@
|
|||
* O que é o formato ELF
|
||||
|
||||
O formato binário ELF, de /Executable and Linking Format/ (/Formato Executável
|
||||
e de Ligação/) foi originalmente desenvolvido e publicado como parte da /Interface
|
||||
Binária de Aplicações/ (ABI) do Unix System V Release 4 (SVR4). Desde então,
|
||||
tornou-se o padrão adotado pela maioria dos sistemas /Unix-like/ para representar
|
||||
arquivos objeto binários, como executáveis e bibliotecas.
|
||||
e de Ligação/), foi originalmente desenvolvido e publicado como parte da ABI
|
||||
(/Interface Binária de Aplicações/) do Unix System V Release 4 (SVR4). Desde
|
||||
então, tornou-se o padrão adotado pela maioria dos sistemas /Unix-like/ para
|
||||
representar arquivos objeto binários, como executáveis e bibliotecas.
|
||||
|
||||
** Principais tipos de arquivos objeto
|
||||
|
||||
|
@ -145,19 +145,19 @@ ou dinamicamente, no momento da execução, o correto processamento das
|
|||
ligações depende da organização interna do arquivo ELF. Essa organização é
|
||||
descrita por suas seções especiais, entre as quais podemos destacar:
|
||||
|
||||
| Seção | Descrição |
|
||||
|---------------+----------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| =.bss= | Contém dados globais não inicializados ou inicializados com zero; ocupa espaço na memória, mas não ocupa espaço no arquivo executável. |
|
||||
| =.data= | Contém dados globais inicializados; ocupa espaço tanto no arquivo quanto na memória. |
|
||||
| =.rodata= | Contém dados que não podem ser alterados (/read only/), geralmente usada para constantes e strings literais. |
|
||||
| =.text= | Seção que contém o código executável do programa (instruções da CPU). |
|
||||
| =.symtab= | Tabela de símbolos completa, usada pelo ligador e depuradores para localizar símbolos. |
|
||||
| =.strtab= | Tabela de strings que armazena os nomes dos símbolos referenciados em =.symtab=. |
|
||||
| Seção | Descrição |
|
||||
|---------+----------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| =.bss= | Contém dados globais não inicializados ou inicializados com zero; ocupa espaço na memória, mas não ocupa espaço no arquivo executável. |
|
||||
| =.data= | Contém dados globais inicializados; ocupa espaço tanto no arquivo quanto na memória. |
|
||||
| =.rodata= | Contém dados que não podem ser alterados (/read only/), geralmente usada para constantes e strings literais. |
|
||||
| =.text= | Seção que contém o código executável do programa (instruções da CPU). |
|
||||
| =.symtab= | Tabela de símbolos completa, usada pelo ligador e depuradores para localizar símbolos. |
|
||||
| =.strtab= | Tabela de strings que armazena os nomes dos símbolos referenciados em =.symtab=. |
|
||||
|
||||
* Tipos de segmentos
|
||||
|
||||
Na execução de um programa ELF, o sistema operacional utiliza a Tabela de
|
||||
Cabeçalhos do Programa para saber quais partes do arquivo devem ser carregadas
|
||||
Na execução de um programa ELF, o sistema operacional utiliza a tabela de
|
||||
cabeçalhos do programa para saber quais partes do arquivo devem ser carregadas
|
||||
na memória e como tratá-las. Cada entrada nessa tabela descreve um segmento
|
||||
que representa uma região de interesse para o carregador, como código do
|
||||
programa, seus dados, informações de ligação dinâmica e o caminho do carregador
|
||||
|
@ -178,53 +178,410 @@ Aqui estão alguns tipos de segmentos:
|
|||
| =GNU_EH_FRAME= | Informações para suporte à pilha de exceções (C, C++, etc.). |
|
||||
| =GNU_RELRO= | Segmento de dados que será tornado somente leitura após inicialização. |
|
||||
|
||||
* Definindo seções ELF em NASM para Linux 64 bits
|
||||
|
||||
** Exemplo de programa mínimo em Assembly
|
||||
Nós podemos definir qualquer seção ELF em Assembly NASM com a /diretiva/ =section=,
|
||||
ou com seu sinônimo =segment=, oriundo de uma terminologia mais antiga para
|
||||
arquiteturas x86 de 16 e 32 bits, onde o conceito de segmentação de memória era
|
||||
explícito. Em ambientes modernos, =section= é mais comum, pois reflete a
|
||||
nomenclatura utilizada no formato ELF e que está padronizada no editor de
|
||||
ligações =ld=, no /loader/ =ld-linux= e em ferramentas como =readelf= e =objdump=.
|
||||
|
||||
#+begin_src asm :tangle exemplos/03/sections.asm
|
||||
; Arquivo : sections.asm
|
||||
; Descrição : Demonstra a definição das seções .rodata, .data, .bss e .text
|
||||
; Montagem : nasm -f elf64 sections.asm
|
||||
; Link-edição: ld sections.o -o sections
|
||||
|
||||
section .rodata
|
||||
msg db "Eu sou imutável!", 0x0a
|
||||
len equ $ - msg
|
||||
|
||||
section .data
|
||||
contador dq 0 ; preenche 8 bytes (qword) com 0x00 em 'contador'
|
||||
|
||||
section .bss
|
||||
buffer resb 32 ; reserva 32 bytes no endereço 'buffer'
|
||||
|
||||
#+begin_src nasm :tangle elf_min.asm
|
||||
section .text
|
||||
global _start
|
||||
global _start ; ponto de entrada do programa
|
||||
|
||||
_start:
|
||||
mov rax, 60
|
||||
xor rdi, rdi
|
||||
syscall
|
||||
mov rax, 1 ; syscall: write
|
||||
mov rdi, 1 ; fd 1 = stdout
|
||||
mov rsi, msg ; endereço da mensagem
|
||||
mov rdx, len ; tamanho da mensagem
|
||||
syscall
|
||||
|
||||
mov rax, [contador] ; copia o dado no endereço 'contador' para rax
|
||||
inc rax ; incrementa em 1 o valor em rax
|
||||
mov [contador], rax ; copia o valor em rax para o endereço 'contador'
|
||||
|
||||
mov rax, 60 ; syscall: exit
|
||||
xor rdi, rdi ; estado de término = 0
|
||||
syscall
|
||||
#+end_src
|
||||
|
||||
** Compilação
|
||||
Antes de falarmos das seções do programa, é importante saber que, no caso de
|
||||
programas em Assembly link-editados para serem carregados pelo sistema como
|
||||
executáveis ELF, a ordem das seções no código-fonte só é mantida no arquivo
|
||||
objeto montado (=.o=). Mas, quando o objeto é link-editado para gerar o arquivo
|
||||
executável, o link-editor (=ld=) reorganiza as seções de modo a atender as
|
||||
especificações do formato ELF.
|
||||
|
||||
#+begin_src sh
|
||||
nasm -f elf64 -o elf_min.o elf_min.asm
|
||||
ld -o elf_min elf_min.o
|
||||
Montando e executando o programa:
|
||||
|
||||
#+begin_example
|
||||
:~$ nasm -f elf64 sections.asm
|
||||
:~$ ld sections.o -o sections
|
||||
:~$ ./sections
|
||||
Eu sou imutável!
|
||||
#+end_example
|
||||
|
||||
Com o utilitário =readelf=, nós podemos listar os cabeçalhos do programa:
|
||||
|
||||
#+begin_example
|
||||
$ readelf -l sections
|
||||
|
||||
Tipo de ficheiro Elf é EXEC (ficheiro executável)
|
||||
Entry point 0x401000
|
||||
There are 4 program headers, starting at offset 64
|
||||
|
||||
Cabeçalhos do programa:
|
||||
Tipo Desvio EndVirtl EndFís
|
||||
TamFich TamMem Bndrs Alinh
|
||||
LOAD 0x0000000000000000 0x0000000000400000 0x0000000000400000
|
||||
0x0000000000000120 0x0000000000000120 R 0x1000
|
||||
LOAD 0x0000000000001000 0x0000000000401000 0x0000000000401000
|
||||
0x0000000000000038 0x0000000000000038 R E 0x1000
|
||||
LOAD 0x0000000000002000 0x0000000000402000 0x0000000000402000
|
||||
0x0000000000000012 0x0000000000000012 R 0x1000
|
||||
LOAD 0x0000000000002014 0x0000000000403014 0x0000000000403014
|
||||
0x0000000000000008 0x000000000000002c RW 0x1000
|
||||
|
||||
Secção para mapa do segmento:
|
||||
Secções do segmento...
|
||||
00
|
||||
01 .text
|
||||
02 .rodata
|
||||
03 .data .bss
|
||||
#+end_example
|
||||
|
||||
Onde:
|
||||
|
||||
- A seção =.text= inicia no byte =0x1000= do arquivo e ocupa 56 bytes (=0x38=).
|
||||
- A seção =.rodata= inicia no byte =0x2000= do arquivo e ocupa 18 bytes (=0x12=).
|
||||
- A seção =.data= inicia no byte =0x2014= do arquivo e ocupa 8 bytes.
|
||||
- A seção =.bss= é indicada para mapeamento na execução, mas não ocupa
|
||||
espaço no arquivo binário.
|
||||
|
||||
#+begin_quote
|
||||
*Nota:* Repare que as seções =.text= e =.rodata= só têm permissão de leitura (=R=),
|
||||
enquanto =.data= e =.bss= têm permissão de leitura e escrita (=RW=).
|
||||
#+end_quote
|
||||
|
||||
Nós podemos localizar a definição da seção =.bss= listando a tabela de cabeçalhos
|
||||
de seção, utilizada para orientar o mapeamento do executável nos segmentos da
|
||||
memória:
|
||||
|
||||
#+begin_example
|
||||
:~$ readelf -S sections
|
||||
There are 8 section headers, starting at offset 0x2188:
|
||||
|
||||
Cabeçalhos de secção:
|
||||
[Nr] Nome Tipo Endereço Desvio
|
||||
Tam. Tam.Ent Bands Lig. Info Alinh
|
||||
[ 0] NULL 0000000000000000 00000000
|
||||
0000000000000000 0000000000000000 0 0 0
|
||||
[ 1] .text PROGBITS 0000000000401000 00001000
|
||||
0000000000000038 0000000000000000 AX 0 0 16
|
||||
[ 2] .rodata PROGBITS 0000000000402000 00002000
|
||||
0000000000000012 0000000000000000 A 0 0 4
|
||||
[ 3] .data PROGBITS 0000000000403014 00002014
|
||||
0000000000000008 0000000000000000 WA 0 0 4
|
||||
[ 4] .bss NOBITS 000000000040301c 0000201c
|
||||
0000000000000024 0000000000000000 WA 0 0 4
|
||||
[ 5] .symtab SYMTAB 0000000000000000 00002020
|
||||
00000000000000f0 0000000000000018 6 6 8
|
||||
[ 6] .strtab STRTAB 0000000000000000 00002110
|
||||
000000000000003e 0000000000000000 0 0 1
|
||||
[ 7] .shstrtab STRTAB 0000000000000000 0000214e
|
||||
0000000000000034 0000000000000000 0 0 1
|
||||
Key to Flags:
|
||||
W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
|
||||
L (link order), O (extra OS processing required), G (group), T (TLS),
|
||||
C (compressed), x (unknown), o (OS specific), E (exclude),
|
||||
D (mbind), l (large), p (processor specific)
|
||||
#+end_example
|
||||
|
||||
Aqui, nós podemos ver que =.bss= deve ocupar um espaço de 36 bytes na memória
|
||||
(=0x24=), a partir do endereço de /offset/ 0x40301c. A diferença entre os 32 bytes
|
||||
reservados no programa e os 36 bytes que vemos na tabela, é o resultado do
|
||||
alinhamento de 4 bytes aplicado pelo =ld=, como podemos ver na última coluna
|
||||
da tabela.
|
||||
|
||||
** Uma nota sobre alinhamento de dados
|
||||
|
||||
Em sistemas Linux 64 bits, é comum que dados sejam alinhados a endereços
|
||||
múltiplos de 8 bytes, o que corresponde à largura dos registradores e garante
|
||||
acesso eficiente e seguro à memória. Se pegarmos o /offset/ da seção =.bss=
|
||||
(=0x201c=) e somarmos os 32 bytes reservados no programa, nós veremos que o
|
||||
próximo dado teria que ser escrito no /offset/ =0x203c= (8252, em base 10), que
|
||||
não é múltiplo de 8 (~8252/8=1031.5~). Somando 4 ao próximo endereço, nós
|
||||
chegamos ao /offset/ =0x2040= (8256, em base 10), que é um múltiplo de 8
|
||||
(~8256/8=1032.0~).
|
||||
|
||||
No entanto, observe que as seções =.rodata= e =.data= também tiveram alinhamento,
|
||||
mas seus tamanhos não são diferentes daqueles definidos no código-fonte. Isso
|
||||
aconteceu porque, diferente de =.bss=, os dados em =.rodata= e em =.data= foram
|
||||
inicializados e, por definição, =.bss= é uma região reservada para dados não
|
||||
inicializados -- logo, o tamanho da seção inclui os bytes de alinhamento.
|
||||
|
||||
#+begin_quote
|
||||
*Nota:* O nome =.bss= vem da linguagem Fortran e significa /Block Started by Symbol/
|
||||
(/bloco iniciado por um símbolo/, em tradução livre).
|
||||
#+end_quote
|
||||
|
||||
** Inspecionando a seção .rodata
|
||||
|
||||
#+begin_src asm
|
||||
section .rodata
|
||||
msg db "Eu sou imutável!", 0x0a
|
||||
len equ $ - msg
|
||||
#+end_src
|
||||
|
||||
** Inspeção do ELF
|
||||
Aqui, o endereço de rótulo =msg= receberá a cadeia de bytes definida com a
|
||||
diretiva de /definição de bytes/ (=db=). Na montagem, esses bytes serão escritos
|
||||
na seção =.rodata=, onde não poderão ser alterados.
|
||||
|
||||
#+begin_src sh
|
||||
file elf_min
|
||||
readelf -h elf_min
|
||||
readelf -S elf_min # Seções
|
||||
readelf -l elf_min # Segmentos (program headers)
|
||||
objdump -d elf_min
|
||||
hexdump -C elf_min | less
|
||||
Como visto na tabela de cabeçalhos do programa, a seção =.rodata= está no
|
||||
/offset/ =0x002000= do arquivo e tem permissão apenas para leitura (=R=):
|
||||
|
||||
#+begin_example
|
||||
Tipo Desvio EndVirtl EndFís
|
||||
TamFich TamMem Bndrs Alinh
|
||||
...
|
||||
LOAD 0x0000000000002000 0x0000000000402000 0x0000000000402000
|
||||
0x0000000000000012 0x0000000000000012 R 0x1000
|
||||
...
|
||||
#+end_example
|
||||
|
||||
Seu conteúdo também pode ser visualizado com a opção =-x= do =readelf=:
|
||||
|
||||
#+begin_example
|
||||
:~$ readelf -x .rodata sections
|
||||
|
||||
Despejo máximo da secção ".rodata":
|
||||
0x00402000 45752073 6f752069 6d7574c3 a176656c Eu sou imut..vel
|
||||
0x00402010 210a !.
|
||||
#+end_example
|
||||
|
||||
Ou com o =xxd=, utilizando as opções =-s= (/skip/) e =-l= (/length/):
|
||||
|
||||
#+begin_example
|
||||
:~$ xxd -s 0x2000 -l 32 sections
|
||||
00002000: 4575 2073 6f75 2069 6d75 74c3 a176 656c Eu sou imut..vel
|
||||
00002010: 210a 0000 0000 0000 0000 0000 0000 0000 !...............
|
||||
#+end_example
|
||||
|
||||
** Inspeção da seção .data
|
||||
|
||||
#+begin_src asm
|
||||
|
||||
section .data
|
||||
contador dq 0 ; preenche 8 bytes (qword) com 0x00 em 'contador'
|
||||
#+end_src
|
||||
|
||||
** Versão em C para comparação
|
||||
Neste exemplo, o valor =0= será escrito na seção =.data=, no endereço indicado
|
||||
pelo rótulo =contador=, e ocupara 8 bytes (diretiva =dq=), resultando em 8 bytes
|
||||
no arquivo (e na memória) preenchidos com zeros.
|
||||
|
||||
#+begin_src C :tangle elf_min.c
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
No NASM, os dados podem ser definidos com tamanhos de:
|
||||
|
||||
- 1 byte: =db=, de /define bytes/
|
||||
- 2 bytes: =dw=, de /define word/
|
||||
- 4 bytes: =dd=, de /define double word/
|
||||
- 8 bytes =dq=, de /define quad word/
|
||||
|
||||
Como visto na tabela de cabeçalhos do programa, a seção =.data= inicia no
|
||||
/offset/ =0x2014= do arquivo e tem permissões de leitura e escrita (=RW=):
|
||||
|
||||
#+begin_example
|
||||
Tipo Desvio EndVirtl EndFís
|
||||
TamFich TamMem Bndrs Alinh
|
||||
...
|
||||
LOAD 0x0000000000002014 0x0000000000403014 0x0000000000403014
|
||||
0x0000000000000008 0x000000000000002c RW 0x1000
|
||||
...
|
||||
#+end_example
|
||||
|
||||
Seu conteúdo pode ser visualizado com a opção =-x= do =readelf=:
|
||||
|
||||
#+begin_example
|
||||
:~$ readelf -x .data sections
|
||||
|
||||
Despejo máximo da secção ".data":
|
||||
0x00403014 00000000 00000000 ........
|
||||
#+end_example
|
||||
|
||||
Ou com o =xxd=, sabendo seu tamanho:
|
||||
|
||||
#+begin_example
|
||||
:~$ xxd -s 0x2014 -l 8 sections
|
||||
00002014: 0000 0000 0000 0000 ........
|
||||
#+end_example
|
||||
|
||||
Ainda no exempĺo, nós escrevemos uma rotina para incrementar o valor no
|
||||
endereço identificado pelo rótulo =contador=:
|
||||
|
||||
#+begin_src asm
|
||||
mov rax, [contador] ; copia o dado no endereço 'contador' para rax
|
||||
inc rax ; incrementa em 1 o valor em rax
|
||||
mov [contador], rax ; copia o valor em rax para o endereço 'contador'
|
||||
#+end_src
|
||||
|
||||
** Exercícios
|
||||
#+begin_quote
|
||||
Em Assembly, isso é o mais próximo que podemos chegar do conceito de
|
||||
/variáveis/, próprio de linguagens de alto nível.
|
||||
#+end_quote
|
||||
|
||||
1. Compare os headers do binário gerado em C com o de Assembly.
|
||||
2. Use `readelf -x .text` para inspecionar o código de máquina.
|
||||
3. Modifique o binário com `hexedit` para alterar manualmente um byte do código.
|
||||
4. Gere um programa com `.data` e `.bss` e localize essas seções no ELF.
|
||||
O efeito dessa rotina só pode ser examinado com o programa em execução, por
|
||||
exemplo, com o depurador GDB (GNU Debugger). Mas, antes, o programa terá que
|
||||
ser montado com símbolos de depuração (opção =-g= do =nasm=):
|
||||
|
||||
** Referências
|
||||
- man 5 elf
|
||||
#+begin_example
|
||||
:~$ nasm -g -f elf64 sections.asm
|
||||
:~$ ld sections.o -o sections
|
||||
#+end_example
|
||||
|
||||
Carregando o programa com o GDB:
|
||||
|
||||
#+begin_example
|
||||
:~$ gdb sections
|
||||
Reading symbols from sections...
|
||||
#+end_example
|
||||
|
||||
Listando o código-fonte (=list=) para descobrir as linhas antes e depois da
|
||||
alteração do dado em =contador=:
|
||||
|
||||
#+begin_example
|
||||
(gdb) list
|
||||
1 ; Arquivo : sections.asm
|
||||
2 ; Descrição : Demonstra a definição das seções .rodata, .data, .bss e .text
|
||||
3 ; Montagem : nasm -f elf64 sections.asm
|
||||
4 ; Link-edição: ld sections.o -o sections
|
||||
5
|
||||
6 section .rodata
|
||||
7 msg db "Eu sou imutável!", 0x0a
|
||||
8 len equ $ - msg
|
||||
9
|
||||
10 section .data
|
||||
(gdb)
|
||||
11 contador dq 0 ; preenche 8 bytes (qword) com 0x00 em 'contador'
|
||||
12
|
||||
13 section .bss
|
||||
14 buffer resb 32 ; reserva 32 bytes no endereço 'buffer'
|
||||
15
|
||||
16 section .text
|
||||
17 global _start ; ponto de entrada do programa
|
||||
18
|
||||
19 _start:
|
||||
20 mov rax, 1 ; syscall: write
|
||||
(gdb)
|
||||
21 mov rdi, 1 ; fd 1 = stdout
|
||||
22 mov rsi, msg ; endereço da mensagem
|
||||
23 mov rdx, len ; tamanho da mensagem
|
||||
24 syscall
|
||||
25
|
||||
26 mov rax, [contador] ; copia o dado no endereço 'contador' para rax
|
||||
27 inc rax ; incrementa em 1 o valor em rax
|
||||
28 mov [contador], rax ; copia o valor em rax para o endereço 'contador'
|
||||
29
|
||||
30 mov rax, 60 ; syscall: exit
|
||||
(gdb)
|
||||
31 xor rdi, rdi ; estado de término = 0
|
||||
32 syscall
|
||||
#+end_example
|
||||
|
||||
Definindo os pontos de parada (=break=) nas linhas 26 e 30:
|
||||
|
||||
#+begin_example
|
||||
(gdb) break 26
|
||||
Breakpoint 1 at 0x40101b: file sections.asm, line 26.
|
||||
(gdb) break 29
|
||||
Breakpoint 2 at 0x40102e: file sections.asm, line 30.
|
||||
#+end_example
|
||||
|
||||
Executando o programa (=run=):
|
||||
|
||||
#+begin_example
|
||||
(gdb) run
|
||||
Starting program: /home/blau/git/pbn/curso/exemplos/03/sections
|
||||
Eu sou imutável!
|
||||
|
||||
Breakpoint 1, _start () at sections.asm:26
|
||||
26 mov rax, [contador] ; copia o dado no endereço 'contador' para rax
|
||||
#+end_example
|
||||
|
||||
Imprimindo o valor no endereço =contador= (8 bytes equivale ao tipo =long=):
|
||||
|
||||
#+begin_example
|
||||
(gdb) print (long *)contador
|
||||
$1 = (long *) 0x0
|
||||
#+end_example
|
||||
|
||||
Continuando a execução (=continue=):
|
||||
|
||||
#+begin_example
|
||||
(gdb) continue
|
||||
Continuing.
|
||||
|
||||
Breakpoint 2, _start () at sections.asm:30
|
||||
30 mov rax, 60 ; syscall: exit
|
||||
#+end_example
|
||||
|
||||
Verificando a alteração do valor no endereço =contador=:
|
||||
|
||||
#+begin_example
|
||||
(gdb) print (long *)contador
|
||||
$2 = (long *) 0x1
|
||||
#+end_example
|
||||
|
||||
* Exercícios propostos
|
||||
|
||||
1. Crie um exemplo em C onde seja possível observar as seções =.text=, =.rodata=,
|
||||
=.data= e =.bss=.
|
||||
2. Com o arquivo objeto do exemplo =sections.asm=, tente interpretar as
|
||||
informações presentes no seu cabeçalho ELF (a descrição dos campos
|
||||
pode ser encontrada na página "ELF" da wiki OS Dev, nas referências).
|
||||
3. Em seguida, interprete o cabeçalho ELF do arquivo executável e anote
|
||||
as diferenças, se houver.
|
||||
|
||||
** Desafio
|
||||
|
||||
Sabendo que o NASM pode montar binários puros, tente criar um programa que
|
||||
resulte em um arquivo executável 64 bits utilizando apenas as especificações
|
||||
ELF para definir os bytes de seu conteúdo, que deverá ser funcional sem a
|
||||
edição de ligações. O programa não precisa fazer nada além de terminar com
|
||||
estado de saída 42.
|
||||
|
||||
Para montar e dar permissões de execução:
|
||||
|
||||
#+begin_example
|
||||
:~$ nasm -f bin -o elf_exit42 elf_exit42.asm
|
||||
:~$ chmod +x elf_exit42
|
||||
#+end_example
|
||||
|
||||
Para testá-lo:
|
||||
|
||||
#+begin_example
|
||||
$ ./elf_exit42
|
||||
$ echo $?
|
||||
42
|
||||
#+end_example
|
||||
|
||||
* Referências
|
||||
|
||||
- =man 5 elf=
|
||||
- [[https://wiki.osdev.org/ELF][OS Dev: ELF]]
|
||||
- https://refspecs.linuxfoundation.org/elf/elf.pdf
|
||||
- https://wiki.osdev.org/ELF
|
||||
|
|
32
curso/exemplos/03/sections.asm
Normal file
32
curso/exemplos/03/sections.asm
Normal file
|
@ -0,0 +1,32 @@
|
|||
; Arquivo : sections.asm
|
||||
; Descrição : Demonstra a definição das seções .rodata, .data, .bss e .text
|
||||
; Montagem : nasm -f elf64 sections.asm
|
||||
; Link-edição: ld sections.o -o sections
|
||||
|
||||
section .rodata
|
||||
msg db "Eu sou imutável!", 0x0a
|
||||
len equ $ - msg
|
||||
|
||||
section .data
|
||||
contador dq 0 ; preenche 8 bytes (qword) com 0x00 em 'contador'
|
||||
|
||||
section .bss
|
||||
buffer resb 32 ; reserva 32 bytes no endereço 'buffer'
|
||||
|
||||
section .text
|
||||
global _start ; ponto de entrada do programa
|
||||
|
||||
_start:
|
||||
mov rax, 1 ; syscall: write
|
||||
mov rdi, 1 ; fd 1 = stdout
|
||||
mov rsi, msg ; endereço da mensagem
|
||||
mov rdx, len ; tamanho da mensagem
|
||||
syscall
|
||||
|
||||
mov rax, [contador] ; copia o dado no endereço 'contador' para rax
|
||||
inc rax ; incrementa em 1 o valor em rax
|
||||
mov [contador], rax ; copia o valor em rax para o endereço 'contador'
|
||||
|
||||
mov rax, 60 ; syscall: exit
|
||||
xor rdi, rdi ; estado de término = 0
|
||||
syscall
|
Loading…
Add table
Reference in a new issue