$cat memset.c(根据实际代码简化)
$xlc -g memset.c
$a.out
Illegal instruction(coredump)
$dbx a.out
Type 'help' for help.
[using memory image in core]
reading symbolic information ...
Illegal instruction (illegal opcode) in . at 0x0
warning: Unable to access address 0x0 from core
查看代码一时没看出什么问题。
用汇编调试了。
tracei: 0x1000038c (main+0x34) 4e800020 blr
[4] stopped in main at line 7
(dbx) registers
$r0:0x00000000 $stkp:0x2ff229d0 $toc:0x20000710 $r3:0x00000000
$r4:0x00000017 $r5:0x00000000 $r6:0x00000000 $r7:0x00000000
$r8:0x00000000 $r9:0x00000000 $r10:0x2ff228d0 $r11:0x2ff22ccf
$r12:0x00000000 $r13:0xdeadbeef $r14:0x00000001 $r15:0x2ff22a50
$r16:0x2ff22a58 $r17:0x00000000 $r18:0xdeadbeef $r19:0xdeadbeef
$r20:0xdeadbeef $r21:0xdeadbeef $r22:0xdeadbeef $r23:0xdeadbeef
$r24:0xdeadbeef $r25:0xdeadbeef $r26:0xdeadbeef $r27:0xdeadbeef
$r28:0xdeadbeef $r29:0xdeadbeef $r30:0xdeadbeef $r31:0xdeadbeef
$iar:0x1000038c $msr:0x0002d0b2 $cr:0x44224804 $link:0x00000000
$ctr:0x00000000 $xer:0x20000020 $mq:0xdeadbeef
Condition status = 0:g 1:g 2:e 3:e 4:g 5:l 7:g
[unset $noflregs to view floating point registers]
in main at line 7
lr寄存器里面地址是0x0000000,导致blr返回到一个错误的地址了。
为什么会这样,那得了解一下POWER平台的,函数调原理了。
当程序进入main函数是首先把lr寄存地址记录在r0里
tracei: 0x10000358 (main) 7c0802a6 mflr r0
再将r0里面的地址写到函数栈里地址是,r1+0x148
tracei: 0x10000360 (main+0x8) 90010148 stw r0,0x148(r1)
当函数退出的时候
将r1+0x148的值取得r0寄存器中,
tracei: 0x10000380 (main+0x28) 80010148 lwz r0,0x148(r1)
然后将r0寄存器的值存到lr寄存中
tracei: 0x10000384 (main+0x2c) 7c0803a6 mtlr r0
然后根据lr寄存器的址进行跳转。
tracei: 0x1000038c (main+0x34) 4e800020 blr
如果看了以上流程大家应该明白问题出在哪里了。
memset的时候把保存栈里的返回地址给至成0了,导致最后报
这个错了错误了。
Illegal instruction in . at 0x0
0x00000000 00000000 Invalid opcode.
。
还没明白的话我们用tracei,监控保持地址的内存。就是r1+0x128;0x2ff229d0 +0x128= 0x2ff229d8;
(dbx) tracei 0x2ff229d8
[8] tracei 0x2ff229d8
tracei: 0x10000358 (main) 7c0802a6 mflr r0
tracei: 0x1000035c (main+0x4) 9421fec0 stwu r1,-320(r1)
tracei: 0x10000360 (main+0x8) 90010148 stw r0,0x148(r1)
tracei: 0x10000364 (main+0xc) 38610040 addi r3,0x40(r1)
after instruction 0x10000360: 0x2ff229d8 = 0x100001dc
[6] stopped in main at line 6
6 memset(path,0,PATH_MAX);
(dbx) c
tracei: 0x10000368 (main+0x10) 38800000 li r4,0x0
tracei: 0x1000036c (main+0x14) 38a003ff li r5,0x3ff
tracei: 0x10000370 (main+0x18) 48000051 bl 0x100003c0 (memset)
tracei: 0x100003c0 (memset) 4800e00a ba 0x0000e008
tracei: 0x10000374 (main+0x1c) 60000000 ori r0,r0,0x0
after instruction 0x100003c0: 0x2ff229d8 = (nil)
#memset后地址变成nil,0x00000000了,
tracei: 0x10000378 (main+0x20) 38600000 li r3,0x0
tracei: 0x1000037c (main+0x24) 48000004 b 0x10000380 (main+0x28)
tracei: 0x10000380 (main+0x28) 80010148 lwz r0,0x148(r1)
tracei: 0x10000384 (main+0x2c) 7c0803a6 mtlr r0
tracei: 0x10000388 (main+0x30) 38210140 addi r1,0x140(r1)
tracei: 0x1000038c (main+0x34) 4e800020 blr
[4] stopped in main at line 7
7 }
查看limits.h里面PATH_MAX,的值是1023。
总结上文。
1.栈上内存的错误实在比较难发现.xlc有提供编译选项,-qheapdebug,很令人失望,只能提供检查堆上面的错误
如果代码如下,是就能发现错
path= (char*)calloc(1, 256);
memset(path, 0, PATH_MAX);
2.令我想起久违的堆栈溢出,呵呵。0day.年纪大了已经很久没接触了,想不到今天在aix遇上了。
3.0x86汇编已经忘了差不多了,感觉在函数压栈这一块和power 差不多。那天有空在好好学习。
4.看来machine级别的调试还是要掌握的。