Assembly-3
汇编语言学习笔记-3
0x00 其他的转移指令
ret与retf
ret使用栈中的数据,来修改IP的内容,来实现近转移(段内转移)。操作如下所示:
1 | (ip)=((ss)*16+(sp)) |
执行ret指令时,相当于进行:pop ip
。
retf则是修改cs和ip的内容,实现远转移(段间转移)。操作如下所示:
1 | (ip)=((ss)*16+(sp)) |
当执行retf指令时,相当于进行:pop ip; pop cs
。
Q&A
补全程序,实现从内存1000:0000
处开始执行指令。
1 | mov ax, 1000H |
call 指令
call指令的执行流程:(1)将当前IP或CS:IP压入栈中。(2)转移。
注意,call指令不能实现短转移(8位长),除此之外,call与jmp指令原理相同。
call 标号
(段内转移)
功能:将当前ip压入栈中,再转到标号处执行指令。相当于:
1 | (sp)=(sp)-2 |
用汇编语言,相当于进行:
1 | push ip |
举例:
1 | ax=6 |
- call的段间转移为:
call far ptr 标号
,如下所示:
1 | (sp)=(sp)-2 |
用汇编语言,相当于:
1 | push cs |
Q&A
1 | ax=1010H |
call word ptr 内存单元地址
汇编相当于:
1 | push ip |
1 | (ip)=0123H |
call dword ptr 内存单元地址
汇编相当于:
1 | push cs |
1 | (cs)=0H |
1 | (1)注:需要说明的是,第一个inc ax相对于start偏移为11h |
call与ret的配合使用
1 | bx=8 |
1 | ; 假设程序从内存1000:0装入 |
0x01 mul指令
例如,mul byte ptr ds:[0]
意思就是(ax)=(al)*(ds*16+0)
;mul word ptr [bx+si+8]
意思就是(dx)=(ax)*((ds)*16+bx+si+8)的高16位
,(ax)=(ax)*((ds)*16+bx+si+8)的低16位
。
Q&A
1 | (ax)=1000 |
1 | (dx)=0FH |
0x02 函数参数与返回值的传递
用寄存器存储参数与结果。
Q&A
1 | assume cs:code, ds:data |
但是,如果要传递特别特别多参数呢?或者传回的数据是一个字符串呢?
将参数放到内存中,然后将它们所在内存空间的首地址放到寄存器上,并传递给需要的子程序。
1 | assume cs:code, ds:data |
注:用栈来传递参数。
1 | assume cs:code, ss:stack, ds:data |
下面给出一个示例程序,看看有何问题:
问题就是captial会改变cx的值,因此会影响s循环,这就是寄存器冲突,如何解决呢?在子程序的开始将子程序中所有用到的寄存器中的内容都保存起来,在子程序返回前再恢复。我们可以用栈来保存寄存器中的内容。那么,子程序的标准框架就是:
0x03 标志寄存器
8086CPU的标志寄存器有16位,其中存储的信息通常叫做程序状态字(PSW:Program Status Word)。
flag寄存器
ZF标志(zero flag)
零标志位。ZF记录相关指令执行后,结果是否为0。结果如果为0,那么ZF=1,否则ZF=0。举例如下:
注:运算指令如add|sub|mul|div|inc|or|and
对标志寄存器有影响,而传送指令如mov|push|pop
对标志寄存器没有影响,inc与loop不影响CF位。
PF标志(partial flag)
奇偶标志位。PF记录指令执行后,结果二进制中1的个数。若PF=1,则为偶数,否则PF=0。举例如下:
SF(sign flag)
符号标志位。进行有符号数计算时,执行指令后,结果为负,SF=1,否则SF=0。SF总会按照有符号数计算结果来影响SF标志位。
有符号数与无符号数如下所示:
CF(carry flag)
进行无符号数计算时,记录了运算结果的最高有效位向更高位进位值,或从更高位的借位值。CF来记录这个进/借位信息。举例如下:
OF(overflow flag)
有符号数运算时发生溢出会导致运算结果不正确,这记录在OF中,发生溢出时OF=1,否则OF=0。如下所示:
Q&A
1 | CF| OF| SF| ZF| PF |
补充
- adc指令。表示带进位的加法指令,其利用了CF位上记录的进位值。例如
adc ax, bx
表示(ax)=(ax)+(bx)+CF
。举例如下:
可能会疑问,adc指令到底有什么用?
add ax, bx
其实等价于add al, bl; adc ah, bh
。那么,adc指令和add指令相配合就可以对更大(数位更宽)的数据进行加法运算(例如32位宽mov数据加法)。
1 | mov bx, 0F000H |
1 | mov cx, 1000H |
1 | assume cs:code, ds:data |
- sbb指令。带借位(CF位)的减法指令。例如
sbb ax, bx
表示(ax)=(ax)-(bx)-CF
1 | sub ax, ax ; 设cf=0 |
- cmp指令。
cmp 操作对象1, 操作对象2
,计算操作对象1-操作对象2
,并将结果设置标志寄存器。举例如下:
对于无符号数而言,有:
注:例如cmp ah, bh
,SF=1不等价于(ah)<(bh)
对于有符号数而言,有:
0x04 条件转移指令
对于无符号数而言:
1 | cmp ah, bh |
1 | (ax)=1 |
1 | (1) |
其他的条件转移指令:
Q&A
1 | jb s0 |
0x05 DF标志与串传送指令
是方向标志位。若DF=0,那么每次操作后si、di递增,若DF=1,那么si、di递减。
与之配套的是movsb指令,其以字节为单位传送,即将ds:si指向的内存单元中的字节送入es:di中,然后根据标志寄存器DF位的值,将 si和di递增或递减1。可以描述为:
1 | ((es)*16+(di))_byte=((ds)*16+(si))_byte |
还有movsw指令,是以字为单位传送。
movsw与movsb指令通常配合rep指令使用。rep指令的作用是根据cx的值,重复执行后面的串传送指令,如下所示:
看几个题:
1 | mov ax, data |
1 | mov ax, data |
补充:
pushf :将标志寄存器的值压栈;popf :从栈中弹出数据,送入标志寄存器中。
pushf 和 popf为直接访问标志寄存器提供了一种方法。
Q&A
1 | (ax)=0000000001000101B |
留言
- 文章链接: https://wd-2711.tech/
- 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明出处!