x86

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

x86

Posted by Bruce Lee on 2023-09-11

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

-标号之后的冒号是可选的。所以下面的写法也是正确的:

1
infi jmp near infi

-把数据声明在所有指令之后,在这个地方,处理器的执行流程无法到达

-尽管在指令中访问这些数据可以使用段超越前缀“CS:”,但习惯上,通过数据段来访问它们更自然一些

-用了一个新的指令 xor 来将 DX 寄存器的内容清零

1
xor  dx,dx

-值得一提的是,尽管都可以用于将寄存器清零,但是编译后,mov dx,0 的机器码是 BA 00 00;而 xor dx,dx 的机器码则是 31 D2,不但较短,而且,因为 xor dx,dx 的两个操作数都是通用寄存器,所以执行速度最快。

-在 NASM 里,“\”是续行符,当一行写不下时,可以在行尾使用这个符号,以表明下一行与当前行应该合并为一行

-单纯的 movsw 只能执行一次,如果希望处理器自动地反复执行,需要加上指令前缀 rep(repeat),意思是 CX 不为零则重复。rep movsw 的操作码是0xF3 0xA5,它将重复执行 movsw 直到 CX 的内容为零。

-ZF标志寄存器的电路是或非门

-loop指令的底层是jmp指令来实现的,jmp指令的源操作数是一个相对于该指令的汇编地址的偏移量
通过标号减去该指令地址,减去该指令的长度来得到源操作数

-在 8086 处理器上,如果要用寄存器来提供偏移地址,只能使用 BX、SI、DI、BP,不能使用其
他寄存器
原因很简单,寄存器 BX 最初的功能之一就是用来提供数据访问的基地址,所以又叫基址寄存器(Base Address Register)。之所以不能用 SP、IP、AX、CX、DX,这是一种硬性规定,说不上有什么特别的理由。而且,在设计 8086 处理器时,每个寄存器都有自己的特殊用途,比如 AX 是累加器(Accumulator),与它有关的指令还会做指令长度上的优化(较短);CX 是计数器(Counter);DX 是数据(Data)寄存器,除了作为通用寄存器使用外,还专门用于和外设之间进行数据传送;SI 是源索引寄存器(Source Index);DI 是目标索引寄存器(Destination Index),用于数据传送操作,我们已经在 movsb 和 movsw 指令的用法中领略过了。

1
2
add ax,1
inc ax

后者的机器码更短

-8086处理器中,有neg指令,用于将寄存器/内存单元中的内容取反

-扩展cbw指令和cwd指令,用于扩展有符号数

-尽管有符号数的最高位通常称为符号位,但并不意味着它仅仅用来表示正负号。事实上,通过上面的讲述和实例可以看出,它既是数的一部分,和其他比特一起共同表示数的大小,同时又用来判断数的正负。

-几乎所有的处理器指令既能操作无符号数,又能操作有符号数。但是,有几条指令除外,比如除法指令和乘法指令

-div是无符号除法指令,因为有符号和无符号的执行结果不一样,而idiv是针对有符号除法指令(乘法也是无符号指令)

-十进制数-3904 的 16 位二进制形式和 32 位二进制形式是不同的。前者是 0xf0c0,后者是 0xfffff0c0。还记得 cwd 吗?

ax,0xf0c0
1
2
3
cwd
mov bx,0x10
idiv bx

-将数字 0x04 传送到寄存器 AH。0x04 是显示属性,即前面讲过的黑底红字,无加亮,无闪烁。到此,AX 中是一个完整的字,前 8 位是显示属性值,后 8 位是字符的 ASCII 码.因为x86是小端字节序

-指令 jns show 的意思是,如果未设置符号位,则转移到标号“show”所在的位置处执行。如图 6-2 所示,Intel 处理器的标志寄存器里有符号位 SF(Sign Flag),很多算术逻辑运算都会影响到该位,比如这里的 dec 指令。如果计算结果的最高位是比特“0”,处理器把 SF 位置“0”,否则 SF 位置“1”。

-奇偶校验不再是主要的错误检测方法。现代计算机系统更倾向于使用更强大和可靠的错误检测和纠正机制,
如循环冗余校验(CRC)和海明码。因此,在现代编程和系统开发中,奇偶标志位的使用并不常见。

-CF 标志始终忠实地记录进位或者借位是否发生,但少数指令除外(如 inc 和 dec)

-在汇编语言源代码里,条件转移指令的操作数是标号。编译成机器码后,操作数是一个立即数,
是相对于目标指令的偏移量。在 16 位处理器上,偏移量可以是 8 位(短转移)或者 16 位(相对近
转移)

-NASM编译器提供了一个标记“$”,该标记等同于标号,你可以把它看成是一个隐藏在当前行行首的标号。因此,jmp near $的意思是,转移到当前指令继续执行,它和infi: jmp near infi是一样的,没有区别,但不需要使用标号,更不必为给标号起一个有意义的名字而伤脑筋。

-or也能做出加法指令的效果!

-and 指令执行后,OF 和 CF 位被清零,SF、ZF、PF 位的状态依计算结果而定,AF 位的状
态未定义

-push pop指令都不影响任何标志位

-使用sp时,默认段寄存器是ss,使用bp时,也是ss

最安全的堆栈,是另起一个64KB的空间,来存放堆栈空间(针对SP寄存器是16位

-BP指针的作用就是在不想破坏堆栈的状态的时候,访问压在堆栈底下的数据

立即寻址
寄存器寻址
内存寻址
-直接寻址
-基址寻址 (bx,bp)
-变址寻址 (si,di)
-基址变址寻址(bx+si,bx+di,bp+si,bp+di)

-adc指令,确实在扩展计算范围是很有用的

-和主引导扇区程序一样,操作系统也位于硬盘上。操作系统是需要安装到硬盘上的,这个
安装过程不但要把操作系统的指令和数据写入硬盘,通常还要更新主引导扇区的内容,好让这
块跳板直接连着操作系统。不像我们,一直用主引导扇区来显示字符和做加法

-BIOS硬件启动执行,然后加载主引导扇区到0x7c00处,然后将处理器的控制权交给主引导扇区程序,主引导扇区程序与操作系统联系

-。我们知道,编译好的程序通常都存放在像硬盘这样的载体上,需要加载到内存之后才能执行。这个过程并不简单,首先要读取硬盘,然后决定把它加载到内存的什么位置。最重要的是,程序通常是分段的,载入内存之后,还要重新计算段地址,这叫做段的重定位。

-NASM中段名称的定义,align对齐设置,段内标号汇编地址计算方式(vstart)


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 !