戏++ 发表于 2016-7-22 10:36:13

王爽测试10.5 问题

assume cs:code
stack segment
        dw 8 dup (0)
stack ends

code segment
        start:mov ax,stack
                  mov ss,ax
                  mov sp,16
                  mov ds,ax
                  mov ax,0
                  
                  call word ptr ds:
                  inc ax
                  inc ax
                  inc ax
                  
                  mov ax,4c00h
                  int 21h
        code ends
end start
;答案:ax=3
;分析:
;1、本题stack段用 dw 8 dup (0)定义了16字节内存为0的栈段,所以ds:~ds:的内存单元全部为0,当然,ds:单元的内存自然就为0了!
;2、本题ds=ss,也即数据段与栈段于同一段内,sp=16,指向栈顶,当指令执行到call word ptr ds:这条指令的时候,相当于进行了:

;(1)PUSH IP(此时IP的值为CALL语句下一条语句的偏移地址,也就是INC AX的偏移地址),由于初始栈顶指针指向16,所以push ip执行时,选将指针进行了ip=ip-2的操作,使ip指向14,也就是0eh,再将call word ptr ds:的下一条指令INC AX的偏移地址入栈到oeh处 ;
;(2)JMP WORD PTR SS(因为DS等于SS):,此时程序跳转到CS:(SS:)处执行,因为 SS:的值为0,所以跳转到CS:0处开始执行,也就是程序的第一条语句MOV AX;
;(3)当程序再一次执行到call word ptr ds:时,指针将跳转到ds: ,而此时的:处的值已经不是0了,它已变成上次执行call时被压栈的INC AX处的移地址,它使执行call word ptr ds:的跳转直接跳到指令inc,ax处,连续3次inc 后,AX的值为3.



下面的答案是网上找的
第一步是说在ds: 处存储了call 的以一条指令的地址
第二步为啥说 ds: 为 0 ,不应该啊?

人造人 发表于 2016-7-22 17:10:37

"第一步是说在ds: 处存储了call 的以一条指令的地址"
怎么理解,你那里不明白吗?

一开始 ds: 的确是0
执行完 call word ptr ds: 后改变成了call word ptr ds:下一条指令的偏移地址 (是执行完以后改变的)

我亲自调试过,上面的分析是正确的

这是我的调试过程,可能会帮到你
(0) context not implemented because BX_HAVE_HASH_MAP=0
f000:fff0 (unk. ctxt): jmp f000:e05b             ; ea5be000f0
<bochs:1> b 0x 7c00
..\bochsdbg.exe:1: syntax error at 'x'
<bochs:2> b 0x7c00
<bochs:3> c
(0) Breakpoint 1, 0x7c00 in ?? ()
Next at t=2393208
(0) 0000:7c00 (unk. ctxt): mov ax, 0x7c0             ; b8c007
<bochs:4> set $ip=0
Error: set: unrecognized symbol.
<bochs:5> info reg
eax            0xaa55         43605
ecx            0x100001         1048577
edx            0x80             128
ebx            0x80             128
esp            0xfffe         0xfffe
ebp            0x0            0x0
esi            0x0            0
edi            0xffe4         65508
eip            0x7c00         0x7c00
eflags         0x282            642
cs             0x0            0
ss             0x0            0
ds             0x0            0
es             0x0            0
fs             0x0            0
gs             0x0            0
<bochs:6> set $eip=0
<bochs:7> set $cs=0x7c0
<bochs:8> s
Next at t=2393209
(0) 07c0:0003 (unk. ctxt): mov ss, ax                ; 8ed0
<bochs:9>
Next at t=2393210
(0) 07c0:0005 (unk. ctxt): mov sp, 0x25            ; bc2500
<bochs:10>
Next at t=2393211
(0) 07c0:0008 (unk. ctxt): mov ds, ax                ; 8ed8
<bochs:11>
Next at t=2393212
(0) 07c0:000a (unk. ctxt): mov ax, 0x0               ; b80000
<bochs:12>
Next at t=2393213
(0) 07c0:000d (unk. ctxt): ds call word ptr ; 3eff162300 // 第一次执行
<bochs:13>
Next at t=2393214
(0) 07c0:0000 (unk. ctxt): mov ax, 0x7c0             ; b8c007 // 这里执行回到一开始的mov ax, 0x7c0             ; b8c007
<bochs:14>
Next at t=2393215
(0) 07c0:0003 (unk. ctxt): mov ss, ax                ; 8ed0
<bochs:15>
Next at t=2393216
(0) 07c0:0005 (unk. ctxt): mov sp, 0x25            ; bc2500
<bochs:16>
Next at t=2393217
(0) 07c0:0008 (unk. ctxt): mov ds, ax                ; 8ed8
<bochs:17>
Next at t=2393218
(0) 07c0:000a (unk. ctxt): mov ax, 0x0               ; b80000
<bochs:18>
Next at t=2393219
(0) 07c0:000d (unk. ctxt): ds call word ptr ; 3eff162300 //第二次执行
<bochs:19>
Next at t=2393220
(0) 07c0:0012 (unk. ctxt): inc ax                  ; 40 //因为第一次执行 call word ptr 时,堆栈段偏移 0x23 的值已经是这条指令的地址
<bochs:20>
Next at t=2393221
(0) 07c0:0013 (unk. ctxt): inc ax                  ; 40
<bochs:21>
Next at t=2393222
(0) 07c0:0014 (unk. ctxt): inc ax                  ; 40
<bochs:22>
Next at t=2393223
(0) 07c0:0015 (unk. ctxt): add byte ptr ds:, al ; 0000
<bochs:23>



这是我用bochs调试的
这是程序源码
        mov ax,0x07c0
        mov ss,ax
        mov sp,stack + 16
        mov ds,ax
        mov ax,0

        call word

        inc ax
        inc ax
        inc ax

stack:       
        resb 16

       times 510-($-$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为   
        dw 0xaa55 ; 结束标志
你如果要自己调试,请修改cs,eip的值(没错,是eip,bochs没有ip寄存器)
cs修改为 0x7c0
eip修改为 0
具体方法看我调试过程
页: [1]
查看完整版本: 王爽测试10.5 问题