Стартап делает гораздо больше вещей. Вообще отчасти это задача
операционной системы: как-то разместить в памяти аргументы
программы, переменные окружения, и передать указатели на них. И
заодно сделать доступной в адресном пространстве программу
(загрузить её, библиотеки, релоцировать...), стек, настроить
регистры... C-стартап должен подготовить "рантайм" к работе и
инициализировать C-библиотеку.... В первую очередь обнулить секцию BSS -- переменные (не)инициализированные нулём (вообще это как бы делает ОС, но в embedded её нет), скопировать инициализированные переменные из ROM в RAM -- секция DATA (тоже делает загрузчик программ в ОС), если C++ -- то вызвать функции конструкторов глобальных/статических экземпляров классов (кроме синглтонов -- static внутри функций, инициализирующихся при первом использовании). Кстати у GCC тоже конструкторы есть в голом C (атрибут "constructor").
Потом должны вызваться функции инициализирующие C-библиотеку: инициализировать стандартные файлы ввода-вывода, кучу (malloc), таймзону (локаль инициализируется пользователем через явный вызов setlocale). Потом вызывается main и предполагается, что он вернётся и будет вызван exit(). Тогда должны вызваться все деструкторы: для статических/глобальных объектов и для синглтонов, потом должны выполниться пользовательские функции зарегистрированные через atexit(), потом должна быть вызвана функция ОС _exit(code). Код возврата как-то передаётся в ОС, в контроллере может быть просто перезапуск. Вообще в контроллере exit() и возврат из main смысла не имеют, как и вызов деструкторов на выходе.
Но программа выйти и через аварийный выход: через abort(), который может вызываться из assert'ов, из std::terminate() в C++, последний вызывается из необрабатываемых исключений. Вот этот выход нужно как-то ловить и сигнализировать, протоколировать, чтоб вообще с ошибками потом разобраться.
Кроме того, возможны аппаратные исключения, у ARM это HardFault_Handler в котором очень весело написан while(1). Конечно там должен быть не цикл -- прибор не должен зависать. Тут неплохо бы распечатать регистры, просигнализировать об ошибке, записать куда-то причину ошибки и диагностику и перезапуститься. Я недавно писал (старое, для не-кортексов), ссылки ниже.
Кроме того в embedded стартап должен выполнить некоторые базовые вещи заранее, до main, иначе старт будет долгим или не завершится вообще:
1) настроить тактовый генератор на высокую частоту, дождаться, убедиться, что PLL работает (иначе -- сигнализация сбоя на низкой частоте и перезапуск);
2) проверить целостность CRC прошивки (иначе -- сигнализация сбоя...);
3) всё остальное перечисленное выше...
См. далее по ссылкам:
https://embeddedartistry.com/blog/2019/04/08/a-general-overview-of-what-happens-before-main/
Ссылки по теме на caxapa:
http://caxapa.ru/1035383
http://caxapa.ru/902079
http://caxapa.ru/768150
http://caxapa.ru/301879 http://caxapa.ru/672102