能力值:
(RANK:350 )
|
-
-
2 楼
------
|
能力值:
( LV2,RANK:10 )
|
-
-
3 楼
初步看法:
你在
mov sp,0
add sp,4
时已初始化栈顶,SP里是4(0004h)
后面接着就
pop ax ;AV《——(SS:0004h,SS:0005h)
pop bx ; BX《——(SS:0006h,SS:0007h)
问题应该出在这,更深更详细的回答就待大佬们了。。。
|
能力值:
( LV9,RANK:180 )
|
-
-
4 楼
|
能力值:
( LV2,RANK:10 )
|
-
-
5 楼
老大,我想问的是为什么是"为什么我的SP=0004,不是说SS:SP永远指向栈顶吗,那么,当堆栈满时,SS:SP也应该为2000:0000为什么,而我看DEBUG在SP栏中显示的是0004而不是0000"这个
|
能力值:
( LV2,RANK:10 )
|
-
-
6 楼
看你的题,好象也王爽书上的,我也才看,只能和您一起交流一下,互相学习,(讨论有时也增加自己进步)。
依我初学来看,你对王爽对堆栈的讲解没看彻底。。。
mov ax,2000h
mov ss,ax
你这里设的是堆栈段地址。究竟堆栈是多大,还要你设,(王爽的书在堆栈超界时也已说到:...8086CPU只知道栈顶在何处,而不知道我们安排的栈空间有多大。。。但也不是很详细)所以,在确定了堆栈段地址SS后,要接着设SP(即初始栈顶),一般来说下面的对栈操作都要在SS:00--SS:SP之间操作,对与你上面说的“当执行过pop ax这里的时候系统提示出错”是否属于段越界,我也不知道,或者那段内容属于保护内容,我也不知道。这些都不是我目前能掌握的。
至于你说的。"为什么我的SP=0004,。。。而不是2000:0000",当你
mov sp,0
add sp,4
时,SP被你调整为0004了,SP自然=0004,根据SP始终指向栈顶,SS:0004就是此时的新栈顶,此时2000:0004-2000:0000空间是空的,如果你在此指令后面接着来2个PUSH(如,PUSH AX PUSH AX )栈才会满,SS:SP才会=2000:0000,2000:0000才成为又一次新栈顶。
我也初学者,说点看法,交流一下。
错了,期望大佬门纠下。
|
能力值:
( LV13,RANK:350 )
|
-
-
7 楼
怎么这个问题是你问的啊,刚刚有人在QQ上也有人问我,应该是看到这个帖子的,我把我的回答贴下吧,诶,郁闷!
moonife 18:24:54
第一:为什么会出错:见14楼。。。。。。。。。。。
moonife 18:26:18
第二:sp是永远指向栈顶的 这个你不需要怀疑 只是什么地方你想错了而已 从你说的 我也不清楚你哪儿错了 所以还请自己探索
|
能力值:
( LV2,RANK:10 )
|
-
-
8 楼
堆栈段说简单也简单,说麻烦也麻烦。看到7楼说的sp是永远指向栈顶的 这个你不需要怀疑这句话,使我想起了一个到今天我还没解开的疑团,就是PUSHA或者PUSHAN时,是先调整SP指向新栈顶再寄存器陆续压栈(这样,压栈的将是调整后的SP值,是调整后的值就有问题了,起不到保护原SP的目的啊?),还是先寄存器陆续压栈再调整SP指向新栈顶(这样保存的是没调整前的旧值,但这样一来,在执行这个指令时,SP没指向栈顶啊),问了很久,都没大佬门的确切回答。。。还是一个大疑团,。。
顺便提下,看看有大佬门解答没。。。也帮帖主顶下帖。。。
|
能力值:
(RANK:260 )
|
-
-
9 楼
堆栈,按照栈顶指针操作,分为“空”堆栈和“满”堆栈;按生长方向,分为“递增”堆栈和“递减”堆栈。
概念的准确解释,谷歌或百度就行。
x86的堆栈是“满递减”堆栈。
ARM处理器支持全部4种堆栈模式。
|
能力值:
( LV2,RANK:10 )
|
-
-
10 楼
也知道书呆版主说的,所谓向下生长和向上生长方式。。。可这问题和那无关。。。你细看下我说的意思就明白了。。。是说这个指令在底层处理过程中,SP在何时开始调整。。。
唉。。。我自己都不想提。。。怪我自己钻了个牛角尖。。。麻烦。。。
还是先看王爽的通俗易懂些。。。
|
能力值:
( LV13,RANK:350 )
|
-
-
11 楼
8楼的问题问得很好,这是一个很正常不过的小误区,我回答一下,希望你能够解惑,指令:
push esp ;这个完成的步骤应该是这样的
1 先取esp的值进行保存,如果你要问这个值保存到什么地方去了,这个还是问intel吧,我也不知道
2 进行push操作,也就是esp-4
3 把保存的值压入esp所指的地址
|
能力值:
( LV2,RANK:10 )
|
-
-
12 楼
11楼也有这个看法。。。
除前期的CPU(具体哪一代开始为界,我也不确定,)如8086,PUSH SP保存的是旧值。这好理解,先调整SP(指向栈顶),再SP压栈,保存的自然是调整后的新值,后期的凡关系到SP(或者ESP)压栈保存的都改为保存旧值,就是没调整前的值,也就是说SP里的值先不调整(当然也就没指向新栈顶了)。就开始把SP的值写入栈。写过后,再调整(也就是指向新栈顶)。这很矛盾的。先压栈再SP指向新栈顶,说不过去啊。。。
很长时间都没大佬们的完美解答。我自己只好瞎猜,有其他寄存器隐性参与了(我瞎猜的。和你的说法差不多)。。。好把自己从牛角尖里拉出。。。晕。。。
|
能力值:
( LV2,RANK:10 )
|
-
-
13 楼
大侠们,我想问问,寄器存有自己保存值的功能,为什么还需要系统记录到栈里,在下次执行之前,恢复数据呢,还有那么,就算记录到栈里,那么SP总应该要发生变化吧,可是我那段,SP从头到尾,他动都不动
|
能力值:
( LV13,RANK:350 )
|
-
-
14 楼
首先我更正我在7楼错误的解释,经过跟踪发现第一个应该是这样的,
:为什么会出错:你在单步执行命令的时候,系统会在每一个中断产生的时候保护主要寄存器的值将它们压栈,执行下一步的时候在恢复,然而lz的add sp,4导致栈空间太小,保护现场的时候已经跨段了,然而不知是ms-dos的机制还是cpu的保护,跨段的压栈操作没有得到进行,至少是cs和ip的值没有得到保存,所以恢复的值肯定是错的就崩溃了
对于12楼的好问,我只能建议:自己探索,要不找intel问问!
|
能力值:
( LV2,RANK:10 )
|
-
-
15 楼
各位大侠们,小鸟,我终于想通了,感谢各位的顶贴,其实没有我们想的那么复杂,原因很简单就是当我们在执行T命令后,系统将数据压入栈里的最低要求就是要将CS,IP里面的值保存,这就是我将ADD SP,4改成ADD SP,5不行,当改成ADD SP,6就可以了,这也是为什么执行POP AX为什么会出错的原因,因为恢复数据时,IP的值不知道,哈哈,我想这应该是对的吧,如果有错,还望各位大侠指正.
|
能力值:
( LV2,RANK:10 )
|
-
-
16 楼
看你说的意思,应该合用一个段,也不知道你这样写程序和T的目的是什么,别人也不好多说啊。你最好把整个程序都帖出来(看样子也就前头没贴),T的过程也抓图更好,问人总要把问题说详细,别人才好答啊。。。
你看你那过程,栈还没进货,就先往外出货,货还不在栈内出,在栈外随便搞个货就出。。。还出出进进几次,谁知道那货是不是别的程序在用的,还是你自己CS段里的。。。那能给你用吗。(大概意思吧,我也初学,只能打比方说了)
信息多了,有时靠几个寄存器器不够用。就要保存一些,腾一些寄存器出来。。。
王爽的书还是很通俗的。。。一步步学,应该能搞定的。。。不能急躁。。。
只能这样了。。。
|
能力值:
( LV2,RANK:10 )
|
-
-
17 楼
谢谢你,你们的思路让我想明白了,多谢你们
|
能力值:
( LV9,RANK:170 )
|
-
-
18 楼
你们对 stack 的理解都太浅了,不够深入透彻
除非使用了 expand-down 类型的 data segment 作为 stack 。
否则 stack 和 普通的 data segment 是完全一致的。
--------------------------------------------------------------
绝大部分的 stack 都是使用 expand-up 类型的 data segment
也就是说:和 DS 寄存器指向的 data segment 是一致的。
在 processor REST# 后:
SS 寄存器初始化为:SS.base = 0000, SS.limit = FFFFh. SS.attribute.type = 0010(它是 expand-up、readable/writable)
初始化后:SS 是 expand-up 类型的 data segment
对于 expand-up 的 data segment:它的 segment offset 有效范围是: 0 ~ limit,也就是 0 ~ FFFFh。
real-mode 的 stack 的 offset 取值范围是:0 ~ FFFFh。
执行:
mov ss,2000h
-------------------------
后 SS.base = 2_0000h(2000 << 4)
所以,此时 stack 的取值范围是:2_0000 ~ 2_FFFF
pop ax
-----------------
意思是: ax = [sp], sp++;
若 [sp] 不在 2_0000 ~ 2_FFFF 范围内就会出现 #SS 异常
在保护模式下:
若 G =1 时,offse 取值为:0 ~ limit * 4K + (4K -1)
-----------------------------------------------------------------
对于 expand-down 类型的 stack 来说,
它的取值范围是:
在实模式下:由于 SS.attribute.D = 0、SS.attribute.G = 0
所以:limit + 1 ~ FFFF
在保护模式下:
(1)D = 1 && G = 0:
offset 取值范围则是: limit + 1 ~ FFFF_FFFF
(2)D = 1 && G =1
offset 取值范围则是:limit * 4K + (4K -1) + 1 ~ FFFF_FFFF
(3)D = 0 && G =1
offset 取值范围则是:limit *4K + (4K -1) + 1 ~ FFFF
----------------
对于 expand-up 类型的 data segment 来说
limit 定义上限。
对于 expand-down 类型的 data segment 来说:
limit 定义下限。
|
能力值:
( LV2,RANK:10 )
|
-
-
19 楼
执行T命令后,系统将数据压入栈里的最低要求就是要将CS,IP里面的值保存,这就是我将ADD SP,4改成ADD SP,5不行,当改成ADD SP,6就可以了
|
能力值:
( LV2,RANK:10 )
|
-
-
20 楼
sp,4太小了
|
|
|