Возможность самостоятельного изменения кода зависит от среды исполнения.
С MARS эта опция может быть включена. Код предполагает Маленькую Endianness для памяти данных (без предположений для памяти кода).
Что ваш профессор, вероятно, хочет это:
- , что вы признаете, что
la
является инструкцией псевдо сделано из ori
и lui
, так что вы правильно рассчитывать команду для копирования как четыре.
- Что вы резервируете место в программном потоке для четырех команд, используя
nop
.
- Что вы знаете формат инструкции для редактирования операндов.
Процесс копирования прост. Вы можете получить помощь ассемблера путем использования меток с помощью меток: просто поместите ярлык сразу после копирования кода (и прямо перед ним, если его нет), а затем скопируйте все данные между этими двумя.
Поскольку мы знаем длину кода для копирования, и он маленький, мы можем копировать вручную.
Для того, чтобы изменить скопированный код, нам нужно увидеть, как это выглядит, как любит машинный код
addiu $v0, 0, 4 #24020004
lui $at, HHHH #3c01HHHH
ori $a0, $at, LLLL #3424LLLL
syscall #0000000c
Как вы можете видеть, у вас есть заменить нижнюю HW 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, $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), совместите возвращенный указатель, скопируйте код, изменить его и добавить вызов SYSCALL 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__: