从二进制到汇编

概述

语言

电子计算机:只有0和1两个状态

机器语言:由0和1组成
假设:
加 0001 0110
减 0100 1000
乘 1101 0111
除 0100 0011

汇编语言:为了助计机器语言,用inc表示加,然后通过编译器转换为机器语言
加 INC -> 编译器 0001 0110
减 DEC-> 编译器 0100 1000
乘 MUL-> 编译器 1101 0111
除 DIV-> 编译器 0100 0011

C语言:更加简化机器语言,便于学习和记忆
加 A+B -> 编译器 0001 0110
减 A-B -> 编译器 0100 1000
乘 A*B -> 编译器 1101 0111
除 A/B -> 编译器 0100 0011

进制

一进制: 1 11 111 1111 11111 111111 1111111 11111111 111111111
二进制: 0 1 10 11 100 101 110 111 1000
八进制:0 1 2 3 4 5 6 7 10 11 12
十进制:0 1 2 3 4 5 6 7 8 9 10
十六进制:0 1 2 3 4 5 6 7 8 9 a b c d e f

进制运算

进制运算的本质就是查数
在这里插入图片描述
在这里插入图片描述

使用8进制计算下面的运算
277+333
277*54
277-35
234/4

 277
 333 +
--------
 632
===============
 277
  54 *
--------
 1374
1673 +
--------
20324
===============
 277
  35 -
--------
 242
===============
 234
  4 /
--------
  47(查看乘法表,看哪个数与4相乘与23接近)

结论:无论是什么进制,本身都有一套完美的运算体系,都可以通过列表的形式将其计算出。

二进制

二进制 0 ~ 1111
0 1 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
1111 1111 :使用16进制表示 0xFF

数据宽度

在计算机中,需要给数据增加计算宽度。因为内存是有限的
在这里插入图片描述
强类型语言中,都需要给数据定义类型,String int …

0 1
字节   0~0xFF0~0xFFFF
双字   0~0xFFFFFFFF
==在计算机中,都需要给数据定义类型,在内存中给它定义宽度==

有符号数和无符号数

数据都是有宽度的,但是给你一个二进制数字,你怎么知道它代表什么含义?
规则,给二进制解码增加一个规则
无符号数规则
这个数是什么,就是什么

1001 1010 
转换为十六进制: 0x9A
十进制:154

有符号数规则
最高位是符号位,1(负数) 0(正数)
负数在计算机中是以补码的形式存在的

已知该二进制表示的是一个负数,求其十进制表示的数
1001 1010 
--------------
1.该二进制是一个补码,先求其原码的反码,即补码减1
反码 1001 1001
原码 1110 0110
转换为十进制就是 -102

在这里插入图片描述

原码反码补码

编码规则
有符号数编码规则

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

反码

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

补码

  • 正数:反码和原码相同
  • 负数符号位是1,反码+1

测试,都是按照8位来运算的

1的原码反码补码
1  如果是正数,都是一样的 
原码 0000 0001
反码 0000 0001
补码 0000 0001
---------------------1的原码反码补码
-1  如果是负数
原码 1000 0001
反码 1111 1110
补码 1111 1111
---------------------7的原码反码补码
-7  
原码 1000 0111
反码 1111 1000
补码 1111 1001

如果看到一个二进制数,需要了解是有符号数还是无符号数

二进制的标志:
2 10
4 100
8 1000
16 10000

寄存器:用来存值,速度比内存快
命令: mov 哪个寄存器,值

-132位寄存器中的表示是0xFFFFFFFF
用二进制表示就是1111 1111 1111 1111 1111 1111 1111 1111

结论:负数在寄存器中是以补码的形式存放的

位运算

学习位运算需要掌握原码反码补码
2*8最高效计算方式:通过位运算(左移一位就是乘以2)

public class test {
    public static void main(String[] args) {
        int a = 8;
        System.out.println(a<<1);  //16
    }
}

很多底层的调试器,需要通过位来判断CPU的状态

与运算(and &)
计算机的本质

与运算:两个都为1,结果为1,任意有一个为0,结果都是0
1001 0110
1010 1100
----------
1000 0100

或运算(or |)

在这里插入图片描述

或运算:一个为1,结果就是1
1001 0110
1010 1100
----------
1011 1110

异或运算(xor ^)
不一样就是1

在这里插入图片描述

异或运算:不相同就是1,相同就是0
1001 0110
1010 1100
----------
0011 1010

非运算符(单目运算符 not ~)

非运算:对其取反
1001 0110
----------
0110 1001

通过这些位运算可以完成加减乘除

位运算
左移乘2,右移除2 (对于十进制来说)
高位就是左边,低位就是右边
左移(shl <<)

0000 0110 所有二进制位全部左移若干位,高位丢弃,低位补0
左移一位:0000 1100

右移(shr >>)

1000 0110 所有二进制位全部右移若干位,低位丢弃,低位补0,1(根据符号)
右移一位:1000 0011

位运算(移动位)
左移:         十进制
0000 0001        1
0000 0010        2
0000 0100        4
0000 1000        8

位运算计算

计算机只认识0和1,基本数学是建立在加减乘除上面的(核心是加法)
4+5?

计算机是怎么操作4+50000 0100
0000 0101
----------
0000 1001 (加法,计算机是不会直接加的,计算机只懂,与或非,异或)
计算机实现原理
第一步,异或,(如果不考虑进位,异或可以直接出结果)
0000 0100
0000 0101
----------异或(不相同为10000 0001

第二步,与运算(判断进位,如果与运算结果为0,说明没有进位)
0000 0100
0000 0101
----------与运算(同为1,结果为10000 0100

第三步,将与运算的结果左移一位(因为进位,需要左移)
0000 0100
----------左移一位
0000 1000

第四步,异或运算(第一次异或结果与左移后的结果进行异或运算)
0000 0001
0000 1000
----------异或运算
0000 1001

第五步,与运算(判断进位是否为00000 0001
0000 1000
----------与运算
0000 0000

结果为0,证明没有进位,所以最终结果是0000 1001

4-5?

计算机是没有减法的 4+-5)
负数在寄存器中是以补码的形式存放的
5
0000 0101
原码 1000 0101
反码 1111 1010
补码 1111 1011
所以-5 就是1111 1011
------------------
4+-50000 0100
1111 1011
----------结果也是一个二进制的补码,根据补码求原码就能知道该数
1111 1111 
----------
补码 1111 1111
反码 1111 1110
原码 1000 0001
最高位为1表示负数,所以结果是-1
----------------------------------------------
计算机实现原理
第一步,异或
0000 0100
1111 1011
----------异或(不相同为11111 1111

第二步,与运算(判断进位,如果与运算结果为0,说明没有进位)
0000 0100
1111 1011
----------与运算(同为1,结果为10000 0000

结果为0,证明没有进位,所以最终结果是1111 1111

再根据补码求原码即可。

乘法:x*y (本质是y个x相加)
除法:x/y (本质上减法,看x能减去多少个y)

符号位在计算机中很重要
0xFF
有符号位:-1
无符号位:255

汇编

通用寄存器

寄存器:
存储数据:CPU>内存>硬盘
32位CPU
64位CPU
通用寄存器:可以存储任意的东西

32位的通用寄存器只有8个

EAX  ECX  EDX  EBX
ESP  EBP  ESI  EDI
寄存器存值的范围 0~0xFFFFFFFF
对于二进制来说,直接修改值

计算机如何向寄存器中存值
汇编:mov指令

mov 存的地址,存的数
mov 存的地址1,存的地址2
可以将数字写入到寄存器中,也可以将寄存器中的值写到寄存器

不同的寄存器

   32168(分为高8位和低8)
0xFFFFFFFF      0xFFFF        0xFF
EAX             AX            AL
ECX             CX            CL
EDX             DX            DL
EBX             BX            BL
ESP             SP            AH
EBP             BP            CH
ESI             SI            DH
EDI             DI            BH
L:8位,H:8位
向高8位存1   00000100
向低8位存1   00000001
所以:高8位加低8位也是一个16位的状态
mov cl,01 -- 00000001
mov ch,01 -- 00000101

除了通用寄存器,还有其他的寄存器,每一位都有独特的功能。

内存

内存地址

存一个数:占用的大小,数据宽度
计算机中内存地址很多,空间很大,每个空间都有一个地址
给内存起的编号,就是内存地址 0x0011FF11
范围0x00000000~0xFFFFFFFF

32位的寻址能力只有4GB
一共有多少个内存空间0xFFFFFFFF+1 就是1 0000 0000,转换为十进制就是42 9496 7296
/1024=4194304KB/1024=4096MB/1024=4GB

内存如何存值

需要知道:
数据宽度 :byte(8) word(16位) dword(32位) qword(64位)
地址的位置:0xFFFFFFFF
不是任意的地址都能写东西的,只能在申请的空间中写数据

汇编向内存中存值
mov 数据宽度 内存地址,需要写入的数
如: mov byte ptr ds:[0x0019FF70],0x1
传递的值得大小一定不能超过定义的数据宽度,不然无法写入

内存地址有多种写法
ds:[0x0019ff70+4](内存地址偏移)
ds:[eax](地址中也可以存放寄存器)
ds:[eax+4](寄存器偏移)
ds:[reg+reg*{1,2,4,8}] (数组)
ds:[reg+reg*{1,2,4,8}+4](数组偏移)

汇编指令

内存复制

堆栈的指令

汇编如何写函数

堆栈传参

堆栈平衡

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值