【问题标题】:MIPS program to replicate itself?MIPS程序自我复制?
【发布时间】:2015-07-21 19:11:05
【问题描述】:

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

【问题讨论】:

    标签: memory assembly mips


    【解决方案1】:

    自行修改代码的能力取决于执行环境。
    使用 MARS 可以启用此选项。 代码假设数据内存为小字节序(不假设代码内存)。

    你的教授可能想要的是这个:

    1. 您认识到la 是由orilui 组成的伪指令,因此您正确地将要复制的指令计为四。
    2. 您在程序流中使用 nop 为四条指令保留空间。
    3. 您了解编辑操作数的指令格式。

    复制过程很简单。您可以通过使用标签的切割器获得汇编程序的帮助:只需在要复制的代码之后(如果没有,则在之前)放一个标签,然后复制这两者之间的所有数据。
    由于我们知道要复制的代码长度,而且它很小,我们可以手动复制。

    为了修改复制的代码,我们需要看看它作为机器码的样子

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

    如您所见,您已经替换了第二条和第三条指令的下部硬件。
    要使用的值是 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
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-28
      • 1970-01-01
      • 2018-11-02
      • 1970-01-01
      相关资源
      最近更新 更多