diff --git a/blog/content/edition-2/posts/02-minimal-rust-kernel/disable-red-zone/index.pt-BR.md b/blog/content/edition-2/posts/02-minimal-rust-kernel/disable-red-zone/index.pt-BR.md new file mode 100644 index 00000000..1d134922 --- /dev/null +++ b/blog/content/edition-2/posts/02-minimal-rust-kernel/disable-red-zone/index.pt-BR.md @@ -0,0 +1,35 @@ ++++ +title = "Desabilitando a Red Zone" +weight = 1 +path = "pt-BR/red-zone" +template = "edition-2/extra.html" + +[extra] +# Please update this when updating the translation +translation_based_on_commit = "9d079e6d3e03359469d6cf1759bb1a196d8a11ac" +# GitHub usernames of the people that translated this post +translators = ["richarddalves"] ++++ + +A [red zone] é uma otimização da [System V ABI] que permite que funções usem temporariamente os 128 bytes abaixo do seu stack frame sem ajustar o ponteiro de pilha: + +[red zone]: https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64#the-red-zone +[System V ABI]: https://wiki.osdev.org/System_V_ABI + + + + + +A imagem mostra o stack frame de uma função com `n` variáveis locais. Na entrada da função, o ponteiro de pilha é ajustado para abrir espaço na pilha para o endereço de retorno e as variáveis locais. + +A red zone é definida como os 128 bytes abaixo do ponteiro de pilha ajustado. A função pode usar esta área para dados temporários que não são necessários entre chamadas de função. Assim, as duas instruções para ajustar o ponteiro de pilha podem ser evitadas em alguns casos (por exemplo, em pequenas funções folha). + +No entanto, esta otimização leva a problemas enormes com exceções ou interrupções de hardware. Vamos assumir que uma exceção ocorre enquanto uma função usa a red zone: + + + +A CPU e o handler de exceção sobrescrevem os dados na red zone. Mas estes dados ainda são necessários pela função interrompida. Então a função não funcionará mais corretamente quando retornarmos do handler de exceção. Isso pode levar a bugs estranhos que [levam semanas para depurar]. + +[levam semanas para depurar]: https://forum.osdev.org/viewtopic.php?t=21720 + +Para evitar tais bugs quando implementarmos tratamento de exceções no futuro, desabilitamos a red zone logo de início. Isso é alcançado adicionando a linha `"disable-redzone": true` ao nosso arquivo de configuração de alvo. \ No newline at end of file diff --git a/blog/content/edition-2/posts/02-minimal-rust-kernel/disable-simd/index.pt-BR.md b/blog/content/edition-2/posts/02-minimal-rust-kernel/disable-simd/index.pt-BR.md new file mode 100644 index 00000000..a397fe80 --- /dev/null +++ b/blog/content/edition-2/posts/02-minimal-rust-kernel/disable-simd/index.pt-BR.md @@ -0,0 +1,50 @@ ++++ +title = "Desabilitando SIMD" +weight = 2 +path = "pt-BR/disable-simd" +template = "edition-2/extra.html" + +[extra] +# Please update this when updating the translation +translation_based_on_commit = "9d079e6d3e03359469d6cf1759bb1a196d8a11ac" +# GitHub usernames of the people that translated this post +translators = ["richarddalves"] ++++ + +Instruções [Single Instruction Multiple Data (SIMD)] são capazes de realizar uma operação (por exemplo, adição) simultaneamente em múltiplas palavras de dados, o que pode acelerar programas significativamente. A arquitetura `x86_64` suporta vários padrões SIMD: + +[Single Instruction Multiple Data (SIMD)]: https://en.wikipedia.org/wiki/SIMD + + + +- [MMX]: O conjunto de instruções _Multi Media Extension_ foi introduzido em 1997 e define oito registradores de 64 bits chamados `mm0` até `mm7`. Esses registradores são apenas aliases para os registradores da [unidade de ponto flutuante x87]. +- [SSE]: O conjunto de instruções _Streaming SIMD Extensions_ foi introduzido em 1999. Em vez de reutilizar os registradores de ponto flutuante, ele adiciona um conjunto de registradores completamente novo. Os dezesseis novos registradores são chamados `xmm0` até `xmm15` e têm 128 bits cada. +- [AVX]: As _Advanced Vector Extensions_ são extensões que aumentam ainda mais o tamanho dos registradores multimídia. Os novos registradores são chamados `ymm0` até `ymm15` e têm 256 bits cada. Eles estendem os registradores `xmm`, então por exemplo `xmm0` é a metade inferior de `ymm0`. + +[MMX]: https://en.wikipedia.org/wiki/MMX_(instruction_set) +[unidade de ponto flutuante x87]: https://en.wikipedia.org/wiki/X87 +[SSE]: https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions +[AVX]: https://en.wikipedia.org/wiki/Advanced_Vector_Extensions + +Ao usar tais padrões SIMD, programas frequentemente podem acelerar significativamente. Bons compiladores são capazes de transformar loops normais em tal código SIMD automaticamente através de um processo chamado [auto-vetorização]. + +[auto-vetorização]: https://en.wikipedia.org/wiki/Automatic_vectorization + +No entanto, os grandes registradores SIMD levam a problemas em kernels de SO. A razão é que o kernel tem que fazer backup de todos os registradores que usa para a memória em cada interrupção de hardware, porque eles precisam ter seus valores originais quando o programa interrompido continua. Então, se o kernel usa registradores SIMD, ele tem que fazer backup de muito mais dados (512-1600 bytes), o que diminui notavelmente o desempenho. Para evitar esta perda de desempenho, queremos desabilitar os recursos `sse` e `mmx` (o recurso `avx` é desabilitado por padrão). + +Podemos fazer isso através do campo `features` na nossa especificação de alvo. Para desabilitar os recursos `mmx` e `sse`, nós os adicionamos prefixados com um menos: + +```json +"features": "-mmx,-sse" +``` + +## Ponto Flutuante +Infelizmente para nós, a arquitetura `x86_64` usa registradores SSE para operações de ponto flutuante. Assim, todo uso de ponto flutuante com SSE desabilitado causa um erro no LLVM. O problema é que a biblioteca core do Rust já usa floats (por exemplo, ela implementa traits para `f32` e `f64`), então evitar floats no nosso kernel não é suficiente. + +Felizmente, o LLVM tem suporte para um recurso `soft-float` que emula todas as operações de ponto flutuante através de funções de software baseadas em inteiros normais. Isso torna possível usar floats no nosso kernel sem SSE; será apenas um pouco mais lento. + +Para ativar o recurso `soft-float` para o nosso kernel, nós o adicionamos à linha `features` na nossa especificação de alvo, prefixado com um mais: + +```json +"features": "-mmx,-sse,+soft-float" +``` \ No newline at end of file diff --git a/blog/content/edition-2/posts/02-minimal-rust-kernel/index.pt-BR.md b/blog/content/edition-2/posts/02-minimal-rust-kernel/index.pt-BR.md new file mode 100644 index 00000000..2c0c3ae6 --- /dev/null +++ b/blog/content/edition-2/posts/02-minimal-rust-kernel/index.pt-BR.md @@ -0,0 +1,504 @@ ++++ +title = "Um Kernel Rust Mínimo" +weight = 2 +path = "pt-BR/minimal-rust-kernel" +date = 2018-02-10 + +[extra] +chapter = "Bare Bones" +# Please update this when updating the translation +translation_based_on_commit = "95d4fbd54c6b0e5a874981558c0cc1fe85d31606" +# GitHub usernames of the people that translated this post +translators = ["richarddalves"] ++++ + +Neste post, criamos um kernel Rust mínimo de 64 bits para a arquitetura x86. Construímos sobre o [binário Rust independente] do post anterior para criar uma imagem de disco inicializável que imprime algo na tela. + +[binário Rust independente]: @/edition-2/posts/01-freestanding-rust-binary/index.pt-BR.md + + + +Este blog é desenvolvido abertamente no [GitHub]. Se você tiver algum problema ou dúvida, abra um issue lá. Você também pode deixar comentários [na parte inferior]. O código-fonte completo desta publicação pode ser encontrado na branch [`post-02`][post branch]. + +[GitHub]: https://github.com/phil-opp/blog_os +[na parte inferior]: #comments + +[post branch]: https://github.com/phil-opp/blog_os/tree/post-02 + + + +## O Processo de Boot +Quando você liga um computador, ele começa a executar código de firmware que está armazenado na [ROM] da placa-mãe. Este código executa um [teste automático de inicialização], detecta a RAM disponível e pré-inicializa a CPU e o hardware. Depois, ele procura por um disco inicializável e começa a inicializar o kernel do sistema operacional. + +[ROM]: https://en.wikipedia.org/wiki/Read-only_memory +[teste automático de inicialização]: https://en.wikipedia.org/wiki/Power-on_self-test + +No x86, existem dois padrões de firmware: o "Basic Input/Output System" (**[BIOS]**) e o mais novo "Unified Extensible Firmware Interface" (**[UEFI]**). O padrão BIOS é antigo e ultrapassado, mas simples e bem suportado em qualquer máquina x86 desde os anos 1980. UEFI, em contraste, é mais moderno e tem muito mais recursos, mas é mais complexo de configurar (na minha opinião, pelo menos). + +[BIOS]: https://en.wikipedia.org/wiki/BIOS +[UEFI]: https://en.wikipedia.org/wiki/Unified_Extensible_Firmware_Interface + +Atualmente, fornecemos apenas suporte para BIOS, mas suporte para UEFI também está planejado. Se você gostaria de nos ajudar com isso, confira o [issue no Github](https://github.com/phil-opp/blog_os/issues/349). + +### Boot BIOS +Quase todos os sistemas x86 têm suporte para boot BIOS, incluindo máquinas mais novas baseadas em UEFI que usam um BIOS emulado. Isso é ótimo, porque você pode usar a mesma lógica de boot em todas as máquinas do último século. Mas essa ampla compatibilidade é ao mesmo tempo a maior desvantagem do boot BIOS, porque significa que a CPU é colocada em um modo de compatibilidade de 16 bits chamado [modo real] antes do boot, para que bootloaders arcaicos dos anos 1980 ainda funcionem. + +Mas vamos começar do início: + +Quando você liga um computador, ele carrega o BIOS de uma memória flash especial localizada na placa-mãe. O BIOS executa rotinas de teste automático e inicialização do hardware, então procura por discos inicializáveis. Se ele encontra um, o controle é transferido para seu _bootloader_, que é uma porção de 512 bytes de código executável armazenado no início do disco. A maioria dos bootloaders é maior que 512 bytes, então os bootloaders são comumente divididos em um primeiro estágio pequeno, que cabe em 512 bytes, e um segundo estágio, que é subsequentemente carregado pelo primeiro estágio. + +O bootloader tem que determinar a localização da imagem do kernel no disco e carregá-la na memória. Ele também precisa mudar a CPU do [modo real] de 16 bits primeiro para o [modo protegido] de 32 bits, e então para o [modo longo] de 64 bits, onde registradores de 64 bits e a memória principal completa estão disponíveis. Seu terceiro trabalho é consultar certas informações (como um mapa de memória) do BIOS e passá-las ao kernel do SO. + +[modo real]: https://en.wikipedia.org/wiki/Real_mode +[modo protegido]: https://en.wikipedia.org/wiki/Protected_mode +[modo longo]: https://en.wikipedia.org/wiki/Long_mode +[segmentação de memória]: https://en.wikipedia.org/wiki/X86_memory_segmentation + +Escrever um bootloader é um pouco trabalhoso, pois requer linguagem assembly e muitos passos pouco intuitivos como "escrever este valor mágico neste registrador do processador". Portanto, não cobrimos a criação de bootloader neste post e em vez disso fornecemos uma ferramenta chamada [bootimage] que anexa automaticamente um bootloader ao seu kernel. + +[bootimage]: https://github.com/rust-osdev/bootimage + +Se você estiver interessado em construir seu próprio bootloader: Fique ligado, um conjunto de posts sobre este tópico já está planejado! + +#### O Padrão Multiboot +Para evitar que todo sistema operacional implemente seu próprio bootloader, que é compatível apenas com um único SO, a [Free Software Foundation] criou um padrão de bootloader aberto chamado [Multiboot] em 1995. O padrão define uma interface entre o bootloader e o sistema operacional, para que qualquer bootloader compatível com Multiboot possa carregar qualquer sistema operacional compatível com Multiboot. A implementação de referência é o [GNU GRUB], que é o bootloader mais popular para sistemas Linux. + +[Free Software Foundation]: https://en.wikipedia.org/wiki/Free_Software_Foundation +[Multiboot]: https://wiki.osdev.org/Multiboot +[GNU GRUB]: https://en.wikipedia.org/wiki/GNU_GRUB + +Para tornar um kernel compatível com Multiboot, basta inserir um chamado [cabeçalho Multiboot] no início do arquivo do kernel. Isso torna muito fácil inicializar um SO a partir do GRUB. No entanto, o GRUB e o padrão Multiboot também têm alguns problemas: + +[cabeçalho Multiboot]: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#OS-image-format + +- Eles suportam apenas o modo protegido de 32 bits. Isso significa que você ainda tem que fazer a configuração da CPU para mudar para o modo longo de 64 bits. +- Eles são projetados para tornar o bootloader simples em vez do kernel. Por exemplo, o kernel precisa ser vinculado com um [tamanho de página padrão ajustado], porque o GRUB não consegue encontrar o cabeçalho Multiboot caso contrário. Outro exemplo é que as [informações de boot], que são passadas ao kernel, contêm muitas estruturas dependentes de arquitetura em vez de fornecer abstrações limpas. +- Tanto o GRUB quanto o padrão Multiboot são documentados apenas esparsamente. +- O GRUB precisa estar instalado no sistema host para criar uma imagem de disco inicializável a partir do arquivo do kernel. Isso torna o desenvolvimento no Windows ou Mac mais difícil. + +[tamanho de página padrão ajustado]: https://wiki.osdev.org/Multiboot#Multiboot_2 +[informações de boot]: https://www.gnu.org/software/grub/manual/multiboot/multiboot.html#Boot-information-format + +Por causa dessas desvantagens, decidimos não usar o GRUB ou o padrão Multiboot. No entanto, planejamos adicionar suporte Multiboot à nossa ferramenta [bootimage], para que seja possível carregar seu kernel em um sistema GRUB também. Se você estiver interessado em escrever um kernel compatível com Multiboot, confira a [primeira edição] desta série de blog. + +[primeira edição]: @/edition-1/_index.md + +### UEFI + +(Não fornecemos suporte UEFI no momento, mas adoraríamos! Se você gostaria de ajudar, por favor nos diga no [issue do Github](https://github.com/phil-opp/blog_os/issues/349).) + +## Um Kernel Mínimo +Agora que sabemos aproximadamente como um computador inicializa, é hora de criar nosso próprio kernel mínimo. Nosso objetivo é criar uma imagem de disco que imprima um "Hello World!" na tela quando inicializada. Fazemos isso estendendo o [binário Rust independente] do post anterior. + +Como você deve se lembrar, construímos o binário independente através do `cargo`, mas dependendo do sistema operacional, precisávamos de nomes de ponto de entrada e flags de compilação diferentes. Isso ocorre porque o `cargo` compila para o _sistema host_ por padrão, ou seja, o sistema em que você está executando. Isso não é algo que queremos para nosso kernel, porque um kernel que executa em cima de, por exemplo, Windows, não faz muito sentido. Em vez disso, queremos compilar para um _sistema alvo_ claramente definido. + +### Instalando o Rust Nightly +O Rust tem três canais de lançamento: _stable_, _beta_ e _nightly_. O Livro do Rust explica a diferença entre esses canais muito bem, então dê uma olhada [aqui](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html#choo-choo-release-channels-and-riding-the-trains). Para construir um sistema operacional, precisaremos de alguns recursos experimentais que estão disponíveis apenas no canal nightly, então precisamos instalar uma versão nightly do Rust. + +Para gerenciar instalações do Rust, eu recomendo fortemente o [rustup]. Ele permite instalar compiladores nightly, beta e stable lado a lado e facilita a atualização deles. Com rustup, você pode usar um compilador nightly para o diretório atual executando `rustup override set nightly`. Alternativamente, você pode adicionar um arquivo chamado `rust-toolchain` com o conteúdo `nightly` ao diretório raiz do projeto. Você pode verificar que tem uma versão nightly instalada executando `rustc --version`: O número da versão deve conter `-nightly` no final. + +[rustup]: https://www.rustup.rs/ + +O compilador nightly nos permite optar por vários recursos experimentais usando as chamadas _feature flags_ no topo do nosso arquivo. Por exemplo, poderíamos habilitar a [macro `asm!`] experimental para assembly inline adicionando `#![feature(asm)]` no topo do nosso `main.rs`. Note que tais recursos experimentais são completamente instáveis, o que significa que versões futuras do Rust podem alterá-los ou removê-los sem aviso prévio. Por esta razão, só os usaremos se absolutamente necessário. + +[macro `asm!`]: https://doc.rust-lang.org/stable/reference/inline-assembly.html + +### Especificação de Alvo +O Cargo suporta diferentes sistemas alvo através do parâmetro `--target`. O alvo é descrito por uma chamada _[target triple]_, que descreve a arquitetura da CPU, o vendor, o sistema operacional e a [ABI]. Por exemplo, o target triple `x86_64-unknown-linux-gnu` descreve um sistema com uma CPU `x86_64`, sem vendor claro, e um sistema operacional Linux com a ABI GNU. O Rust suporta [muitos target triples diferentes][platform-support], incluindo `arm-linux-androideabi` para Android ou [`wasm32-unknown-unknown` para WebAssembly](https://www.hellorust.com/setup/wasm-target/). + +[target triple]: https://clang.llvm.org/docs/CrossCompilation.html#target-triple +[ABI]: https://stackoverflow.com/a/2456882 +[platform-support]: https://forge.rust-lang.org/release/platform-support.html +[custom-targets]: https://doc.rust-lang.org/nightly/rustc/targets/custom.html + +Para nosso sistema alvo, no entanto, precisamos de alguns parâmetros de configuração especiais (por exemplo, nenhum SO subjacente), então nenhum dos [target triples existentes][platform-support] se encaixa. Felizmente, o Rust nos permite definir [nosso próprio alvo][custom-targets] através de um arquivo JSON. Por exemplo, um arquivo JSON que descreve o target `x86_64-unknown-linux-gnu` se parece com isto: + +```json +{ + "llvm-target": "x86_64-unknown-linux-gnu", + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": 64, + "target-c-int-width": 32, + "os": "linux", + "executables": true, + "linker-flavor": "gcc", + "pre-link-args": ["-m64"], + "morestack": false +} +``` + +A maioria dos campos é exigida pelo LLVM para gerar código para aquela plataforma. Por exemplo, o campo [`data-layout`] define o tamanho de vários tipos integer, floating point e pointer. Então há campos que o Rust usa para compilação condicional, como `target-pointer-width`. O terceiro tipo de campo define como a crate deve ser construída. Por exemplo, o campo `pre-link-args` especifica argumentos passados ao [linker]. + +[`data-layout`]: https://llvm.org/docs/LangRef.html#data-layout +[linker]: https://en.wikipedia.org/wiki/Linker_(computing) + +Também visamos sistemas `x86_64` com nosso kernel, então nossa especificação de alvo será muito similar à acima. Vamos começar criando um arquivo `x86_64-blog_os.json` (escolha qualquer nome que você goste) com o conteúdo comum: + +```json +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": 64, + "target-c-int-width": 32, + "os": "none", + "executables": true +} +``` + +Note que mudamos o SO no `llvm-target` e no campo `os` para `none`, porque executaremos em bare metal. + +Adicionamos as seguintes entradas relacionadas à compilação: + +```json +"linker-flavor": "ld.lld", +"linker": "rust-lld", +``` + +Em vez de usar o linker padrão da plataforma (que pode não suportar alvos Linux), usamos o linker multiplataforma [LLD] que vem com o Rust para vincular nosso kernel. + +[LLD]: https://lld.llvm.org/ + +```json +"panic-strategy": "abort", +``` + +Esta configuração especifica que o alvo não suporta [stack unwinding] no panic, então em vez disso o programa deve abortar diretamente. Isso tem o mesmo efeito que a opção `panic = "abort"` no nosso Cargo.toml, então podemos removê-la de lá. (Note que, em contraste com a opção Cargo.toml, esta opção de alvo também se aplica quando recompilamos a biblioteca `core` mais adiante neste post. Então, mesmo se você preferir manter a opção Cargo.toml, certifique-se de incluir esta opção.) + +[stack unwinding]: https://www.bogotobogo.com/cplusplus/stackunwinding.php + +```json +"disable-redzone": true, +``` + +Estamos escrevendo um kernel, então precisaremos lidar com interrupções em algum momento. Para fazer isso com segurança, temos que desabilitar uma certa otimização do ponteiro de stack chamada _"red zone"_, porque ela causaria corrupção do stack caso contrário. Para mais informações, veja nosso post separado sobre [desabilitando a red zone]. + +[desabilitando a red zone]: @/edition-2/posts/02-minimal-rust-kernel/disable-red-zone/index.md + +```json +"features": "-mmx,-sse,+soft-float", +``` + +O campo `features` habilita/desabilita recursos do alvo. Desabilitamos os recursos `mmx` e `sse` prefixando-os com um menos e habilitamos o recurso `soft-float` prefixando-o com um mais. Note que não deve haver espaços entre flags diferentes, caso contrário o LLVM falha ao interpretar a string de features. + +Os recursos `mmx` e `sse` determinam suporte para instruções [Single Instruction Multiple Data (SIMD)], que frequentemente podem acelerar programas significativamente. No entanto, usar os grandes registradores SIMD em kernels de SO leva a problemas de desempenho. A razão é que o kernel precisa restaurar todos os registradores ao seu estado original antes de continuar um programa interrompido. Isso significa que o kernel tem que salvar o estado SIMD completo na memória principal em cada chamada de sistema ou interrupção de hardware. Como o estado SIMD é muito grande (512-1600 bytes) e interrupções podem ocorrer com muita frequência, essas operações adicionais de salvar/restaurar prejudicam consideravelmente o desempenho. Para evitar isso, desabilitamos SIMD para nosso kernel (não para aplicações executando em cima!). + +[Single Instruction Multiple Data (SIMD)]: https://en.wikipedia.org/wiki/SIMD + +Um problema com desabilitar SIMD é que operações de ponto flutuante em `x86_64` exigem registradores SIMD por padrão. Para resolver este problema, adicionamos o recurso `soft-float`, que emula todas as operações de ponto flutuante através de funções de software baseadas em inteiros normais. + +Para mais informações, veja nosso post sobre [desabilitando SIMD](@/edition-2/posts/02-minimal-rust-kernel/disable-simd/index.md). + +```json +"rustc-abi": "x86-softfloat" +``` + +Como queremos usar o recurso `soft-float`, também precisamos dizer ao compilador Rust `rustc` que queremos usar a ABI correspondente. Podemos fazer isso definindo o campo `rustc-abi` para `x86-softfloat`. + +#### Juntando Tudo +Nosso arquivo de especificação de alvo agora se parece com isto: + +```json +{ + "llvm-target": "x86_64-unknown-none", + "data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128", + "arch": "x86_64", + "target-endian": "little", + "target-pointer-width": 64, + "target-c-int-width": 32, + "os": "none", + "executables": true, + "linker-flavor": "ld.lld", + "linker": "rust-lld", + "panic-strategy": "abort", + "disable-redzone": true, + "features": "-mmx,-sse,+soft-float", + "rustc-abi": "x86-softfloat" +} +``` + +### Construindo nosso Kernel +Compilar para nosso novo alvo usará convenções Linux, já que o linker-flavor ld.lld instrui o llvm a compilar com a flag `-flavor gnu` (para mais opções de linker, veja [a documentação do rustc](https://doc.rust-lang.org/rustc/codegen-options/index.html#linker-flavor)). Isso significa que precisamos de um ponto de entrada chamado `_start` como descrito no [post anterior]: + +[post anterior]: @/edition-2/posts/01-freestanding-rust-binary/index.pt-BR.md + +```rust +// src/main.rs + +#![no_std] // não vincule a biblioteca padrão do Rust +#![no_main] // desativar todos os pontos de entrada no nível Rust + +use core::panic::PanicInfo; + +/// Esta função é chamada em caso de pânico. +#[panic_handler] +fn panic(_info: &PanicInfo) -> ! { + loop {} +} + +#[unsafe(no_mangle)] // não altere (mangle) o nome desta função +pub extern "C" fn _start() -> ! { + // essa função é o ponto de entrada, já que o vinculador procura uma função + // denominado `_start` por padrão + loop {} +} +``` + +Note que o ponto de entrada precisa ser chamado `_start` independentemente do seu SO host. + +Agora podemos construir o kernel para nosso novo alvo passando o nome do arquivo JSON como `--target`: + +``` +> cargo build --target x86_64-blog_os.json + +error[E0463]: can't find crate for `core` +``` + +Falha! O erro nos diz que o compilador Rust não consegue mais encontrar a [biblioteca `core`]. Esta biblioteca contém tipos básicos do Rust como `Result`, `Option` e iteradores, e é implicitamente vinculada a todas as crates `no_std`. + +[biblioteca `core`]: https://doc.rust-lang.org/nightly/core/index.html + +O problema é que a biblioteca core é distribuída junto com o compilador Rust como uma biblioteca _pré-compilada_. Então ela é válida apenas para target triples host suportados (por exemplo, `x86_64-unknown-linux-gnu`) mas não para nosso alvo customizado. Se quisermos compilar código para outros alvos, precisamos recompilar `core` para esses alvos primeiro. + +#### A Opção `build-std` + +É aí que entra o [recurso `build-std`] do cargo. Ele permite recompilar `core` e outras crates da biblioteca padrão sob demanda, em vez de usar as versões pré-compiladas enviadas com a instalação do Rust. Este recurso é muito novo e ainda não está finalizado, então é marcado como "unstable" e disponível apenas em [compiladores Rust nightly]. + +[recurso `build-std`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#build-std +[compiladores Rust nightly]: #instalando-o-rust-nightly + +Para usar o recurso, precisamos criar um arquivo de [configuração cargo] local em `.cargo/config.toml` (a pasta `.cargo` deve estar ao lado da sua pasta `src`) com o seguinte conteúdo: + +```toml +# em .cargo/config.toml + +[unstable] +build-std = ["core", "compiler_builtins"] +``` + +Isso diz ao cargo que ele deve recompilar as bibliotecas `core` e `compiler_builtins`. Esta última é necessária porque é uma dependência de `core`. Para recompilar essas bibliotecas, o cargo precisa de acesso ao código-fonte do rust, que podemos instalar com `rustup component add rust-src`. + +