Anotações aula 10 #19
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
LENBUF
Buffer é um espaço na memória utilizado para acumular cadeia de bytes, normalmente caracteres.
E quando falamos em assembly, não temos as caracteristícas de alto nível, como o conceito de vetor, que é uma estrutura de dados do mesmo tipo/tamanho.
Em baixo nível não temos a medida, somos nós é que vamos dizer. Se reservarmos 20 bytes para receber dados e reservar 5 double words para o baixo nível isto não faz diferença. Depende de de como vamos acessar o endereço do primeiro dado.
Se puxarmos os conceitos de alto nível vamos pensar que o programa vai pensar as convenções de tipo, mas ele não vai. Outro problema é termos dificuldade de elaborar uma solução por estarmos justamente preocupados com isso.
Outro ponto importante é que em alto nível, temos a tradução direta de, por exemplo, um dado escrito na memória com a ordem invertida dos bytes little endian e quando acessamos está na ordem "correta". Mas em baixo nível isto acontece.
A ordem com que processamos certas informações, principalmente quando vamos escrever em buffers vai afetar a sequência e a localização que os bites serão acessados.
Depois, entramos no exemplo que está nas issues para aula 10.
pbuf.asm
Este exemplo reúne vários problemas e antecipa possíveis soluções para outros que ainda não conhecemos.
Reservamos em .bss um espaço de 5 double words(4 bytes cada) _ buf resd 5_ que multiplicado por 5, temos 20. No endereço, rotulado buf temos este espaço para 20 bytes. Que podemos utilizar para 19 caracteres mais o nulo.
Este número também é suficiente para escrevermos o maior número inteiro longo sem sinal neste espaço - razão para escolhermos este valor.
No espaço em .rodata temos uma string que é uma sequência de 10 caracteres e terminador nulo. Pois vamos imprimir e manipular o conteúdo do espaço da memória.
É necessário colocar ,0 para termos o terminador nulo, após as aspas da string.
Depois entramos na seção .text e na entrada do programa.
E vamos calcular o tamanho da string em txt.
Para isso, apresentamos a importância de trabalhar com subrotinas. Depois conversamos sobre a importância delas, para organizar o código e possíveis abstrações.
Começamos pela implementação da subrotina para obter o tamanho da rotina até exclusive ou terminador nulo: a estratégia é percorrer cada um dos bytes e implementar um contador.
Na subrotina str_len temos organizadas a entrada, os dados onde se esperam alterações (saída) e os registradores afetados.
Por exemplo, vimos que a chamada syscall altera alguns registradores e é importante preservar seja na subrotina ou antes de fazer a chamada da subrotina. Por isso é importante comentar.
Na abordagem, sabemos que o registrador rsi tem nome de source index, então todas as vezes que pensamos em origem, já utilizamos ele. Nela que vamos receber o tamanho da string. Endereço do primeiro byte.
A mesma coisa em relação a rax que é acumulador, porém, todas as convenções que temos, de chamada de função e de chamadas de sistema, os retornos das funções são dados pelo registrador rax primeiramente. Ao manter esta coerência, quando tenho que dar um retorno, utilizamos ele como saída.
A rotina é extremamente simples. Vamos utilizar rcx como contador, também pelo nome associado, mas poderia ser outro.
Este contador deve ser inicializado por 0, como é normalmente um índice. A estratégia será utilizador o registrador rax neste momento para receber cada um dos bytes do endereço em rsi, incrementar o contador, o endereço e fazer o teste para saber se este byte jé é o zero. Em loop, resolve o problema.
Agora vamos utilizar o byte menos significativa de rax utilizado em al para receber o byte em rsi. Comparamos com zero e se for, chegamos ao fim da string. Se não for, incrementamos rsi e rcx.
Em .done a subrotina move os dados em rax conforme especificação criada no próprio programa.
Conversamos que em assembly string não é necessariamente uma cadeia de caracteres terminada em zero, este é um conceito de alto nível, mas existem várias convenções que utilizam esta implementação.
Comentários do Juca no chat:
existem programas que trabalham com 1 byte indicando o número de caracteres da string seguido pelons N bytes
20:12
Felipe "Juca" Sanches disse:existe até programas que usam 2 bytes para o número de caracteres
20:13
Felipe "Juca" Sanches disse:a linguagem C veio antes do formato ELF
No compilador C, as regras foram implementadas em determinado momento.
Em assembly, você convenciona do jeito que queremos. Estamos apenas convenciando próximo ao nosso sistema que é mais natural, para seguirmos algumas soluções da glib formato ELF, etc.
Xico comentou sobre utilizarmos uma operação de soma em .count_loop.
Como poderíamos testar se rax tem de fato a quantidade de caracteres, no caso 10?
gdb, marcando breakpoint e manda rodar, quando chegar no ponto de parada temos o info registers rax.
Depois, voltamos para a impressão da string que está no endereço txt com _bufp_Onde vamos utilizar rsi de novo para conseguir o primeiro endereço de txt. Ela chama a subrotina echo_str, que chama outras duas subrotinas.
Uma maneira de deixar o código mais enxuto.
Outra coisa que normalmente precisamos fazer é copiar um string/endereço de origem para um endeço de destino, por isso a subrotina write_buf. Utilizamos rdi neste caso, por padronização, já d é de destination.
Em .write_loop copiamos e escrevemos os dados que vão ser manipulados.
Após copiar e imprimir o buffer. Vamos inverter o conteúdo da string com a subrotina rev_buf