概述
为什么要学习汇编语言
进制运算
运算的本质是查表
二进制
略
为什么要学习理解二进制? 寄存器、内存、位…底层的每一个位都是有含义的。这是汇编入门理解的基础。 汇编高级则是了解程序的深层和操作系统的内核。
数据宽度
- 计算机内存有限制,数字没有无穷大(长度),因此要给数字增加数据宽度
bit:1位 Byte:8位 Word:16位 DWord:32位 - C、C++和Java等都需要定义数据的类型。计算机底层需要我们给这些数据定义宽度。
位:0、1 字节:0~0xFF 字:0~0xFFFF 双字:0~0xFFFFFFFF - 在计算机中,每一个数据需要给它定义类型。给它定义宽度,在内存中的宽度。
无符号数和有符号数
无符号数规则 你这数字是什么,那就是什么(就是一串数字)
1001 1010 十六进制:0x9A 十进制:154
有符号数规则 最高位是符号位:负数:1;正数:0
1001 1010 如何转换?
原码、反码、补码
有符号数的编码规则 原码:最高位是符号位,其余位表示数值的大小
反码:
- 正数:反码和原码相同
- 负数:符号位一定是1,其余位对原码取反
补码:
- 正数:补码和原码相同
- 负数:符号位一定是1,反码+1
以8位数据举例
如果是正数,大家都一样
1:
原码:0 0 0 0 0 0 0 1
反码:0 0 0 0 0 0 0 1
补码:0 0 0 0 0 0 0 1
如果是负数
-1
原码:1 0 0 0 0 0 0 1
反码:1 1 1 1 1 1 1 0
补码:1 1 1 1 1 1 1 1
-7
原码:1 0 0 0 0 1 1 1
反码:1 1 1 1 1 0 0 0
补码:1 1 1 1 1 0 0 1
如果看到一个二进制的数字,需要了解它是无符号数还是有符号数
位运算
2*8的最高效计算方式? 很多底层的调试器,需要通过位来判断CPU的状态
与运算(and &) 全都为1,结果为1。
或运算(or |) 只要有一个1,结果都为1。
异或运算(xor ^) 不一样就是1。
非运算(单目运算符 not ~) 取反。(单目运算符意为只需一个数字就能完成操作)
通过位运算可以实现加减乘除。 位运算 移动位,左移为×2,右移为÷2
0000 0001 1
0000 0010 2
0000 0100 4
0000 1000 8
左移:(shl <<) 所有二进制位全部左移若干位,高位丢弃,低位补0
0000 0001
左移1位
0000 0010
右移:(shr >>) 所有二进制位全部右移若干位,低位丢弃,高位就要补0或1(符号位决定补0还是补1)
0000 0001
右移1位
0000 0000
位运算实现加减乘除
计算机只认识0和1 基本数学是建立在加减乘除上的,只要搞定加法,其他都能用加法表示。
4 + 5 =?
# 二进制加法:
0000 0100
0000 0101
--------------(计算机不会直接加的)
0000 1001
# 计算机实现加法的原理:
# 第一步:异或 如果不考虑进位,异或就可以直接出结果。
0000 0100
0000 0101
--------------
0000 0001
# 第二步:与运算 判断进位,如果与运算结果为0则表示没有进位
0000 0100
0000 0101
--------------
0000 0100
# 第三步:将与运算的结果左移一位
0000 0100——>0000 1000
# 第四步:将上一步的结果跟前面异或的结果再异或
0000 1000
0000 0001
--------------
0000 1001
# 第五步:与运算 判断进位,如果与运算结果为0则表示没有进位
0000 1000
0000 0001
--------------
0000 0000
最终结果就是与运算结果的上一个异或运算的结果。否则继续重复步骤一到五。
4 - 5 =?
即4+(-5) 计算机中的负数用补码表示
# 二进制减法:
0000 0100
1111 1011
--------------(计算机不会直接减的)
1111 1111
# 第一步:异或 如果不考虑进位,异或就可以直接出结果。
0000 0100
1111 1011
--------------
1111 1111
# 第二步:与运算 判断进位,如果与运算结果为0则表示没有进位
0000 0100
1111 1011
--------------
0000 0000
所以最终结果:
1111 1111
乘:x*y,就是y个x相加,还是加法
除:x/y,本质就是减法,就是x能减去多少个y,本质也是加法
计算机只会做加法 机器语言就是位运算。都是电路来实现的,这就是计算机最底层的本质。
对这些数定义一些规则(数据宽度、有符号数和无符号数、原码反码补码这些),规则之上加入位运算,就能表示很多东西。
汇编学习环境和必要说明
汇编语言
即通过指令来代替二进制编码。 例如上面的复杂的加法操作通过一个ADD指令,使计算机将ADD直接转换为二进制加法操作的机器语言
在学习汇编之前,需要先掌握环境的配置:
- VC6(程序到汇编的理解)
- OD
- 抓包工具
- 加密解密工具
学汇编不是为了写代码,是为了理解程序的本质。 建议学习32位的《汇编语言》,至于64位,本质架构区别不大,只是,寻址能力增加。 汇编入门:了解汇编和程序的对应关系,程序的本质即可。
通用寄存器
寄存器: 存储数据:CPU>内存>硬盘 32位CPU 64位CPU
通用寄存器(可以存储任意的内容) 32位的通用寄存器只有8个: EAX、ECX、EDX、EBX、ESP、EBP、ESI、EDI 存值的范围:0~FFFFFFFF
计算机向寄存器存值: mov指令
mov 地址,值
mov 地址1,地址2
不同的寄存器
FFFFFFFF FFFF FF
32位 16位 8位
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:低八位 H:高8位
除了通用寄存器之外,其他的寄存器每一位都有其特定的功能。比如开机关机啥的。
内存
寄存器很小,不够用,所以数据要放在内存中。 每个应用程序进程都有4GB的内存空间(但是相当于空头支票),程序真正运行的时候才会用到物理内存。 1B = 8bit 1KB = 1024B …
4G的内存(4096M)最终计算为位,就是这个内存可以存储的最大容量。因此4G内存中的内存地址很多,空间很大。
内存地址 存一个数:占用的大小?数据宽度?存到哪里? 计算机中内存很多,空间很大,每个空间分配一个地址、名字。这些给内存起的编号,就是我们的内存地址。
每个内存地址都有一个编号。可以通过这些编号向里面存值。 内存如何存值?
汇编如何向内存中写值
mov 数据宽度 内存地址,值
例mov byte ptr ds:[0x19FF70],1
传递的值的大小一定要和数据宽度匹配
内存地址有多种写法: ds:[0x19FF70+4] 内存地址偏移 ds:[eax] 寄存器 ds:[eax+4] 寄存器偏移
数组[]: ds:[reg+reg*{1,2,4,8}] 数组 ds:[reg+reg*{1,2,4,8}] 数组偏移
未完待续
|