Memory MIPS程序是否复制自身?

Memory MIPS程序是否复制自身?,memory,assembly,mips,Memory,Assembly,Mips,我如何创建一个mips程序,使其在主函数中打印出版本1,然后将整个代码复制到内存中,最后执行复制的版本。复制的代码版本必须打印版本2。除了version1和version2之外,您不能在数据部分添加任何内容 如何将整个代码复制到内存中并执行它?我以前从未做过这样的事情,所以我不知道从哪里开始 .data version1: .asciiz "This is version1" version2: .asciiz "this is version2" main:

我如何创建一个mips程序,使其在主函数中打印出版本1,然后将整个代码复制到内存中,最后执行复制的版本。复制的代码版本必须打印版本2。除了version1和version2之外,您不能在数据部分添加任何内容

如何将整个代码复制到内存中并执行它?我以前从未做过这样的事情,所以我不知道从哪里开始

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

自我修改代码的能力取决于执行环境。
使用MARS可以启用此选项。 代码对数据内存的端性假设很小(对代码内存没有假设)

你的教授可能想要的是:

  • 确认
    la
    是由
    ori
    lui
    组成的伪指令,以便正确地将要复制的指令计为四条
  • 使用
    nop
    在程序流中为四条指令保留空间
  • 识别用于编辑操作数的指令格式
  • 复制过程很简单。您可以通过切割器使用标签得到汇编程序的帮助:只需在要复制的代码后面放置一个标签(如果没有标签,则放在前面),然后复制这两个代码之间的所有数据。
    因为我们知道要复制的代码的长度,而且很小,所以我们可以手工复制

    为了修改复制的代码,我们需要查看它作为机器代码的外观

    addiu $v0, 0, 4      #24020004
    lui $at, HHHH        #3c01HHHH
    ori $a0, $at, LLLL   #3424LLLL
    syscall              #0000000c
    
    如您所见,您已经替换了第二条和第三条指令的较低硬件。
    要使用的值是版本2的地址。
    该地址的上下硬件可以通过基本位操作获得

    您还必须添加代码以很好地终止程序

    这里有一个针对火星的有意简化的工作示例(激活设置中的自我修改代码)

    如果您对动态分配内存(使用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__:   
    
    .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__: