x86

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

x86

Posted by Bruce Lee on 2023-09-23

-它仅仅是编译阶段确定的汇编地址,在用户程序加载到内存后,需要根据加载的实际位置重新计算(浮动)。

-,因为主引导程序的实际加载地址是0x0000:0x7c00,当我们引用一个标号时,还得手工加上那个落差 0x7c00使用vstart子句

-不管是什么设备,都必须通过它自己的 I/O 接口电路同 ICH相连

-端口的数据宽度又设备商决定

-端口访问采取映射或M/IO#总线电路(独立编制)

-独立编制中,in指令的目的操作数必须是al或ax,源操作数应当是dx因为 in 指令不允许使用别的通用寄存器,也不允许使用内存单元作为操作数(in指令的机器码简短)

-in指令的两字节形式,意味着端口的数量最多只能用一个字节来定位,故只能访问0~255号端口

-in 指令不影响任何标志位

-端口号可以放在dx中

-out指令与in指令同理

-磁盘读写时LBA模式,目前是LBA23模式

-一台机器一次读写的数据量,都是由其记录这个数据的寄存器位数所决定的。本机器在记录要读取的扇区数量的0x1f2端口是一个8位端口,因此只能读取255个扇区

-所谓的过程调用,这个过程就是例程的意思

-call指令中没有任何关键字,则编译器默认是近调用,近调用和jmp近转移原理一致

-call相对近调用:call+标号/call+内存数值(当前代码段相对偏移地址)
call间接绝对近调用:call+寄存器/call+内存地址(当前代码段汇编地址)
以上可省略关键词near
直接绝对远调用:call+绝对地址
偏移地址在前,段地址在后
处理器在执行时,首先将代码段寄存器 CS 的当前内容压栈,接着再把指令指针寄存器 IP 的当
前内容压栈。紧接着,用指令中给出的段地址代替 CS 原有的内容,用指令中给出的偏移地址代替
IP 原有的内容
间接绝对远调用:call+far+内存地址/寄存器

-处理器在执行相对偏移地址时,用指令指针寄存器 IP 的内容加上指令中的偏移量,以及当前指令
的长度,算出被调用过程的绝对偏移地址

-ret:近返回指令(从堆栈中弹出一个字到IP)
retf:远返回指令(弹出两个字,给IP,CS)

-call 指令在执行过程调用时不影响任何标志位,
ret/retf 指令对标志位也没有任何影响。

-表号是数值,是一个内存偏移地址的数值,是指向一个地址的指针(曾经被搞糊涂了,错把表号当成类似宏了)

-shr或shl指令的原操作数是8位立即数或者是寄存器cl

-注意,源操作数为 1 的逻辑右移指令是特殊设计的优化指令,比如以上的 shr ax,1,它的机器码是 D1 E8;而类似的指令 shr ax,5则拥有完全不同的机器码 C1 E8 05。

-ror和orl是循环移动指令

jmp指令
相对短转移8:(也是偏移量,机器码仅两个字节,后一个字节为偏移量,大小为-128~127,使用关键字short)
相对短转移指令的汇编语言操作数只能是标号和数值
相对近转移16:(偏移量,3字节,大小为-32768~32767,使用关键字near)
间接绝对近转移16:(可省略near,使用bx,cx,内存来存储绝对汇编地址)
直接绝对远转移16:jmp 段:偏移,机器码中,前面的是ip,后面的cs
间接绝对远转移16:在内存中存放地址,小端是偏移,大端是段地址

-用户程序开始执行后,先初始化自己的各个段寄存器,但是cs寄存器不用初始化,这是加载器要做的事

-伪指令 resb(REServe Byte)的意思是从当前位置开始,保留指定数量的字节,但不初始
化它们的值
(resw,resd)

-各个段寄存器的初始化顺序很重要。如果先初始化数据段和附加段,那
么,段 header 中的数据将无法访问

-现代处理器都支持直接压入立即数

-非屏蔽中断,通过NMI信号线引脚来传输信号

-几乎所有触发 NMI 的事件对处理器
来说都是致命的,甚至是不可纠正的

-也正是这个原因,在实模式下,NMI 被赋予了统一的中断号 2,不再进行细分。一旦发生 2 号
中断,处理器和软件系统通常会放弃继续正常工作的“念头”,也不会试图纠正已经发生的问题和
错误,很可能只是由软件系统给出一个提示信息。

-可屏蔽中断通过INTR引脚传输信号

-Inerl处理器8259中断代理芯片(可编程中断控制器)

-中断向量表中,偏移地址在前,段地址在后

-中断返回iret

-INTR中断,处理器会从8259获得中断号,但是在NMI中断中,处理器会自己生成2号中断,

-BIOS在初始化中断向量表时,有些不知道中断处理程序的向量,会默认指向一个程序地址,这里之后iret指令等待着

-为什么在访问RTC时,阻断NMI信号?
RTC是一个高精度设施,用于追踪时间,日期,还可以用于定时,设置闹钟,
我们在访问RTC时,应该具有连贯性,将某一个近时间距离的时间信息读取。如果在访问RTC时,出现了NMI中断,会导致时间精度下降,出现错误
时间数据不准确

-hlt指令,让处理器处于停机状态,可以被外中断唤醒以使其继续执行后面的指令

-not指令,使一个字节或字反转(不影响任何标志位)

-test指令用于测试寄存器和内存中某一个bit位的值,通过影响标志寄存器来反馈,同时不影响目的操作数和源操作数的值

-中断控制器内部的中断服务寄存器(8位),对应着各自的引脚,当中断处理结束时,在中断处理程序的最后,需要明示的向中断服务寄存器发送清零,以使中断服务寄存器能在下一次中断来临时,能够接受中断,向处理器发送中断信号

-非法指令产生中断6内部中断不受标志寄存器IF的影响,其中断类型是固定的,可以立即转入相应的处理程序一般外部中断会收到中断总线周期的影响,总线通信时,存在一定的时间周期

-外部中断(处理器外部的硬件中断)
内部中断
软中断(无需中断识别总线周期)

-int3,断点中断指令(与int 3指令不同)

-into溢出中断指令,当执行这条指令时,如果OF位为1,则产生4号中断,否则什么也不做

-可以为所有的中断类型自定义中断处理过程,包括内部中断、硬件中断和软中断

-从内存物理地址 A0000 开始,到 FFFFF 结束,有相当一部分空间是留给外
围设备的

-在计算机启动期间,BIOS 程序会以 2KB 为单位搜索内存地址 C0000~E0000 之间的区域。当
它发现某个区域的头两个字节是 0x55 和 0xAA 时,那意味着该区域有 ROM 代码存在,是有效的。
接着,它对该区域做累加和检查,看结果是否和第三个单元相符。如果相符,就从第四个单元进入。
这时,处理器执行的是硬件自带的程序指令,这些指令初始化外部设备的相关寄存器和工作状态,
最后,填写相关的中断向量表,使它们指向自带的中断处理过程

32位intel微处理器编程架构

-不管在16为模式下,还是在32为模式下,ip和eip寄存器都不能直接通过汇编代码修改,而是通过某些指令隐式的修改

-当程序访问一个段时,处理器将用固件实施各种检查工作,以防止对内存的违规访问。

-不过,它也提供了一种变通的方案,即,只分一个段,段的基地址是 0x00000000,段的长度(大
小)是 4GB。在这种情况下,可以视为不分段,即平坦模型(Flat Mode)。

-在32位模式下,传统的段寄存器cs,ds,ss,es中存储的不是段基地址,而是段选择子(选项位于描述符高速缓存器(64位)中,里面是段基地址
和访问属性)

-额外添加FS,GS段寄存器

-80286的段寄存器也是16位的,但是地址线有24位,段地址存储在段寄存器的描述符高速缓存中(最早提出保护模式(16位保护模式)

-为了充分发挥处理器的性能,我们支持多任务,为每一个任务分配空间,当A任务在执行过程中出现了指令“停止”,处理器可以去执行另一个任务。
多处理器,就可以同时处理多个任务。
我们在给任务分配空间的时候,大型任务就分配多一点空间,小型任务就分配小一点空间,这是合理的,高效的。
但是时间长了之后,内存空间就会碎片化,导致的结果就是,总内存空闲空间是充足的,但是不支持给一个大型程序分配足够的空间。
于是页模式诞生

-页大小是4KB


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 !