MIPS 程序自我复制?
MIPS program to replicate itself?
如何创建一个 mips 程序,以便在 main 函数中打印出 version1,然后将整个代码复制到内存中,最后执行复制的版本。复制的代码版本必须打印 version2。除了版本 1 和版本 2 之外,您不能在数据部分添加任何内容。
如何将整个代码复制到内存中并执行?我以前从未做过这样的事情,所以我不知道从哪里开始。
.data
version1: .asciiz "This is version1"
version2: .asciiz "this is version2"
main:
li $v0, 4
la $a0, version1
syscall
#(how do I copy code and execute it?????)
自行修改代码的能力取决于执行环境。
使用 MARS 可以启用此选项。
代码假设数据内存采用小端字节序(代码内存没有假设)。
你的教授可能想要的是:
- 您认识到
la
是由 ori
和 lui
组成的伪指令,因此您正确地将要复制的指令计为四个。
- 您在程序流程中为使用
nop
的四个指令保留 space。
- 您认识编辑操作数的指令格式。
复制过程很简单。您可以通过切肉刀使用标签来获得汇编器的帮助:只需在要复制的代码之后放置一个标签(如果有 none,则在前面放置一个标签),然后复制这两者之间的所有数据。
由于我们知道要复制的代码长度,而且比较小,所以可以手工复制。
为了修改复制的代码,我们需要看看它看起来像机器码
addiu $v0, 0, 4 #24020004
lui $at, HHHH #3c01HHHH
ori $a0, $at, LLLL #3424LLLL
syscall #0000000c
如您所见,您已经替换了第 2 条和第 3 条指令的低位硬件。
要使用的值是 version2.
的地址
该地址的高位和低位 HW 可以通过基本的位操作获得。
您还必须添加代码才能很好地终止程序。
这里是为 MARS 制作的有意简化的工作示例(在设置中激活自修改代码)。
.data
version1: .asciiz "This is version1"
version2: .asciiz "this is version2"
.text
main:
li $v0, 4 #1 instruction addiu $v0, [=11=], 4
la $a0, version1 #2 instructions lui $a0, H ori $a0, L
syscall #1 instruction
#Load src and dest address
la $t0, main
la $t1, new_code
#Copy the four words of code
lw $t2, ($t0)
sw $t2, ($t1)
lw $t2, 4($t0)
sw $t2, 4($t1)
lw $t2, 8($t0)
sw $t2, 8($t1)
lw $t2, 0xc($t0)
sw $t2, 0xc($t1)
#Load the address of version2
la $t0, version2
add $t2, [=11=], [=11=]
lui $t2, 0xffff #t2 = 0ffff0000h
andi $t3, $t0, 0xffff #t3 = Lower HW of address
srl $t0, $t0, 0x10 #t0 = Upper HW of address
#Edit ori $a0, L
lw $t4, 8($t1) #Load the instruction in register
and $t4, $t4, $t2 #Clear lower hw
or $t4, $t4, $t3 #Set lower hw
sw $t4, 8($t1) #Save the instruction
#Edit lui $a0, H
lw $t4, 4($t1) #Load the instruction in register
and $t4, $t4, $t2 #Clear lower hw
or $t4, $t4, $t0 #Set lower hw
sw $t4, 4($t1) #Save the instruction
new_code:
nop
nop
nop
nop
li $v0, 10
syscall
如果您对动态分配内存的更通用版本感兴趣(使用系统调用 9),对齐返回的指针,复制代码,修改它并添加对系统调用 10 的调用,这里是
.data
version1: .asciiz "This is version1"
version2: .asciiz "this is version2"
.text
main:
__copy_start__: #Sign the start of code to copy
li $v0, 4 #1 instruction addiu $v0, [=12=], 4
la $a0, version1 #2 instruction2 lui $a0, H ori $a0, L
syscall #1 instruction
__copy_end__:
li $v0, 9 #Allocate buffer
li $a0, 27 #16 bytes (4 instructions) + 8 bytes (2 instructions) + 3 byte for aligning
syscall
#Align the pointer by consuming the first bytes (this is usually not needed, just for completeness)
addi $v0, $v0, 3
andi $v0, $v0, 0xfffffffc
#Prepare for the copy
la $t0, __copy_start__ #t0 = Source start
la $t1, __copy_end__ #t1 = Source end (exclusive)
add $t2, [=12=], $v0 #t2 = Destination start
ori $t4, [=12=], 1 #t4 = 1: Extra code to be copied 0: Extra code copied
do_copy:
#Move from Source to Dest
lw $t3, ($t0)
sw $t3, ($t2)
#Increment the pointers
addi $t0, $t0, 4
addi $t2, $t2, 4
#If not reached the Source end, copy again
bne $t0, $t1, do_copy
#Copy done
#If the extra code has been copied, do the jump to the new code
beqz $t4, do_jump
#Extra code need to be copied
la $t0, __copy_extra__ #New source start
la $t1, __copy_extra_end__ #New source end
add $t4, [=12=], [=12=] #Signal extra code is being copied
#Copy again
b do_copy
do_jump:
#Get the address of version2
la $t0, version2
#Save the low half word into the low halfword of the 3rd instruction (ori $a0, L)
sh $t0, 8($v0)
#Get the upper hw in the lower hw of $t0
srl $t0, $t0, 16
#Save the high half word into the low hw of the 2nd instruction (lui $a0, H)
sh $t0, 4($v0)
#Jump indirect
jr $v0
#Extra code to append to the end of the new code
__copy_extra__:
li $v0, 10
syscall
__copy_extra_end__:
如何创建一个 mips 程序,以便在 main 函数中打印出 version1,然后将整个代码复制到内存中,最后执行复制的版本。复制的代码版本必须打印 version2。除了版本 1 和版本 2 之外,您不能在数据部分添加任何内容。
如何将整个代码复制到内存中并执行?我以前从未做过这样的事情,所以我不知道从哪里开始。
.data
version1: .asciiz "This is version1"
version2: .asciiz "this is version2"
main:
li $v0, 4
la $a0, version1
syscall
#(how do I copy code and execute it?????)
自行修改代码的能力取决于执行环境。
使用 MARS 可以启用此选项。
代码假设数据内存采用小端字节序(代码内存没有假设)。
你的教授可能想要的是:
- 您认识到
la
是由ori
和lui
组成的伪指令,因此您正确地将要复制的指令计为四个。 - 您在程序流程中为使用
nop
的四个指令保留 space。 - 您认识编辑操作数的指令格式。
复制过程很简单。您可以通过切肉刀使用标签来获得汇编器的帮助:只需在要复制的代码之后放置一个标签(如果有 none,则在前面放置一个标签),然后复制这两者之间的所有数据。
由于我们知道要复制的代码长度,而且比较小,所以可以手工复制。
为了修改复制的代码,我们需要看看它看起来像机器码
addiu $v0, 0, 4 #24020004
lui $at, HHHH #3c01HHHH
ori $a0, $at, LLLL #3424LLLL
syscall #0000000c
如您所见,您已经替换了第 2 条和第 3 条指令的低位硬件。
要使用的值是 version2.
的地址
该地址的高位和低位 HW 可以通过基本的位操作获得。
您还必须添加代码才能很好地终止程序。
这里是为 MARS 制作的有意简化的工作示例(在设置中激活自修改代码)。
.data
version1: .asciiz "This is version1"
version2: .asciiz "this is version2"
.text
main:
li $v0, 4 #1 instruction addiu $v0, [=11=], 4
la $a0, version1 #2 instructions lui $a0, H ori $a0, L
syscall #1 instruction
#Load src and dest address
la $t0, main
la $t1, new_code
#Copy the four words of code
lw $t2, ($t0)
sw $t2, ($t1)
lw $t2, 4($t0)
sw $t2, 4($t1)
lw $t2, 8($t0)
sw $t2, 8($t1)
lw $t2, 0xc($t0)
sw $t2, 0xc($t1)
#Load the address of version2
la $t0, version2
add $t2, [=11=], [=11=]
lui $t2, 0xffff #t2 = 0ffff0000h
andi $t3, $t0, 0xffff #t3 = Lower HW of address
srl $t0, $t0, 0x10 #t0 = Upper HW of address
#Edit ori $a0, L
lw $t4, 8($t1) #Load the instruction in register
and $t4, $t4, $t2 #Clear lower hw
or $t4, $t4, $t3 #Set lower hw
sw $t4, 8($t1) #Save the instruction
#Edit lui $a0, H
lw $t4, 4($t1) #Load the instruction in register
and $t4, $t4, $t2 #Clear lower hw
or $t4, $t4, $t0 #Set lower hw
sw $t4, 4($t1) #Save the instruction
new_code:
nop
nop
nop
nop
li $v0, 10
syscall
如果您对动态分配内存的更通用版本感兴趣(使用系统调用 9),对齐返回的指针,复制代码,修改它并添加对系统调用 10 的调用,这里是
.data
version1: .asciiz "This is version1"
version2: .asciiz "this is version2"
.text
main:
__copy_start__: #Sign the start of code to copy
li $v0, 4 #1 instruction addiu $v0, [=12=], 4
la $a0, version1 #2 instruction2 lui $a0, H ori $a0, L
syscall #1 instruction
__copy_end__:
li $v0, 9 #Allocate buffer
li $a0, 27 #16 bytes (4 instructions) + 8 bytes (2 instructions) + 3 byte for aligning
syscall
#Align the pointer by consuming the first bytes (this is usually not needed, just for completeness)
addi $v0, $v0, 3
andi $v0, $v0, 0xfffffffc
#Prepare for the copy
la $t0, __copy_start__ #t0 = Source start
la $t1, __copy_end__ #t1 = Source end (exclusive)
add $t2, [=12=], $v0 #t2 = Destination start
ori $t4, [=12=], 1 #t4 = 1: Extra code to be copied 0: Extra code copied
do_copy:
#Move from Source to Dest
lw $t3, ($t0)
sw $t3, ($t2)
#Increment the pointers
addi $t0, $t0, 4
addi $t2, $t2, 4
#If not reached the Source end, copy again
bne $t0, $t1, do_copy
#Copy done
#If the extra code has been copied, do the jump to the new code
beqz $t4, do_jump
#Extra code need to be copied
la $t0, __copy_extra__ #New source start
la $t1, __copy_extra_end__ #New source end
add $t4, [=12=], [=12=] #Signal extra code is being copied
#Copy again
b do_copy
do_jump:
#Get the address of version2
la $t0, version2
#Save the low half word into the low halfword of the 3rd instruction (ori $a0, L)
sh $t0, 8($v0)
#Get the upper hw in the lower hw of $t0
srl $t0, $t0, 16
#Save the high half word into the low hw of the 2nd instruction (lui $a0, H)
sh $t0, 4($v0)
#Jump indirect
jr $v0
#Extra code to append to the end of the new code
__copy_extra__:
li $v0, 10
syscall
__copy_extra_end__: