Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Окружение Rust с no_std

Термин "встраиваемое программирование" используется для широкого спектра классов программирования. От программирования 8-битных микроконтроллеров (например, ST72325xx) с всего несколькими КБ ОЗУ и ПЗУ до систем вроде Raspberry Pi (Model B 3+), которая имеет 32/64-битный 4-ядерный процессор Cortex-A53 с частотой 1.4 ГГц и 1 ГБ ОЗУ. Разные ограничения применяются при написании кода в зависимости от цели и случая использования.

Существуют два общих класса встраиваемого программирования:

Хостинговые окружения

Такие окружения близки к обычному окружению ПК. Это означает, что предоставляется системный интерфейс например, POSIX, который дает примитивы для взаимодействия с различными системами, такими как файловые системы, сеть, управление памятью, потоки и т.д. Стандартные библиотеки, в свою очередь, обычно зависят от этих примитивов для реализации своей функциональности. Также может быть sysroot и ограничения на использование ОЗУ/ПЗУ, а также специальное оборудование или ввод/вывод. В целом это похоже на программирование в специальной среде ПК.

Окружения без ОС (Bare Metal)

В окружении без ОС (bare metal) перед вашей программой не загружено никакого кода. Без ПО, предоставляемого ОС, мы не можем загрузить стандартную библиотеку. Вместо этого программа вместе с используемыми крейтами может использовать только аппаратное обеспечение (bare metal) для выполнения. Чтобы предотвратить загрузку стандартной библиотеки Rust, используйте no_std. Части стандартной библиотеки, не зависящие от платформы, доступны через libcore. libcore также исключает вещи, которые не всегда желательны в окружении встраиваемых систем. Одна из них — распределитель памяти для динамического выделения памяти. Если требуется это или другие функциональности, часто есть крейты, которые их предоставляют.

Runtime libstd

Как упоминалось ранее, использование libstd требует некоторой системной интеграции, но не только потому, что libstd просто предоставляет общий способ доступа к абстракциям ОС, она также предоставляет runtime. Эта runtime, среди прочего, настраивает защиту от переполнения стека, обрабатывает аргументы командной строки и порождает основной поток перед вызовом главной функции программы. Эта runtime также недоступна в окружении no_std.

Итог

#![no_std] — это атрибут на уровне крейта, указывающий, что крейт будет ссылаться на крейт core вместо std. Крейт libcore, в свою очередь, — это подмножество std, не зависящее от платформы, которое не делает предположений о системе, на которой будет работать программа. Таким образом, он предоставляет API для языковых примитивов, таких как числа с плавающей запятой, строки и слайсы, а также API, раскрывающие функции процессора, такие как атомарные операции и инструкции SIMD. Однако он не предоставляет API для чего-либо, что включает интеграцию с платформой. Благодаря этим свойствам код с no_std и libcore может использоваться для любого вида загрузочного (stage 0) кода, такого как загрузчики, прошивки или ядра.

Обзор

Функцияno_stdstd
куча (динамическая память)*
коллекции (Vec, BTreeMap и т.д.)**
защита от переполнения стека
выполнение кода инициализации перед main
доступна libstd
доступна libcore
написание прошивки, ядра или кода загрузчика

* Только если вы используете крейт alloc и подходящий распределитель, такой как alloc-cortex-m.

** Только если вы используете крейт collections и настраиваете глобальный распределитель по умолчанию.

** HashMap и HashSet недоступны из-за отсутствия безопасного генератора случайных чисел.

См. также