C语言的逻辑运算
C语言的逻辑运算只有两种结果,0x00和0x01。
为什么只有这两种结果?
因为逻辑运算只有两种结果,true和false。只要不是0(如果是0的话,结果就为0x00),其他的结果都是0x01。
如何取反?
因为逻辑运算只有两种结果,而我们的取反是按结果取反,而不是按位取反,所以0的取反就是1,1的取反就是0。综上0x00取反是0x01,0x01取反是0x00。举例:当遇到“!”比如!0x00,取反的结果就是0x01。
全1 是-1
最大的负数是 11111111,也就是10进制的-1
而最小的负数是 10000000,也就是10进制的-128
几乎所有的机器都是用补码来表示有符号数,所以-1(1111 1111)是1000 0001的补码。
T2U和U2T
T2U表示的是有符号数到无符号数的函数映射
将较大的数值转化成较小的数值类型,想要保持数值不变是不可能的。
将较小的数值转化成较大的数值类型,可以保持数值不变。
习题
算术运算和逻辑运算
左移右移
右移有两种形式,算术右移,逻辑右移。
左移都是补0。
逻辑右移和算数右移
算术右移要看符号位,0的话就补0,1的话就补1
逻辑右移都是补0。
超线程
超线程也就是同时多线程
超线程处理器可以在单周期基础上决定执行哪一个线程
Amdanl公式
内存地址空间
从上往下依次是:内核——用户栈——共享库——栈——数据、代码
提高计算机的计算能力
指令级并行:现代处理器同时执行多条指令
单指令多数据:一条指令产生多个并行操作
SIMD的指令多是为了处理视频、声音这类数据的执行速度
提高系统性能
可以通过增加CPU核心数
一个CPU内部
都有自己的L1 cache和L2 cache,四个CPU共享L3 cache,四个CPU核心集成在一个芯片上。
在CPU内部,程序计数器和寄存器文件这样的硬件部分有多个备份,但是像浮点运算这样的硬件部件还是只有一份。
抽象
位模式:一位一位表示数据的模式
使用二进制比较冗长,使用十进制与位模式之间的转换又比较复杂,故而使用十六进制。
字长决定了虚拟空间的大小
位运算的一个常见用法就是实现掩码运算:通过位运算可以得到特定的位序列
对于操作数 如果想要得到最低有效字节,可以与0x00 00 00 FF
几乎所有的编译器以及机器的组合都是对有符号数使用算术右移。
无符号数的最值
有符号数的最值
加法逆元
就是相反数
无符号数的逆元
有符号数的除法
汇编
gcc指的是编译器
-Og是告诉编译器生成符合原始C代码整体结构的机器代码
-O1/-O2 可以提高编译性能
-o prog表示生成可执行文件的文件名
-S 说明生成的是汇编文件
-c可以产生机器代码文件.o文件
以“.”开头的行是知道汇编器和链接器工作的伪指令
pushq 是指将寄存器rbx的值压入程序栈进行保存,是用来保存寄存器rbx的内容
movq 是将rdx的内容复制到rbx中
q 表示数据的大小
movq是将rax的值的内存地址存放在rbx中
popq 恢复寄存器rbx的内容
ret是函数返回
为什么程序一开始要保存寄存器rbx的内容?
16个通用目的寄存器
调用者保存寄存器和被调用者保存寄存器
函数A调用函数B,函数A称为调用者,函数B称为被调用者
调用者保存
被调用者保存
规定
32位的数据类型称为双字,64位数据的类型称为四字
movb表示传送字节
movw表示传送字
movl表示传送双字 long word
movq表示传送四字
汇编器是将机器代码翻译成二进制文件
objdump是反汇编工具:将机器代码翻译成汇编代码
寄存器
rax用于保存函数的返回值
rsp用于保存程序栈的结束位置
6个寄存器用于传递函数参数
操作码,操作数
$后面加上数字:代表立即数
(%rsi):表示内存引用
内存引用
有效地址
立即数要进行补码扩展
之后将32位的数据进行符号扩展到64位
当立即数是64位,目的操作数只能是寄存器
64位处理器的规定:当movl的目的操作数是寄存器时,它会将给寄存器的高4字节设置为0
即:任何位寄存器生成32位值得指令都会把寄存器的高位部分置为0
当源操作数的位数小于目的操作数,要对目的操作数剩余的字节进行0扩展或者符号位扩展
z指的是zero
第一个bbwbw是指源操作数大小
第二个wllqq指的是目的操作数大小
cltq==movslq %eax,%rax
程序栈
数据传输指令![](https://img-blog.csdnimg.cn/fdffd9cf6fc74a85877f3088c48ae042.png)
逻辑指令
leaq:加载有效地址,加法,有限的乘法运算
把有效地址复制到寄存器rax中
×去内存地址5x+7处读取数据
✔将有效地址5x+7这个值写入目的寄存器rax
源操作数可以是立即数、寄存器或者内存地址
第二个操作数可以是源操作数,也可以是目的操作数,可以是寄存器、内存地址,但不能是立即数
移位
移位指令只允许以特定的寄存器cl作为操作数。
疑惑判断a<b
跳转指令
寄存器分类
优化程序性能
内存别名使用:将两个指针可能指向同一内存位置的情况
限制可能的优化策略:两个数指向同一个内存地址、函数调用
表示程序的性能:集中精力减小CPE
循环展开:一次迭代可以得出两个元素的值
CPE:每个元素执行所需要的周期数,CPE越小表示程序执行得越快
编译器
代码移动
减少函数调用
消除函数调用
消除不必要的内存引用
现代处理器
延迟界限、吞吐量界限的CPE值
数据流图
提高并行性
2*2循环展开
1、写穿透:写入Cache,也顺便写入内存
2、写回:只写入Cache
3、写分配:把目标数据所在的块从内存加载到Cache,再写入Cache
4、写不分配:把要写的内容写到内存里
通常,23搭配,14搭配使用
链接
可重定位文件
ELF header
魔术:确认文件类型
魔术如果不正确,会拒绝加载
第七个字节表示ELF文件的版本号,通常是1
archive文件是一组可重定位目标文件的集合
三个集合:
E:存放可重定位目标文件
U:存放引用了但尚未定义的符号
D:存放输入文件中已定义的符号
重定位条目:告诉链接器在合成可执行文件时如何修改这个引用
BCD码:8421码
补码的移位是按照符号位填补的方式
IEEE 754 浮点数转换
加法器的进位生成信号
leal 6(%eax), %edx //把eax的值+6放入edx中。
decq (%rsp) //使栈顶的8字节元素-1 类似于C语言中的--
incq (%rsp) //使栈顶的8字节元素+1 类似于C语言中的++
sal $4 左移四位
sar 右移
orq |
习题汇总
第二章
进制转换
2.1 如ppt所示 2.2是求2^n在十进制和16进制中的表示
书中例子:课本例子314156转换成16进制表示——4CB2C,除法的每次余数12/2/11/12/4
2.3 进制转换题目:2/10/16
2.4 类似ppt上的“运算”
大小端
练习 2.5 show_bytes的调用三个例子——大小端
2.6 show_bytes的例子——找出整数和浮点数相同的位模式
布尔运算
2.8件ppt下部动画
2.9 三原色表示彩色的例子
逻辑位运算
2.10 用位运算实现无中间变量的交换算法。
2.11对一个数组顺序反转,其中对中间的一个元素处理有bug 额外练习:
1)对一个16位数值去低8位,请用逻辑位运算完成
2)不知道字长的情况下,生成全1掩码——例如要讲高8位清零
逻辑运算
2.14 很简单的罗吉运算
2.15用位级运算实现“==”
移位运算
2.16 简单的移位练习
整数表示
书中p42页有完整的相关“函数”和“常数”和“操作”,请关注 1)B——binary二进制 2——to转换 T——two补码(2的补码) U——unsigned无符号
B2Tw指的是二进制转补码
B2Uw指的是二进制转无符号数
-2147483647-1和-2147483648