[PT-BR] Introdução à programação em baixo nível
Tags: computerscience, tutorial, beginners, performance
Published: 2022-05-17 19:05:13

## O que é programação em baixo nível?

Programação em baixo nível é um tipo de programação mais próxima do hardware, ou seja, utilizando linguagens de programação muito próximas à linguagem de máquina. Programando em linguagens de baixo nível, é possível ter total controle dos recursos de máquina; é possível acessar registradores, memória e cache diretamente e também alocar espaço de memória.

&nbsp;

## Como um programa é executado?

Primeiramente o código é compilado de uma linguagem de alto nível para uma linguagem de baixo nível. Após isso, esse código de baixo nível deve ser montado e linkeditado.

Dadas essas etapas, o código já pode ser executado, porém a execução também possui algumas etapas, sendo elas:

1. Fetch
2. Decode
3. Execute
4. Move o ponteiro para a próxima instrução
5. Volta para o primeiro passo

&nbsp;

## Mas, afinal o que são linguagens de alto nível?

As linguagens de programação de alto nível são aquelas que, grosso modo, estão mais próximas da linguagem humana do que da linguagem de máquina. Geralmente têm a maioria dos seus termos em inglês e não requerem manipulação direta da memória e dos registradores.

### Exemplos de linguagens de programação de alto nível

- JavaScript
- Java
- Python
- Elixir
- PHP

### Exemplos de linguagens de programação de baixo nível

- Assembly ARM - 64 bits
- Assembly AMD/Intel - 64 bits
- Assembly 8086

&nbsp;

## C e C++ são linguagens de alto nível?

Muitas pessoas ficam confusas ao escutarem que C e C++ são linguagens de alto nível, isso acontece, pois essas linguagens são consideradas “complicadas” e “difíceis”. Se considerarmos a definição formal, sim, elas são consideradas linguagem de alto nível, pois elas são muito mais próximas do inglês do que o Assembly e não requerem manipulação direta da memória e dos registradores; APESAR de ser possível.

Porém, se você comparar C ou C++ com Python ou JavaScript por exemplo, a diferença será enorme a um ponto que elas podem ser consideradas linguagens de baixo nível. Entretanto, se compararmos essas mesmas linguagens com Assembly ou código binário, elas são consideradas linguagens de alto nível.

Oficialmente essas linguagens são de alto nível, mas devido a essa questão de perspectiva, eu gosto de pensar que elas são linguagens de nível intermediário.

### O que é Assembly e como funciona?

Assembly é uma linguagem de montagem, ela é classificada como baixo nível. Assembly não é compilada e nem interpretada, ela é montada. Quando dizemos que uma linguagem é “de montagem” ou “montada”, isso significa que para cada palavra naquela linguagem há um binário exato, idêntico, portanto não existe uma tradução, apenas uma associação entre os mneumônicos (palavras) e seus respectivos binários.

Assembly é uma linguagem, porém ela possui muitas variações, pois por ser uma linguagem extremamente próxima à maquina, ela depende da arquitetura do computador. Há vários tipos de Assembly para diferentes arquiteturas, 16 bits, 32 bits, 64 bits, Intel, ARM etc. Por isso nos referimos a linguagens de baixo nível como “não portáveis”.

O programa responsável pela montagem do código Assembly para binário é chamado de Assembler, e assim como já dito antes, cada Assembler é diferente de acordo com a sua arquitetura de máquina.

&nbsp;

## Gerando código de baixo nível

Vamos ver um exemplo comparativo de código de baixo nível (Assembly) e código C. Um algoritmo bem simples é o bubble sort, muito utilizado para ordenação de arrays. O código em C para esse algoritmo é o seguinte:

```c
#include <stdio.h>

void print_array(int arr[], int arr_length) {
    for (int k = 0; k < arr_length; k++) {
        printf("%d, ", arr[k]);
    }
}

void bubblesort(int arr[], int arr_length) {

    int swap;

    for (int i = 0; i < arr_length; i++) {
        printf("\n[%d] ", i+1);
        for (int j = 0; j < arr_length; j++) {
            if (arr[j] > arr[j+1]) {    
                swap = arr[j];
                arr[j] = arr[j+1];
                arr[j+1] = swap;
            }
        }

        print_array(arr, arr_length);
    }

    printf("\n");
}

int main() {
    int arr[25] = { -223, -12, -1000, -90, -3, 
        40, 55, 11, 32, 67, 5, 74, 
        89, 38, 66, 27, 36, 79, 99, 
        2, 0, 1, 100, 282, 370};

    int arr_length = sizeof arr / sizeof *arr;

    bubblesort(arr, arr_length);
    return 0;
}
```

Esse código em C, para muitas pessoas já não é considerado simples, mas ainda assim é bem descritivo e mais próximo do inglês do que da linguagem de máquina. Agora vamos rodar o seguinte comando:

```bash
gcc bubble_sort.c -o bubble_sort.o && objdump -S --disassemble bubble_sort.o > bubble_sort.asm
```

O comando acima compila o código C e gera o arquivo executável em código de máquina, já a segunda parte do comando é o que gera o código Assembly a partir do executável. Abra o arquivo bubble_sort.asm e veja o que aconteceu. Um simples código para um algoritmo bubble sort em Assembly possui mais de 300 linhas, e o código em C possui apenas 30 linhas.

&nbsp;

## Conclusão

Agora você já conhece um pouco mais de programação em baixo nível, pode seguir seus estudos nessa área ou voltar para as linguagens de alto nível. Programar em baixo nível é muito mais difícil e chato do que programar em alto nível, porém, é importante conhecer pelo menos o básico, isso permite que você entenda melhor como os computadores, compiladores, interpretadores e diferentes arquiteturas funcionam.