05 计算机指令:使用纸带编程

一、编译成汇编

test.c

// test.c
int main()
{
    int a = 1;
    int b = 2;
    a = a + b;
}

程序想要在 Linux 操作系统上运行,需要将整个程序翻译成一个汇编代码的程序,这个过程叫编译成汇编代码
对于汇编代码,可以再使用汇编器翻译成机器码。机器码由 0 和 1 组成的机器语言表示。一条条机器码就是一条条的计算机指令

使用 gcc 和 objdump 两个命令,打印出程序对应的汇编代码和机器码

gcc -g -c test.c
// -M:指定了指令集的类型为 intel
objdump -d -M intel -S test.o

命令执行结果

test.o:     文件格式 elf64-x86-64

Disassembly of section .text:

0000000000000000 <main>:
int main()
{
    0:	55                   	push   rbp
    1:	48 89 e5             	mov    rbp,rsp
    int a = 1;
    4:	c7 45 f8 01 00 00 00 	mov    DWORD PTR [rbp-0x8],0x1
    int b = 2;
    b:	c7 45 fc 02 00 00 00 	mov    DWORD PTR [rbp-0x4],0x2
    a = a + b;
    12:	8b 45 fc             	mov    eax,DWORD PTR [rbp-0x4]
    15:	01 45 f8             	add    DWORD PTR [rbp-0x8],eax
    18:	b8 00 00 00 00       	mov    eax,0x0
}
    1d:	5d                   	pop    rbp
    1e:	c3                   	ret
  • 8 行:push rbp,将 rbp 基址指针寄存器 push 入栈
  • 9 行:mov rbp,rsp,将 rsp 栈指针寄存器指向地址赋给 rbp 基址指针寄存器
  • 11 行:mov DWORD PTR [rbp-0x8],0x1
    DWORD 双字(四个字节)、PTR 即指针,pointer 的缩写
    [] 里的值对应一个地址值,地址指向一个双字型数据
    mov DWORD PTR [rbp-0x8],0x1 意思是将 16 进制的 1 赋值给基址指针寄存器偏移 8 位的位置
  • 13 行:mov DWORD PTR [rbp-0x4],0x2,同 11 行,意思是将 16 进制的 2 赋值给基址指针寄存器偏移 4 位的位置
  • 15 行:mov eax,DWORD PTR [rbp-0x4],将基址指针寄存器偏移 4 位的位置的指向赋给 eax 寄存器
  • 16 行:add DWORD PTR [rbp-0x8],eax,将 eax 和基址指针寄存器偏移 8 位的位置指向的值相加,结果赋给基址指针寄存器偏移 8 位的位置,即 eax(2)+ rbp-8(1)= 3,结果 3 赋给基址指针寄存器偏移 8 位的位置
  • 17 行:mov eax,0x0,将 eax 寄存器清零
  • 19 行:pop rbp,将 rbp 基址指针寄存器 pop 弹出
  • 20 行:ret,函数返回

补充:生成 Linux 汇编

Linux 和 Windows 生成的汇编参数的顺序是反的,Linux 是正序,Windows 是逆序
生成汇编

二、解析指令和机器码

  • 第一类:算术类指令
    加减乘除,在 CPU 层面,都会变成一条条算数指令
  • 第二类:数据传输类指令
    给变量赋值、在内存里读写数据
  • 第三类:逻辑类指令
    逻辑上的与或非
  • 第四类:条件分支类指令
    if-else 等
  • 第五类:无条件跳转指令
    在调用函数时,其实就是发起了一个无条件跳转指令

指令示例

2.1 MIPS 指令集

MIPS 指令集
操作码(Opcode):高 6 位,代表这条指令具体是什么样的指令
R 指令:一般用来做算数和逻辑操作,里面有读取和写入寄存器的地址,如果是逻辑位移,后面还有位移操作的偏移量,功能码是在前面的操作码不够的时候,扩展操作码来表示对应的具体指令
I 指令:通常用在数据传输、条件分支,以及运算时使用的是常数的时候,因为没有位移量和操作码,也没有了第三个寄存器(rd),而是把直接把这三部分合并成一个地址值或者一个常数
J 指令:是一个跳转指令,高 6 位之外的 26 位都是一个跳转后的地址

三、举个栗子

add $t0,$s1,$s2

这是一个加法算数指令,解释一下具体操作

add:表示这是一个加法操作,对应 MIPS 指令里的 opcode 是 0,5 位二进制:000000
rs:代表第一个寄存器,对应 s1 的地址是 17???,5 位二进制:10001
rt:代表第二个寄存器,对应 s2 的地址是 18???,二进制:10010
rd:代表目标的临时寄存器,对应 t0 的地址是 8???,二进制:01000
不是位移操作,位移量是 0,二进制:00000
功能码是 32???,二进制:100000
000000 10001 10010 01000 00000 100000 = 000000 0010 0011 0010 0100 0000 0010 0000 = 0 2 3 2 4 0 2 0 = 0x02324020

打在纸带上,就是这样
加法指令纸带打孔

加法指令执行的过程,以及 CPU 怎么和 ALU 算数逻辑单元串联起来,待续…

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值