汇编之趣味计算机

汇编之有趣的计算机

Wirte by 021. Leave a message if i messed up ! : )

汇编语言入门教程- 阮一峰的网络日志

汇编的加减乘除:

1
2
3
4
5
6
7
8
9
10
11

汇编语言 编译器 机器语言

加 INC EAX ---> 0100 0000

减 DEC EAX ---> 0100 1000

乘 MUL EAX ---> 1111 0111 1110 0000

除 DIV EAX ---> 1111 0111 1111 0000

进制换算

1
2
3
4
5
6
7
8
9
10
11
12

0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

0 1 2 3 4 5 6 7 8 9 A B C D E F

测试:
hex : 6d 7f 008c e3 246

hex to bin
6 + d = 0110 1101, 7 + f = 0111 1111, 8 + c =0000 0000 1000 1100, e + 3 = 1110 0011, 2 + 4 + 6 = 0010 0100 0110.

数据宽度

  • 超过数据宽度将被丢弃
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

位 bit: 0,最大值 1.

字节 byte: 0000 0000 , 最大值 1111 1111 , 0 - ff. 0xff.

字word: 0000 0000 0000 0000 ,最大值 1111 1111 1111 1111 , 0 - ffff, 0xffff.

双字doubleWord: 0000 0000 0000 0000 0000 0000 0000 0000 0000 , 最大值 0xffffffff.

数据宽度测试:
char a = 0x1ff, 存入数据是ff 舍弃了1,因为宽度不够.

Xcode 进入debug 模式, 在右边控制台或者内存值, 输出:

x/1xb 0x7ffeefbff3df , 取1个字节的值,用16进制表示,表示单字节
0x7ffeefbff3df: 0xff 只存了ff。

x/nfu <addr>

n,表示要显示的内存单元的个数
f,表示显示方式, 可取如下值:
x 按十六进制格式显示变量
d 按十进制格式显示变量
u 按十进制格式显示无符号整型
o 按八进制格式显示变量
t 按二进制格式显示变量
a 按十六进制格式显示变量
i 指令地址格式
c 按字符格式显示变量
f 按浮点数格式显示变量

u,表示一个地址单元的长度:
b 表示单字节
h 表示双字节
w 表示四字节
g 表示八字节


x/16xb self
会显示 self 指针地址内容,16 个字节,16 进制。
x/8cb 0x7fc359a03040
会显示地址 0x7fc359a03040 地址的内容,8 个字节,按字符格式显示。

有符号 与 无符号

  • 有符号数与无符号数正数显示结果一样,负数结果不一样

  • 有符号

1
无符号 0000 0001 就是 0000 0001, 
  • 无符号
1
2
3
4
5
6
7
8
9
10
11
12
测试: 1 , 0x01,
最高位 0, 是正数.
0000 0001

最高位 1,是负数.
1000 0001 , 0x81

int x = 0x81000000;
printf("有符号表示 %u\n",x);
printf("无符号表示 %d\n",x);
有符号表示 2164260864
无符号表示 -2130706432

原码 反码 补码

原码

  • 正数存储用原码反码补码都一样
1
2
最高位是符号位,其余位为数值的绝对值. 
1 的原码 0000 0001

反码

  • 正数的反码原码相同,负数符号位1,其余位取反
1
2
3
-1
原码: 1000 0001
反码: 1111 1110 , 最高位不变.

补码 -!!!负数存储!!!

  • 负数补码存储,符号位不变,正数不变,其余位反码加1,

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    正码
    1 , 0000 0001.
    反码
    -1, 1111,1110.
    反码
    -1, 1111 1111.

    测试: 求 1,-1 在内存中的16进制值;

    1: 正数无需关心,直接转16进制 = 0x01.

    -1: 反码+1, 原码 1000 0001 , 反码 ,1111 1110 , 补码+1 , 1111 1111, 得出内存值 0xff.

    cha x = -1;
    输出:
    x/1xb 0x7ffeefbff3df
    0x7ffeefbff3df: 0xff

位运算

与运算

  • **同位为1,结果才是1,否则是0. **
  • 并且(当2个开关都闭合灯才亮)

image-20211113185951722

1
2
3
4
测试:C: 1 & 2 ,  assembly: and
0000 0001
0000 0010
结果 : 0000 0000; 结果为0;

或运算

  • 同位只要有1,就是1
  • 或者 (两个开关只要一个开关闭合灯就能亮)

image-20211113190157102

1
2
3
4
5
测试: C: 1 | 2 , assembly : or
0000 0001
0000 0010
结果为: 0000 0011; 结果为3;

异或运算

  • 同位相反才为1,否则为0
  • 不一样的时候才为1

image-20211113191238456

1
2
3
4
5
6
测试: C: 1 ^ 2 , assembly : xor
0000 0001
0000 0010
结果为: 0000 0011; 结果为3;


非运算

  • 同位交换,单数运算
1
2
3
4
5

测试: 1 ,C: ~ , assembly : not
0000 0001

结果为: 1111 1110;

左移运算

  • 各二进制位全部向左移动若干位,高位丢弃,地位补0
1
2
3
4
5
6
7
8
9
10
C:<< , assembly : shl

测试 : 1,左移1位,
0000 0001 ,结果: 0000 0010; = 2.
左移2;
0000 0001, 结果: 0000 0100; = 4.

char c = 1 << 2;
输出为:4

右移运算

  • 各二进制位向右移动若干位,无符号高位补0或者有符号高位补1,低位丢弃
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
C:>> , assembly : shr

测试 : 1,

右移1位,
0000 0001 ,结果: 0000 0000; = 0.
右移2;
0000 0001, 结果: 0000 0000; = 0.


补符号: 高位补1
C:>> , assembly : sar
测试数: 10;右移2位;
0000 1100; 结果: 1000 0011; 负数存的是反码+1, 1111 1101, 内存值= 0xfd;

1000 1010 -> 1111 0110 补码值 :0xf6 右移-> 1111 1101; fd

+ - * /

+

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
求 10 + 7 = ?
//混搭伪代码
int a = 10;
int b = 7;

funcAdd(a,b)
{

//转换
0000 1010
0000 0111
//第一步先异或
int tmp = funXor(a,b) funXor(a,b); = 0000 1101
//第二步判断是否有进位
int shlTemp = funcCmp(a,b); 0000 0010; 有进位

//判断是否有进位 ,
if(shlTemp!=0)
{
//有进位需要位移,位移后的值.
int shlTempValue = funcSHL(shlTemp,1); 0000 0100;

//将第一次的结果与进位的结果异或 ,第一次递归调用
funcAdd(tmp,shlTempValue);
//第二次异或;
0000 1101
0000 0100
= tmp = 0000 1001;
第二次与运算对比,有进位;shlTemp = 0000 0100
shlTempValue = funcSHL(shlTemp ,1) = 0000 1000;

//第二次递归调用funcAdd(tmp, shlTempValue);
0000 1001
0000 1000
//第三次异或运算
tem = 0000 0001
//第三次对比 与 运算
shlTemp =0000 1000;
//有进位,第三次位移
shlTempValue = 0001 0000;

//第三次次递归调用funcAdd(tmp, shlTempValue)
//第四次异或
0000 0001
0001 0000
tem = 0001 0001 = 17;
//第四次与运算,判断是否有进位
//第四次无进位,判断执行完毕,执行后面代码
}
returun tem;

}

//与运算
funcCmp(a,b)
{
0000 1010
&
0000 0111

return a&b = 0000 0010; 如果非0,作为返回值继续异或
}

//左移1位
funcSHL(int a,int offset){
a = 0000 0010;
offset = 1;
return a << 1 = 0000 0100;
}

//异或运算
funXor(a,b)
{
a = 0000 1010
b = 0000 0111
// 假设没进位
return a^b; 0000 1101;
}


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
求 10 - 7 = ?

减法就是加法 , 10-7 = 1 + (-7);

-7 是补码存储,求补码:
正码: 0000 0111; 反码: 1111 1000;补码=反码+1= 1111 1001; 内存=0xf9;

//混搭伪代码
int a = 10;
int b = -7;
funcAdd(a,b)
{

//转换
0000 1010
1111 1001
//第一步先异或
int tmp = funXor(a,b) funXor(a,b); = 1111 0011
//第二步判断是否有进位
int shlTemp = funcCmp(a,b); 0000 1000; 有进位

//判断是否有进位 ,
if(shlTemp!=0)
{
//有进位需要位移,位移后的值.
int shlTempValue = funcSHL(shlTemp,1); 0001 0000;

//将第一次的结果与进位的结果异或 ,第一次递归调用
funcAdd(tmp,shlTempValue);
//第二次异或;
1111 0011
0001 0000
= tmp = 1110 0011;
第二次与运算对比,有进位;shlTemp = 0001 0000
shlTempValue = funcSHL(shlTemp ,1) = 0010 0000;

--------------n次递归-----------------
求 10 - 7 = 10 + (-7)
0000 1010
1111 1001
异或 tmp = 1111 0011
进位: 0000 1000
进位后的值 shlTempValue = funcSHL(000 1000 ,1) = 0001 0000
-------------------------------------
1111 0011
0001 0000
异或 tmp = 1110 0011
进位: 0001 0000
进位后的值 shlTempValue = funcSHL(0001 0000 ,1) = 0010 0000
---------------------------------------
1110 0011
0010 0000
tmp = 1100 0011
shlTempValue = funcSHL(0010 0000 ,1) = 0100 0000
-------------------------------
0100 0000
1100 0011
tmp = 1000 0011
shlTempValue = funcSHL(0100 0000 ,1) = 1000 0000
---------------------------------
1000 0000
1000 0011
tmp = 1000 0011;
shlTempValue = funcSHL(0100 0000 ,1) = 0001 0000 0000
0001 0000 0000
0000 0000 0011
0001 0000 0011 ??????WTF 此时结果产生了溢出; 篇幅原因 就不展开讲了
-------------------------------------
tem = 0001 0000 0011 ;
//第四次与运算,判断是否有进位
//第四次无进位,判断执行完毕,执行后面代码
}
returun tem;

}

//与运算
funcCmp(a,b)
{
0000 1010
&
0000 0111

return a&b = 0000 0010; 如果非0,作为返回值继续异或
}

//左移1位
funcSHL(int a,int offset){
a = 0000 0010;
offset = 1;
return a << 1 = 0000 0100;
}



//异或运算
funXor(a,b)
{
a = 0000 1010
b = 0000 0111
// 假设没进位
return a^b; 0000 1101;
}


*

1
2
3
4
5
6
7
8
9
求 10 * 7 = ? 
解: 7 个 10 相加;
int a = 10;
int b = 7;

for (int i =0; i < 7 ; i++ ){
funcAdd(a,a);
}

/

1
2
3
4
5
6
7
8
9
10
求 10 * 7 = ? 
解: 7 个 10 相加;
int a = 10;
int b = 7;

for (int i =0; i < 7 ; i++ ){
//转换补码负数
b = 1111 1001;
funcAdd(a,b);
}