MIPS:如何获取字符串的第 5 个字节并用它替换不同字符串的第 4 个字节?
MIPS: How do I take the 5th byte of a string and replace the 4th byte of a different string with it?
假设我有一个字符串 .asciiz "cheese" 和另一个 .asciiz "beefsteak"。我想把奶酪的第 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)
但这似乎不起作用。我该怎么办?
除了语法错误和忘记商店外,你很接近了。
使用string1: .asciiz "cheese"
。 string1:
是一个与 main:
完全相同的标签,使用相同的语法。它只是在不同的部分。 name = .asciiz ""
不起作用; =
用于定义assemble-时间常数,如string1_length = . - string1
,而不是用于将数据字节组装到内存中。
la $t1, string 2
在符号名称中有一个 space 显然不起作用。
lb $t1, 0($t0)
破坏了 string2
指针 。为您的角色临时选择一个不同的寄存器,例如lb $t0, 5($t0)
因为你不再需要那个指针了。
lbu
也可以,但您不会读取寄存器的完整字值,因此零扩展和符号扩展之间的选择无关紧要。
您需要用 sb $t0, 4($t1)
.
之类的东西存储您的结果
在运行时执行 addi
对于已知常量偏移量毫无意义:lb
和 sb
也有一个 16 位立即数字段;用它来简化你的代码。 MIPS 只有一种寻址方式:register + imm16。或者你可以只 la
你想要的地址,比如 la $t0, string1+5
此外,第 5 个字节位于 string1+4
。第一个字节是 c
,位于 string1+0
。所以第 5 个字节是单词的第 5 个字母,在索引 4 处。偏移量就像从 0 开始索引的 C 数组。您想要 cheese
中的 s
,而不是最终的 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
这 应该 assemble 4 条机器指令(2 条用于 la
,或者如果 .data 部分是 64k 对齐则可能只有 1 条。)
在实践中 clang -target mips
sb
assemble 到 lui+addi+sb
作为伪指令,完全没有意义。这些指令没有重定位,只有小常量,所以更聪明的 assembler 不会将 sb
扩展为伪指令。
string2-string1
是一个小的编译时常量,所以可以要求 assembler 将它嵌入到 lbu
或 sb
指令的立即数中,再加上一些其他小常量。 (如果这些符号都在同一部分的 this 编译单元中定义,我们没问题;如果它们需要由链接器填充,我们就会遇到减法问题。 )
如果我们知道字节在同一个 64kiB 块中并且可以让 assembler 仅将 lui
发送到临时文件中,然后 lbu
和sb
符号地址的低位部分。使用 GAS %hi(string1)
和 %low(string1) + string2-string1+3
或其他东西。
或者在 MARS 上,如果你要求模拟器将数据段放在低地址,你可以使用 lbu $t0, string1($zero)
,因为完整地址适合 16 位立即数。
或者使用 lbu / sb 作为伪指令,让 assembler 发出 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
.
假设我有一个字符串 .asciiz "cheese" 和另一个 .asciiz "beefsteak"。我想把奶酪的第 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)
但这似乎不起作用。我该怎么办?
除了语法错误和忘记商店外,你很接近了。
使用string1: .asciiz "cheese"
。 string1:
是一个与 main:
完全相同的标签,使用相同的语法。它只是在不同的部分。 name = .asciiz ""
不起作用; =
用于定义assemble-时间常数,如string1_length = . - string1
,而不是用于将数据字节组装到内存中。
la $t1, string 2
在符号名称中有一个 space 显然不起作用。
lb $t1, 0($t0)
破坏了 string2
指针 。为您的角色临时选择一个不同的寄存器,例如lb $t0, 5($t0)
因为你不再需要那个指针了。
lbu
也可以,但您不会读取寄存器的完整字值,因此零扩展和符号扩展之间的选择无关紧要。
您需要用 sb $t0, 4($t1)
.
在运行时执行 addi
对于已知常量偏移量毫无意义:lb
和 sb
也有一个 16 位立即数字段;用它来简化你的代码。 MIPS 只有一种寻址方式:register + imm16。或者你可以只 la
你想要的地址,比如 la $t0, string1+5
此外,第 5 个字节位于 string1+4
。第一个字节是 c
,位于 string1+0
。所以第 5 个字节是单词的第 5 个字母,在索引 4 处。偏移量就像从 0 开始索引的 C 数组。您想要 cheese
中的 s
,而不是最终的 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
这 应该 assemble 4 条机器指令(2 条用于 la
,或者如果 .data 部分是 64k 对齐则可能只有 1 条。)
在实践中 clang -target mips
sb
assemble 到 lui+addi+sb
作为伪指令,完全没有意义。这些指令没有重定位,只有小常量,所以更聪明的 assembler 不会将 sb
扩展为伪指令。
string2-string1
是一个小的编译时常量,所以可以要求 assembler 将它嵌入到 lbu
或 sb
指令的立即数中,再加上一些其他小常量。 (如果这些符号都在同一部分的 this 编译单元中定义,我们没问题;如果它们需要由链接器填充,我们就会遇到减法问题。 )
如果我们知道字节在同一个 64kiB 块中并且可以让 assembler 仅将 lui
发送到临时文件中,然后 lbu
和sb
符号地址的低位部分。使用 GAS %hi(string1)
和 %low(string1) + string2-string1+3
或其他东西。
或者在 MARS 上,如果你要求模拟器将数据段放在低地址,你可以使用 lbu $t0, string1($zero)
,因为完整地址适合 16 位立即数。
或者使用 lbu / sb 作为伪指令,让 assembler 发出 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
.