MIPS汇编自学 #1

MIPS汇编自学 #1

MIPS本质上是3地址指令:源操作数1 或/和 源操作数2 (立即数、寄存器编号、内存地址)、目的操作数地址 (寄存器编号、内存地址);

内存地址的取决于操作数的存储的地方;

.data: 表示在其后的若干行存储data数据格式如下

       .data
       
          name1: .word 0x1,0x22...
       
          name2:...

.text: 表示在其后才是指令区;

          li $v0,XXX    (告诉机器你需要的打印类型,整数是1,字符是4)

first program

.data
    myMessege: .asciiz"Hello,World!\n"


.text
    li $v0,4         #在该寄存器中存放一个值
    la $a0,myMessage #load address
    syscall          #执行它

打印字符(与打印字符串类似)

.data
    myChar: .byte 'x'

.text
    li $v0,4         #存4
    la $a0,myChar    #load address
    syscall

打印整数

.data
    age: .word 5

.text
    li $v0,1         #存1
    lw  $a0,age       #load word
    syscall          #执行它

打印float

.data
     PI: .float 3.1415

.text
    li $v0,2         #存2
    lwcl  $f12,pI       #call the system the messege
    syscall          #执行它

打印double

.data
     PI: .double 3.1415926
     zeroDouble .double 0.05

.text
    ldc1 $f2,PI           #load double
    ldcl  $f0,zeroDouble  #load double
    li $v0,3              #存3
    add.d $f12,$f2,$f0    #$f12=$f2+$f0
    syscall          #执行它

addition

.data 
     Numa: .word 5
     Numb: .word 9
.text
     lw $t0,Numa($zero)
     lw $t1,Numb($zero)
     add $t2,$t1,$t0      #$t2=$t1+$t0
     li $v0,1
     add $a0,$zero,$t2   #将t2寄存器中的数据移到a0中,用来打印出来
     syscall

subtract(与加法类似)

.data 
     Numa: .word 5
     Numb: .word 9
.text
     lw $t0,Numa($zero)
     lw $t1,Numb($zero)
     sub $t2,$t1,$t0      #$t2=$t1-$t0
     li $v0,1            
     add $a0,$zero,$t2   #将t2寄存器中的数据移到a0中,用来打印出来,也可以用move $a0,$t2
     syscall

使用乘法

有三种方式:1.mul(3个寄存器),2.mult(两个寄存器),3.sil(逻辑运算)

.data
.text
     addi $s0,$zero,10   #直接存储在寄存器中而不是最开始在随机位置
     addi $s1,$zero,5
     mul $a0,$s0,$s1
     li $v0,1
     syscall
.data
.text
     addi $t0,$zero,10   #直接存储在寄存器中而不是最开始在随机位置
     addi $t1,$zero,5
     mult $t0,$t1        #乘积得到的结果存储在低位和高位中
     mflo $s0            #将低位的数据移动到$so寄存器中,move from low
                         #mfhi(move from high),移动高位数据
     li $v0,1            
     add $a0,$zero,$s0   #将$s0的存储数据放入$a0中
     syscall
.data
.text
     addi $s0,$zero,4
     sll  $t0,$s0,2     #左移两位,并将结果存储在t0寄存器中
     li $v0,1
     add $a0,$t0,$zero
     syscall

使用除法(有两种,和乘法相似)

  • 在第二种方法中,除法得到的商存储在low,余数存储在high
.data
     
.text
     addi $t0,$zero,10   #直接存储在寄存器中而不是最开始在随机位置
     addi $t1,$zero,5
     div $s0,$t0,$t1
     li $vo,1
     add $a0,$s0,$zer0
     syscall

方法(函数)的创建及引用

.data
     message:"xxxx" 
.text
     main:            #主程序标签
          jal PrintMessage        #引用函数



     li $v0,10        #告诉system程序完成
     syscall


     PrintMessage:    #方法(函数)名
          li $v0,4   
          la $a0,message
          syscall

          jr $ra      #函数return寄存器

函数传参

.data
.text
     main:            #主程序标签
          addi $a1,$zero,50
          addi,$a2,$zero,100
          jal addNum       #引用函数
          li $v0,1
          add $a0,$v1,0


     li $v0,10        #告诉system程序完成
     syscall


     addNum:    #方法(函数)名
          add $v1,$a1,$a2

          jr $ra      #函数return寄存器

存储寄存器,函数调用时不影响原来的内容

.data
     message: .asciiz "\n"
.text
     main:            #主程序标签
          addi $s0,$zero,50
          jal addNum
          li $v0,4
          la $a0,message
          syscall
          move $a0,$s0
          li $v0,1
          syscall
          
          
          

     li $v0,10        #告诉system程序完成
     syscall


     addNum:    #方法(函数)名
          addi $sp,$sp,-4
          sw   $s0,0($sp)
#调用堆栈
          addi $s0,$s0,50
          li $v0,1
          move $a0,$s0
          syscall
          lw $s0,0($sp)
          addi $sp,$sp,4
          
          jr $ra      #函数return寄存器

函数内部调用另一个函数

.data
     message: .asciiz "\n"
.text
     main:            #主程序标签
          addi $s0,$zero,50
          jal addNum
          li $v0,4
          la $a0,message
          syscall
          move $a0,$s0
          li $v0,1
          syscall
          
          
          

     li $v0,10        #告诉system程序完成
     syscall


     addNum:    #方法(函数)名
          addi $sp,$sp,-8
          sw   $s0,0($sp)
          sw   $ra,4($sp)
          
          addi $s0,$s0,50
          
          jal printValue
          
          lw   $s0,0($sp)
          lw   $ra,4($sp)
          addi $sp,$sp,8
          
          jr $ra      #函数return寄存器
     printValue:
          li $v0,1
          move $a0,$s0
          syscall
          jr $ra

得到用户的输入

  1. 整数:
.data
     message: .asciiz "enter your age\n"
     return: .asciiz "\nyour age is "
.text
     li $v0,4
     la $a0,message
     syscall
     
     li $v0,5               #告诉系统我们要写入一个整数,存储在$v0中
     syscall
     move $t0,$v0           #将$v0得到的输入转到$t0中
     
     li $v0,4
     la $a0,return 
     syscall
     li $v0,1
     move $a0,$t0
     syscall
  1. float:
.data
     message: .asciiz "enter your height\n"
     return: .asciiz "\nyour height is "
     zeroFloat: .float 0.0
.text
     lwc1 $f4,zeroFloat     #float没有zero寄存器
     
     li $v0,4
     la $a0,message
     syscall
     
     li $v0,6               #告诉系统我们要写入一个float,存储在$v0中
     syscall
     #add.s $f12,$f0,$f4     #float默认打印的寄存器是$f12
     mov.s  $f12,$f0         #移动float到$f12寄存器
     
     li $v0,4
     la $a0,return 
     syscall
     
     li $v0,2               #打印float
     syscall
  1. doubles:
.data
     message: .asciiz "enter your height\n"
     return: .asciiz "\nyour height is "
.text
     li $v0,4
     la $a0,message
     syscall
     
     li $v0,7               #告诉系统我们要写入一个double,存储在$v0中
     syscall
     
     li $v0,4
     la $a0,return 
     syscall
     
     li $v0,3               #打印double
     add.d $f12,$f0,$f2     #double有默认值0.0
     syscall
  1. TEXT:
.data
     message: .asciiz "Hello,"
     text: .space 20                        #允许输入多少字节(字符)
.text
     main:
          li $v0,8                     #告诉系统接下来输入字符串
          la $a0,text
          li $a1,20                   #多长
          syscall
          
          li $v0,4
          la $a0,message
          syscall
          
          li $v0,4
          la $a0,text
          syscall
          
          
     li,$v0,10
     syscall

分支结构(标签跳转)

  1. 判断是否相等:
.data
     message1: .asciiz "Equal\n"
     message2: .asciiz "Nothing\n"                       #允许输入多少字节(字符)
.text
     main:
          li $v0,5
          syscall
          move $t0,$v0
          li $v0,5
          syscall
          move $t1,$v0
          #addi $t0,5
          #addi $t1,20
          # compare+
          #b Equal                          #不需要条件直接转到标签上
          beq $t0,$t1,Equal                 #如果相等则跳到Equal标签
          bne $t0,$t1,NotEqual              #如果不相等则跳到NotEqual标签
          
     li,$v0,10
     syscall
         
     NotEqual:
          li $v0,4
          la $a0,message2
          syscall
     Equal:
          li $v0,4
          la $a0,message1
          syscall
  1. 判断两个数的大小:
.data
     message1: .asciiz "The number is less than the other\n"
.text
     main:
          li $v0,5
          syscall
          move $t0,$v0
          li $v0,5
          syscall
          move $t1,$v0
          slt $s0,$t0,$t1                  #如果$t0小于$t1,则让$s0为1,否则$s0为零
          bne $s0,$zero,Message            #判断是否等于零
          
     li,$v0,10
     syscall
         
     Message:
          li $v0,4
          la $a0,message1
          syscall

循环结构

.data
     message1: .asciiz "Loop ends\n"
     line:.asciiz "\n"
.text
     main:
          addi $t0,$zero,0             #i=0
          while:
               bgt $t0,10,exit         #i>y10时退出循环
               jal printNum
               addi $t0,$t0,1          #i++
               j while                 #loop
          exit:
               li $v0,4
               la $a0,message1
               syscall
     li $v0,10
     syscall
     printNum:
          li $v0,1
          add  $a0,$t0,$zero
          syscall
          li $v0,4
          la $a0,line
          syscall
          jr $ra
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
setjmp是一个C语言库函数,主要实现的功能是保存当前进程的执行现场状态,并返回一个标记值。在程序需要从当前函数中跳跃到前面的函数时,可以使用该标记值恢复执行现场状态,从而实现跳到指定位置(不受函数调用堆栈层次结构限制)。在MIPS汇编语言中,可以使用汇编指令来实现setjmp函数的功能,具体实现方法如下: 1. 定义一个全局变量,用于存储setjmp返回的标记值: .data jmp_buf: .space 16 # 定义一个16字节的缓冲区,用于存储标记值 2. 实现setjmp函数,使用mips汇编语言实现: .text .globl setjmp setjmp: sw $ra, 0($a0) # 将返回地址保存到标记缓冲区的第一个字中 sw $fp, 4($a0) # 将栈帧指针保存到标记缓冲区的第二个字中 move $v0, $a0 # 将标记缓冲区地址作为返回值 jr $ra # 返回到调用者处 3. 在程序中调用setjmp函数,获取标记值并保存: jal setjmp # 调用setjmp函数 sw $v0, jmp_buf # 将标记值保存到全局变量jmp_buf中 4. 在需要跳到指定位置时,恢复执行现场状态,并跳转到目标位置: lw $ra, 0(jmp_buf) # 从标记缓冲区中读取返回地址 lw $fp, 4(jmp_buf) # 从标记缓冲区中读取栈帧指针 j target_address # 跳转到目标位置 以上就是使用MIPS汇编语言实现setjmp函数的基本方法,通过使用汇编指令保存和恢复执行现场状态,实现了跳转无限制的功能。注意,由于MIPS架构的特点,需要保存的执行现场信息可能比x86架构要多一些,具体实现时需要根据实际情况进行修改。同时,使用setjmp函数可能会导致函数调用堆栈层次结构的混乱,从而增加程序调试的困难度,因此应在需要跳转无限制时再使用,尽量减少使用次数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值