MIPS汇编语言之常用指令介绍
「这是我参与11月更文挑战的第22天,活动详情查看:2021最后一次更文挑战」。
简介
咱们知道x86架构cpu用于PC端和工作站较多,ARM架构cpu常见于手机和单片机,那么MIPS架构的cpu主要在哪些设备可以找到它们的身影呢?
- 中国龙芯
- PS游戏机
学习环境搭建
- 安装JDK, 主要用于运行mips模拟器mars
- MARS模拟器:http://courses.missouristate.edu/KenVollmar/mars/download.htm
寄存器
在mips中通用寄存器用$开头表示,一共有32个
| 寄存器编号 | 寄存器名 | 寄存器用途 | | :----------: | :------------------------------------------------------------ :|: -----------------------------------------------------------:| | $0 | $zero | 永远返回0 | | $1 | $at | 保留寄存器 | | $2-$3 | $v0-$v1 | 一般用于存储表达式或者函数的返回值(value的简写) | | $4-$7 | $a0-$a3 | 参数寄存器(Argument简写) | | $8-$15 | $t0-$t7 | 一般用于存储临时变量(temp简写) | | $16-$23 | $s0-$s7 | 存放子函数调用过程需要被保留的数据(saved values) | | $24-$25 | $t8-$t9 | 属性同$t0-$t7 | | $26-$27 | $k0-$k1 | 一般存储中断函数返回值 | | $28 | $gp | GlobalPointer简写 | | $29 | $sp | 栈指针,指向栈顶(Stack Pointer简写) | | $30 | $s8/$fp | (Save / Frame Pointer)帧指针 | | $31 | $ra | 一般用于存储函数返回地址(return address简写) |
寄存器编号和别名一一对应,同一个寄存器可以有两种不同表示方法:$0或者$zero
- program counter (PC) 无法直接修改,通过跳转指令可以改动
- HI 和 LO :这两个寄存器特别用来保存乘法、除法、乘法累加的结果。
MIPS汇编中的分段处理
```assembly .data #数据段
.text #代码段 ```
传送指令
- 加载立即数指令
li
li
(load immediate) :用于将立即数传送给寄存器
assembly
li $t0,1 ;十六进制数据使用0x前缀表示
- 加载地址指令
la
la
(load address) :用于将地址传送至寄存器中, 多用于通过地址获取数据段中的地址
```assembly .data msg: .ascii "hello world"
.text la $a0,msg # 将字符串数据所在的地址赋值给$a0寄存器
```
- 寄存器数据传送指令
move
用于将一个寄存器中的数据传送至另一个寄存器当中
assembly
move $t0,$t1 # 将寄存器$t1中的数据传送至$t0
系统服务指令 syscall
在C语言中输出文本可以使用printf
函数,但是汇编中没有printf这么一说,如果想要输出文本,需要借助syscall
指令
如果想要输出一个数字1,那么syscall
指令从$a0寄存器中取出需要输出的数据
因此, 你在执行syscall
指令之前需要将数据提前放入$a0
之中:
assembly
li $a0,1
syscall
同时,还需要指定输出的数据类型,数据类型的指定保存在$v0寄存器中
```assembly
$v0=1, syscall--->print_int
$v0=4, syscall--->print_string
```
$v0
存入1,表示syscall
将$a0
中的数据当做数字输出
$v0
存入4,表示syscall
将$a0
中的数据当做数据的地址,然后输出对应的数据
syscall指令读写对照表
| Service | Code in $v0 | Arguments | Result |
| ------------------------------------------------------------ | ----------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| print integer | 1 | $a0 = integer to print | |
| print float | 2 | $f12 = float to print | |
| print double | 3 | $f12 = double to print | |
| print string | 4 | $a0 = address of null-terminated string to print | |
| read integer | 5 | | $v0 contains integer read |
| read float | 6 | | $f0 contains float read |
| read double | 7 | | $f0 contains double read |
| read string | 8 | $a0 = address of input buffer $a1 = maximum number of characters to read | See note below table |
| sbrk (allocate heap memory) | 9 | $a0 = number of bytes to allocate | $v0 contains address of allocated memory |
| exit (terminate execution) | 10 | | |
| print character | 11 | $a0 = character to print | See note below table |
| read character | 12 | | $v0 contains character read |
| open file | 13 | $a0 = address of null-terminated string containing filename $a1 = flags $a2 = mode | $v0 contains file descriptor (negative if error). See note below table |
| read from file | 14 | $a0 = file descriptor $a1 = address of input buffer $a2 = maximum number of characters to read | $v0 contains number of characters read (0 if end-of-file, negative if error). See note below table |
| write to file | 15 | $a0 = file descriptor $a1 = address of output buffer $a2 = number of characters to write | $v0 contains number of characters written (negative if error). See note below table |
| close file | 16 | $a0 = file descriptor | |
| exit2 (terminate with value) | 17 | $a0 = termination result | See note below table |
| Services 1 through 17 are compatible with the SPIM simulator, other than Open File (13) as described in the Notes below the table. Services 30 and higher are exclusive to MARS. | | | |
| time (system time) | 30 | | $a0 = low order 32 bits of system time $a1 = high order 32 bits of system time. See note below table |
| MIDI out | 31 | $a0 = pitch (0-127) $a1 = duration in milliseconds $a2 = instrument (0-127) $a3 = volume (0-127) | Generate tone and return immediately. See note below table |
| sleep | 32 | $a0 = the length of time to sleep in milliseconds. | Causes the MARS Java thread to sleep for (at least) the specified number of milliseconds. This timing will not be precise, as the Java implementation will add some overhead. |
| MIDI out synchronous | 33 | $a0 = pitch (0-127) $a1 = duration in milliseconds $a2 = instrument (0-127) $a3 = volume (0-127) | Generate tone and return upon tone completion. See note below table |
| print integer in hexadecimal | 34 | $a0 = integer to print | Displayed value is 8 hexadecimal digits, left-padding with zeroes if necessary. |
| print integer in binary | 35 | $a0 = integer to print | Displayed value is 32 bits, left-padding with zeroes if necessary. |
| print integer as unsigned | 36 | $a0 = integer to print | Displayed as unsigned decimal value. |
| (not used) | 37-39 | | |
| set seed | 40 | $a0 = i.d. of pseudorandom number generator (any int). $a1 = seed for corresponding pseudorandom number generator. | No values are returned. Sets the seed of the corresponding underlying Java pseudorandom number generator (java.util.Random
). See note below table |
| random int | 41 | $a0 = i.d. of pseudorandom number generator (any int). | $a0 contains the next pseudorandom, uniformly distributed int value from this random number generator's sequence. See note below table |
| random int range | 42 | $a0 = i.d. of pseudorandom number generator (any int). $a1 = upper bound of range of returned values. | $a0 contains pseudorandom, uniformly distributed int value in the range 0 = [int] [upper bound], drawn from this random number generator's sequence. See note below table |
| random float | 43 | $a0 = i.d. of pseudorandom number generator (any int). | $f0 contains the next pseudorandom, uniformly distributed float value in the range 0.0 = f 1.0 from this random number generator's sequence. See note below table |
| random double | 44 | $a0 = i.d. of pseudorandom number generator (any int). | $f0 contains the next pseudorandom, uniformly distributed double value in the range 0.0 = f 1.0 from this random number generator's sequence. See note below table |
| (not used) | 45-49 | | |
| ConfirmDialog | 50 | $a0 = address of null-terminated string that is the message to user | $a0 contains value of user-chosen option 0: Yes 1: No 2: Cancel |
| InputDialogInt | 51 | $a0 = address of null-terminated string that is the message to user | $a0 contains int read $a1 contains status value 0: OK status -1: input data cannot be correctly parsed -2: Cancel was chosen -3: OK was chosen but no data had been input into field |
| InputDialogFloat | 52 | $a0 = address of null-terminated string that is the message to user | $f0 contains float read $a1 contains status value 0: OK status -1: input data cannot be correctly parsed -2: Cancel was chosen -3: OK was chosen but no data had been input into field |
| InputDialogDouble | 53 | $a0 = address of null-terminated string that is the message to user | $f0 contains double read $a1 contains status value 0: OK status -1: input data cannot be correctly parsed -2: Cancel was chosen -3: OK was chosen but no data had been input into field |
| InputDialogString | 54 | $a0 = address of null-terminated string that is the message to user $a1 = address of input buffer $a2 = maximum number of characters to read | See Service 8 note below table $a1 contains status value 0: OK status. Buffer contains the input string. -2: Cancel was chosen. No change to buffer. -3: OK was chosen but no data had been input into field. No change to buffer. -4: length of the input string exceeded the specified maximum. Buffer contains the maximum allowable input string plus a terminating null. |
| MessageDialog | 55 | $a0 = address of null-terminated string that is the message to user $a1 = the type of message to be displayed: 0: error message, indicated by Error icon 1: information message, indicated by Information icon 2: warning message, indicated by Warning icon 3: question message, indicated by Question icon other: plain message (no icon displayed) | N/A |
| MessageDialogInt | 56 | $a0 = address of null-terminated string that is an information-type message to user $a1 = int value to display in string form after the first string | N/A |
| MessageDialogFloat | 57 | $a0 = address of null-terminated string that is an information-type message to user $f12 = float value to display in string form after the first string | N/A |
| MessageDialogDouble | 58 | $a0 = address of null-terminated string that is an information-type message to user $f12 = double value to display in string form after the first string | N/A |
| MessageDialogString | 59 | $a0 = address of null-terminated string that is an information-type message to user $a1 = address of null-terminated string to display after the first string | N/A |
使用syscall指令输出helloworld示例:
```assembly .data
msg: .ascii "hello world\0" #类似于C语言中 char* msg="hello world"
.text la $a0,msg li $v0,4 syscall ```
Mips汇编指令汇总表
类别 | 指令名称 | 实例 | 含义 | 注释 | 英文注解 |
算 数 | 加法 | add $s1, $s2, $s3 | $s1 = $s2 + $s3 | 三个寄存器操作数 | addition 加法 |
减法 | sub $s1, $s2, $s3 | $s1 = $s2 - $s3 | 三个寄存器操作数 | subtraction 减法 | |
立即数加法 | addi $s1, $s2, 20 | $s1 = $s2 + 20 | 用于加常数数据 | add immediate 立即加法 | |
数 据 传 输 | 取字 | lw $s1, 20 ($s2) | $s1 = Memory[$s2 + 20] | 将一个字从内存中取到寄存器中 | load word 加载字 |
存字 | sw $s1, 20 ($s2) | Memory[$s2 + 20] = $s1 | 将一个字从寄存器中取到内存中 | store word 存储字 | |
取半字 | lh $s1, 20 ($s2) | $s1 = Memory[$s2 + 20] | 将半个字从内存中取到寄存器中 | load halfword 加载半字 | |
取无符号半字 | lhu $s1, 20 ($s2) | $s1 = Memory[$s2 + 20] | 将半个字从内存中取到寄存器中 | load halfword unsigned | |
存半字 | sh $s1, 20 ($s2) | Memory[$s2 + 20] = $s1 | 将半个字从寄存器中取到内存中 | stroe halfword 存储半字 | |
取字节 | lb $s1, 20 ($s2) | $s1 = Memory[$s2 + 20] | 将一字节从内存中取到寄存器中 | load byte | |
取无符号字节 | lbu $s1, 20 ($s2) | $s1 = Memory[$s2 + 20] | 将一字节从内存中取到寄存器中 | load byte unsigned | |
存字节 | sb $s1, 20 ($s2) | Memory[$s2 + 20] = $s1 | 将一字节从寄存器中取到内存中 | store byte | |
取链接字 | ll $s1, 20 ($s2) | $s1 = Memory[$s2 + 20] | 取字作为原子交换的前半部 | load linked | |
存条件字 | sc $s1, 20 ($s2) | Memory[$s2 + 20] = $s1; $s1 = 0 or 1 | 存字作为原子交换的后半部分 | store conditional | |
取立即数的高位 | lui $s1, 20 | $s1 = 20 * 216 | 取立即数并放到高16位 | load upper immediate | |
逻 辑 | 与 | and $s1, $s2, $s3 | $s1 = $s2 & $s3 | 三个寄存器操作数按位与 | and |
或 | or $s1, $s2, $s3 | $s1 = $s2 | $s3 | 三个寄存器操作数按位或 | or | |
或非 | nor $s1, $s2, $s3 | $s1 = ~ ($s2 | $s3) | 三个寄存器操作数按位或非 | not or | |
立即数与 | andi $s1, $s2, 20 | $s1 = $s2 & 20 | 和常数按位与 | and immediate | |
立即数或 | ori $s1, $s2, 20 | $s1 = $s2 | 20 | 和常数按位或 | or immediate | |
逻辑左移 | sll $s1, $s2, 10 | $s1 = $s2 << 20 | 根据常数左移相应位 | set left logical | |
逻辑右移 | srl $s1, $s2, 10 | $s1 = $s2 >> 20 | 根据常数右移相应位 | set right logical | |
条 件 分 支 | 相等时跳转 | beq $s1, $s2, 25 | if ($s1 == $s2) go to PC + 4 + 25 * 4 | 相等检测: 和PC相关的跳转 | branch on equal |
不相等时跳转 | bne $s1, $s2, 25 | if ($s1 != $s2) go to PC + 4 + 25 * 4 | 不相等检测: 和PC相关的跳转 | branch on not equal | |
小于时跳转 | slt $1, $s2, $3 | if ($s2 < $s3) $s1 = 1; else $s1 = 0 | 比较是否小于 | set less than | |
无符号数比较小时置位 | sltu $1, $s2, $3 | if ($s2 < $s3) $s1 = 1; else $s1 = 0 | 比较是否小于无符号数 | set less than unsigned | |
无符号数小于立即数时置位 | slti $1, $s2, 20 | if ($s2 < 20) $s1 = 1; else $s1 = 0 | 比较是否小于常数 | set less than immediate | |
无符号数比较小于无符号立即数时置位 | sltiu $1, $s2, 20 | if ($s2 < 20) $s1 = 1; else $s1 = 0 | 比较是否小于无符号常数 | set less than immediate unsigned | |
无 条 件 跳 转 | 跳转 | j 2500 | go to 2500 * 4 | 跳转到目标地址 | jump |
跳转至寄存器所指位置 | jr $ra | go to $ra | 用于switch语句,以及过程调用 | jump register | |
跳转并链接 | jal 2500 | $ra = PC + 4; go to 2500 * 4; | 用于过程调用(方法) 正常的执行流程执行完A自然要执行B指令,现在要跳转执行C方法,这时就把B地址存入寄存器中,执行完C后跳转到B | jump and link |
Mips内存结构图:
- Git如何删除某次commit
- Windows平台使用QEMU搭建ARM Linux开发环境
- 汇编语言之GNU ARM
- ARM32汇编语言之汇编和C语言交互
- MIPS汇编语言之常用指令介绍
- android设备上如何运行C语言原生程序
- x86汇编语言之内中断
- x86汇编语言之字符串和函数的定义以及变量的取值赋值
- smali语言之locals和registers的区别
- python中的base64加密解密
- 汇编语言之ARM64汇编
- 汇编语言之数据段和代码段以及栈段的理解
- Python进行DES 加密和解密 解决和java结果不一致的问题
- 汇编语言之代码分段
- 汇编语言之debug模式常用指令介绍
- android NDK编译涉及的cpu架构种类
- Android逆向开发之smali语言的学习
- apk逆向之so库的破解和调用
- android原生shell中端可使用的命令
- Windows环境下使用ndk-build指令编译c/c 生成so库