2015-07-21 156 views
1

如何創建一個mips程序,以便在主函數中打印出版本1,然後將整個代碼複製到內存中並最終執行復制的版本。代碼的複製版本必須打印版本2。除了版本1和版本2之外,您不能在數據部分添加任何內容。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這個選項可以啓用。 該代碼假定數據存儲器的小端格式(沒有代碼存儲器的假設)。

什麼你的教授可能想是這樣的:

  1. 你認識la是由orilui,讓你正確計算指令要複製四僞指令。
  2. 您在程序流程中使用nop爲四條指令保留空間。
  3. 您認識到編輯操作數的指令格式。

複製過程很簡單。您可以通過切割器使用標籤來獲得彙編程序的幫助:只需在要複製的代碼之後放置一個標籤(如果沒有,就在之前),然後複製這兩者之間的所有數據。
由於我們知道要複製的代碼的長度並且它很小,所以我們可以手工複製。

爲了修改複製的代碼,我們需要看看它是如何喜歡看機器代碼

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__: