当前位置:   article > 正文

mips汇编基础与解析_汇编jarl

汇编jarl

如果只是需要看懂MIPS汇编程序的逻辑和内容其实相对简单,只需要对基本的MIPS指令了解、熟悉即可,部分少见的指令临时查看手册或者搜索即可,以下内容为基础的MIPS指令,完成以下内容的学习将可以读懂大部分简单的MIPS程序。

数据类型

  • 所有MIPS指令都是32位长的
  • 各单位:1字节=8位,半字长=2个字节,1字长=4个字节
  • 一个字符空间=1个字节
  • 一个整型=一个字长=4个字节
  • 单个字符用单引号,例如:‘b’
  • 字符串用双引号,例如:“A string”

寄存器

  • MIPS下一共有32个通用寄存器
  • 在汇编中,寄存器标志由$符开头
  • 寄存器表示可以有两种方式
  • 直接使用该寄存器对应的编号,例如:从$0到$31
    使用对应的寄存器名称,例如:$t1, $sp(详细含义,下文有表格
  • 对于乘法和除法分别有对应的两个寄存器$lo, $hi
    对于以上二者,不存在直接寻址;必须要通过mfhi(“move from hi”)以及mflo(“move from lo”)分别来进行访问对应的内容
  • 栈的走向是从高地址到低地址
Register Number寄存器编号Alternative Name寄存器名Description寄存器用途
0zerothe value 0永远返回零
1$at(assembler temporary) reserved by the assembler汇编保留寄存器(不可做其他用途)
2-3$v0 - ​$v1(values) from expression evaluation and function resultsValue简写)存储表达式或者是函数的返回值
4-7$a0 - ​$a3(arguments) First four parameters for subroutine. Not preserved across procedure callsArgument简写)存储子程序的前4个参数,在子程序调用过程中释放
8-15$t0 - ​$t7(temporaries) Caller saved if needed. Subroutines can use w/out saving. Not preserved across procedure callsTemp简写)临时变量,同上调用时不保存
16-23$s0 - ​$s7(saved values) - Callee saved. A subroutine using one of these must save original and restore it before exiting. Preserved across procedure callsSaved or Static简写?)静态变量?调用时保存
24-25$t8 - ​$t9(temporaries) Caller saved if needed. Subroutines can use w/out saving. These are in addition to $t0 - $t7 above. Not preserved across procedure calls.Temp简写)算是前面$0$7的一个继续,属性同$t0$t7
26-27$k0 - ​$k1reserved for use by the interrupt/trap handler(breaK off简写?)中断函数返回值,不可做其他用途
28$gpglobal pointer. Points to the middle of the 64K block of memory in the static data segment.Global Pointer简写)指向64k(2^16)大小的静态数据块的中间地址(字面上好像就是这个意思,块的中间)*
29$spstack pointer *Points to last location on the stack.**(*Stack Pointer简写)栈指针,指向的是栈顶
30$s8/​$fpsaved value / frame pointer Preserved across procedure calls(Saved/Frame Pointer简写)帧指针
31$rareturn address返回地址,目测也是不可做其他用途

程序结构

  • 本质其实就只是数据声明+普通文本+程序编码(文件后缀为.s,或者.asm也行)
  • 数据声明在代码段之后(其实在其之前也没啥问题,也更符合高级程序设计的习惯)

数据声明

  • 数据段以 .data为开始标志
  • 声明变量后,即在主存中分配空间。

代码

  • 代码段以 .text为开始标志
  • 其实就是各项指令操作
  • 程序入口为**main:**标志(这个都一样啦)
  • 程序结束标志(详见下文)

注释

  • 同C系语言

      • MIPS程序的基本模板如下:

        # Comment giving name of program and description of function
        # 说明下程序的目的和作用(其实和高级语言都差不多了)
        # Template.s
        #Bare-bones outline of MIPS assembly language program
        
                   .data       # variable declarations follow this line                    # 数据变量声明
                               # ...
        														
                   .text       # instructions follow this line	
        		       		  # 代码段部分															
        main:                  # indicates start of code (first instruction to execute)               # 主程序
                               # ...
        									
        
        • 1
        • 2
        • 3
        • 4
        • 5
        • 6
        • 7
        • 8
        • 9
        • 10
        • 11
        • 12
        • 13

数据声明

format for declarations:

声明的格式:

name: storage_type value(s)
变量名:(冒号别少了) 数据类型 变量值

    • create storage for variable of specified type with given name and specified value
    • value(s) usually gives initial value(s); for storage type .space, gives number of spaces to be allocated
    • 通常给变量赋一个初始值;对于**.space**,需要指明需要多少大小空间(bytes)

Note: labels always followed by colon ( : )

example

var1: .word 3
#create a single integer variable with initial value 3
#声明一个 word 类型的变量 var1, 同时给其赋值为 3

array1: .byte ‘a’,‘b’
#create a 2-element character array with elements initialized
#to a and b                  
#声明一个存储2个字符的数组 array1,并赋值 ‘a’, ‘b’

array2: .space 40
#allocate 40 consecutive bytes, with storage uninitialized
#could be used as a 40-element character array, or a
#10-element integer array; a comment should indicate which!
#为变量 array2 分配 40字节(bytes)未使用的连续空间,当然,对于这个变量到底要存放什么类型的值, 最好事先声明注释下!

加载/保存(也许这里写成读取/写入 可能更易理解一点) 指令集

  • 如果要访问内存,不好意思,你只能用 load 或者 store 指令
  • 其他的只能都一律是寄存器操作

load:

lw register_destination, RAM_source
#copy word (4 bytes) at source RAM location to destination register.

从内存中 复制 RAM_source 的内容到 对应的寄存器中

(1lw中的’w’意为’word’,即该数据大小为4个字节)

lb register_destination, RAM_source
#copy byte at source RAM location to low-order byte of destination register,
# and sign-e.g.tend to higher-order bytes

同上, lb 意为 load byte

store word:

sw register_source, RAM_destination

#store word in source register into RAM destination

#将指定寄存器中的数据 写入 到指定的内存中

sb register_source, RAM_destination

#store byte (low-order) in source register into RAM destination

load immediate:

li register_destination, value

#load immediate value into destination register

顾名思义,这里的 li 意为 load immediate

example:
	.data
var1:	.word	23		
# declare storage for var1; initial value is 23
# 先声明一个 word 型的变量 var1 = 3;
	.text
__start:
	lw	$t0, var1	
# load contents of RAM location into register $t0:  $t0 = var1
# 令寄存器 $t0 = var1 = 3;

	li	$t1, 5		
# $t1 = 5   ("load immediate")     
# 令寄存器 $t1 = 5;


	sw	$t1, var1	
# store contents of register $t1 into RAM:  var1 = $t1     
# 将var1的值修改为$t1中的值: var1 = $t1 = 5;
	done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

立即与间接寻址

load address:

直接给地址

	la	$t0, var1
  • 1
  • copy RAM address of var1 (presumably a label defined in the program) into register $t0

indirect addressing:

地址是寄存器的内容(可以理解为指针)

	lw	$t2, ($t0)
  • 1
  • load word at RAM address contained in $t0 into $t2
	sw	$t2, ($t0)
  • 1
  • store word in register $t2 into RAM at address contained in ​$t0

based or indexed addressing:

+偏移量

	lw	$t2, 4($t0)
  • 1
  • load word at RAM address ($t0+4) into register $t2
  • “4” gives offset from address in register $t0
	sw	$t2, -12($t0)
  • 1
  • store word in register t 2 i n t o R A M a t a d d r e s s ( t2 into RAM at address ( t2intoRAMataddress(t0 - 12)
  • negative offsets are fine

Note: based addressing is especially useful for:

不必多说,要用到偏移量的寻址,基本上使用最多的场景无非两种:数组,栈。

  • arrays; access elements as offset from base address
  • stacks; easy to access elements at offset from stack pointer or frame pointer
example:栗子:

		.data
array1:		.space	12		
#  declare 12 bytes of storage to hold array of 3 integers
#  定义一个 12字节 长度的数组 array1, 容纳 3个整型


		.text
__start:	la	$t0, array1	 #  load base address of array into register $t0 
                              #  让 $t0 = 数组首地址

		   li	$t1, 5		#  $t1 = 5   ("load immediate")
		   sw $t1, ($t0)	 #  first array element set to 5; indirect                                # addressing 对于数组第一个元素赋值 array[0] = $1 = 5
		   li $t1, 13		 #   $t1 = 13
		   sw $t1, 4($t0)	 #  second array element set to 13           							# 对于 数组第二个元素赋值 array[1] = $1 = 13                  # (该数组中每个元素地址相距长度就是自身数据类型长度,
		   				    #即4字节, 所以对于array+4就是array[1])
		   li $t1, -7		 #   $t1 = -7
		   sw $t1, 8($t0)	 #  third array element set to -7        
		   					# 同上, array+8 = (address[array[0])+4)+ 4 = 
		   					# address(array[1]) + 4 = address(array[2])
		   done
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

算术指令集

  • 最多3个操作数
  • 再说一遍,在这里,操作数只能是寄存器,绝对不允许出现地址
  • 所有指令统一是32位 = 4 * 8 bit = 4bytes = 1 word

add $t0,$t1,$t2

#​ $t0 = ​$t1 + $t2;

# add as signed (2’s complement) integers

		sub		$t2,$t3,$t4	#  $t2 = $t3 Ð $t4
		addi	$t2,$t3, 5	#  $t2 = $t3 + 5;   "add immediate" (no sub immediate)
		addu	$t1,$t6,$t7	#  $t1 = $t6 + $t7;   add as unsigned integers
		subu	$t1,$t6,$t7	#  $t1 = $t6 + $t7;   subtract as unsigned integers

		mult	$t3,$t4		
				#  multiply 32-bit quantities in $t3 and $t4, and store 64-bit
				#  result in special registers Lo and Hi: (Hi,Lo)= $t3*$t4
				#  运算结果存储在hi,lo(hi高位数据, lo地位数据)
		div	$t5,$t6	     #  Lo = $t5 / $t6   (integer quotient)
					    #  Hi = $t5 mod $t6  (remainder)         
					    #  商数存放在 lo, 余数存放在 hi
		mfhi	$t0		#  move quantity in special register Hi to $t0:   $t0 = Hi
        				#  不能直接获取hi或lo中的值,需要mfhi, mflo指令传值给寄存器
		mflo	$t1		#  move quantity in special register Lo to $t1:   $t1 = Lo
					    #  used to get at result of product or quotient
		move	$t2,$t3	 #  $t2 = $t3
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

常见指令

jarl		使用寄存器的跳转指令,并且带有链接功能,指令的跳转地址在寄存器中,跳转发生时指令的放回地址放在R31这个寄存器中	
BENZ R1,NAME		R1不等于0,程序跳转以NAME为偏移地址,否则,执行下一条指令	
BEQZ R1,NAME		R1=0,程序跳转到以NAME为偏移地址,否则,执行下一条指令	
  • 1
  • 2
  • 3

前面框架部分转载修改优秀的参考文章:https://www.cnblogs.com/thoupin/p/4018455.html

https://blog.csdn.net/qq_41191281/article/details/85933985#1.%E6%8C%87%E4%BB%A4%E6%A0%BC%E5%BC%8F

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/272016
推荐阅读
相关标签
  

闽ICP备14008679号