过程P调用Q的机制:
传递控制:在进入过程Q的时候,程序计数器必须被设置为Q的代码的起始地址,然后再返回时,要把程序计数器设置为P重调用Q后面那条程序的地址
传递数据:P必须能够向Q提供一个或多个参数,Q必须能够像P返回一个值
分配和释放内存:在开始时,Q可能需要为局部变量分配空间,而在返回时,需要释放这些空间
运行时栈
在 x86-64 中,所谓的栈,实际上一块内存区域,这个区域的数据进出满足先进后出的原则。越新入栈的数据,地址越低,所以栈顶的地址是最小的。下图中箭头所指的就是寄存器 %rsp 的值,这个寄存器是栈指针,用来记录栈顶的位置。
我们假设一开始 %rsp 为红色,对于 push 操作,对应的是 pushq Src 指令,具体会完成下面三个步骤:
从地址 Src 中取出操作数
把 %rsp 中的地址减去 8(也就是到下一个位置)
把操作数写入到 %rsp 的新地址中
这个时候 %rsp 就对应蓝色。
重来一次,假设一开始 %rsp 为红色,对于 pop 操作,对应的是 popq Dest 指令,具体会完成下面三个步骤:
从 %rsp 中存储的地址中读入数据
...
条件码条件码寄存器(Condition Code Register),在 x86-64 架构中,也被称为 EFLAGS 寄存器,用于存储 CPU 执行算术或逻辑运算后的状态信息。这些状态信息由一组 条件码(condition flags)表示,通常用于判断运算结果并进行条件分支跳转。
条件码寄存器的主要用途:
保存运算结果的状态:每当 CPU 执行加法、减法、乘法、除法、比较等运算时,条件码寄存器会根据运算结果自动更新某些标志位。
用于条件跳转:汇编中的条件跳转指令(如 jz、jnz、jl 等)通过检查条件码寄存器中的标志位来决定程序执行的下一步操作。
主要的条件码标志位:条件码寄存器中有几个位用于表示算术或逻辑操作后的状态,以下是最常见的几个标志位:
条件码是隐式设置的,即不需要一条指令设置条件码,其在算术运算后自动设置(带来的电路的增多)
CF(Carry Flag,进位标志):
在无符号运算中,进位标志用于表示加法时最高位发生了进位或减法时借位。
置位条件:如果执行加法时有进位,或减法时发生了借位,则 CF 被设置为 1。
使用场景:无符号运算中的溢出检测。
C语言表示: ...
前言处理器架构处理器架构(Processor Architecture)是指计算机处理器内部的设计框架或蓝图,它定义了处理器如何执行指令、管理数据、通信等一系列操作。处理器架构是计算机硬件和软件之间的桥梁,决定了处理器如何与操作系统、编译器以及程序交互。
关键组成部分:
指令集架构(ISA):
指令集架构是处理器架构的核心部分,定义了处理器可以理解和执行的基本指令。例如,x86 和 ARM 是两种常见的指令集架构。
它包括指令的操作码(操作类型)和操作数(需要处理的数据)。ISA 还定义了寄存器的数量和大小、内存访问模式以及数据类型等内容。
寄存器和内存模型:
不同的处理器架构定义了不同的寄存器数量和大小。寄存器是处理器内部用于快速存储和处理数据的高速存储器。
内存模型决定了处理器如何与内存通信,例如是采用分段式、分页式内存管理等。
并行处理能力:
现代处理器架构通常支持多核和多线程,允许多个任务并行处理。架构设计决定了处理器如何调度这些任务和共享资源。
扩展和特性:
处理器架构还可以决定一些高级特性,如虚拟化支持、加密加速、浮点计算能力、低功耗设计等。
...
浮点数二进制小数简而言之,就是原来的整数多了个小数点。
浮点数可以这样表示:$$\sum_{k=-j}^{i}b_{k}\times\ 2^{k}$$例如:$$5\frac{3}{4}=101.11_{2},2\frac{7}{8}=10.111_{2},1\frac{7}{16}=1.0111_{2}$$这样的好处是,除以二就相当于右移,并且可以横跨小数点。
但是这种表示方式有明显的限制,比如说,只有形如$$\frac{x}{2^{k}}$$可以被精确表示,其他的就只能变成循环的小数,例如$$\frac{1}{3}=0.0101010101[01]…_{2}$$除此之外,另一个问题在于,如果给定了 w 个比特,能够表达的数字其实是有限的.
IEEE浮点数
IEEE 的浮点数标准更多是从数值角度来建立的,对于舍入,上溢出和下溢出都有比较统一的处理方法。但与此同时也给硬件优化带来了比较大的困难。因为和平时使用的数制也有一定差异,从理解的角度来看不够直观,但是好在主流的 CPU 都支持浮点数,所以我们不必过多涉及这方面的细节。
IEE ...
为什么学习这本书很多东西并不像看起来那样简单比如:
算法性能分析结果$\neq$实际程序性能(底层实现问题)
计算机系统中的算术$\neq$数学中的算术(溢出问题)
我们知道,在纸面上看$$ (x+1)^2≥0$$
是一定的,但是在计算机中就不一定了,比方说:
$ lldb(lldb) print (233333 + 1) * (233333 + 1)(int) $0 = -1389819292
这就是整数的溢出,当然用浮点数的表示方法可以避免溢出,但是浮点数有精度问题
# dawang at wdxtub.local in ~ [9:05:02]$ lldb(lldb) print (1e20 + -1e20) + 3.14(double) $0 = 3.1400000000000001(lldb) print 1e20 + (-1e20 + 3.14)(double) $1 = 0
你了解内存吗?我们都学过的C或者C++都没有提供任何内存保护机制,再加上强大且危险的指针,出现溢出或者段错误实在是家常便饭。这类问题的问题在于,很难确定是程序本身的问题,还是编 ...