Рассмотрим следующий фрагмент ассемблерного кода, написанного для встроенной архитектуры процессора Nios II :
.section .data
.align 2
va: .long 0x0
vb: .long 0x11223344
vc: .long 0x55667788
Необходимо сделать следующее:
Я не понимаю, как это можно сделать с помощью набора инструкций, и надеялся получить некоторое представление о том, как происходит перевод приведенного выше кода в набор инструкций.
Это выделение памяти, и это не имеет ничего общего с набором инструкций. Ассемблеры невероятно просты — строки в ассемблерном файле почти точно соответствуют выходному бинарному файлу, делается очень мало перестановок. Строка «.long 0x0» просто означает «дайте мне четыре байта прямо здесь и загрузите их со значением 0x0». Данные «распределяются» так же, как и инструкции. Строка «MOV R12, R11» просто означает «дайте мне четыре байта прямо здесь и загрузите их двоичной кодировкой для MOV R12, R11». Данные являются смежными по той же причине, что и ваши инструкции, — вы ввели их на смежных строках в файле сборки. «va:» просто означает «назовите расположение этих четырех байтов «va»». Это используется только внутри ассемблера. Везде, где вы ссылаетесь на «ва» в коде ассемблер вставит адрес четырех байтов данных, на которые ссылается «va», что является просто числом. Обратите внимание, что это может сделать не ассемблер, а компоновщик. Однако строка 'va' никогда не появится в выходном двоичном файле.
По сути, ассемблер — это почти прямое представление содержимого памяти. Последовательные линии сборки заканчиваются последовательными адресами. Единственным исключением является изменение разделов (.section). Любые данные, явно расположенные в коде, будут непрерывными, если они непрерывны в файле сборки. Теперь секции немного возятся с этим. Возможно, что все .data попадает в одну часть памяти, а все .text — в другую. Однако блоки не будут разбиты — если они являются смежными в файле сборки, они будут смежными и в выходных данных.
Подобные данные не «распределяются» совершенно одинаково.
Что происходит, так это то, что когда вы запускаете программу, эта программа загружается в память. Если эта программа где-то содержит 0x000000001122334455667788, то эти ячейки памяти (всего 12, если я не ошибся) будут содержать эти значения. Когда вы компилируете свой код, все ИМЕНА переводятся в адреса памяти. С этого момента для этого фактически не выполняются никакие инструкции — память есть, она «выделена» (выделено достаточно памяти для хранения всей программы, статических переменных, таких как эта и все такое), и поскольку вся программа размещается в этой памяти инициализируются переменные.
Затем, когда вы говорите «загрузить переменную va в регистр 'X'», скомпилированный код (который говорит «загрузить адрес 0x84573412 в регистр 'X'») получит правильный бит данных.
Имена переменных приведены только для вашего удобства, иначе вам пришлось бы самостоятельно выделять конкретные адреса.
Игнасио Васкес-Абрамс
Фархад
Игнасио Васкес-Абрамс
Фархад
Игнасио Васкес-Абрамс
Игнасио Васкес-Абрамс