首页
学习
活动
专区
圈层
工具
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

《coredump问题原理探究》Linux x86版7.11节string对象

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1344575

在定位map coredump的那一节已经接触了string对象.在这里重温一下.

看一个例子:

代码语言:javascript
复制
  1 #include <string>
  2 #include <stdio.h>
  3 
  4 int main()
  5 {
  6     std::string str;
  7     char* ptr = "hello world!";
  8 
  9     for ( int i = 0; i < 0x10; i++ )
 10     {
 11         str.append( ptr );
 12     }
 13 
 14     return 0;
 15 }

看一下汇编:

代码语言:javascript
复制
(gdb) disassemble main 
Dump of assembler code for function main:
   0x08048584 <+0>:	push   %ebp
   0x08048585 <+1>:	mov    %esp,%ebp
   0x08048587 <+3>:	and    $0xfffffff0,%esp
   0x0804858a <+6>:	push   %esi
   0x0804858b <+7>:	push   %ebx
   0x0804858c <+8>:	sub    $0x28,%esp
   0x0804858f <+11>:	lea    0x14(%esp),%eax
   0x08048593 <+15>:	mov    %eax,(%esp)
   0x08048596 <+18>:	call   0x8048460 <_ZNSsC1Ev@plt>
   0x0804859b <+23>:	movl   $0x80486d4,0x18(%esp)
   0x080485a3 <+31>:	movl   $0x0,0x1c(%esp)
   0x080485ab <+39>:	jmp    0x80485c6 <main+66>
   0x080485ad <+41>:	mov    0x18(%esp),%eax
   0x080485b1 <+45>:	mov    %eax,0x4(%esp)
   0x080485b5 <+49>:	lea    0x14(%esp),%eax
   0x080485b9 <+53>:	mov    %eax,(%esp)
   0x080485bc <+56>:	call   0x80484a0 <_ZNSs6appendEPKc@plt>
   0x080485c1 <+61>:	addl   $0x1,0x1c(%esp)
   0x080485c6 <+66>:	cmpl   $0xf,0x1c(%esp)
   0x080485cb <+71>:	setle  %al
   0x080485ce <+74>:	test   %al,%al
   0x080485d0 <+76>:	jne    0x80485ad <main+41>
   0x080485d2 <+78>:	mov    $0x0,%ebx
   0x080485d7 <+83>:	lea    0x14(%esp),%eax
   0x080485db <+87>:	mov    %eax,(%esp)
   0x080485de <+90>:	call   0x8048490 <_ZNSsD1Ev@plt>
   0x080485e3 <+95>:	mov    %ebx,%eax
   0x080485e5 <+97>:	add    $0x28,%esp
   0x080485e8 <+100>:	pop    %ebx
   0x080485e9 <+101>:	pop    %esi
   0x080485ea <+102>:	mov    %ebp,%esp
   0x080485ec <+104>:	pop    %ebp
   0x080485ed <+105>:	ret    
   0x080485ee <+106>:	mov    %edx,%ebx
   0x080485f0 <+108>:	mov    %eax,%esi
   0x080485f2 <+110>:	lea    0x14(%esp),%eax
   0x080485f6 <+114>:	mov    %eax,(%esp)
   0x080485f9 <+117>:	call   0x8048490 <_ZNSsD1Ev@plt>
   0x080485fe <+122>:	mov    %esi,%eax
   0x08048600 <+124>:	mov    %ebx,%edx
   0x08048602 <+126>:	mov    %eax,(%esp)
   0x08048605 <+129>:	call   0x80484c0 <_Unwind_Resume@plt>
End of assembler dump.

在0x080485bc打断点.

由上面汇编可知,esp+0x14是string对象的this指针, 字符串”hello world”放在esp+0x18.

构造完毕的string对象

代码语言:javascript
复制
(gdb) x /wx $esp+0x14
0xbffff664:	0x00d2ff5c
(gdb) x /8wx 0x00d2ff5c
0xd2ff5c <_ZNSs4_Rep20_S_empty_rep_storageE+12>:	0x00000000	0x00000000	0x00000000	0x00000000
0xd2ff6c <_ZNSt9money_putIwSt19ostreambuf_iteratorIwSt11char_traitsIwEEE2idE>:	0x00000000	0x00000000	0x00000000	0x00000000

由_ZNSs4_Rep20_S_empty_rep_storageE+12这一行,我们看一下把string对象的this指针-12,看看内容是怎样?

代码语言:javascript
复制
(gdb) x /8wx 0x00d2ff5c-0xc
0xd2ff50 <_ZNSs4_Rep20_S_empty_rep_storageE>:	0x00000000	0x00000000	0x00000000	0x00000000
0xd2ff60 <_ZNSt10moneypunctIwLb0EE2idE>:	0x00000000	0x00000000	0x00000000	0x00000000

看不出什么东西。

调用第一次append后.

代码语言:javascript
复制
(gdb) ni
0x080485c1 in main ()
(gdb) x /wx $esp+0x14
0xbffff664:	0x0804a014
(gdb) x /8wx 0x0804a014    
0x804a014:	0x6c6c6568	0x6f77206f	0x21646c72	0x00000000
0x804a024:	0x00020fe1	0x00000000	0x00000000	0x00000000
(gdb) x /8wx 0x0804a014-0xc
0x804a008:	0x0000000c	0x0000000c	0x00000000	0x6c6c6568
0x804a018:	0x6f77206f	0x21646c72	0x00000000	0x00020fe1

由于字符串”helloworld!”的大小是12(0xc),而0x804a008开始的两个单元都是0xc,究竟哪一个才是实际大小。而0x0804a014所存放的就是”hello world!”.

看一下多调用几次append之后会怎样:

代码语言:javascript
复制
(gdb) c
Continuing.

Breakpoint 1, 0x080485bc in main ()
(gdb) ni
0x080485c1 in main ()
(gdb) x /wx $esp+0x14
0xbffff664:	0x0804a034
(gdb) x /8wx 0x0804a034-0xc 
0x804a028:	0x00000018	0x00000018	0x00000000	0x6c6c6568
0x804a038:	0x6f77206f	0x21646c72	0x6c6c6568	0x6f77206f
(gdb) c
Continuing.

Breakpoint 1, 0x080485bc in main ()
(gdb) ni
0x080485c1 in main ()
(gdb) x /wx $esp+0x14
0xbffff664:	0x0804a064
(gdb) x /16wx 0x0804a064-0xc
0x804a058:	0x00000024	0x00000030	0x00000000	0x6c6c6568
0x804a068:	0x6f77206f	0x21646c72	0x6c6c6568	0x6f77206f
0x804a078:	0x21646c72	0x6c6c6568	0x6f77206f	0x21646c72
0x804a088:	0x00000000	0x00000000	0x00000000	0x00000000
(gdb) c
Continuing.

Breakpoint 1, 0x080485bc in main ()
(gdb) ni
0x080485c1 in main ()
(gdb) x /wx $esp+0x14
0xbffff664:	0x0804a064
(gdb) x /16wx 0x0804a064-0xc
0x804a058:	0x00000030	0x00000030	0x00000000	0x6c6c6568
0x804a068:	0x6f77206f	0x21646c72	0x6c6c6568	0x6f77206f
0x804a078:	0x21646c72	0x6c6c6568	0x6f77206f	0x21646c72
0x804a088:	0x6c6c6568	0x6f77206f	0x21646c72	0x00000000
(gdb) c
Continuing.

Breakpoint 1, 0x080485bc in main ()
(gdb) ni
0x080485c1 in main ()
(gdb) x /wx $esp+0x14
0xbffff664:	0x0804a0ac
(gdb) x /16wx 0x0804a0ac-0xc
0x804a0a0:	0x0000003c	0x00000060	0x00000000	0x6c6c6568
0x804a0b0:	0x6f77206f	0x21646c72	0x6c6c6568	0x6f77206f
0x804a0c0:	0x21646c72	0x6c6c6568	0x6f77206f	0x21646c72
0x804a0d0:	0x6c6c6568	0x6f77206f	0x21646c72	0x6c6c6568

可见,string对象有如下特征:

1.     第一个成员是字符串大小

2.     第二个成员是字符串对象的最大空间

3.     第四个成员存放着字符串

4.     当字符串的大小超过对象最大空间时,字符串对象会重新分配一段连续内存。

5.     当字符串对象刚刚构造完成时,并没有分配任何空间。

下一篇
举报
领券