浮点数在不同平台上实现不同
有的处理器有浮点运算单元(Floating Point Unit,FPU),称为硬浮点(Hard-float)实现
有的处理器没有浮点运算单元,只能做整数运算,需要用整数运算来模拟浮点运算,称为软浮点(Soft-float)实现
在 x86 平台上,大多数编译器实现的 long double 型是 80 位
gcc 实现的 long double 型是 12 字节(96 位)
C 中有转换级别机制,以下类型转换级别(Rank)越来越高:char、short、int、long、long long
避免不同类型数值赋值操作;
因为 C 语言中不存在 8 位整数的二进制位运算,所有位运算执行之前都被提升为 int 类型
在一定的取值范围内
左移 1 位=乘以 2
右移 1 位=除以 2
一个数和自己做异或的结果是 0
和 0 做异或保持原值不变,和 1 做异或得到原值的相反值
可用于奇偶校验:例如 a1 ^ a2 ^ a3 ^ … ^ an 的结果是 1,则表示 a1、a2、a3…an 之中 1 的个数为奇数个,否则为偶数个
x ^ x ^ y == y
CPU 的核心功能包括这部分
内存映射 LO 定义
无论是在 CPU 外部接总线的设备还是在 CPU 内部接总线的设备都有各自的地址范围,都可以像访问内存一样访问
MMU 工作原理
CPU 发出获取内存地址请求,此时传递虚拟地址 VA
给 MMU,MMU 将 VA 转换成物理地址 PA
给 CPU 外部的指定芯片引脚
如果 MMU 不工作,那么 CPU 发出的内存地址请求均为 PA,直接对应外部芯片引脚
MMU 管理一张虚拟页表,一一对应物理内存上的物理页表内容
每次 CPU 访问内存时,都会触发 MMU 的查表和地址转换操作
MMU 存在的意义
汇编程序根据编译器的不同,使用 asm 或者 s 作为后缀;
首先要将汇编源文件使用汇编器翻译成机器指令,生成后缀为 o 的文件,然后再通过链接器编译成可执行文件
.section .data
.section .text
.globl _start
_start:
movl $1,%eax #this is the Linux kerneL command
movl $4,%ebx #this is the status number we wiLL
int $0x80 #this wakes up the kerneL to run
#
汇编中表示单行注释
汇编程序中以.开头的名称并不是指令的助记符,不会被翻译成机器指令,而是给汇编器一些特殊指示,称为汇编指示(Assembler Directive)
或伪操作(Pseudo-operation)
.section .text
section 表示开始划分段的标志,text 表示后续的代码都属于 text 段
.globl
可理解为设置全局变量
_start
汇编程序入口点,必须被设置为全局变量
_start:
在这里开始写主入口程序
movl $1,%eax
movl 其实是 mov+l 的结合,l 表示该变量类型为 long
1 表示立即数 1 ( 1 表示立即数1( 1表示立即数1(加任意数字都可以表示一个立即数)
%eax 表示寄存器 eax(所有寄存器都必须加%)
不难得出移位的格式为 movl [立即数],[欲保存到的寄存器]
int $0x80
软中断指令,可使程序故意产生一个异常导致程序终止运行;可以将其视为程序出口点
x86 汇编存在两种主流语法:
movl $1,%eax
mov eax,edx
(寄存器不加%且存取位置互换)x86 通用寄存器:eax、ebx、ecx、edx、edi、esi
某些特殊场景下,他们会变得不那么“通用”,此时寄存器会有一个或者多个限制
(比如进行除法运算时)
x86 特殊寄存器:ebp、esp、eip、efLags
efLags 保存着计算过程中产生的标志位
ebp 和 esp 用于维护函数调用的栈帧
# 定义数据存储段data
.section .data
# 类似于数组名
data_items:
# 定义数组类型,.long表示32位,.byte表示8位
.long 3,67,34,222,45,75,54,34,44,33,22,11,66,0
# 主程序段text
.section .text
# 程序入口点与全局变量
.globl _start
_start:
movl $0,%edi #move 0 into the index register
movl data_items(,%edi,4), %eax # Load the first byte of data
movl %eax,%ebx #since this is the first item,%eax is
# 循环开始,开头定义一个start_loop
start_loop:
cmpl $0,%eax # 比较寄存器eax是否等于0,如果为0表示已到末尾,需要跳出循环
je loop_exit # je即比较,如果上方代码相等,那么跳转到对应标志位
incl %edi # edi寄存器移到下一位(即加载下一个数据)
movl data_items(,%edi,4), %eax
cmpl %ebx,%eax
jle start_loop # jle(jump if less than or equal)
movl %eax,%ebx
jmp start_loop # jmp是一个无条件跳转指令,类似c语言中的default
# 循环结束,结尾定义一个loop_exit
loop_exit:
movl$1,%eax
int $0x80
访问内存的三个方式:数组基地址、元素长度和下标
内存寻址指令的通用格式:ADDRESS_OR_OFFSET(%BASE_OR_OFFSET,%INDEX,MULTIPLIER)
几种主要的寻址方式
UNIX 可执行文件均采用 ELF 格式,它包含以下三种类型
程序简易的汇编、链接、运行流程