汇编先导课笔记

一、概述

  • 语言
  • 进制
  • 进制如何运算
  • 二进制
  • 数据宽度
  • 有符号数和无符号数
  • 原码反码补码
  • 位运算
  • 位运算计算
  • 汇编
  • 寄存器
  • 内存
  • 汇编指令
  • 内存复制
  • 堆栈的指令
  • 汇编如何写函数
  • 堆栈传参
  • 堆栈平衡
  • 外挂

二、为什么要学汇编语言

  • 语言

    • 人和人沟通就是通过语言,人和计算机交流就需要计算机的语言。
  • 机器语言:

    # 我们目前主流的电子计算机
    0和1  电路有通断,代表两种状态 
    # 最早的程序员:穿孔卡带!都是通过0101来个状态来进行编程
    要解决的基本问题:加减乘除,本质上都是加的问题,加减乘除就是一堆01组成的命令
    加:假设为0100 0000
    减:假设为0100 1000
    乘:假设为0100 1000 0100 1000
    除:假设为0100 1000 1100 1000
    
    • 这些复杂的机器语言,不方便记忆,因此助词符出现了,如加用INC,减用DEC,乘用MUL,除用DIV,这些助记符就是汇编语言,汇编语言可以直接操作计算机的底层,甚至是操作底层数据的位。
    • 通过编译器,将人能理解的语言转化成计算机能理解的二进制语言。
    加 INC -编译器->  0100 0000
    减 DEC			0100 1000
    乘 MUL			0100 1000 0100 1000
    除 DIV			0100 1000 1100 1000
    
    • 因为有上面这层关系,所以离java等编写的程序的本质会有一个隔阂,也就是不知道程序的本质是怎么运行实现的。
    • 汇编语言一般用于底层或单片机等的编写
  • C语言:汇编语言的进一步简化

    加 A+B -编译器->  0100 0000
    减 A-B			0100 1000
    乘 A*B			0100 1000 0100 1000
    除 A/B			0100 1000 1100 1000
    

6da3f8f7ab0939967a89b1af8c8dd24

d42c9e713761baaf944cd617f27ef2b

  • 暴破(暴力破解 ):必须要弄懂底层的东西

三、进制的思想本质

  • 二进制的本质是 0 1
  • 学习进制的障碍:受10进制的传统思想禁锢,人类天然的选择就是10进制(10个手指,“屈指可数”),要跳出固有的思维方法。
  • 进制
    • 思想:每一种进制都是完美的,都有自己的计算方式
  • 多种进制
    • 1进制:一进一,结绳记事。1 1
    • 2进制:二进一,计算机。0 1 10 11
    • 8进制:八进一,8个符号组成 ,0 1 2 3 4 5 6 7
    • 10进制:十进一,10个符号组成,0 1 2 3 4 5 6 7 8 9
    • 16进制:十六进一,16个符号组成,0 1 2 3 4 5 6 7 8 9 a b c d e f
    • 进制远远没有那么复杂,只要会查数就可以

测试

#一进制	1-20
1 11 111 1111...
#三进制 	1-20
0 	1 	2	10  11  12	20	21	22	100 101	102 110 111	112	120	121
#七进制 	1-20
0 	1	2	3	4	5	6	10	11	12	13	14	15	16	20	21	22
#十进制 	1-20
0	1	2	3	4	5	6	7	8	9	10	11	12	13	14	15	16
#二进制	1-20
0	1	10  11  100 101	110	111	1000 1001 1010 1011 1100 1101 1110	1111
#进制的本质就是一组符合,逢几进几
  • 问题:1+1=3?
    • 大众化的十进制: 0 1 2 3 4 5 6 7 8 9 10
    • 十进制所用的符号可随便定义: 0 2 5 a t a s d 8 6 20,可以自己随便定义,要从学习转变成创作者
  • 加密解密:程序员可以使用进制加密,破解程序会很麻烦,是一种高级加密,这种加密方式,数字量一大,总是有规律的。

四、进制的运算

#使用八进制计算下面的结果 
2+3=5(2后移动3位)
2*3=6(=3+3)
4+5=11(4后移5位)
4*5=24(4后移动4个5,相当于5+5+5+5)

#运算的本质就是查数
0 1 2 3 4 5 6 7 10 11 12 13 14 15 16 17 20 21 22 23 24 25 26

#使用八进制计算下面的结果 九九乘法表=加法表 进位
277+333=632
276*54=20250
237-54=163
234/4=47
  • 八进制乘法表

image-20220608171921008

  • 八进制加法表

image-20220608171955940

#运算的本质就是查数
277
333	+
------
632


  276
   54 *
------
 1370
1666  +
------
20250

#减法的本质就是加法

237
 54 -
------
163
	
	
#除法的本质,除数乘以哪个数最接近结果即可
234		#2和4除不够除,先找谁*4最接近23,不能超过23
  4  /
------
 47
  • 结论:无论是什么进制,本身都是有一套完美的运算体系,我们都可以通过列表的方式将它计算出来。

五、二进制

  • 计算机使用二进制0 1,用不同的状态来表示,因为现在使用的电子计算机,用高低电平来表示0和1。
  • 电子计算机有物理极限:摩尔定律(集成电路上可以容纳的晶体管数目在大约每经过18个月便会增加一倍),这种极限到头后,追求语言的极限,如并发语言(软操作)。
  • 量子计算机:
    • 可以实现量子计算的计算机。传统的计算机:通过集成电路来实现电路的通断,通过高低电平来表现出两个值0和1
    • 量子计算机的单位:昆比特(量子比特)。量子的两态,还有一个叠加态。
    • 量子计算机的核心要素是提高计算机的计算力
  • 传统计算机中的二进制
#二进制   0-1111
0 10 11 100 101 110 111 1000 1001 1010 1011 1100 1101 1110 1111

二进制这么去写很麻烦,二进制能否简写?

0 1 2 3 4 5 6 7 8 9 a b c d e f

这就是16进制出来了。

  • 为什么要学二进制:
    • 寄存器、内存、位,底层的每一个位都是有含义的。
    • 汇编高级:了解程序的深层,操作系统的内核。

六、数据宽度

  • 计算机内存中,任何的数据类型都是有宽度的,宽度就是表示这种数据类型的数据占多大的空间。

image-20220612090658337

  • c和c++ java都需要定义数据的类型,计算机底层需要我们给这些数据定义宽度。

位 0 1

字节 0-0xFF

字 0-0xFFFF

双字 0-0xFFFFFFFF

  • 在计算机中,每个数据都需要给它定义类型。目的就是给它定义宽度,在内存中的宽度。

七、有符号数和无符号数

  • 数据都是有宽度的,每个数据代表什么意思,需要设定规则,如mp3播放需要mp3的解码规则等

  • 二进制数也需要解码,也需要规则。

  • 无符号数规则

    • 数字是什么,那就是什么
    1 0 0 1  1 0 1 0  十六进制:0x9A  十进制:154
    
  • 有符号数规则

    • 最高位是符号位:1(负数) 0(正数)
    • 那数据是多少是如何转换的,就需要用到原码反码和补码。

八、原码反码补码

  • 有符号数的编码规则

  • 原码:最高位是符号位,对其他位进行本身绝对值即可。

  • 反码:

    • 正数:反码和原码相同
    • 负数:符号位一定是1,其他位对原码取反
  • 补码:

    • 正数:补码和原码相同
    • 负数:符号位一定是1,其他位+1

测试

#针对的是8位数
#如果是正数,都是一样的
1
#原码:0000 0001
#反码:0000 0001
#补码:0000 0001

-1
#原码:1000 0001
#反码:1111 1110
#补码:1111 1111

-7
#原码:1000 0111
#反码:1111 1000
#补码:1111 1001

#如果看到一个数字,二进制的,需要了解它是胡符号数还是无符号数

九、位运算的理解

  • 寄存器:存值的,比内存的速度要快,mov指令可以往寄存器中存值

  • 计算机中的负数是用补码的方式存储的

  • 位运算:

    • 2*8的最高效的运算方式 :

      • 2 << 3 或者 8 << 1
        2 << 3 即 2 左移 3 位
        系统中运算是二进制,左移一位即乘2
    • 很多底层的调度器。需要通过位来判断CPU的状态。

    • 与运算(and &):

      • 计算机的本质

      image-20220612172441160

      • 1011 0001
        1101 1000
        --------------与运算
        1001 0000
        
    • 或运算(or |)

      image-20220613161303536

      • 1011 0001
        1101 1000
        --------------或运算
        1111 1001
        
    • 异或运算(xor ^)

      image-20220613162408906

      • 不一样就是1,如01=1,11=0

      • 1011 0001
        1101 1000
        --------------异或运算
        0110 1001
        
    • 非运算(单目运算符 not ~)

      • 0就是1,1就是0,取反

      • 1101 1000
        ------------取反
        0010 0111
        
    • 位运算(移动位):

      二进制 	十进制->左移*2,右移/2
      0000 0001   1
      0000 0010   2
      0000 0100   4
      0000 1000   8
      
      • 左移:(shl <<)
      0000 0001   #所有二进制位全部左移若干位,高位就丢弃,低位补零
      0000 0010
      
      • 右移:(shr >>)
      0000 0001   #所有二进制位全部右移若干位,低位就丢弃,高位补0或1(符号位决定)
      0000 0000
      
    • 通过上面的位运算来实现加减乘除

十、位运算的加减乘除

  • 计算机只认识0 1

  • 基本数学是建立在 加减乘除上的,主要是加法。

# 4+5
0000 0100
0000 0101
--------------加(计算机不会直接加,只懂得与或非和异或运算)
0000 1001

#计算机的实现原理 
#第一步:异或,不考虑进位,异或就可以直接出结果
0000 0100
0000 0101
--------------异或
0000 0001
#第二步:与运算(判断进位,如果与运算的结果都为0,则没有进位;如果不为0.则代表当前位需要进位)
0000 0100
0000 0101
--------------与
0000 0100 #1处需要进位
#第三步:将与运算的结果左移一位,就是进位的结果。
0000 0100
--------------<
0000 1000
#第四步:将第一的结果和第三步的结果异或
0000 0001
0000 1000
--------------异或
0000 1001
#第五步:与运算,将第一的结果和第三步的结果在进行与运算 (判断是否有进位,为0,则最终结果就是上面的结果)
0000 0001
0000 1000
--------------与
0000 0000
#所以最终结果就是0000 1001

# 4-5=4+(-5) -5用补码来表示=1111 1011(取反加一)
0000 0100
1111 1011
--------------加(计算机不会直接加,只懂得与或非和异或运算)
1111 1111

#计算机的实现原理 
#第一步:异或,不考虑进位,异或就可以直接出结果
0000 0100
1111 1011
--------------异或
1111 1111
#第二步:与运算(判断进位,如果与运算的结果都为0,则没有进位;如果不为0.则代表当前位需要进位)
0000 0100
1111 1011
--------------与
0000 0000 #无进位
#所以最终结果就是1111 1111
  • 乘:x*y,就是y个x相加
  • 除:x/y,就是x能减去多少个y
  • 计算机只会做加法

十一、汇编学习环境

  • 从零开始设计一套进制规则,自己设计电路,来实现加减乘除,10进制和2进制的转换。

  • 机器语言就是位运算。都是电路来实现的,这就是计算机最底层的本质。

  • 通过机器语言来实现加法计算器。设计电路

  • 汇编语言

    • 就是通过指令来代替我们的二进制编码,如可以通过add指令来表示一堆的二进制操作

    image-20220616101525845

    • 通过汇编指令可以给计算机发一些操作,然后让计算机执行(通过编译器)。

    • 编译器的发展,学习底层,用越原始的ide越好

      • VC6.0(c语言,程序到汇编的过程)
      • OD(反汇编工具)

      image-20220616103224413

      • 抓包工具
      • 加密解密工具
    • 学汇编不是为了写代码,而是为了理解程序的本质

    image-20220616102405778

    • 16位的汇编、32位和64位的汇编
      • 32和64位本质架构区别不大,寻址能力增加
    • 汇编入门:要了解汇编和程序的对应关系

十二、通用寄存器

  • 寄存器:cpu中有寄存器

  • 存储数据:CPU>内存>硬盘

    • 32位 CPU ,支持8位 、16位、 32位的寄存器

    • 64位 CPU,支持8位 、16位、 32位、64位的寄存器

    • 位代表的是寻址能力

  • 通用寄存器,可以存储任何的值

# 32位cpu中的通用寄存器只有8个
# 存值范围都是从0~FFFF FFFF,FF=1111 1111,8个F就是4个8位,就是32位

image-20220617101741006

  • 对于二进制来说,直接修改值

  • 对于汇编,计算机如何往寄存器存值

    • 使用mov指令
      • 可以将数字写入到寄存器,也可以将寄存器的值写入到寄存器。
    mov 存的地址,存的数
    mov	存的地址1,存的地址2
    

    d8ac5332b711a10de067d6af92c9c32

  • 计算机的本质就是计算力

  • 不同的寄存器

FFFF FFFF		FFFF	  FF
32168位
EAX				 AX		  AL	
ECX				 CX		  CL	
EDX				 DX		  DL		
EBX				 BX		  BL
ESP				 SP		  AH	
EBP				 BP		  CH
ESI				 SI		  DH
EDI				 DI		  BH
#8位:L代表低8位,H代表高8位,两个8位合成一个16位

49975274d436ec6fb66f6351bbe5b45

f07308e46e418c2c2aac7fed927ea6e

  • 除了这些通用寄存器之外,那么其他的寄存器每一位都有自己特定的功能,如开机关机

十三、内存

  • 寄存器很小,不够用。所以说,数据放到内存(就是平时所说的内存条)中。
  • 每个应用程序进程都有4GB的内存空间。2G的内存可以跑4G的程序,这里就要用到虚拟内存。
  • 程序真正运行的时候,才会用到物理内存
  • 换算
    • 1B=8bit
    • 1KB=1024B
    • 1MB=1024KB
    • 1GB=1024MB
  • 4G的内存,4096M=>最终计算为位,就是这个内存可以存储的最大容量,目前的内存条一般是按10进制来换算的,也就是4G达不到4096M
  • 计算机中内存地址很多,空间很大。
    • 存一个数:先考虑占用的大小 (数据宽度),一个byte是1个字节(8b),一个WORD是一个字(16位),一个DWORD是一个双字(32位);
    • 内存地址是解决数据要存到哪里的。我们为每个空间分配一个地址,也就是取一个名字,8位代表一个字节,取一个内存地址名称,从0x0000 0000-0xFFFF FFFF,这些给内存起的名字,就是我们的内存地址。
    • 32位,cpu与主内存32条线路连接,每条线路有0和1两种信号 ,总共可以形成2的32次方个寄存器地址,每个 寄存器单元8bit,就是8个16进制的值,一个F对应一个1111,所以32位的cpu最大的寻址能力就是FFFF FFFF+1=10000 0000(0000 0000也是一个数),换成10进制就是42 9496 7296*8字节/8=419 4304千字节/1024=4,096兆字节/1024=4G字节,因此32位CPU最大的内存也就用到4G,在多了就过剩。
    • 如果是64位,就是0000 0000 0000 0000-FFFF FFFF FFFF FFFF,理论上支持很大的内存寻址,无上限

4357701a88455b2af197cc758b09276

  • 汇编如何向内存中写值

    • 数据宽度 byte word(2个字节) dword(4个字节) qword(8个字节64位)

    • 地址的位置:0x0000 0111等

    • mov 数据宽度 ptr ds:[内存地址],写入的值# ptr:Pointer Record
      内存地址有多种写法
      	[0x11110f70]:经典写法
      	[0x11110f70+4]:偏移量写法
      	[eax]:寄存器写法,指的是eax寄存器中的值所对应的内存地址
      	[eax+4]:寄存器偏移量写法
      	
      数组[]如何开辟空间
      	[reg+reg*{1,2,3,4}]#reg代表寄存器
      	[reg+reg*{1,2,3,4}+4]#reg代表寄存器,数组的偏移量
      

      image-20220618105923464image-20220618111724408

    • 不是任意的地址都可以写东西的,只有程序申请使用的内存地址才能写。

posted @   是韩信啊  阅读(131)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示