2015-07-21 5 views
1

Как создать программу mips так, чтобы в основной функции она печатала версию1, а затем копировала весь код в память и окончательно выполняла скопированную версию. Скопированная версия кода должна печатать версию2. Вы не можете добавить ничего в раздел данных, отличный от версии version1 и version2.Программа MIPS для репликации?

Как скопировать весь код в память и выполнить его? Я никогда не делал ничего подобного раньше, поэтому я не знаю, с чего начать.

.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?????) 

ответ

1

Возможность самостоятельного изменения кода зависит от среды исполнения.
С MARS эта опция может быть включена. Код предполагает Маленькую Endianness для памяти данных (без предположений для памяти кода).

Что ваш профессор, вероятно, хочет это:

  1. , что вы признаете, что la является инструкцией псевдо сделано из ori и lui, так что вы правильно рассчитывать команду для копирования как четыре.
  2. Что вы резервируете место в программном потоке для четырех команд, используя nop.
  3. Что вы знаете формат инструкции для редактирования операндов.

Процесс копирования прост. Вы можете получить помощь ассемблера путем использования меток с помощью меток: просто поместите ярлык сразу после копирования кода (и прямо перед ним, если его нет), а затем скопируйте все данные между этими двумя.
Поскольку мы знаем длину кода для копирования, и он маленький, мы можем копировать вручную.

Для того, чтобы изменить скопированный код, нам нужно увидеть, как это выглядит, как любит машинный код

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__: 
Смежные вопросы