MIPS: Как мне взять 5-й байт строки и заменить на него 4-й байт другой строки? - PullRequest
0 голосов
/ 23 октября 2019

Скажем, у меня есть строка .asciiz "сыр" и еще один .asciiz "бифштекс". Я хочу взять 5-й байт сыра и поместить его туда, где находится f в бифштексе. Я не могу понять это. Вот что у меня есть:

.data
string1 = .asciiz "cheese"
string2 = .asciiz "beefsteak"

.text
.globl main
main:
la $t0, string1
la $t1, string 2
add $t0, $t0, 5
add $t1, $t1, 4
lb $t1, 0($t0)

Но, похоже, это не работает. Что мне делать?

1 Ответ

2 голосов
/ 23 октября 2019

Вы близки, за исключением синтаксических ошибок и забыли магазин .

Используйте string1: .asciiz "cheese". string1: - это метка в точности как main: с использованием идентичного синтаксиса. Это просто в другом разделе. name = .asciiz "" не работает;= предназначен для определения констант времени сборки, таких как string1_length = . - string1, а не для сборки байтов данных в память.

la $t1, string 2 содержит пробел внутри имени символа, который, очевидно, не работает.


lb $t1, 0($t0) уничтожает указатель string2 . Выберите временный регистр для вашего персонажа, например lb $t0, 5($t0), потому что вам больше не нужен этот указатель.

lbu тоже сработает, но вы не собираетесь читать полное значение словазарегистрируйтесь, чтобы выбор между нулем и расширением знака не имел значения.

Вам нужно сохранить результат с чем-то вроде sb $t0, 4($t1).

Выполнение addi во время выполнения бессмысленно длясмещения известных констант: lb и sb также имеют 16-битное непосредственное поле;используйте это, чтобы упростить ваш код. MIPS имеет только один режим адресации: регистр + imm16. Или вы могли бы просто la адрес, который вы хотите в первую очередь, как la $t0, string1+5


Кроме того, 5-й байт в string1+4. Первый байт - c, в string1+0. Таким образом, 5-й байт является 5-й буквой слова в индексе 4. Смещения подобны 0-индексированным массивам C. Вы хотите s в cheese, а не в финале e.


Интересный факт: вы также можете сохранять инструкции при генерации адреса, обращаясь к одной строке относительно другой.

# assembles (inefficiently) with clang
# untested with MARS or GAS; pretty sure it will work at least with GAS

.data
string1: .asciiz "cheese"
string2: .asciiz "beefsteak"

.text
.globl main
main:
   la   $t0, string1
   lbu  $t1, 4($t0)                   # 5th byte = start+4 of string 1
   sb   $t1, 3+string2-string1($t0)

   jr   $ra   # return

Этот должен собираться в 4 машинные инструкции (2 для la или, возможно, только 1, если раздел .data выровнен на 64 КБ.)

На практике с clang -target mips sb собирается в lui+addi+sb как псевдоинструкция, совершенно бессмысленно. В этих инструкциях нет перемещений, только небольшие константы, поэтому умный ассемблер не расширил бы sb как псевдоинструкцию.

string2-string1 - небольшая константа времени компиляции, так что все в порядкепопросить ассемблер встроить его в непосредственную команду lbu или sb, плюс некоторую другую небольшую константу. (Если бы оба символа были определены в этом модуле компиляции в одном и том же разделе, у нас все в порядке; если они должны быть заполнены компоновщиком, у нас возникнет проблема с вычитанием.)

Еще лучше было бы, если бы мы знали, что байты были в одном и том же блоке размером 64 КБ и могли заставить ассемблер выдавать во временную память только lui, затем lbu и sb с нижней частью адресов символов,Используя GAS %hi(string1) и %low(string1) + string2-string1+3 или что-то в этом роде.

Или на MARS, если вы попросите, чтобы симулятор поместил секцию данных в низкий адрес, вы можете использовать lbu $t0, string1($zero), потому что полный адрес помещается в16-битный немедленный.

Или используйте lbu / sb в качестве псевдоинструкций, заставляя ассемблер испускать lui + lbu с непосредственным предоставлением lbu младших 16 бит адреса, вместо того, чтобы тратитьaddiu или ori генерация точного адреса в регистр, что приводит к потере непосредственных битов при фактической загрузке.

# tested with clang: assembles to lui+lbu,   lui+sb
   lbu $t0, string1+4
   sb  $t0, string2+3

Это, конечно, легко написать в исходном коде asm, и трудно превзойти в действительностиэффективность после расширения псевдоинструкций, если только вы не используете вручную, зная, что string1 и string2 находятся в одной и той же 64k выровненной области и могут совместно использовать lui.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...