x86

x86编程思考过程片段(3)关于编程技巧,注意事项,指令细节

x86

Posted by Bruce Lee on 2023-10-11

-每个任务都有4GB的虚拟内存空间(线性,平坦)

-流水线技术-分解指令任务,同时差别执行(减少时钟周期个数)

-静态存储器(SRAM)是用寄存器的材料做的内存(反馈原理制作的存储电路,使用触发器)
动态存储器(DRAM),因其电容需要定时刷新,故得名动态
高速缓存采用的程序的局部性原理

-乱序执行的本质不是胡乱取指令,而是在更微小层面上的流水线技术
将指令拆分成若干细小操作,在执行该指令中的细小操作时,可以继续执行下一条指令的细小操作。
相当于该指令还没有执行完毕,就已经开始执行下一条指令了(Out-Of-Order Execution)

-寄存器重命名,任何一个逻辑寄存器如EAX,EBX等,在处理器内部有大量的临时寄存器,可以用来临时代替真实寄存器,这样可以用来优化指令执行速度

-现代处理器中,流水线操作分为很多步骤,包括取指令、译码、寄存器分配和重命名、微操
作排序、执行和引退

-分支目标预测和分支目标缓存器(处理器在执行一条指令时,已经开始处理下一条指令,当遇见跳转指令时,会付出较大的代价

-16位处理器可以允许基址寄存器+变址寄存器+8/16位偏移量来寻址

-,相同的机器指令,在 16 位模式下和 32 位模式下的解释和执行效果是不同的
我们需要在将要编译的程序前面加
bits 16[bits 16]
或者bits 32[bits 32]

-和 16 位时代一样,在 32 位处理器上,逻辑移动指令的源操作数如果是寄存器的话,则依然必
须使用 CL。同时,32 位处理器在实际执行时,要先将源操作数(在 CL 寄存器内)同 0x1F 做逻辑
与。也就是说,仅保留源操作数的低 5 位,因此,实际移动的次数最大为 31。

-push指令,可以压入32位
当压入立即数时,立即数要扩展到对应的位数,将最高位(符号位)扩展完全

-全局描述符表中,一个描述符占据8字节(段基地址占据32位,段界限占据20位)

-段基地址可以是 0~4GB 范围内的任意地址,不过,还是建议应当选取那些 16 字节对齐的地
址。尽管对于 Intel 处理器来说,允许不对齐的地址,但是,对齐能够使程序在访问代码和数据时
的性能最大化。这一点,对于那些学过计算机原理,特别是了解内存芯片组织的人来说,是最清楚
不过的。

-有些处理器指令(特权指令)只能由 0 特权级的程序来执行,为的就是安全

-有了段描述符表,规定了段界限,如果指令执行超过了规范的内存空间,或者访问了没有权限的内存空间,
处理器在硬件一级上提供了支持(发出中断信号)

-四种不同的特权级,特权级表示访问该段最低拥有的特权级程序

-P 位是由处理器负责检查的。每当通过描述符访问内存中的段时,如果 P 位是“0”,处理器就
会产生一个异常中断。通常,该中断处理过程是由操作系统提供的,该处理过程的任务是负责将该
段从硬盘换回内存,并将 P 位置 1。在多用户、多任务的系统中,这是一种常用的虚拟内存调度策
略。

-主扇区引导程序负责加载段描述符表,然后加载全局描述符表寄存器
使用lgdt指令

-GDTR寄存器中有48位,前32位是段基地址,后16位是段大小
在内存中segment_size放在低端地址,segment_address放在高端地址

-实模式和保护模式对指令的不同解读,第一:内存访问方式的不同
第二:段寄存器的存储内容不一致
第三:功能的扩展,需要更高效的解读方式

-8086 处理器的段寄存器是 16 位的,共有 4 个:CS、DS、ES 和 SS。而在 32 位处理器内,段
寄存器是 80 位的(16 位段选择器和 64 位描述符高速缓存器)。而且,在原先的基础上又增加了两
个段寄存器 FS 和 GS。

从实模式切换到保护模式,不久需要建立全局描述符表和全局描述符寄存器,还有设置A20管脚,还要通过CR0寄存器来真正切换两个模式

段的修改:
-每当改变段寄存器内容时,处理器会自动处理地址数值,将其左移4位然后放在描述符高速缓存中,以后就直接使用高缓中的内容
在实模式下,也是一样,但是实模式的地址有效是低20位的,所以在IA-32架构中,运行实模式代码,其64位的描述符高速缓存中,段地址区的
低20位是有效的,高16位是无效的,全是0.

-机器码前面加上前缀0x66,表示将操作数反向,如果原操作数是16位的,那么就变成32位,如果是32位的,就变成16位的
通常用在实模式转保护模式的时候,或者在保护模式下运行实模式代码的时候

-我们可以在16位实模式下使用32位寄存器,如eax

-我们在错误使用某些变量时,这些变量通常在初始化时为0,所以为了阻止不安全的访问,我们在索引字段为0的选择子中,全部设置为0.

-我们在主引导扇区程序中,负责将处理器工作模式从实模式转换成保护模式,这样子就决定了里面必须有两种形式的代码-16为代码和32位代码
(在一个程序中,要同时运行16位代码和32位代码)

-别名技术(运用在对代码段调试,修改代码或者多个程序共享同一个内存区域,我们便可以为灭一个程序都创建一个描述符,使他们都指向同一
内存段)

-在保护模式下,改变段寄存器,处理器的固件在转移之前会检查段选择子是否合法,如果超过GDT的界限,直接异常中断13

-然后进行描述符与段寄存器的匹配

-对于cs,ss段选择子,不可以在传送0,而es,ds,fs,gs可以

-堆栈段的保护,eip的值减去操作数的长度,与段界限比较。
由于堆栈段的保护机制的缺陷(只保护低端地址空间,无法保护高端地址空间)所以我们在选择堆栈段的段界限是,应该尽可能设在高端地址
比如:段界限:0xffffe,粒度(G)=1,
则实际段最低偏移地址是:0xffffe000+0xfff=0xffffefff
eip必须大于0xffffefff+1=0xfffff000
小于0xffffffff
则可以控制堆栈段空间大小为4KB
同时可以利用段基址的选择,循环进位的寄存器特性,选择实际的堆栈空间基地址

-32位模式下也可以使用16位寄存器来寻址

-xchg指令,用来交换两个操作数的内容

-IA-32中,处理器允许在基址寄存器的基础上使用比例因子
如:mov [es:0x0b80a0+ebx*2],ax

-在设置段描述符时,使用rol指令,bswap指令

-cmovcc指令,可以在简化一些多余的jmp指令,提升处理器运行速度

-32 位的计算
机系统建议内存地址最好是 4 字节对齐的,这样做的好处是访问速度最快

-movsx用于扩展传送
movzx同理
movzx使用0扩展
movsx使用符号位扩展

-和一般的数据段不同,堆栈描述
符中的基地址,应当是堆栈空间的高端地址。所以,第 470 行,用 allocate_memory 返回的低端
地址,加上堆栈的大小,得到堆栈空间的高端地址

-cmps指令,加快处理器比较速度


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. All the images used in the blog are my original works or AI works, if you want to take it,don't hesitate. Thank you !