paulo1205
(usa Ubuntu)
Enviado em 15/05/2016 - 06:26h
Assembly não é muito a minha praia, mas vamos lá.
joaovitor02 escreveu:
Boa noite, estou começando a estudar assembly e tenho dúvidas sobre o exercício que estou resolvendo. O primeiro estou tentando criar uma seção de variáveis nao inicializadas, e as inicializadas e fazer as seguintes cópias
n1 = v1
n2 = v2
n3 = v3
fiz este código, gostaria de ver se está realmente certo o que eu fiz ou se tem possível melhoras, usar algum outro registrador
Você está usando sintaxe Intel. Está usando NASM, gas com opção “-msyntax=intel”, ou algum outro assembler? Algumas das coisas que eu vou dizer podem depender dos defaults do seu assembler.
section .data
v1: db 10d
v2: dd -20d
v3: dq -30d
Cuidado com o alinhamento de variáveis.
v1,
v2 e
v3 têm tamanhos, respectivamente, de 1, 2 e 4 bytes. Quando eu testei seu programa aqui (depois de adaptá-lo para sintaxe AT&T, usando gas, antes de descobrir que o gas aceita também sintaxe Intel), essa ordem de declaração deixou
v2 e
v3 em endereços ímpares, o que pode prejudicar o desempenho de acesso.
Se o seu assembler fornecer alinhamento otimizado automaticamente, um efeito colateral pode ser um aumento no tamanho do código (nesse caso, de apenas um byte, ao empurrar
v2 um byte para frente, para alinhá-lo num endereço múltiplo de 2;
v3 vai de carona, e acaba alinhado num múltiplo de 4, como deveria mesmo ser).
Curiosamente (ou nem tanto), se você inverter a ordem das variáveis (nesse caso) e já começar alinhado em múltiplo de 4, não terá nenhum problema de alinhamento.
section .bss
n1: resb 1
n2: resw 2
n3: resd 4
Mesmos comentários a respeito de alinhamento.
section .text
global _start
_start:
mov al , [v1]
mov [n1] , al
mov ebx , [v2]
mov [n2] , ebx
Na cópia de
v2 para
n2, você usou um registrador de 4 bytes (
EBX) para copiar um dado de apenas 2 (que caberia perfeitamente bem em apenas
BX). Na leitura, isso pode significar perda de desempenho por possíveis problemas de alinhamento (
BX supostamente usaria alinhamento 2 para não perder desempenho; para
EBX, esse alinhamento teria de ser 4). Na escrita, além do alinhamento, existe a possibilidade de você acabar sobrescrevendo dois bytes adjacentes a
n2 e que talvez pertençam a outro dado (isso de fato ocorreu na versão que eu testei aqui).
Se você
garantir que os dados (particularmente o de destino) estão alinhados em endereços múltiplos de 4, não haverá maiores problemas com as transferências feitas com um registrador de 4 bytes (aliás, pode até ser uma otimização, pois as instruções que movimentam 2 bytes são ocupam um byte a mais na memória do que as que manipulam 1, 4 ou 8 bytes). Entretanto, se você eventualmente for fazer contas com tais dados, terá de se lembrar de usar apenas os bytes relevantes, e o leitor do seu código eventualmente poderá estranhar se você fizer transferências com
EBX mas operar apenas com
BX.
mov al , [v3]
mov [n3] , al
Aqui você fez meio que o oposto: de um dado declarado como tendo 4 bytes de comprimento, está transferindo apenas um byte. Não é um erro, mas certifique-se de que é isso mesmo que você quer.
fim:
mov rax, 1
mov rbx, 0
Cada uma dessas instruções gera 7 bytes depois de montadas, num total de 14. Se você as substituir por
xor rax, rax
inc rax
xor rbx, rbx
terá os mesmos resultados, mas com um total de apenas 9 bytes (3 de cada instrução; no caso da atribuição de
RAX, fica um byte mais curta, na de
RBX, diminui 4 bytes). Entretanto, note que essa alternativa altera os valores dos flags. Se os valores dos flags forem importantes para a operação que você fizer em seguida, a forma original, com
MOV, pode ser preferível.
Outra coisa, de que quase esqueci (e aqui vou usar a sintaxe AT&T porque não sei como é o equivalente com sintaxe Intel): em todas as operações com
mov de/para endereço fixo, as formas “mov v1(%rip), %al” e “mov %al, n1(%rip)” produzem, cada uma, um byte a menos do que as respectivas e equivalentes versões “mov v1, %al” e “mov %al, n1”, que foi o que você usou originalmente.