版权声明:本文为博主原创文章,未经博主允许不得转载。 https://cloud.tencent.com/developer/article/1344575
在定位map coredump的那一节已经接触了string对象.在这里重温一下.
看一个例子:
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 }
看一下汇编:
(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对象
(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,看看内容是怎样?
(gdb) x /8wx 0x00d2ff5c-0xc
0xd2ff50 <_ZNSs4_Rep20_S_empty_rep_storageE>: 0x00000000 0x00000000 0x00000000 0x00000000
0xd2ff60 <_ZNSt10moneypunctIwLb0EE2idE>: 0x00000000 0x00000000 0x00000000 0x00000000
看不出什么东西。
调用第一次append后.
(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之后会怎样:
(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. 当字符串对象刚刚构造完成时,并没有分配任何空间。