有关stack的异常

今天说第二件事情。那就是stack异常然后导致程序终止的问题。

到目前来说,我还是用这种模糊的方式描述,那是因为,我们可爱的bochs提示的信息总是那么的点到为止,不留一点更多的信息。

执行了一遍代码,每次当我要call那个readfromharddisk过程的时候,它总是打印如下错误异常:

<bochs:31> s
00035650269e[CPU0 ] stackPrefetch(4): access [0x0000fffc] > SS.limit [0x00008000]
00035650269e[CPU0 ] fetch_raw_descriptor: GDT: index (f007) 1e00 > limit (27)
00035650269e[CPU0 ] interrupt(): gate descriptor is not valid sys seg (vector=0x08)
00035650269i[CPU0 ] CPU is in protected mode (active)
00035650269i[CPU0 ] CS.mode = 32 bit
00035650269i[CPU0 ] SS.mode = 16 bit
00035650269i[CPU0 ] EFER   = 0x00000000
00035650269i[CPU0 ] | EAX=00000020  EBX=00040000  ECX=00098000  EDX=00000000
00035650269i[CPU0 ] | ESP=00000000  EBP=00000000  ESI=000e0001  EDI=00000000
00035650269i[CPU0 ] | IOPL=0 id vip vif ac vm RF nt of df if tf sf ZF af PF cf
00035650269i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00035650269i[CPU0 ] |  CS:0010( 0002| 0|  0) 00007c00 00000200 0 1
00035650269i[CPU0 ] |  DS:0008( 0001| 0|  0) 00000000 ffffffff 1 1
00035650269i[CPU0 ] |  SS:0020( 0004| 0|  0) 000b8000 00008000 0 0
00035650269i[CPU0 ] |  ES:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00035650269i[CPU0 ] |  FS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00035650269i[CPU0 ] |  GS:0000( 0005| 0|  0) 00000000 0000ffff 0 0
00035650269i[CPU0 ] | EIP=000000c0 (000000c0)
00035650269i[CPU0 ] | CR0=0x60000011 CR2=0x00000000
00035650269i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
(0).[35650269] [0x0000000000007cc0] 0010:00000000000000c0 (unk. ctxt): call .+154 (0x00007d5f)   ;
00035650269e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, res
00035650269i[SYS  ] bx_pc_system_c::Reset(HARDWARE) called
00035650269i[CPU0 ] cpu hardware reset
00035650269i[APIC0] allocate APIC id=0 (MMIO enabled) to 0x00000000fee00000
00035650269i[CPU0 ] CPUID[0x00000000]: 00000002 756e6547 6c65746e 49656e69
00035650269i[CPU0 ] CPUID[0x00000001]: 00000633 00010800 00002008 1fcbfbff
00035650269i[CPU0 ] CPUID[0x00000002]: 00410601 00000000 00000000 00000000
00035650269i[CPU0 ] CPUID[0x80000000]: 80000008 00000000 00000000 00000000
00035650269i[CPU0 ] CPUID[0x80000001]: 00000000 00000000 00000101 2a100000
00035650269i[CPU0 ] CPUID[0x80000002]: 20202020 20202020 20202020 6e492020
00035650269i[CPU0 ] CPUID[0x80000003]: 286c6574 50202952 69746e65 52286d75
00035650269i[CPU0 ] CPUID[0x80000004]: 20342029 20555043 20202020 00202020
00035650269i[CPU0 ] CPUID[0x80000005]: 01ff01ff 01ff01ff 40020140 40020140
00035650269i[CPU0 ] CPUID[0x80000006]: 00000000 42004200 02008140 00000000
00035650269i[CPU0 ] CPUID[0x80000007]: 00000000 00000000 00000000 00000000
00035650269i[CPU0 ] CPUID[0x80000008]: 00003028 00000000 00000000 00000000
00035650269i[     ] reset of 'pci' plugin device by virtual method
00035650269i[     ] reset of 'pci2isa' plugin device by virtual method
00035650269i[     ] reset of 'cmos' plugin device by virtual method
00035650269i[     ] reset of 'dma' plugin device by virtual method
00035650269i[     ] reset of 'pic' plugin device by virtual method
00035650269i[     ] reset of 'pit' plugin device by virtual method
00035650269i[     ] reset of 'floppy' plugin device by virtual method
00035650269i[     ] reset of 'vga' plugin device by virtual method
00035650269i[     ] reset of 'acpi' plugin device by virtual method
00035650269i[     ] reset of 'ioapic' plugin device by virtual method
00035650269i[     ] reset of 'keyboard' plugin device by virtual method
00035650269i[     ] reset of 'harddrv' plugin device by virtual method
00035650269i[     ] reset of 'pci_ide' plugin device by virtual method
00035650269i[     ] reset of 'unmapped' plugin device by virtual method
00035650269i[     ] reset of 'biosdev' plugin device by virtual method
00035650269i[     ] reset of 'speaker' plugin device by virtual method
00035650269i[     ] reset of 'extfpuirq' plugin device by virtual method
00035650269i[     ] reset of 'parallel' plugin device by virtual method
00035650269i[     ] reset of 'serial' plugin device by virtual method
00035650269i[     ] reset of 'gameport' plugin device by virtual method
00035650269i[     ] reset of 'iodebug' plugin device by virtual method
Next at t=35650270

最直观的的错误无非就是下面这两句,但是什么意思呢? fffc是啥鸟? ss.limit为啥是0x8000。

00035650269e[CPU0 ] stackPrefetch(4): access [0x0000fffc] > SS.limit [0x00008000]
00035650269e[CPU0 ] fetch_raw_descriptor: GDT: index (f007) 1e00 > limit (27)

这个时候,就需要重新想想,首先ss.limit=0x8000肯定是不对的,因为我的代码写的很清楚,ss指向的stack段应该是这样子的:也就是limit应该是0xf1000fff,这个是负数的表示,因为是expand-down的。正数来看就是0x1000

<bochs:13> info gdt
Global Descriptor Table (base=0x0000000000007e00, limit=39):
GDT[0x00]=??? descriptor hi=0x00000000, lo=0x00000000
GDT[0x01]=Data segment, base=0x00000000, limit=0xffffffff, Read/Write
GDT[0x02]=Code segment, base=0x00007c00, limit=0x00000200, Execute-Only, Non-Conforming, 32-bit
GDT[0x03]=Data segment, base=0x00007c00, limit=0xf1000fff, Read/Write, Expand-down
GDT[0x04]=Data segment, base=0x000b8000, limit=0x00008000, Read/Write
You can list individual entries with 'info gdt [NUM]' or groups with 'info gdt [NUM] [NUM]'
<bochs:14>
再仔细看,0x8000不就是GDT[0x04],即显存内存段的limit,看到这里,基本可以推测错误的原因了,八成就是段选择子搞错了,走读下代码,发现初始化堆栈段,eax赋错了,应该是0x18(即是index=0x03)。而不是0x04。

protect:	
	;[7].进入到保护模式后,为了给予内核最大的访问内存能力,ds段寄存器使用4G段描述符
	;初始化ds
	mov eax, 0x00000008 	
	mov ds, eax
	;初始化堆栈段
	mov eax, 0x00000020	
	mov ss, eax
	xor esp, esp	


火速把选择子修改下,重编译,断点,step大法,成功pass。
到这里,貌似进行得很顺利,很和谐,bochs非常完美的协助我们把问题捕获了,定位了、解决了。但是自己心里很清楚,我们是人,所以会发散的思维,去思考。但是bochs只是一个人写的代码而已,它又是怎么判断这里出现异常的呢?到这里,我又觉得,我还是没搞明白,没弄清楚,这个错误是在什么情况下触发的呢?

再看一遍这个错误提示信息:

00035650269e[CPU0 ] stackPrefetch(4): access [0x0000fffc] > SS.limit [0x00008000]
00035650269e[CPU0 ] fetch_raw_descriptor: GDT: index (f007) 1e00 > limit (27)
个人理解,处理的流程应该是这样子:既然提示是stackprefetch(4),那么应该就是提前去call的那个函数取指令,那么就是首先push这个函数的返回地址(这个昨天的第一个问题里面阐述了)。既然是push,那么写入的地址肯定就是当前eps-4, 那应该就是 0xfffffffc, 当把这个返回地址XXX写到内存地址[ss:esp]的时候,cpu开始检测这个偏移的合法性,发现这个偏移太大了,因为由于代码的错误,ss寄存器指向的堆栈段是原来的显存段,段属性不是expand-expand的,所以我猜:ss的base+这个偏移是往内存高的地址推动的,那么显而易见, 0xfffffffc 远远大于0x8000的limit。那么肯定就会抛出一个access异常。

但是,这里还是有几个疑点:

1.为什么提示是0x0000fffc.而不是0xfffffffc?

2.如果真的是那样子,可以这样子做个实验,段选择子正确的设置好,指向stack段,但是stack段的段属性去掉expand-down,看看是否也出现这种异常。如果出现的异常也是这样子的。那基本上可以确定就是我推测的原因了。


以上纯属个人猜测。具体细节,等待后续学习的深入,再回头refine。


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值