❤️💕💕汇编语言目前仍在发挥着不可替代的作用,在效率上无可替代,在底层,学习linux内核,计算机外围设备和驱动,都离不开汇编。Myblog:http://nsddd.top
[TOC]
排名 | 编程语言 | 流行度 | 对比上月 | 年度明星语言 |
---|---|---|---|---|
1 | Python | 12.74% | 1.18% | 2010, 2007, 2018, 2020, 2021 |
2 | C | 11.59% | 1.12% | 2017, 2008, 2019 |
3 | Java | 10.99% | 0.17% | 2015, 2005 |
4 | C++ | 8.83% | 0.55% | 2003 |
5 | C# | 6.39% | 0.43% | |
6 | Visual Basic | 5.86% | 0.46% | |
7 | JavaScript | 2.12% | 0.29% | 2014 |
8 | Assembly language | 1.92% | 0.43% | |
9 | SQL | 1.87% | 0.41% | |
10 | PHP | 1.52% | 0.12% | 2004 |
graph LR
编译指令(编译指令)
程序员((程序员))
编译器((编译器))
程序员 --> 编译指令 --> 编译器 --> 机器码
- 向上理解各种软件的原理,打下技术理论的基础。
- 向下为掌握计算机硬件系统的原理,打下实践应用基础。
- 机器语言是机器指令的集合
- 机器指令是一台计算机可以正确执行的命令
- 机器语言由一串二进制数表示,
01010001
C++和Java等高级语言与汇编语言的关系
- C++和Java等高级语言与汇编语言及机器语言之间是一对多的关系。
- 一条简单的C++语句会被扩展成多条汇编语言或者机器语言指令。
应用程序类型 | 高级语言 | 汇编语言 |
---|---|---|
用于单一平台的中到大型商业应用软件 | 正式的结构化支持使组织和维护大量代码很方便 | 最小的结构支持使程序员需要人工组织大量代码,使各种不同水平的程序员维护现存代码的难度极高 |
硬件驱动程序 | 语言本身未必提供直接访问硬件的能力,即使提供了也因为要经常使用大量的技巧而导致维护困难 | 硬件访问简单直接。当程序很短并且文档齐全时很容易维护 |
多种平台下的商业应用软件 | 可移植性好,在不同平台可以重新编译,需要改动的源代码很少 | 必须为每种平台重新编写程序,通常要使用不同的汇编语言,难于维护 |
需要直接访问硬件的嵌入式系统和计算机游戏 | 由于生成的执行代码过大,执行效率低 | 很理想,执行代码很小并且运行很快 |
使用一个函数$$print()$$打印一个
int
数的二进制信息
public static void print(int num) {
for(int i = 31; i >= 0; i--) {
System.out.println((num & (1 << i) == 0 ? "0" : "1"));
}
System.out.println();
}
package main
import (
"fmt"
)
func main() {
fmt.Println("hello word!")
var s int
Print := func(a int) int {
for i := 31; i >= 0; i-- {
//小端,高位低存
s = (a & (1 << i))
if s == 0 {
s = 0
} else {
s = 1
}
fmt.Printf("%d", s)
}
return 0
}
fmt.Println("Print地址为:", Print)
Print(3)
fmt.Println()
func(a int) {
for i := 31; i >= 0; i-- {
//小端,高位低存
s = (a & (1 << i))
if s == 0 {
s = 0
} else {
s = 1
}
fmt.Printf("%d", s)
}
}(2)
}
为什么需要if -- else 判断呢?
如果不进行判断的话,或许会有进位,产生的效果可能就是
00000000000000000000000000000021
- 对应高级操作系统的笔记
- 对应的Linux内核笔记
- 汇编语言的主体是汇编指令
- 汇编语言和机器语言的差别在于指令的表达方式上
- 汇编指令是机器指令便于记忆的书写格式
- 汇编指令是机器指令的逐记符
两种汇编格式: AT&T 汇编、Intel汇编
-
寄存器前缀%
AT&T: %eax Intel: eax
-
源/目的操作数顺序
AT&T: movl %eax,%ebx Intel: mov ebx,eax ;反过来的
-
常数/立即数的格式
AT&T: movl _value, %ebx #把变量_value的地址放入ebx movl $0xd00d, %ebx Intel: mov eax, offset _value mov ebx,0d00dh
-
操作数长度标识:b-1字节,w-2,L-4 ,q-8
AT&T: movw var_x, %bx Intel: mov bx, word ptr var_x
;变址寻址/基址变址寻址/相对基址变址寻址/带比例因子的**
AT&T: movl %ecx, var (,%eax)
movl %ecx, array(,%eax,4)
movl %ecx, array(%ebx,%eax,8)
Intel: mov [eax + var], ecx
mov [eax*4 + array] , ecx
mov [ebx + eax*8 + array], ecx
;C中嵌入式汇编
asm( “pushl %eax\n\t” asm{
"movl $0,%eax\n\t" pushl eax;
"popl %eax"); mov eax,0;
asm("movl %eax,%ebx"); }
asm("xorl %ebx,%edx"); asm mov ebx,eax;
asm("movl $0,_booga); asm xor edx,ebx;
asm mov _booga,0;
$ as hello.s -o hello.o $ ld hello.o -o hello $ ./hello
#hello.s
.data # 数据段声明
msg : .string "Hello, world! --------- AT&T ASM\r\n “ # 要输出的字符串
len = . – msg # 字串长度
.text # 代码段声明
.global _start # 指定入口函数
_start: # 在屏幕上显示一个字符串
movl $len, %edx # 参数三:字符串长度
movl $msg, %ecx # 参数二:要显示的字符串
movl $1, %ebx # 参数一:文件描述符(stdout)
movl $4, %eax # 系统调用号(sys_write)
int $0x80 # 调用内核功能
# ==================退出程序
movl $0,%ebx # 参数一:退出代码
movl $1,%eax # 系统调用号(sys_exit)
int $0x80 # 调用内核功能
; hello.asm
.data ; 数据段声明
msg db "Hello, world! --------- Intel ASM .", 0xA ; 要输出的字符串
len equ $ - msg ; 字串长度
.text ; 代码段声明
global _start ; 指定入口函数
_start: ; 在屏幕上显示一个字符串
mov edx, len ; 参数三:字符串长度
mov ecx, msg ; 参数二:要显示的字符串
mov ebx, 1 ; 参数一:文件描述符(stdout)
mov eax, 4 ; 系统调用号(sys_write)
int 80h ; 调用内核功能
; =================退出程序
mov ebx, 0 ; 参数一:退出代码
mov eax, 1 ; 系统调用号(sys_exit)
int 80h ; 调用内核功能
两种汇编格式: AT&T 汇编、Intel汇编
汇编器
GAS汇编器——AT&T汇编格式 Linux 的标准汇编器,GCC 的后台汇编工具
as -gstabs -o hello.o hello.s
-gstabs :生成的目标代码中包含符号表,便于调试。
NASM——intel汇编格式
提供很好的宏指令功能,支持的目标代码格式多,包括 bin、a.out、coff、elf、rdf 等。 采用人工编写的语法分析器,执行速度要比 GAS 快
nasm -f elf hello.asm
连接器
ld 将目标文件链接成可执行程序
为便于用 GDB 和 DDD 来进行源码级调试,要在生成的可执行程序中包含符号表,GAS 可以在生成的目标代码中包含符号表:
as --gstabs -o hello.o hello.s ld -o hello hello.o
注意:ld的-s选项会剥离所有符号,调试的时候不方便。
- 计算机中的数据和指令,存储在内存或者磁盘中
- 指令和数据都是二进制信息
在汇编语言中如何表示数据
- 10001001110111101B(二进制)
- 89D8H(十六进制):使用的最多,简单
- 104730O(八进制)
- 45288D(十进制,可以去掉D,默认)
存储器被划分为若干个存储单元,每个存储单元从0开始顺序编号。
计算机中连接CPU和其他芯片的导线,通常称之为总线
- 物理上:一条导向的集合
- 逻辑上划分为:
- 地址总线:
- 数据总线
- 控制总线
- CPU通过地址总线指定存储单元
- 地址总线宽度,决定了可寻址的存储单元大小
- N根地址总线(宽度为N),对应的寻址空间为2^N^
- CPU和其他器件之间的数据传输是通过数据总线进行的
- 数据总线宽度决定了CPU和外界的数据传输速度
- CPU通过控制总线对外部器件进行控制的
- 控制总线式一些不同控制线的集合
- 控制总线的宽度决定了CPU对外部器件的控制能力
CPU通过总线向接口卡发送命令,接口卡根据CPU的命令控制外设工作。如:网卡、显卡、声卡等。
RAM: 随机存储器,可读可写,但必须带电存储,断电后存储内容消失。 ROM: 只读存储器,只能读出,不能写入。断电后存储内容不消失。 BIOS: Basic Input/Output System,基本输入输出系统。BIOS是由主板和各类接口卡(如显卡、网卡等)厂商提供的软件系统。 可以通过它利用该硬件设备进行最基本的输入输出。在主板和某些接口卡上茶油存储相应BIOS的ROM。例如,主板上的ROM中存储着主板的BIOS(通常称为系统BIOS);显卡上的ROM存储着显卡的BIOS;如果网卡上装有ROM,那其中就可以存储网卡的BIOS。
- 所有的物理存储器都被看作由若干个存储单元组成的逻辑存储器
- 每个物理存储器在这个逻辑存储器中占有一个地址段,即一段地址空间
- CPU在这段地址空间中读写数据,实际上就是在相对应的物理存储器中读写数据
8086内存地址空间分配方案
- 架构(Architecture)
- 即,指令集体系结构,处理器设计的一部分,理解或编写汇编/机器代码时需要知道。
- 例如:指令集规范,寄存器
- 微架构(Microarchitecture)
- 架构的具体实现
- 例如:缓存大小、核心的频率
- 代码格式(Code Forms)
- 机器码(Machine Code):处理器接执行的字节级程序
- 汇编码(Assembly Code): 机器码的文本表示
- 指令体系结构(ISA)例子:
- Intel: x86, IA32, Itanium, x86-64
- ARM: 广泛用于移动电话
32位 | 16位 | 高8位 | 低8位 |
---|---|---|---|
EAX | AX | AH | AL |
EBX | BX | BH | BL |
ECX | CX | CH | CL |
EDX | DX | DH | DL |
EBP ESP ESI EDI只有低16位有特别名字,通常在编写实地址模式程序时使用
32位 | 16位 |
---|---|
EBP | BP |
ESP | SP |
ESI | SI |
EDI | DI |
在实地址模式下,段寄存器用于存放段的基址;
段寄存器包括:CS、SS、DS、ES、FS、GS。
- CS往往用于存放代码段(程序的指令)地址;
- DS存放数据段(程序的变量)地址;
- SS存放堆栈段(函数的局部变量和参数)地址;
- ES、FS和GS则可指向其他数据段。
- 保护模式下,段寄存器存放段描述符表的指针(索引)。