MIPS程序要复制自己吗?

时间:2015-07-21 19:11:06

标签: memory assembly mips

如何创建一个mips程序,以便在main函数中打印出version1,然后将整个代码复制到内存中,最后执行复制的版本。复制的代码版本必须打印版本2。除了版本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?????)

1 个答案:

答案 0 :(得分:1)

自我修改代码的能力取决于执行环境 使用MARS可以启用此选项。 该代码假设数据存储器具有Little Endianness(不假设代码存储器)。

你的教授可能想要的是:

  1. 您认识到la是由orilui组成的伪指令,因此您可以正确地将要复制的指令计为4个。
  2. 您使用nop在程序流程中为四条指令预留空间。
  3. 您认识到编辑操作数的指令格式。
  4. 复制过程很简单。你可以通过切割器使用标签来获得汇编程序的帮助:只需在代码后面放一个标签进行复制(如果没有则复制之前),然后在这两者之间复制所有数据。
    由于我们知道要复制的代码的长度并且它很小,我们可以手动复制。

    为了修改复制的代码,我们需要看看它看起来像机器代码

    addiu $v0, 0, 4      #24020004
    lui $at, HHHH        #3c01HHHH
    ori $a0, $at, LLLL   #3424LLLL
    syscall              #0000000c
    

    如您所见,您已经替换了第2和第3指令的较低HW 要使用的值是 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)感兴趣,请对齐返回的指针,复制代码,修改代码并将调用添加到系统调用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__: