自我修改代碼的能力取決於執行環境。
隨着MARS這個選項可以啓用。 該代碼假定數據存儲器的小端格式(沒有代碼存儲器的假設)。
什麼你的教授可能想是這樣的:
- 你認識
la
是由ori
和lui
,讓你正確計算指令要複製四僞指令。
- 您在程序流程中使用
nop
爲四條指令保留空間。
- 您認識到編輯操作數的指令格式。
複製過程很簡單。您可以通過切割器使用標籤來獲得彙編程序的幫助:只需在要複製的代碼之後放置一個標籤(如果沒有,就在之前),然後複製這兩者之間的所有數據。
由於我們知道要複製的代碼的長度並且它很小,所以我們可以手工複製。
爲了修改複製的代碼,我們需要看看它是如何喜歡看機器代碼
addiu $v0, 0, 4 #24020004
lui $at, HHHH #3c01HHHH
ori $a0, $at, LLLL #3424LLLL
syscall #0000000c
正如你可以看到你有更換第二和第三指令的下HW。
要使用的值是地址版本2。
該地址的上限和下限硬件可以通過基本的位操作獲得。
您還必須添加代碼以很好地終止程序。
這裏有一個故意簡化工作示例爲MARS(在設置中激活自修改代碼)。
.data
version1: .asciiz "This is version1"
version2: .asciiz "this is version2"
.text
main:
li $v0, 4 #1 instruction addiu $v0, $0, 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, $0, $0
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, $0, 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, $0, $v0 #t2 = Destination start
ori $t4, $0, 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, $0, $0 #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__: