# Instruções de movimentação de dados

### MOVAP(S|D)/MOVUP(S|D) | Move Aligned/Unaligned Packed (Single|Double)-precision floating-point

```nasm
MOVAPS xmm(n), xmm(n)
MOVAPS xmm(n), float(4)
MOVAPS float(4), xmm(n)

MOVUPS xmm(n), xmm(n)
MOVUPS xmm(n), float(4)
MOVUPS float(4), xmm(n)


MOVAPD xmm(n), xmm(n)
MOVAPD xmm(n), double(2)
MOVAPD double(2), xmm(n)

MOVUPD xmm(n), xmm(n)
MOVUPD xmm(n), double(2)
MOVUPD double(2), xmm(n)
```

As instruções MOVAPS e MOVUPS fazem a mesma coisa: Movem 4 valores *float* empacotados entre registradores XMM ou de/para memória principal. MOVAPD e MOVUPD porém lida com 2 valores *double*.

A diferença é que a instrução MOVAPS/MOVAPD espera que o endereço do valor na memória esteja alinhado a um valor de 16 bytes, caso não esteja a instrução dispara uma exceção #GP (General Protection ou "segmentation fault" como é conhecido no Linux). O motivo dessa instrução exigir isso é que acessar o endereço alinhado é muito mais performático.

Já a instrução MOV**U**PS/MOV**U**PD pode acessar um endereço de memória desalinhado (***u**naligned*) sem ocorrer nenhum erro, porém ela é menos performática.

Um exemplo de uso da MOVAPS na nossa PoC:

{% tabs %}
{% tab title="main.c" %}

```c
#include <stdio.h>

void assembly(float *array);

int main(void)
{
  float array[4];
  assembly(array);

  printf("%f, %f, %f, %f\n", array[0], array[1], array[2], array[3]);
  return 0;
}
```

{% endtab %}

{% tab title="assembly.asm" %}

```nasm
bits 64
default rel

section .rodata align=16
    local_array: dd 1.23
                 dd 2.45
                 dd 3.67
                 dd 4.89

section .text

global assembly
assembly:
    movaps xmm5, [local_array]
    movaps [rdi], xmm5
    ret

```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
Sem entrar em detalhes ainda sobre a convenção de chamada, o ponteiro recebido como argumento pela função **assembly()** está no registrador RDI.

Sobre o atributo **align=16** usado na seção **.rodata** ele serve para fazer exatamente o que o nome sugere: Alinhar o endereço inicial da seção em um múltiplo de 16, que é uma exigência da instrução MOVAPS.
{% endhint %}

Um detalhe interessante que vale citar é que apesar da instrução ter sido feita para lidar com um determinado tipo de dado nada impede de nós carregarmos outros dados nos registradores XMM. No exemplo abaixo usei a instrução MOVUPS para mover uma string de 16 bytes com apenas duas instruções:

{% tabs %}
{% tab title="main.c" %}

```c
#include <stdio.h>

void assembly(char *array);

int main(void)
{
  char text[16];
  assembly(text);

  printf("Resultado: %s\n", text);
  return 0;
}
```

{% endtab %}

{% tab title="assembly.asm" %}

```nasm
bits 64
default rel

section .rodata
    string: db "Hello World!", 0, 0, 0, 0

section .text

global assembly
assembly:
    movups xmm0, [string]
    movups [rdi], xmm0
    ret
```

{% endtab %}
{% endtabs %}

### MOVS(S|D) | Move Scalar (Single|Double)-precision floating-point

```nasm
MOVSS xmm(n), xmm(n)
MOVSS xmm(n), float(1)
MOVSS float(1), xmm(n)


MOVSD xmm(n), xmm(n)
MOVSD xmm(n), double(1)
MOVSD double(1), xmm(n)
```

Move um único *float/double* entre registradores XMM, onde o valor estaria contido na *double word* (4 bytes) ou *quadword* (8 bytes) menos significativo do registrador. E também é possível mover de/para memória principal.

### MOVLP(S|D) | Move Low Packed (Single|Double)-precision floating-point

```nasm
MOVLPS xmm(n), float(2)
MOVLPS float(2), xmm(n)


MOVLPD xmm(n), double(1)
MOVLPD double(1), xmm(n)
```

A instrução MOVLPS instrução é semelhante à MOVUPS porém carrega/escreve apenas dois floats. No registrador os dois *floats* ficam armazenados no *quadword* (8 bytes) menos significativo. O *quadword* mais significativo do registrador não é alterado.

Já MOVLPD faz a mesma operação porém com um *double* contido no *quadword* menos significativo.

### MOVHP(S|D) | Move High Packed (Single|Double)-precision floating-point

```nasm
MOVHPS xmm(n), float(2)
MOVHPS float(2), xmm(n)


MOVHPD xmm(n), double(1)
MOVHPD double(1), xmm(n)
```

Semelhante a instrução acima porém armazena/ler o valor do registrador XMM no *quadword* mais significativo. O *quadword* menos significativo do registrador não é alterado.

### MOVLHPS | Move Packed Single-precision floating-point Low to High

```nasm
MOVLHPS xmm(n), xmm(n)
```

Move o *quadword* (8 bytes) menos significativo do registrador fonte (a direita) para o *quadword* mais significativo do registrador destino. O *quadword* menos significativo do registrador destino não é alterado.

### MOVHLPS | Move Packed Single-precision floating-point High to Low

```nasm
MOVHLPS xmm(n), xmm(n)
```

Move o *quadword* (8 bytes) mais significativo do registrador fonte (a direita) para o *quadword* menos significativo do registrador destino. O *quadword* mais significativo do registrador destino não é alterado.

### MOVMSKP(S|D) | Move Packed (Single|Double)-precision floating-point mask

```
MOVMSKPS reg32/64, xmm(n)


MOVMSKPD reg32/64, xmm(n)
```

MOVMSKPS move os bits mais significativos (MSB) de cada um dos quatro valores *float* contido no registrador XMM para os 4 bits menos significativo do registrador de propósito geral. Os outros bits do registrador são zerados.

Já MOVMSKPD faz a mesma coisa porém com os 2 valores *doubles* contidos no registrador, assim definindo os 2 bits menos significativos do registrador de propósito geral.

Essa instrução pode ser usada com o intuito de verificar o sinal de cada um dos valores *float/double*, tendo em vista que o bit mais significativo é usado para indicar o sinal do número (**0** caso positivo e **1** caso negativo).


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://mentebinaria.gitbook.io/assembly/aprofundando-em-assembly/entendendo-sse/instrucoes-de-movimentacao-de-dados.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
