# Ambiente hosted

Na especificação da linguagem C é descrito dois ambientes de execução de código: Os ambientes *hosted* e *freestanding*. Neste tópico vamos entender alguns pontos em relação a como funciona a estrutura e a execução de um programa em C no ambiente *hosted*.

O ambiente *hosted* essencialmente é o ambiente de execução de um código em C que executa sobre um sistema operacional. Nesse ambiente é esperado que haja suporte para múltiplas *threads* e todos os recursos descritos na especificação da biblioteca padrão (libc). A inicialização do programa ocorre quando a função **main** é chamada e antes de inicializar o programa é esperado que todos os objetos com [*storage-class*](/assembly/programando-junto-com-c/variaveis-em-c.md) `static` estejam inicializados.

## A função main

A função **main** pode ser escrita com um dos dois protótipos abaixo:

```c
int main(void)
{
  // ...
}
```

```c
int main(int argc, char *argv[])
{
  // ...
}
```

Ou qualquer outro protótipo que seja equivalente a um desses. Como por exemplo `char **argv` também seria válido por ter equivalência a `char *argv[]`. Também pode-se usar qualquer nome de parâmetro, `argc` e `argv` são apenas sugestões.

O primeiro parâmetro passado para a função **main** indica o número de argumentos e o segundo é uma *array* de ponteiros para `char` onde cada índice na *array* é um argumento e `argv[argc]` é um ponteiro NULL.

Se o tipo de retorno da função **main** for `int` (ou equivalente), o valor de retorno da primeira chamada para **main** é equivalente a chamar a função **exit** passando esse valor como argumento.

## C startup code

{% hint style="info" %}
Os detalhes de implementação descritos aqui são baseados no código-fonte da glibc e podem ser diferentes em outras implementações da libc. Consulte [as referências](/assembly/metadados/referencias.md#glibc) para ver a lista de completa de arquivos fonte consultados.
{% endhint %}

O código na glibc responsável pela inicialização do programa é chamado de *C startup* (CSU). Ele se encarrega de obter os argumentos de linha de comando, inicializar o TLS, executar o código na seção `.init` dentre outras tarefas de inicialização do programa.

O arquivo `start.S` é o que declara o símbolo `_start`, ou seja, a função de *entry point* do programa. A última chamada nessa função é para outra função chamada `__libc_start_main` que recebe o endereço da função **main** como primeiro argumento. Depois de algumas inicializações essa função chama a **main**, obtém o valor retornado em EAX e passa como argumento para a função responsável por finalizar o programa no sistema operacional (`exit_group` no Linux e `ExitProcess` no Windows).

Todos esses códigos estão em arquivos objetos pré-compilados no seu sistema operacional. Eles são *linkados* por padrão quando você invoca o GCC mas não são *linkados* por padrão se você chamar o *linker* (`ld`) diretamente.

No meu Linux o arquivo objeto `Scrt1.o` ("crt" é sigla para "*C runtime*") é o que contém o *entry point* (código do `start.S`). Os arquivos `crti.o` e `crtn.o` contém o prólogo e o epílogo, respectivamente, para as seções `.init` e `.fini`.

No meu Linux esses arquivos estão na pasta `/usr/lib/x86_64-linux-gnu/` e sugiro que consulte o conteúdo dos mesmos com a ferramenta **objdump**, como por exemplo:

```
$ objdump -d /usr/lib/x86_64-linux-gnu/Scrt1.o
```

### Fazendo seu próprio startup code

{% hint style="info" %}
Apenas para fins de curiosidade e dar uma noção mais "palpável" de como isso ocorre, irei ensinar aqui como você pode desabilitar a *linkedição* do CSU e programar uma versão personalizada do mesmo no Linux. Não recomendo que isso seja feito em um programa de verdade tendo em vista que você perderá diversos recursos que o *C runtime* padrão da glibc provém.
{% endhint %}

Use o seguinte código de teste:

{% tabs %}
{% tab title="start.s" %}

```
STDOUT_FILENO = 1
SYS_WRITE = 1
SYS_EXIT_GROUP = 231

    .section .rodata
init_msg:
    .string "* Initializing...\n"
    MSG_LENGHT = . - init_msg

    .text
    .globl _start
_start:
    mov $STDOUT_FILENO, %rdi
    lea init_msg(%rip), %rsi
    mov $MSG_LENGHT, %rdx
    mov $SYS_WRITE, %rax
    syscall         # write(STDOUT_FILENO, init_msg, MSG_LENGTH)

    pop %rdi        # argc: RDI
    mov %rsp, %rsi  # argv: RSI
    call main

    mov %rax, %rdi
    mov $SYS_EXIT_GROUP, %rax
    syscall         # exit_group( main(argc, argv) )
```

{% endtab %}

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

```c
#include <stdio.h>

int main(int argc, char **argv)
{
  printf("argc = %d\n", argc);

  for (int i = 0; i < argc; i++)
  {
    printf("argv[%d] = '%s'\n", i, argv[i]);
  }

  // Esperamos que argv[argc] seja um ponteiro NULL
  printf("argv[argc] = %s\n", argv[argc]);
  return 0;
}
```

{% endtab %}
{% endtabs %}

Compile com:

```
$ as start.s -o crt1.o
$ gcc main.c -o main.o -c
$ gcc *.o -o test -nostartfiles
```

A opção `-nostartfiles` desabilita a *linkedição* dos arquivos objeto de inicialização.

O que o nosso `start.s` está fazendo é simplesmente chamar a syscall `write` para escrever uma mensagem na tela, chama a função **main** passando `argc` e `argv` como argumentos e depois chama a syscall `exit_group` passando como argumento o retorno da função **main**.

{% hint style="info" %}
No Linux, logo quando o programa é iniciado no *entry point*, o valor contendo o número de argumentos de linha de comando (argc) está em `(%rsp)`. E logo em seguida (RSP+8) está o início da *array* de ponteiros para os argumentos de linha de comando, terminando com um ponteiro NULL.
{% endhint %}

Experimente rodar `objdump -d test` nesse executável "customizado" e depois compare compilando com o CSU comum. Verá que o programa comum contém diversas funções que foram *linkadas* nele.

## Seções .init e .fini

As seções `.init` e `.fini` contém funções construída nos arquivos `crti.o` e `crtn.o`.

O propósito da função em `.init` é chamar todas as funções na *array* de ponteiros localizada em outra seção chamada `.init_array`. Essas funções são invocadas antes da chamada para a função **main**.

Já a função em `.fini` invoca as funções da *array* na seção `.fini_array` na finalização do programa (após **main** retornar ou na chamada de `exit()`).

No GCC você pode adicionar funções para serem invocadas na inicialização do programa com o atributo `constructor`, e para a finalização do programa com o atributo `destructor`. Experimente ver o código Assembly do exemplo abaixo:

```c
#include <stdio.h>

__attribute__((constructor))
void constructor1(void)
{
  puts("* constructor 1");
}

__attribute__((constructor))
void constructor2(void)
{
  puts("* constructor 2");
}

__attribute__((destructor))
void destructor1(void)
{
  puts("* destructor 1");
}

__attribute__((destructor))
void destructor2(void)
{
  puts("* destructor 2");
}

int main(void)
{
  puts("* main");
}
```

Ao [ver o Assembly gerado](/assembly/programando-junto-com-c.md#vendo-o-codigo-de-saida-do-gcc) do programa acima irá notar que os endereços das funções são despejados nas seções `.init_array` e `.fini_array`, como em:

```
	.section	.init_array,"aw"
	.align 8
	.quad	constructor1
```

## Funções de saída

### exit

Quando a função `exit()` é invocada (ou **main** retorna), funções registradas pela função `atexit()` são executadas. Onde as funções registradas devem seguir o protótipo:

```c
void funcname(void);
```

As funções registradas por `atexit()` são invocadas na ordem inversa a que foram registradas.

### quick\_exit

Quando a função `quick_exit()` é invocada o programa é finalizado sem invocar as funções registradas por `atexit()` e sem executar quaisquer *handlers* de sinal.

As funções registradas por `at_quick_exit` são invocadas na ordem inversa em que foram registradas.

Exemplo:

```c
#include <stdio.h>
#include <stdlib.h>

void func_atexit(void)
{
  puts("* exiting...");
}

void func_at_quick_exit(void)
{
  puts("* Quick exiting...");
}

int main(void)
{
  atexit(func_atexit);
  at_quick_exit(func_at_quick_exit);

  puts("* main");
  // quick_exit(EXIT_SUCCESS);
  return 0;
}
```

Experimente executar o programa acima e depois recompilar com a chamada para **quick\_exit** na linha 20.

{% hint style="info" %}
A quantidade máxima de funções que podem ser registradas com **atexit** ou **at\_quick\_exit** depende da implementação. Mas a especificação do C11 garante que no mínimo 32 funções podem ser registradas por cada uma destas funções.
{% endhint %}

### \_Exit

A função `_Exit()` finaliza a execução do programa sem executar quaisquer funções registradas por **atexit** ou **at\_quick\_exit**. Também não executa nenhum *handler* de sinal.


---

# 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/programando-junto-com-c/ambiente-hosted.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.
