Обновить
8K+
320
Николай Шлей@CodeRush

Firmware Security Engineer

28,1
Рейтинг
692
Подписчики
Отправить сообщение
Вставки — это хорошо, но решение MS не поддерживать ключевое слово __asm в 64-битном режиме компиляции в MSVC и требования совместимости отучили от вставок и разработчиков, поэтому сейчас я весь код на ассемблере выношу в отдельные файлы .asm/.s и вызываю как обыкновенные функции с соглашением MS x64.

LLVM — ничего страшного, если вставки работают правильно, то их хватит.

Про стек — я так и думал, и меня такой ответ вполне устраивает. Большое спасибо.
Без стека можно писать на ассемблере, используя для хранения переменных регистры, а для передачи управления — ближние и дальние переходы. На С писать по настоящему без стека нельзя, конечно, но можно минимизировать его использование, тоже передавая параметры через регистры и заменяя вызовы через call на переходы, ядро PEI и некоторые ранние модули так и работают. Конечно, это уже не совсем C, но я готов и на «не совсем Rust», была бы возможность. Если нет — тоже не беда, весь этот кусок можно писать как раньше, кода там совсем немного.
Торжественно обещаю Хабру попробовать написать DXE-драйвер на Rust, несмотря на пару неудачных попыток ранее. Язык выглядит действительно вкусно для написания компонентов прошивки, не являющихся критически важными, но при этом имеющими большую и запутанную кодовую базу, к примеру — драйверов PCIe и USB, которым по 5 лет уже, а баги в них до сих пор вылезают постоянно, и конца этому процессу не видно.
К знатокам такой вопрос: можно писать на Rust без стека? А без кучи? А есть у вас все содержимое памяти — read-only, кроме стека (так происходит, если исполнять PEI-модули прямо из SPI-чипа, не копируя в оперативную память, которой пока еще нет, а стек выделять из кэша второго уровня в Non-Eviction Mode)? На С — можно, если можно и на Rust — на нем можно будет написать UEFI-совместимую прошивку, минимально разбавив ассемблером. Если нет — значит, только некоторые ее компоненты.
По поводу работы без отладчика — половина реального процесса BIOS development / board bring-up проходит без отладчика, т.к. подключение текстового вывода в UART, не говоря уже об отладке на уровне исходного кода, сильно замедляет загрузку и сбивает все тайминги. Иногда это вполне терпимо, но в других случаях — совершенно неприемлимо. Если вмешиваться в процесс загрузки релизной прошивки нельзя, а отлаживать её надо, единственным доступным средством является включение декодирования порта CPU IO 0x80 на LPC или PCI и сбор последовательности POST-кодов.
От нестандартности всё. Этих #pragma развели три мешка, даже в стандарт добавили в #pragma STDC, а большую часть проблем они если и решают, то только на определенных компиляторах и при определенной фазе луны. От того их и не любят почти все, кто с ними работает.
Внезапно, отлично, буду знать.
У меня, честно говоря, нет ни malloc, ни free (вместо них AllocatePool/FreePool и AllocatePages/FreePages, первая из которых по умолчанию выравнивает по sizeof(size_t), а вторая — по размеру страницы), но я помню проблемы с выравниванием выделенной malloc памяти при работе с Cortex-M0 в Keil uVision 4, видимо, это был баг в реализации для этих ядер или просто процессор попался неудачный.
Вот про «может быть и больше» я и пытаюсь говорить, но видимо, построил слишком уж категорический императив, прошу пардону.
Сигнатуры — видел:
void* memcpu(void*, const void*, size_t)
void* malloc(size_t)

Теперь поговорим о байтах. Если вы считаете, что «байт» — это uint8_t, то в общем случае, вы не правы. Если считаете, что malloc выделяет ровно столько «байт», сколько вами запрошено, то вы тоже не всегда правы (это сильно зависит от реализации, может вообще целую страницу выделить).
Все, что вам гарантирует malloc — это то, что вам вернут достаточно большой кусок нетипизированной памяти для хранения указанного числа «байт», размер которых зависит от архитектуры, и что память потом можно будет освободить при помощи free, либо NULL, если выделить не получилось. Обычная malloc из C даже выравнивание не гарантирует, и в POSIX специально пришлось вводить posix_memalign, чтобы не ловить CPU Exception'ы в случайном месте.
Все, что я хочу тут сказать — в языке нет и не было понятия «восьмибитный байт», а само слово «байт» в документации используется в значении «минимальная единица размера типа».
Еще раз, в C никаких байт нет, и потому никакая память в них не измеряется, точка, конец истории.
Если делать функции работы с памятью через uint8_t*, то на некоторых архитектурах с hard-fail на misaligned read, к примеру, на ARM Cortex-M0, у вас процессор будет просто зависать на первом же обращении к такой памяти примерно в 3/4 случаев.
void* — это не «указатель на ничего», это указатель на кусок памяти без типа, ровно такой, как нам её выделяет malloc() и освобождает free(). В C, вообще говоря, нет типа данных «байт», и даже нигде не написано, что в байте должно быть 8 бит (это написано в стандарте POSIX, но на C можно писать и для архитектур с другим размером байта), и, таким образом, использовать uint8_t в этом месте — совершенно неразумное ограничение как переносимости, как так и удобства использования вашего кода. Понятно, что явное лучше, чем неявное, но в данном случае void* все-таки намного лучше отражает намерения программиста, на мой взгляд.
Переводите оба тогда, там есть что обсудить и о чем поспорить.
Там не только с маскированием ошибок проблемы, там integer overflow потенциальный при любом вызове. Если уж советовать замену, то на reallocarray() из OpenBSD, что автор вышеупомянутой статьи и предлагает.
Очень много крайне спорных советов, на самом деле. Вот достойный ответ, особенно на использование calloc.
Ради школьников тратить §20M на RnD и $10M на отладку получившейся «аппаратной поддержки второй стрелки» никто не будет, извините. Пусть эти школьники спокойно пьют свое пиво.
Не могу не процитировать часть вот этого ответа на SO, который однозначно стоит прочитать целиком:
What must be understood is that in all these constructions, each circuit gate must map to an instance of Gentry's fully homomorphic encryption scheme, and at every clock cycle for the obfuscated circuit, all gates must be processed, regardless of whether they are «active» or not in the circuit (this is a big part of why the obfuscation theoretically works: it does not reveal active gates, by always making them all active). This article gives performance result: on a rather big PC, we are up for minutes of computation. That's for each gate in the obfuscated circuit, and for each clock cycle.
В общем, насколько я понял из статей и процитированного ответа, там вся теоретическая обфускация разбивается о практическую производительность, и с этим за пару лет ничего сделать не получится.
Всем, libstdcpp и STLPort — два разных рантайма с разными же возможностями (и размерами), первый предосталяет только некоторые функции, а второй — всю стандартную библиотеку.
Тем не менее, даже гугловская libstdc++ не поддерживает STL, так что в каком-то смысле они тоже правы.
Катит, но там не только их не хватает, а в итоге нет ни исключений, ни стандартной библиотеки, и непонятно, зачем вообще огород городить, если на C уже все готово. В Rust хотя бы borrow checker поможет и иммутабельность по умолчанию, а чем хорош C++ в данном случае я просто не знаю.
Не получится, т.к. нет рантайма (т.е new, delete и прочие красивости C++ просто не работают), а без него C++ мало чем лучше C. Вот тут Count Chu рассказывает, как он заводил код на C++ в EDK2, но успехом я такое решение точно не назову.
Уже однажды попробовал и не смог.
Среда UEFI достаточно сильно отличается от привычной стандартной библиотеки, к примеру, там почти все строки — в UCS2, и уже одно это приносит кучу боли, т.к. строковые литералы просто как L«String» теперь не запишешь — в Rust UTF8 везде. Плюс абсолютно всё получается внутри unsafe {}, и в итоге преимуществ у Rust почти не остается, а недостатки вроде необходимости писать врапперы к библиотекам и протоколам — никуда не деваются. Я видел пару попыток, но их авторы тоже бросили, практически не начав.
Если время найду, попробую еще раз.

Информация

В рейтинге
303-й
Дата рождения
Зарегистрирован
Активность

Специализация

Инженер встраиваемых систем, Системный инженер
Ведущий