(MIPS Assembler) Можем ли мы инициализировать счетчик программ самостоятельно? - PullRequest
0 голосов
/ 22 февраля 2019

Я все еще пытаюсь разработать Ассемблер MIPS как часть моего задания.И мне дали эти входные и выходные файлы.

main:   lw $a0, 0($t0)          
begin:  addi $t0, $zero, 0      # beginning
    addi $t1, $zero, 1
loop:   slt $t2, $a0, $t1       # top of loop
    bne $t2, $zero, finish
    add $t0, $t0, $t1
    addi $t1, $t1, 2
    j loop              # bottom of loop
finish: add $v0, $t0, $zero

и вывод должен быть в машинном коде следующим образом:

10001101000001000000000000000000
00100000000010000000000000000000
00100000000010010000000000000001
00000000100010010101000000101010
00010101010000000000000000001000
00000001000010010100000000100000
00100001001010010000000000000010
00001000000000000000000000000011
00000001000000000001000000100000

И я заметил, что машинный код, который представляет инструкцию«цикл j» равен

00001000000000000000000000000011

В соответствии с форматом команды J-типа последние 26 битов будут представлять целевой адрес.Из двоичного кода, который я написал выше, я замечаю, что целевой адрес этой инструкции перехода (который в основном является адресом «цикла») равен 00000000000000000000000011, что составляет 3.

Я разработал свою версию программы, и все жецелевой адрес, который он получил для "loop", намного больше этого.

Мне было интересно, можно ли каким-либо образом инициализировать счетчик программы до 0 или что-нибудь еще, чтобы я мог получить тот же целевой адрес, что и в выходном файле, который мне дали.А как именно работает счетчик программ?Увеличивается ли он для каждой строки кода?

Пожалуйста, сообщите.Спасибо!

1 Ответ

0 голосов
/ 24 февраля 2019

Существует лот сложности, который входит в любой вид полного ответа здесь.Однако для сборки MIPS мы можем [см. Комментарии ниже] получить небольшой перерыв.

Нам нужно будет рассмотреть режимы адресации и концепцию относительной адресации против абсолютная адресация .Это связано с тем, что, как отмечал zwol в комментарии , выходные данные компиляторов и ассемблеров, как правило, на самом деле не готовы к работе код , а скорее являются объектными файлами полный инструкций, которые интерпретируются компоновщиком и / или загрузчиком .

компоновщик - это программа, которая принимает несколько объектных файлов и объединяет их вболее полная программа.Это может принимать форму другого объектного файла или библиотеки, которая по сути является коллекцией объектных файлов.Если формат библиотеки достаточно прост, библиотека может быть построена просто путем объединения объектных файлов с возможностью добавления оглавления, но иногда вы хотите выполнить определенное количество предварительных ссылок, чтобы соединить конкретные объектные файлы вместе внеразрушимый блок для последующего связывания с другими объектными файлами или библиотеками.Компоновщики могут быть довольно сложными, поскольку им, возможно, придется иметь дело с символическими именами (именами функций и переменных) и предоставлять информацию для отладчиков (таблиц символов, описаний областей памяти и т. Д.).

A loader принимает объектные файлы, которые часто по крайней мере частично разрешаются компоновщиком, иногда полностью разрешаются, и загружают их в память.Некоторые загрузчики сами по себе являются компоновщиками типа, обычно называемого runtime linker или runtime loader.Это позволяет исполняемым объектным файлам загружать другие объектные файлы во время выполнения, а не предварительно связывать все заранее.

Так или иначе, хотя обычно операция времени загрузки назначает фактическоеадреса к коду и данным.Объектный файл может содержать инструкции, которые говорят, что код может выполняться где угодно или что код должен выполняться по какому-то определенному (фиксированному) адресу.Те же правила могут применяться к данным.Если требуется фиксированный адрес, возможно, этот адрес недоступен, поэтому часто желательно перемещаемый код - код, который можно переместить с какого-либо адреса по умолчанию на другой другой адрес.

Это приводит к концепции относительной адресации .Предположим, что машина работает, выполняя несколько очень простых шагов:

  1. Загрузка инструкции с адреса, указанного в регистре IP (указатель инструкций) или ПК (счетчик команд).
  2. Увеличьте этот регистр нанекоторая константа, например 4.
  3. Выполнить только что загруженную инструкцию.

A ответвление инструкция состоит из директивы change theРегистр IP / ПК, либо до какого-либо нового значения, либо путем добавления или вычитания некоторого значения.

Теперь предположим, что исполняемый объектный файл рекомендует чтобы программа загружалась, например, по адресу 0x04000000.Предположим далее, что десятая инструкция, которая будет находиться по адресу 0x04000028, является инструкцией ветвления, и что она должна быть настроена так, чтобы инструкция next была загружена из 0x0400000c, т.е. третья инструкция:

04000000       instruction#0
04000004       instruction#1
04000008       instruction#2
0400000c loop: instruction#3
04000010       #4
04000014       #5
04000018       #6
0400001c       #7
04000020       #8
04000024       #9
04000028       j   loop
0400002c

Учитывая нашу модель выше, регистр IP или ПК будет, во время выполнения инструкции # 10, j loop, который переходит к инструкции # 3,удерживайте значение 0400002c, потому что мы описали операцию как «загрузить, увеличить на 4, выполнить».

Еслинам нужно использовать абсолютную адресацию, нам нужна актуальная j loop инструкция, чтобы вставить буквальное значение 0400000c непосредственно в регистр указателя инструкций.Однако только загрузчик может знать, действительно ли программа работает с 04000000.Если этот адрес использовался, загрузчик мог вместо этого переместить программу на 08000000, и вместо этого значение для вставки в регистр ip теперь 0800000c.

Если мы используем относительныйТем не менее, , обращаясь к инструкции j loop, необходимо собрать в машинный код, который говорит не «перейти к 0400000c», а «идти вперед или назад от того места, где мы сейчас находимся, 0400002c, туда, где мыхочу быть на 0400000c ".Это, очевидно, обратный скачок, на 0400002c - 0400000c или 20 (шестнадцатеричный, 32 десятичный) байт или на восемь инструкций.

Редактировать : см. Комментарии ниже, следующая часть была неправильной -Я полагался на другой ответ StackOverflow и на веб-страницу, на которую я ссылаюсь, чтобы предположить переходы с ПК.Я обновил это, чтобы использовать абсолютную адресацию для команд j.

Процессоры MIPS используют регистр с именем pc (но труднодоступный) и поддерживают относительную адресацию в условных ветвях (например, beq; см. Сборочный режим относительной адресации ПК ).Следовательно, некоторые из сложностей могут исчезнуть: нам нужно только поручить ЦПУ перейти назад на восемь инструкций, т. Е. Добавить отрицательную восьмерку в регистр ПК.CPU автоматически умножает это значение на 4, так что оно добавляет отрицательное значение-32.Если бы мы были действительно загружены в 04000000, pc будет 0400002c, и перемещение его назад сильно изменит его на 0400000c, что мы и хотим.Если бы мы действительно были загружены в 08000000 вместо этого, то же самое движение относительно приводит нас к 0800000c, что мы и хотим.

Это было бы так, если бы мы использовали b инструкция.Но инструкции j являются абсолютными в пределах области 256 МБ: они просто перезаписывают младшие 28 бит счетчика программы.

Как правило, у нас будет ассемблер, выводящий нашу абсолютную инструкцию jump с типом перемещенияэто говорит любому загрузчику во время выполнения: добавьте любое необходимое смещение во время загрузки. Поэтому нам просто нужно убедиться, что при сборке мы знаем, куда мы намереваемся загрузить - будь топросто 0, или 04000000, или что-то еще - и мы выдадим для j инструкции абсолютный адрес целевой команды, но также некоторые дополнительные инструкции компоновщика / загрузчика, которые говорят: константаВ этой инструкции может потребоваться настройка во время соединения или загрузки. Обратите внимание, что компоновщик и загрузчик должны быть достаточно умными, чтобы понимать ограничения адресации: не ОК, чтобы переместить программу так, чтобы она соответствовалаодна область 256 МБ, теперь охватывает две такие области, если сегмент кода использует инструкции j для перехода в одну область.

(веб-сайт https://en.wikibooks.org/wiki/MIPS_Assembly/MIPS_Details утверждает, что инструкции j являются относительными, но это, похоже, неправильно;см. комментарии.)

(Обратите внимание, что отрицательные числа представляются в виде дополнения до двух. Поскольку инструкция j принимает 26-битный относительный адрес, который она автоматически умножает на 4, она может представлять 28-битнуюдиапазон адресов от -2 27 до 2 27 -1 или -08000000..07fffffc с шагом 4.)

...