Вы близки, за исключением синтаксических ошибок и забыли магазин .
Используйте 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
.