输出两行1 9 3
or 30h
是为了转换为\(ASCII\)码输出。 \(30h\) 是ASCII中 \('0'\) 的编号,其二进制形式为:\(0011 0000\) ,所以or上一个 \(30h\) 表示输出从'0'开始偏移量为1 9 3的数字
如果 or 61h
,则输出的是偏移量减去 \(1\) 的小写字母。( \(61h\) 是 \(0110 0001\) ,从1开始)
$
是预定义符号,表示当前的偏移地址,使用 jmp $
,可以进入死循环。
反汇编查看机器码,可以看到其机器码为 \(E2F2\)
\(E2\) 表示LOOP
\(F0\) 是补码形式的位移量, \(F2\) 转换为二进制为 \(11110010\)
将其转换为原码 \(1!(1110010-1) = 1!(1110001) = 10001110 = -8+-4+-2=-14\)
所以其位移量为 \(-14\) 。当前ip为 \(0x19\) ,即 \(25\) ,\(25-14=11\)
但是s1处的偏移量为 \(D\) ,即 \(13\) 。
所以整个转移的过程如下
ip指向 \(25\) 偏移处的指令,先取指令,然后ip自动 \(+2\) ,变为 \(27\) ,然后执行指令的过程中,将ip减去 \(14\) ,得到 \(13\) ,那么下一条要执行的指令就在偏移量为 \(13\) 的地方,即s1标号处。
重复问题1的操作步骤。
\(F0\) 的二进制形式为: \(11110000\)
得到其原码: \(1!(1110000-1) = 1!(1101111) = 10010000 = -16\)
为什么指令数量相同,但是位移量不同?原因出在inc
和add
的指令占字节数不同。8086汇编采用动态指令长度,所以每条指令的长度都不是相同的。所以这里会有位移量的不同。
CPU计算得到s2之后指令的地址方式和问题1一样,这里不重复描述。
assume cs:code, ds:data data segment dw 200h,0h,230h,0h data ends stack segment db 16 dup(0) stack ends code segment start: mov ax,data mov ds,ax mov word ptr ds:[0],offset s1 mov word ptr ds:[2],offset s2 mov ds:[4],cs mov ax,stack mov ss,ax mov sp,16 call word ptr ds:[0] ;push ip ;jmp word ptr ds:[0] s1: pop ax ;(ax) = stack.top() = offset line23 + size(line23) = offset s1 call dword ptr ds:[2] ;push cs ;push ip ;jmp dword ptr ds:[2] s2: pop bx ;(bx) = stack.top() = offset line28 + size(line28) = offset s2 pop cx ;(bx) = stack.top() = cs = code mov ah,4ch int 21h code ends end start