IBM早在1928年就推出了规格为190x84mm的打孔卡 Punched Card 用长方形孔提高存储密度 通常可以存储80列x12行数据 相当于120字节。后来做成了穿孔纸带。
打孔卡与穿孔纸带在很长一段时间内共存 是机械化存储技术时代的标志。
这种存储介质我们一直在使用。
“0” 表示光没有通过 “1”表示光通过了。为什么早期的计算机会采用打孔卡这样的存储设备 而不用像C或者Python这样的高级计算机语言编写呢 因为早期的计算机或者CPU没有理解这些高级语言的能力。但是 即便是2021年的今天 计算机也只能计算由“0”和“1”组成的二进制 即“机器码”或机器语言 Machine Language 只是计算机对人而言更友好了 它们会自动“翻译” 更准确都说是“编译” 不同的语言。计算机用二进制语言 人用高级计算机语言 例如 英语 。
CPU Central Processing Unit 从硬件工程师的角度看 是一个超大规模集成电路 Very Large Scale Integrated Circuit 简写VLSI 。但从软件工程师德角度看 CPU是一个执行各种计算机指令 Intruction 能听懂各种计算机语言 进行计算的设备。但是 不同的CPU能够听懂的计算机语言不太一样 专业术语叫做不同架构的CPU。主要有
1 以Intel、AMD公司为代表的X86架构的CPU 用的是复杂指令集 Complex Instruction Set Computer 简写CISC 主要用途为个人电脑 Personal Computer 简写PC 、服务器。
2 以Apple、ARM公司为代表的ARM架构的CPU 用的是精简指令集 Reduced Instruction Set Computer 简写RISC 主要用途为各种手机、苹果电脑。
3 以IBM公司为代表的PowerPC架构的CPU 用的也是简指令集 Reduced Instruction Set Computer 简写RISC 主要用途为中高端的嵌入式系统中。
可见PC机上编写的程序不能通过复制到手机上运行 就是因为不同架构的CPU支持的**计算机指令集 Instruction Set **是不同的。
计算机程序不可能只有一条指令 而是由成千上万的指令组成的。CPU 中不可能一直存放着所有指令 所以计算机程序平时是存储在存储器中的。这种程序指令存储在存储器里面的计算机 就叫作存储程序型计算机 Stored-program Computer 。
其实 早前还有一种非存储程序型计算机 就做“插线板计算机” Plugboard Computer
以一段C语言程序为例
// test.c int main() int a 1; int b 2; a a b;
如何让这个程序在Linux操作系统 or Windows操作系统 上运行起来呢
答 需要将C语言翻译成一个汇编语言 Assembly Language 简写ASM 这个过程称为编译 Compile 再由汇编器 Assembler 翻译为机器码。这些由“0”和“1”组成的机器码就是一条条计算机的指令。为了阅读方便 否则太长 用16进制来表示机器码。
在Linux操作系统上 使用gcc和objdump命令将汇编语言和机器码打印出来。
$ gcc -g -c test.c $ objdump -d -M intel -S test.o
一条C语言指令可以对应一条汇编语言指令 也可以对应多条 2条以上 含2条 汇编语言指令。汇编语言指令与机器码则是一一对应的。
test.o: file format 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 fc 01 00 00 00 mov DWORD PTR [rbp-0x4],0x1 int b 2; b: c7 45 f8 02 00 00 00 mov DWORD PTR [rbp-0x8],0x2 a a b; 12: 8b 45 f8 mov eax,DWORD PTR [rbp-0x8] 15: 01 45 fc add DWORD PTR [rbp-0x4],eax 18: 5d pop rbp 19: c3 ret
汇编语言是给“程序员看的机器码”。
问 在Windows操作系统上 是如何实现的呢
4. 汇编指令和机器指令的解析指令可以分为五大类
1 算术指令 加减乘除。
2 数据传输指令 给变量赋值 在内存里读写数据。
3 逻辑指令 与、或、非、异或。
4 条件分支指令 if…else… for while。
5)无条件跳转指令 函数 function 调用 方法 method 调用 goto。
不同的CPU的指令集是不同的 例如Intel的CPU的指令集有2000多条指令。这里选用最简单的MIPS指令集来学习。MIPS指令集是MIPS公司在二十世纪80年代设计的CPU指令集 现在已经开源了 可以点击MIPS官网和这里获得。国产龙芯2E微处理器是一款实现64位MIPSⅢ指令集的通用RISC处理器。
MPIS指令集是32位 bit 的指令。
1 高6位是操作码 Operational Code 即OP code 可以理解为具体的动词 CPU具体的操作指令/行为。剩余的26位有R、I、J三种格式。
2 R指令 用来做算术和逻辑操作 里面有读取和写入数据的寄存器的地址。如果是逻辑位移操作 后面还有位移操作的位移量。而最后的功能码 则是在前面的操作码不够的时候 扩展操作码表示对应的具体指令。
3 I指令 用在数据传输、条件分支 以及在运算的时候使用的并非变量而是常数的时候。这个时候 没有了位移量和操作码 也没有了第三个寄存器 而是把这三部分直接合并成了一个地址值或者一个常数。
4 J指令 跳转指令 高 6 位之外的 26 位都是一个跳转后的地址。
例如
add $t0,$s1,$s2 #将寄存器t0中的内容变为寄存器S1和寄存器S2中内容的和
1 操作码 汇编指令【add】 机器指令【opcode中的0】。
2 rs 第一个源操作数(OP num) 汇编指令【



