第一章 汇编语言和汇编指令

  • Post author:
  • Post category:其他



【用最少的指令来实现功能】

自用

文章基于《计算机体系结构新讲》(中国地质大学出版社)


目录


一、汇编指令


(1)MIPS汇编指令示例解析


(2)MIPS指令集


二、汇编指令中的操作数


(1)寄存器


(2)立即数


(3)内存


三、MIPS程序控制指令


【if】


【while】


【for】


【switch】


四、函数调用


(一)跳转


(二)嵌套


(三)栈


五、逻辑运算



一、汇编指令

什么是汇编语言?

汇编语言(Assembly Language)是任何一种用于

电子计算机



微处理器



微控制器

或其他可编程器件的低级语言,亦称为符号语言。其中,本系列笔记将以MIPS汇编语言为例来进行解析。

(1)MIPS汇编指令示例解析

a=b+c   //C风格
add a b c  //MIPS汇编
指令代码 操作数1 操作数2 操作数3(MIPS汇编指令格式)

(2)MIPS指令集

521088dd12a24dc9a93ce503a08987cd.jpeg

935aba218b0a45688b01aacd6696febf.jpeg


二、汇编指令中的操作数

(1)寄存器

MIPS处理器的汇编语言中,算数运算指令的操作数只能是寄存器。(设计简单)

规定指令由四个部分构成(规则性、统一性)

在MIPS计算机中设计了32个32位的通用寄存器来作为汇编指令的操作数。

寄存器约定

309ba5ed6a994b13a48392f117a41e24.png

*注:

$0:恒为常数0。

$s0~&s7:若使用,必须恢复。

$sp:若使用,必须恢复。

$ra:在嵌套调用时,调用函数需将它保存到栈上。

(2)立即数

类似于C语言里面的常数

为何叫立即数?

该数可以在代码中立即获得,不需要先存放到寄存器,等到用的时候再去取。

(3)内存

内存与寄存器的数据交换指令

将内存看作一个一维数组,从而可以使用一个指向内存的指针来简单访问内存

从内存中装入(load)数据到寄存器
lw $1 imm($2)s
# $1是用来存储从内存中获取的数据的寄存器
# $2是用来存储访问内存的指针,称为基址
# imm是偏移量(offset),必须是常数(有符号)
# $1=memory[$2 + offest]

将寄存器的值存储(store)到内存中
sw $1 imm($2)
# $1是用来保存即将要存入内存的数据的寄存器
# $2是用来存储访问内存的指针,称为基址
# imm是偏移量(offset),必须是常数(有符号)
# memory[$2 + offest]=$1

word 字 32位
1 word = 4 Byte = 32 Bit

上述memory[i]表示的是内存中的第i个字(word),而基址的单位是字节(Byte),offest的单位也是字节(Byte),但是不管是lw指令还是sw指令,每次但是传递一个字的内容,所以此时就要求基址和offest
的和为4的倍数(实现字对齐)。

以上全部是MIPS的字数据传送,下面将介绍MIPS中的字节数据传送:
字节传送指令:lb,sb
形如 lb $1 imm($2) 的指令,是将内存中第(imm+$2)字节的内容传递到$1寄存器中,但是第(imm+$2)字节的内容只有8位,但是寄存器有32位,此时MIPS就会采用符号拓展的方式(lbu指令是采用零拓展的方式)来填充高24位,从而与原有的8位数组成一个32位的数值保存到寄存器中。(sb指令就是将寄存器中一字节的数据传送到内存中)


三、MIPS程序控制指令

条件分支指令:
beq $1 $2 loop  #若$1==$2,则跳转到loop,否则进行下一条指令
ben $1 $2 loop  #若$1!=$2,则跳转到loop,否则进行下一条指令
无条件分支指令:
j loop  #直接跳转到loop(类似与C语言中的goto)

结合条件分支指令实现C语言中if,while,for,switch等等到汇编语言的转换:


【if】

【C语言】
int a;
if(a==0)
    clause 1;
else if(a<0)
    clause 2;
else
    clause 3;

【MIPS汇编】
假设$t0中存放的是a
    beq $t0 $0 loop1    # $t0==$0 -> jump to loop1
    slt $t1 $0 $t0      # $0<$t0 -> $t1=1 // $0>$t0 -> $t1=0
    beq $t1 $0 loop2    # $t1==$0 -> jump to loop2
loop3:
    clause 3
    j exit
loop1:
    clause 1
    j exit 
loop2:
    clause 2
exit:


【while】

(1)do…while

【C语言】
do{
    clause
}while(a>=100)

【MIPS汇编】
假设a存放在$t0中 
    li $t1 100         #int num=100 -> $t1
loop:
    clause
    slt $t2 $t0 $t1    # $t0<$t1 -> $t2=1 // $t0>=$t1 -> $t2=0
    beq $t2 $0 loop    # $t2==0 -> jump to loop
exit: 

(2)while…

【C语言】
while(a>=100)
{
    clause;
}

【MIPS汇编】
假设a存放在$t0中 
    li $t1 100         #int num=100 -> $t1
    slt $t2 $t0 $t1    # $t0<$t1 -> $t2=1 // $t0>=$t1 -> $t2=0
    li $t3 1           # $t3=1
    beq $t2 $t3 exit   # $t2==$t3 -> jump to exit
loop:
    clause
    slt $t2 $t0 $t1    # $t0<$t1 -> $t2=1 // $t0>=$t1 -> $t2=0
    beq $t2 $0 loop    # $t2==0 -> jump to loop
exit:

(3)课内上机do…while实例

题目:将下面C++代码翻译成对应的MIPS汇编语言

void main( )

{


int i, sum(0);

cin >> i;

do  {


sum = sum + i * 2;

i++;

} while ( i<= 5);

cout << “sum=” << sum << endl;

}

答案:

.data 
    I:.asciiz "please enter the value of I:"
    result:.asciiz "sum="
.text
    #print I
    li $v0 4
    la $a0 I
    syscall
    
    #Enter I
    li $v0 5
    syscall
    
    #store the I to $to
    move $t0 $v0
    
    li $s0 0 #int sub=0
    li $s1 5
    Loop: add $t1 $t0 $t0
          add $s0 $s0 $t1
          addi $t0 $t0 1
          slt $t2 $s1 $t0  #if $t0>5 $s1=1; if $t0<=5 $s1=0
          beq $t2 $0 Loop
    Exit:
    
    #print result
    li $v0 4
    la $a0 result
    syscall
    
    #print sub
    li $v0 1
    move $a0 $s0
    syscall


【for】

【C语言】
for(int i=0;i<100;i++)
{
    clause;
}

【MIPS汇编】    
    li $t0 100         # $t0=100
    add $t1 $0 $0      # int i=0 -> $t1
loop:
    clause
    addi $t1 $t1 1     # i++
    slt $t2 $t1 $t0    # $t1<$t0 -> $t2=1 // $t1>=$t0 -> $t2=0
    li $t3 1           # $t3=1
    beq $t2 $3 loop    # $t2==0 -> jump to loop
exit:


【switch】

【C语言】
switch(k)
{
case 0:
    clause 0;
    break;
case 1:
    clause 1;
    break;
case 2:
    clause 2;
    break;
case 3:
    clause 3;
    break;
default:
    clause;
}

【MIPS汇编】
假设k存放在$t0中
    bne $t0 $0 loop1    # k!=0 -> jump to loop1
loop0:
    clause 0
    j exit
loop1:
    addi $t1 $t0 -1     # $t1=k-1
    bne $t1 $0 loop2    # k!=1 -> jump to loop2
    clause 1
    j exit
loop2:
    addi $t1 $t0 -2     # $t1=k-2
    bne $t1 $0 loop3    # k!=2 -> jump to loop3
    clause 2
    j exit
loop3:
    addi $t1 $t0 -3     # $t1=k-3
    bne $t1 $0 loop4    # k!=3 -> jump to loop4
    clause 3
    j exit
loop4:
    clause
exit:


四、函数调用

(一)跳转

课内上机实例

题目 :将下面C++语句翻译成对应的汇编语言

int Test(int a, int b)

{


int c = 0;

if (a >= b)

c = 4 * a + b;

else

c = 8 * a – b;

return c;

}

void main()

{


int x = 5, y = 6;

cout << Test(x, y) << endl;

cout << Test(10, 20) << endl;

}

答案:

.data
    first:.asciiz"Test(x, y) = "
    second:.asciiz"\nTest(10, 20) = "
.text
main: 
    li $t1 5   
    li $t2 6   
    add $a1 $t1 $0   
    add $a2 $t2 $0   
    jal Test   
      
    #print first and result
    li $v0 4
    la $a0 first        
    syscall
    li $v0 1
    move $a0 $t0
    syscall
      
    li $t1 10 
    li $t2 20  
    add $a1 $t1 $0   
    add $a2 $t2 $0 
    jal Test   
      
    #print second and result
    li $v0 4
    la $a0 second      
    syscall
    li $v0 1
    move $a0 $t0
    syscall
      
    #finish
    li $v0 10
    syscall 

Test: 
    add $t0 $t0 $0
    slt $t3 $a2 $a1 
    beq $t3 $0 else  
    sll $t0 $t1 2
    add $t0 $t0 $t2
else:
    sll $t0 $t1 3
    sub $t0 $t0 $t2
    jr $ra 

(二)嵌套

实例

【C语言】
main()
{
    sumSquare(a,b);
}
int sumSquare(int x,int y)
{
    return mult(x,x)+y;
}
int mult(int x,int y)
{
    return x*y;
}

【MIPS汇编】
/* a,b : $s0,$s1 */
1000        add $a0 $s0 $0     #x=a
1004        add $a1 $s1 $0     #y=b
1008        addi $ra $0 1016   #$ra=1016
1012        j sumSquare
...                            #主函数
2000   sumSquare:
2004        add $t9 $ra $0     #$t9=1016
2008        addi $ra $0 2024   #$ra=2024
2012        add $t8 $a1 $a0    #$t8=$a1
2016        add $a1 $a0 $0     #$a1=$a0
2020        j mult
2024        add $a1 $t8 $0     #$a1=$t8=y(b)
2028        add $v0 $v0 $a1    #$v0= mult(x,y)+y
2032        add $ra $t9 $0     #$ra=$t9=1016
2036        jr $ra             #jump to 1016
2040    mult:
2044        mul $v0 $a0 $a1    #$v0=x*y
2048        jr $ra             #jump to 2024

(三)栈

对于更多层的嵌套,需要更多的寄存器,所以肯定会出现寄存器不够用的情况,同时在传参数的过程中,只有四个参数寄存器($a0~$a3,详见寄存器约定),也会出现不够用的情况,那么此时就要使用栈(stack)来保存这些数据。




是一种先进后出的数据结构,在MIPS汇编语言中需要程序员自己维护栈。(自开自关)

实例:

前面(二)中实例中的sumSquare函数可以结合栈的使用编译成下面的汇编语言
sumSquare:
    addi $sp $sp -8    #申请栈空间
    sw $ra 4($sp)      #保存主调函数的返回地址(即上面的1016)[$t9]
    sw $a1 0($sp)      #保存y[$t8]
    add $a1 $a0 $0     #mult(x,x)将第二个参数复制成第一个
    jal mult           #跳转到mult,并且将下一条指令地址保存到$ra
    lw  $a1 0($sp)     #恢复y
    ad $v0 $v0 $a1     #mult()+y
    lw $ra 4($ap)      #取回主调函数的返回地址
    addi $sp $sp 8     #恢复栈
    jr $ra
mult:


*注:addi $sp $sp -n 中,n一定是4的倍数,且使用该栈是可以从0用到n-4(间隔为四)。

五、逻辑运算

常见的逻辑运算包括“与”运算和“或”运算,即and和or。

“与“运算(and)逻辑:当且仅当两个输入都为1时,结果才为1;否则为0。

”或“运算(or)逻辑:两个输入中只要有一个为1时,结果即为1;否则为0.

MIPS汇编语言中的三个移位指令:

(1)sll(逻辑左移):左移,空位补0。

(2)srl(逻辑右移):右移,空位补0.

(3)sra(算数右移):右移,空位进行符号拓展。

*注:左移可以用做乘2的幂次,右移可以用作除以2的幂次。



版权声明:本文为weixin_63479919原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。