Точно такой же отладочный вывод можно применять и в ассемблерном проекте. Кстати, это вполне себе повод ознакомиться с представлением строк в си и хотя бы самой простой работе с ними.
Файл retarget.c пусть и остаётся самим собой, реализация функции ITM_SendChar описана в файле cm4_core.h и пусть она там остаётся. Желающие, конечно, могут переписать на асм, она маленькая.
читать дальшеСтроки представляются ассемблеру как массив байт:
Если будут использоваться какие-либо функции из языка Си (например, библиотечные strcmp, strcpy и т.д.), то в конце каждой должен присутствовать ноль. Он, по соглашению, и обозначает конец. За перенос строки отвечает код 0x0a (10). Коды иных спецсимволов можно узнать в таблице ASCII/ANSI.
Строки лучше всего разместить в отдельной секции с иными неизменяемыми данными. В секции кода им делать нечего. Как-нибудь так:
Использование их не представляет ничего экстраординарного:
Что надо передавать в printf смотрите в мануале по стандартной библиотеке языка Си.
Библиотека Microlib поддерживает это хоть и не в совсем полном объёме, но вполне достаточном для использования.
А что делать с printf и другими функциями, если аргументов больше, чем четыре?
Например, printf("%d %d %d %d %s %d", 1, 2, 3, 4, "mimimi", 5)?
Указатель на строку для форматирования записывается в регистр R0. Потом три аргумента ещё влезают в регистры R0-R3. А дальше фиг, регистров для аргументов больше нет. Регистры R4-R12 вложенная функция трогать не должна, они не для неё. Зато есть стек. Все аргументы функции, что не влезли в регистры, должны располагаться там, куда указывает SP. То есть пятый аргумент будет взят по адресу *SP, шестой по адресу *(SP + 4), седьмой - *(SP + 8) и т.д.
А для этого надо их туда поместить, ничего не сломав. Мы помним, что стек в армах растёт в сторону меньших адресов. Каждый PUSH одного регистра уменьшает SP на 4, каждый POP увеличивает на 4. Это значит, что в сторону больших адресов лежат всякие важные данные. Например, адреса возврата, сохранённые с помощью PUSH {LR}.
Если будем записывать вот так прямо по указателю SP, то всё будет плохо:
Потому сдвинем указатель так, чтоб вся запись оказалась в безопасной и никому кроме нас не нужной зоне:
Так вот, для передачи дополнительных аргументов через стек, надо бы сначала указатель подвинуть на достаточное и безопасное расстояние и заполнить все значения.
Ассемблер кейла настоятельно желает, чтобы указатель стека всегда мог быть нацело поделён на 8, потому сдвигаем его на числа, кратные 8: 8, 16, 24, 32 и т.д, даже если нам
лишние байты не нужны. Размер каждого аргумента 4 байта, как размер регистра. Он не зависит от типа аргумента никак, такое вот соглашение.
Пример передачи семи аргументов в функцию printf:
В общем, подобным образом можно использовать все строковые функции из стандартной библиотеки, их там много полезных.
Файлы:
main.s
Проект.<< Предыдущее Следующее >>