Top-office11.ru

IT и мир ПК
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Arm ассемблер руководство

Базовые макросы. Взгляд из ассемблера ARM Cortex-M.

Здесь я коротко напишу про вид из ассемблера базовых макросов min(a,b), max(a,b) и isEqual(a,b).

Первые два иногда пригождаются, третий — весьма спорный, но иногда его удобно использовать.

Заметка будет короткой и наверняка не интересной для профи, которые знакомы с архитектурой ARM-Cortex, и понимающие отличия ARM-режима процессора от THUMB-режима) Кому все же интересно — добро пожаловать под кат.

Изучаю STM32 на примере завалявшейся платки STM32VLDiscovery, бывшей когда-то, помнится, весьма популярной. Стало интересно во что компилируются самые простые макросы, и насколько накладно их использование.
Использую GCC (Code Sourcery) + Eclipse + OpenOCD/Zylin на Mac OS X.

Итак, сами макросы:

Код, использующий эти макросы:

Всё довольно бессмысленно и беспощадно, но суть не в этом.
Разберём, во что разворачивается этот код.

Инициализация переменных.

Чтобы сразу понять как инициализируются переменные, нужно прокрутить asm-листинг чуть выше и посмотреть на строчки, с которых начинается функция main():

1. Сначала мы сохраняем в стек регистры r4, r7 и lr(r14, в котором хранится вектор возврата при вызове функций).
2. Далее вычитаем из sp (r13 — указатель вершины стека) число 36 (необходимое для последующего сохранения в стек 36 байт).
3. И, наконец, сохраняем новое значение sp в r7 командой:

Которая в данном случае эквиваентна команде:

Далее, собственно, код инициализации:

Все переменные в нашем примере локальные, а значит живут на стеке (кроме переменной с модиикатором register, но о ней позже). Переменные a и b занимают всего лишь по 1 байту, и a живёт по адресу в стеке sp + 27d, а b по адресу sp + 26d. Команда mov.w — это 32-битная (wide) команда mov в Thumb-2. Суффикс -b в команде strb говорит о том, что мы хотим сохранить из регистра в память unsigned byte переменную.

Читать еще:  Выровнять текст по левому краю html
Max(a,b)

Код, в который разворачивается строка:

1. Сначала мы загружаем из стека в r2 значение по адресу sp + 26d (как мы помним, это переменная b).
2. А в регистр r3 значение переменной a.
3. Далее сравниваем эти два значения командой cmp. Эта команда работает точно так же как вычитание — sub, только результат нигде не сохраняется. В данном случае из r2 (= b = 2) вычитается r3 (= a = 3).
4. И далее весёлая команда, которая есть в наборе инструкций THUMB/THUMB-2, но её нет в наборе инструкций ARM.
it — это команда if-then, после которой могут следовать блоки из 4 команд, для условия инструкции it, или инверсного условия. То есть мы можем объявить условие выполнения/невыполнения для нескольких последующих инструкций после it. В принципе, эту команду можно опустить, но она гарантирует, что после неё будут команды, отрабатывающие объявленное условие.
Итак, it cs — это объявление условия CS — unsigned higher or same. Так как мы сравнивали r2(b) с r3(a), то если r2 > r3, то должно выполниться условие CS, и, соответственно должны выполниться команды с условиями cs, следующие после it.
5. Следующая команда movcs r3, r2mov с условием cs. То есть, если r2 > r3 — она выполнится, иначе — не выполнится. В нашем случае она не выполняется, что легко заметить в отладчике.
Регистры до выполнения movcs:

Регистры после выполнения movcs:

6. И завершающая команда strb r3, [r7, #25] — сохраняем результат в переменную c, лежащую в стеке по адресу sp + 25d. Эта команда уже не относится к макросу, а относится к инициализации переменной c.

Как видим, всё очень просто.

Читать еще:  Scanf в си примеры
Min(a,b)

Код этого макроса (с такой же инициализацией в конце) почти ничем не отличается от предыдущего:

Как видим, в коде макроса вообще всего 1 отличие — это условие CC (unsigned lower), согласно которому в нашем случае movcc не будет игнорироваться, и в r3 (= a = 3) окажется значение r2 (= b = 2), которым и будет проинициализирована переменная d по адресу sp + 24.d.

isEqual(a,b)

В случае с isEqual удобно посмотреть на asm-листинг так, как он коррелирует с c-листингом:

Здесь тоже нет ничего сложного, только я хотел посмотреть как себя ведут в программе переменные с модификатором register. При оптимизации -o0, любая, даже не используемая локальная переменная сохраняется на стеке — то есть ей выделяется память. Если инициализировать (объявлять) переменные с модификатором register, то, при их не использовании, даже с -o0 компилятор просто выбрасывает код, связанный с их инициализацией. Это я на всякий случай посмотрел из ассемблера, а здесь оставил только для того, чтобы показать, как выглядят эти переменные в asm-листинге.

Итак, начнём:
1, 2. Загружаем из стека c и d в r2 и r3 соответственно.
3. Сравниваем r2 и r3.
4. Если r2 и r3 равны, то после выполнения предыдущей инструкции, поднимается флаг Z. bne.n — выполняется, если флаг Z НЕ поднялся, иначе не выполняется. Суффикс .n указывает на то, что это 16-битная инструкция из набора команда THUMB/THUMB-2. То есть, если r2 == r3, то флаг Z поднимается и инструкция bne.n игнорируется, если же r2 != r3 (как в нашем случае), то Z НЕ поднимаается и мы шагаем на адрес 0x8000d46 обрабатывать блок else.
5. Продолжим с адреса 0x8000d46 (вариант с выполнением условия блока if примерно такой же). Загружаем в r4 переменную d из стека по адресу sp + 24. Обратите внимание, хоть мы и объявили переменную uint32_t register_variable, но компилятор, исходя из того, что она объявлена с модификатором register, не выделяет под неё память в стеке (хотя, если вспомнить с чего начинается функция main(), то r4 сохраняется в стек в самом начале).
5. Ну а далее, думаю, всё совсем очевидно. add.w r4, r4, #4294967295 — добавляем к r4 значение 0xFFFFFFFF, что эквивалентно sub.w r4, #1.
6. Сохраняем r4 в переменную local_variable по адресу sp + 16. Она займёт там 4 байта, так как её тип — uint32_t.

Читать еще:  Ссылка на почтовый ящик html

Таким образом, можно увидеть, что простые макросы особо не нагружают ни процессор, ни память, и их использовать можно везде, где удобно и семантично)

На этом, думаю, мы и закончим)
Если тема интересная, то пишите в комментариях, я люблю порыться в asm-коде программ, чтобы понять как там что работает, и могу попробовать написать подобные заметки и про другие макросы/функции.
Если вам не понравилось, или вы нашли ошибки — тоже пишите, буду исправляться)

Спасибо за внимание.

  • ARM,
  • Assembler,
  • Macro,
  • Define,
  • Noobie
  • +4
  • 17 октября 2014, 13:37
  • Zloy_Pakimon

Комментарии ( 14 )

На -o0 это не интересно. Интересней было бы посмотреть на оптимизированный код — но код в примере будет просто выкинуть компилятором целиком 🙂

А заче команда it, если команды после нее все равно идут условные? Я бы понял, если бы условность команд выкинули,

Ссылка на основную публикацию
Adblock
detector