gdb How to dump out the data of a structure? - gdb

Using a very simple sample that uses an int pointer to point to a structure with longs. Granted it isn't the preferred method but it is being done to mimic other code. The objective is to view the data in the register before the free call.
This is the code.
#include <stdio.h>
#include <stdlib.h>
//#include <unistd.h>
typedef struct
{
unsigned long x;
unsigned long y;
unsigned long z;
}
myStruct;
int main () {
int *p_Struct = (int *)0;
int size = sizeof (myStruct);
printf("Size of (bytes)...\n");
printf(" myStruct : %d\n", sizeof (myStruct));
p_Struct = ( int*) malloc(size);
memset((int *)p_Struct, 0, size);
((myStruct *)p_Struct)->x = 111;
((myStruct *)p_Struct)->y = 222;
((myStruct *)p_Struct)->z = 333;
free(p_Struct);
return(0);
}
Using the following gdb version to step through the code.
Using > gdb
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-94.el7
Gdb is used to start the application then disassembled to acquire the line of code for the free command.
(gdb) disassemble main
Dump of assembler code for function main:
0x000000000040064d <+0>: push %rbp
0x000000000040064e <+1>: mov %rsp,%rbp
0x0000000000400651 <+4>: sub $0x10,%rsp
=> 0x0000000000400655 <+8>: movq $0x0,-0x8(%rbp)
0x000000000040065d <+16>: movl $0x18,-0xc(%rbp)
0x0000000000400664 <+23>: mov $0x400770,%edi
0x0000000000400669 <+28>: callq 0x400500 <puts#plt>
0x000000000040066e <+33>: mov $0x18,%esi
0x0000000000400673 <+38>: mov $0x400783,%edi
0x0000000000400678 <+43>: mov $0x0,%eax
0x000000000040067d <+48>: callq 0x400510 <printf#plt>
0x0000000000400682 <+53>: mov -0xc(%rbp),%eax
0x0000000000400685 <+56>: cltq
0x0000000000400687 <+58>: mov %rax,%rdi
0x000000000040068a <+61>: callq 0x400550 <malloc#plt>
0x000000000040068f <+66>: mov %rax,-0x8(%rbp)
0x0000000000400693 <+70>: mov -0xc(%rbp),%eax
0x0000000000400696 <+73>: movslq %eax,%rdx
0x0000000000400699 <+76>: mov -0x8(%rbp),%rax
0x000000000040069d <+80>: mov $0x0,%esi
0x00000000004006a2 <+85>: mov %rax,%rdi
0x00000000004006a5 <+88>: callq 0x400520 <memset#plt>
0x00000000004006aa <+93>: mov -0x8(%rbp),%rax
0x00000000004006ae <+97>: movq $0x6f,(%rax)
0x00000000004006b5 <+104>: mov -0x8(%rbp),%rax
0x00000000004006b9 <+108>: movq $0xde,0x8(%rax)
0x00000000004006c1 <+116>: mov -0x8(%rbp),%rax
0x00000000004006c5 <+120>: movq $0x14d,0x10(%rax)
0x00000000004006cd <+128>: mov -0x8(%rbp),%rax
0x00000000004006d1 <+132>: mov %rax,%rdi
0x00000000004006d4 <+135>: callq 0x4004f0 <free#plt>
0x00000000004006d9 <+140>: mov $0x0,%eax
0x00000000004006de <+145>: leaveq
0x00000000004006df <+146>: retq
End of assembler dump.
Using the specific line of code, a break point is set on free.
(gdb) break *0x00000000004006d4
Continue until the code breaks on the free command.
(gdb) continue
Continuing.
Size of (bytes)...
myStruct : 24
Breakpoint 2, 0x00000000004006d4 in main () at freeQuestion.c:28
28 free(p_Struct);
Display the available registers.
(gdb) info reg
rax 0x602010 6299664
rbx 0x0 0
rcx 0x602010 6299664
rdx 0x18 24
rsi 0x0 0
rdi 0x602010 6299664
rbp 0x7fffffffc160 0x7fffffffc160
rsp 0x7fffffffc150 0x7fffffffc150
r8 0x602000 6299648
r9 0x18 24
r10 0x7fffffffbed0 140737488338640
r11 0x2aaaaad56700 46912498919168
r12 0x400560 4195680
r13 0x7fffffffc240 140737488339520
r14 0x0 0
r15 0x0 0
rip 0x4006d4 0x4006d4 <main+135>
eflags 0x283 [ CF SF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb)
I assume that rdi register will house the data that is being freed at address 0x602010. To be sure all the data will be visible the examine command is executed to display 80 bytes of data starting 16 bytes prior.
(gdb) x/80d 0x602000
0x602000: 0 0 0 0 0 0 0 0
0x602008: 33 0 0 0 0 0 0 0
0x602010: 111 0 0 0 0 0 0 0
0x602018: -34 0 0 0 0 0 0 0
0x602020: 77 1 0 0 0 0 0 0
0x602028: -31 15 2 0 0 0 0 0
0x602030: 0 0 0 0 0 0 0 0
0x602038: 0 0 0 0 0 0 0 0
0x602040: 0 0 0 0 0 0 0 0
0x602048: 0 0 0 0 0 0 0 0
(gdb)
From the above, 111 is visible but not 222, or 333.
How can all the data (111,222,333) be viewed prior to the free command being executed?

From the above, 111 is visible but not 222, or 333.
There is no way that you could have observed this output while stopped before the CALL free instruction. We clearly see that values 0x6f == 111, 0xde == 222 and 0x14d == 333 are loaded at offset 0, 8 and 16 from $RAX:
0x00000000004006ae <+97>: movq $0x6f,(%rax)
0x00000000004006b9 <+108>: movq $0xde,0x8(%rax)
0x00000000004006c5 <+120>: movq $0x14d,0x10(%rax)
and then $RAX is copied to $RDI just before the call to free:
0x00000000004006d1 <+132>: mov %rax,%rdi
0x00000000004006d4 <+135>: callq 0x4004f0 <free#plt>
Here is the expected output (that I observe with your program):
(gdb) p/x $rdi
$1 = 0x602420
(gdb) x/6d $rdi
0x602420: 111 0 222 0
0x602430: 333 0
But if you execute nexti (to step over the call to free), then the values can be overwritten (you can't expect the contents of now freed memory to be anything in particular).
After nexti, I observe:
(gdb) x/6d 0x602420
0x602420: 0 0 222 0
0x602430: 333 0
but it could just as easily be 111 0 0 0 0 0 that you observed.

Related

Dwarf DW_AT_location objdump and dwarfdump inconsistent

I am playing around with CPython and trying to understand how a debugger works.
Specifically, I am trying to get the location of the last PyFrameObject so that I can traverse that and get the Python backtrace.
In the file ceval.c, line 689 has the definition of the function:
PyObject * PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
What I am interested in getting is the location of f on the stack. When dumping the binary with dwarfdump I get that f is at $rbp-824, but if I dump the binary with objdump I get that the location is $rbp-808 - a discrepancy of 16. Also, when debugging with GDB, I get that the correct answer is $rbp-808 like objdump gives me. Why the discrepancy, and why is dwarfdump incorrect? What am I not understanding?
How to technically recreate the problem:
Download python-2.7.17.tgz from Python website. Extract.
I compiled python-2.7.17 from source with debug symbols (./configure --enable-pydebug && make). Run the following commands on the resulting python binary:
dwarfdump Python-2.7.17/python has the following output:
DW_AT_name f
DW_AT_decl_file 0x00000001 /home/meir/code/python/Python-2.7.17/Python/ceval.c
DW_AT_decl_line 0x000002b1
DW_AT_type <0x00002916>
DW_AT_location len 0x0003: 91c879: DW_OP_fbreg -824
I know this is the correct f because the line the variable is declared on is 689 (0x2b1). As you can see the location is:
DW_AT_location len 0x0003: 91c879: DW_OP_fbreg -824: Meaning $rbp-824.
Running the command objdump -S Python-2.7.17/python has the following output:
PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
{
f7577: 55 push %rbp
f7578: 48 89 e5 mov %rsp,%rbp
f757b: 41 57 push %r15
f757d: 41 56 push %r14
f757f: 41 55 push %r13
f7581: 41 54 push %r12
f7583: 53 push %rbx
f7584: 48 81 ec 38 03 00 00 sub $0x338,%rsp
f758b: 48 89 bd d8 fc ff ff mov %rdi,-0x328(%rbp)
f7592: 89 b5 d4 fc ff ff mov %esi,-0x32c(%rbp)
f7598: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
f759f: 00 00
f75a1: 48 89 45 c8 mov %rax,-0x38(%rbp)
f75a5: 31 c0 xor %eax,%eax
Debugging this output will show you that the relevant line is:
f758b: 48 89 bd d8 fc ff ff mov %rdi,-0x328(%rbp) where you can clearly see that f is being loaded from -0x328(%rbp) which is $rbp-808. Also, GDB supports this finding.
So again, the question is, what am I missing and why the 16 byte discrepency between dwarfdump and reality?
Thanks
Edit:
The dwarfdump including the function above is:
< 1><0x00004519> DW_TAG_subprogram
DW_AT_external yes(1)
DW_AT_name PyEval_EvalFrameEx
DW_AT_decl_file 0x00000001 /home/meir/code/python/Python-2.7.17/Python/ceval.c
DW_AT_decl_line 0x000002b1
DW_AT_prototyped yes(1)
DW_AT_type <0x00000817>
DW_AT_low_pc 0x000f7577
DW_AT_high_pc <offset-from-lowpc>53969
DW_AT_frame_base len 0x0001: 9c: DW_OP_call_frame_cfa
DW_AT_GNU_all_tail_call_sites yes(1)
DW_AT_sibling <0x00005bbe>
< 2><0x0000453b> DW_TAG_formal_parameter
DW_AT_name f
DW_AT_decl_file 0x00000001 /home/meir/code/python/Python-2.7.17/Python/ceval.c
DW_AT_decl_line 0x000002b1
DW_AT_type <0x00002916>
DW_AT_location len 0x0003: 91c879: DW_OP_fbreg -824
According to the answer below, DW_OP_fbreg is offset from the frame base - in my case DW_OP_call_frame_cfa. I am having trouble identifying the frame base. My registers are as following:
(gdb) info registers
rax 0xfffffffffffffdfe -514
rbx 0x7f6a4887d040 140094460121152
rcx 0x7f6a48e83ff7 140094466441207
rdx 0x0 0
rsi 0x0 0
rdi 0x0 0
rbp 0x7ffd24bcef00 0x7ffd24bcef00
rsp 0x7ffd24bceba0 0x7ffd24bceba0
r8 0x7ffd24bcea50 140725219813968
r9 0x0 0
r10 0x0 0
r11 0x246 582
r12 0x7f6a48870df0 140094460071408
r13 0x7f6a48874b58 140094460087128
r14 0x1 1
r15 0x7f6a48873794 140094460082068
rip 0x5559834e99c0 0x5559834e99c0 <PyEval_EvalFrameEx+46153>
eflags 0x246 [ PF ZF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
As stated above, I already know that %rbp-808 works. What is the correct way to do it with the registers that I have?
Edit:
I finally understood the answer. I needed to unwind one more function, and find the place my function was called. There, the variable I was looking for really was in $rsp and $rsp-824 was correct
DW_OP_fbreg -824: Meaning $rbp-824
It does not mean that. It means, offset -824 from frame base (virtual) register, which is not necessarily (nor usually) equal to $rbp.
You need to look for DW_AT_frame_base to know what the frame base in the current function is.
Most likely it's defined as DW_OP_call_frame_cfa, which is the value of $RSP just before current function was called, and is equal to $RBP-16 (8 bytes for return address saved by the CALL instruction, and 8 bytes for previous $RBP saved by the first instruction of your function).

GDB: Print the value of memory address

According to https://www.ethicalhacker.net/columns/heffner/intro-to-assembly-and-reverse-engineering
mov 0xffffffb4,0x1
moves the number 1 into 0xffffffb4.
So, I decided to test this on my own.
In GDB, x is the command to print the value of memory address.
However, when I run
x 0x00000000004004fc
I'm not getting the value of 133 (decimal) or 85 (hexadecimal)
Instead, I'm getting 0x85f445c7. Any idea what is this?
me#box:~/c$ gdb -q test
Reading symbols from test...done.
(gdb) l
1 #include <stdio.h>
2
3 int main(){
4 int a = 1;
5 int b = 13;
6 int c = 133;
7 printf("Value of C : %d\n",c);
8 return 0;
9 }
(gdb) b 7
Breakpoint 1 at 0x400503: file test.c, line 7.
(gdb) r
Starting program: /home/me/c/test
Breakpoint 1, main () at test.c:7
7 printf("Value of C : %d\n",c);
(gdb)
Disassemble
(gdb) disas
Dump of assembler code for function main:
0x00000000004004e6 <+0>: push %rbp
0x00000000004004e7 <+1>: mov %rsp,%rbp
0x00000000004004ea <+4>: sub $0x10,%rsp
0x00000000004004ee <+8>: movl $0x1,-0x4(%rbp)
0x00000000004004f5 <+15>: movl $0xd,-0x8(%rbp)
0x00000000004004fc <+22>: movl $0x85,-0xc(%rbp)
=> 0x0000000000400503 <+29>: mov -0xc(%rbp),%eax
0x0000000000400506 <+32>: mov %eax,%esi
0x0000000000400508 <+34>: mov $0x4005a4,%edi
0x000000000040050d <+39>: mov $0x0,%eax
0x0000000000400512 <+44>: callq 0x4003c0 <printf#plt>
0x0000000000400517 <+49>: mov $0x0,%eax
0x000000000040051c <+54>: leaveq
0x000000000040051d <+55>: retq
End of assembler dump.
(gdb) x 0x00000000004004fc
0x4004fc <main+22>: 0x85f445c7
(gdb)
;DRTL
To print a value in GDB use print or (p in short form) command.
in your command
x 0x00000000004004fc
You have missed p command. You have to use x with p command pair to print value as hexadecimal format, like below:
(gdb) p/x 0x00000000004004fc
If the memory address is some pointer to some structure then you have to cast the memory location before using the pointer. For example,
struct node {
int data;
struct node *next
};
is some structure and you have the address of that structure pointer, then to view the contents of that memory location you have to use
(gdb) p *(struct node *) 0x00000000004004fc
Notable:
The command
x 0x00000000004004fc
Will look at the instruction and related data for this instruction:
0x00000000004004fc <+22>: movl $0x85,-0xc(%rbp)
... as you can see that the left column (address) is equal to the value used for the command (the address to read)
In the instruction 0x85 is clearly the destination address for the mov, and reflected in the printed value; 0x85f445c7 - which stored as MSB (most significant byte) at the address.

Tracing call stack in disassembled code

I am trying to debug a tricky core dump (from an -O2 optimized binary).
// Caller Function
void caller(Container* c)
{
std::list < Message*> msgs;
if(!decoder.called(c->buf_, msgs))
{
....
.....
}
// Called Function
bool
Decoder::called(Buffer* buf, list < Message*>& msgs)
{
add_data(buf); // Inlined code to append buf to decoders buf chain
while(m_data_in && m_data_in->length() > 0)
{
.....
}
}
In both caller and the callee, the first argument is optimized out, that means it must be somewhere in the register.
Caller Disassembly:
push %r15
mov %rdi,%r15
push %r14
push %r13
push %r12
push %rbp
push %rbx
sub $0x68,%rsp
test %rsi,%rsi
je 0x8ccd62
cmpq $0x0,(%rsi)
je 0x8ccd62
lea 0x40(%rsp),%rax
lea 0x1b8(%rdi),%rdi
mov %rax,(%rsp)
mov %rax,0x40(%rsp)
mov %rax,%rdx
mov %rax,0x48(%rsp)
mov (%rsi),%rsi
callq 0x8cc820
Caller Register Info:
rax 0x7fbfffc7e0 548682057696
rbx 0x2a97905ba0 182931446688
rcx 0x0 0
rdx 0x2 2
rsi 0x1 1
rdi 0x7fbfffc7e2 548682057698
rbp 0x4f 0x4f
rsp 0x7fbfffc870 0x7fbfffc870
r8 0x40 64
r9 0x20 32
r10 0x7fbfffc7e0 548682057696
r11 0x2abe466600 183580911104
r12 0x7fbfffd910 548682062096 // THIS IS HOLDING buf_
r13 0x7fbfffdec0 548682063552
r14 0x5dc 1500
r15 0x2a97905ba0 182931446688
rip 0x8cca89 0x8cca89
eflags 0x206 [ PF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
Called function Disassembly:
push %r14
push %r13
mov %rdx,%r13
push %r12
mov %rdi,%r12
push %rbp
push %rbx
sub $0x10,%rsp
mov 0x8(%rdi),%rdx
test %rdx,%rdx
jne 0x8cc843
jmpq 0x8cc9cb
mov %rax,%rdx
mov 0x8(%rdx),%rax
test %rax,%rax
mov %rsi,0x8(%rdx)
mov 0x8(%r12),%rax
test %rax,%rax
xor %edx,%edx
add 0x4(%rax),%edx
mov 0x8(%rax),%rax
lea 0x8(%rsp),%rsi
mov %r12,%rdi
movq $0x0,0x8(%rsp)
Called function Register Info :
rax 0x7fbfffc7e0 548682057696
rbx 0x2abc49f9c0 183547591104
rcx 0x0 0
rdx 0x2 2
rsi 0x1 1
rdi 0x7fbfffc7e2 548682057698
rbp 0xffffffff 0xffffffff
rsp 0x7fbfffc830 0x7fbfffc830
r8 0x40 64
r9 0x20 32
r10 0x7fbfffc7e0 548682057696
r11 0x2abe466600 183580911104
r12 0x2a97905d58 182931447128
r13 0x7fbfffc8b0 548682057904
r14 0x5dc 1500
r15 0x2a97905ba0 182931446688
rip 0x8cc88a 0x8cc88a
eflags 0x206 [ PF IF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
The issue is, in the called function, it appears that "add_data" function achieved nothing.
So, wanted to know whether in disassembly of called function, do we see the "buf_" pointer being used anywhere (Register r12 in callee function).
I do understand assembly to some level, but all those code inlining has left me confused.
Would appreciate some help in demistifying called function disassembly.
UPDATE:
add_data does below:
if (m_data_in) {
m_data_in->next = data;
} else {
m_data_in = data;
}
This looks like if (m_data_in)
mov 0x8(%rdi),%rdx
test %rdx,%rdx
test %rdx,%rdx
jne 0x8cc843
jmpq 0x8cc9cb
Now, I don't quite know where 0x8cc843 and 0x8cc9cb are located in your code, so can't really follow the code further. There is still not enough code & information to say exactly what is going on in the original question. I'm happy to fill in more of this answer if more information is provided.

core dump with same pattern

My application crashes once in a while and generates coredump.
Each time stack is different. But each time when it dumps, i find that one of the pointer will be corrupt. and each time first 4 bytes of pointer value will be 0X100 (256). By this i can make out that this dump is because of memory corruption. But i have no idea as how to proceed. I ran all the static tools on the code. But i cant really attach valgrind (I have no access to site)
#0 0x00002b5775455738 in _STL::_List_base<int, _STL::allocator<int> >::clear (this=0x2b576debd408) at /home/enipcore/core/add-ons/include/stlport/stl/_list.c:72
72 in /home/xxxx/core/add-ons/include/stlport/stl/_list.c
(gdb) info locals
__tmp = 0x10084a957f0
__cur = 0x10084a957f0
(gdb)
I will share the info which i have, Pls suggest me how to proceed. I really do not know what info to give here. If any one want me to run any command and get memory print i can share.
(gdb) p &__tmp
$13 = (_STL::_List_node<int> **) 0x2b577b70e4b8
(gdb)
Registers, eax will have this wrong value
$13 = (_STL::_List_node<int> **) 0x2b577b70e4b8
(gdb) i r
rax 0x10084a957f0 1101737318384
rbx 0x2b5771e1fccb 47654572784843
rcx 0x2b576e1251d0 47654508843472
rdx 0x85 133
rsi 0x2b571729eee8 47653050773224
rdi 0x2b576debd408 47654506320904
rbp 0x2b577b70e4c0 0x2b577b70e4c0
rsp 0x2b577b70e4a0 0x2b577b70e4a0
r8 0x2b576d176480 47654492398720
r9 0x7bbe 31678
r10 0x2b5774f0a5e0 47654624077280
r11 0x2b57165c3f80 47653037293440
r12 0x2b577b716e68 47654733180520
r13 0x0 0
r14 0x2b57188221e0 47653073330656
r15 0x2b577b716e68 47654733180520
rip 0x2b5775455738 0x2b5775455738 <_STL::_List_base<int, _STL::allocator<int> >::clear()+40>
eflags 0x10206 [ PF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
es 0x0 0
fs 0x0 0
gs 0x0 0
fctrl 0x37f 895
fstat 0x0 0
ftag 0xffff 65535
fiseg 0x0 0
fioff 0x0 0
foseg 0x0 0
fooff 0x0 0
fop 0x0 0
mxcsr 0x1fa0 [ PE IM DM ZM OM UM PM ]
(gdb)
Some memory dump.
(gdb) x/20a 0x2b577b70e4b8 -20
0x2b577b70e4a4: 0x6debd40800002b57 0x84a957f000002b57
0x2b577b70e4b4: 0x84a957f000000100 0x7b70e4e000000100
0x2b577b70e4c4: 0x754557fb00002b57 0x7b70e55000002b57
0x2b577b70e4d4: 0x6debd40800002b57 0x7b70e50000002b57
0x2b577b70e4e4: 0x7545583100002b57 0x7b716e6800002b57
0x2b577b70e4f4: 0x6debd40800002b57 0x7b70e55000002b57
0x2b577b70e504: 0x75451de100002b57 0x6de161a000002b57
0x2b577b70e514: 0x100002b57 0x6debd40800000000
0x2b577b70e524: 0x6debd3c800002b57 0x2b57
0x2b577b70e534: 0x167f860800000000 0x71e1fccb00002b57

Storage of the "hidden array" behind initializer_list

In the C++11 standard there is a note regarding the array backing the uniform initialisation that states:
The implementation is free to allocate the array in read-only memory if an explicit array with the same initializer could be so allocated.
Does GCC/Clang/VS take advantage of this? Or is every initialisation using this feature subject to additional data on the stack, and additional initialisation time for this hidden array?
For instance, given the following example:
void function()
{
std::vector<std::string> values = { "First", "Second" };
...
Would each of the compilers mentioned above store the backing array to the uniform initialisation in the same memory as a variable declared static const? And would each of the compilers initialise the backing array when the function is called, or on application initialisation? (I'm not talking about the std::initializer_list<std::string> that would be created, but rather the "hidden array" it refers to.
This is my attempt to answer my own question for at least GCC. My understanding of the assembler output of gcc is not fantastic, so please correct as necessary.
Using initializer_test.cpp:
#include <vector>
int main()
{
std::vector<long> values = { 123456, 123457, 123458 };
return 0;
}
And compiling using gcc v4.6.3 using the following command line:
g++ -Wa,-adhln -g initializer_test.cpp -masm=intel -std=c++0x -fverbose-asm | c++filt | view -
I get the following output (cut down to the hopefully relevant bits):
5:initializer_test.cpp **** std::vector<long> values = { 123456, 123457, 123458 };
100 .loc 2 5 0
101 0009 488D45EF lea rax, [rbp-17] # tmp62,
102 000d 4889C7 mov rdi, rax #, tmp62
103 .cfi_offset 3, -24
104 0010 E8000000 call std::allocator<long>::allocator() #
104 00
105 0015 488D45D0 lea rax, [rbp-48] # tmp63,
106 0019 BA030000 mov edx, 3 #, <-- Parameter 3
106 00
107 001e BE000000 mov esi, OFFSET FLAT:._42 #, <-- Parameter 2
107 00
108 0023 4889C7 mov rdi, rax #, tmp63 <-- Parameter 1
109 0026 E8000000 call std::initializer_list<long>::initializer_list(long const*, unsigned long) #
109 00
110 002b 488D4DEF lea rcx, [rbp-17] # tmp64,
111 002f 488B75D0 mov rsi, QWORD PTR [rbp-48] # tmp65, D.10602
112 0033 488B55D8 mov rdx, QWORD PTR [rbp-40] # tmp66, D.10602
113 0037 488D45B0 lea rax, [rbp-80] # tmp67,
114 003b 4889C7 mov rdi, rax #, tmp67
115 .LEHB0:
116 003e E8000000 call std::vector<long, std::allocator<long> >::vector(std::initializer_list<long>, std::allocator<long> const&) #
116 00
117 .LEHE0:
118 .loc 2 5 0 is_stmt 0 discriminator 1
119 0043 488D45EF lea rax, [rbp-17] # tmp68,
120 0047 4889C7 mov rdi, rax #, tmp68
121 004a E8000000 call std::allocator<long>::~allocator() #
and
1678 .section .rodata
1679 0002 00000000 .align 16
1679 00000000
1679 00000000
1679 0000
1682 ._42:
1683 0010 40E20100 .quad 123456
1683 00000000
1684 0018 41E20100 .quad 123457
1684 00000000
1685 0020 42E20100 .quad 123458
1685 00000000
Now if I'm understanding the call on line 109 correctly in the context of x86-64 System V AMD64 ABI calling convention (the parameters I've annotated to the code listing), this is showing that the backing array is being stored in .rodata, which I am taking to be the same memory as static const data. At least for gcc 4.6 anyway.
Performing a similar thing test but with optimisations turned on (-O2) it seems the initializer_list is optimised out:
70 .file 2 "/usr/include/c++/4.6/ext/new_allocator.h"
71 .loc 2 92 0
72 0004 BF180000 mov edi, 24 #,
72 00
73 0009 E8000000 call operator new(unsigned long) #
73 00
74 .LVL1:
75 .file 3 "/usr/include/c++/4.6/bits/stl_algobase.h"
76 .loc 3 366 0
77 000e 488B1500 mov rdx, QWORD PTR ._42[rip] # ._42, ._42
77 000000
90 .file 4 "/usr/include/c++/4.6/bits/stl_vector.h"
91 .loc 4 155 0
92 0015 4885C0 test rax, rax # D.11805
105 .loc 3 366 0
106 0018 488910 mov QWORD PTR [rax], rdx #* D.11805, ._42
107 001b 488B1500 mov rdx, QWORD PTR ._42[rip+8] # ._42, ._42
107 000000
108 0022 48895008 mov QWORD PTR [rax+8], rdx #, ._42
109 0026 488B1500 mov rdx, QWORD PTR ._42[rip+16] # ._42, ._42
109 000000
110 002d 48895010 mov QWORD PTR [rax+16], rdx #, ._42
124 .loc 4 155 0
125 0031 7408 je .L8 #,
126 .LVL3:
127 .LBB342:
128 .LBB343:
129 .loc 2 98 0
130 0033 4889C7 mov rdi, rax #, D.11805
131 0036 E8000000 call operator delete(void*) #
All in all, std::initializer_list is looking pretty optimal in gcc.
First of all: VC++, as of version VS11=VS2012 in its initial release does not support initializer lists, so the question is a bit moot for VS atm., but as I'm sure they'll patch this up, it should become relevant in a few months (or years).
As additional info, I'll add what VS 2012 does with local array initialization, everybody may draw it's own conclusion as for what that means for when they'll implement initializer lists:
Here's initialization of built-in arrays what VC++2012 spits out in the default release mode of the compiler:
int _tmain(int argc, _TCHAR* argv[])
{
00B91002 in al,dx
00B91003 sub esp,28h
00B91006 mov eax,dword ptr ds:[00B94018h]
00B9100B xor eax,ebp
00B9100D mov dword ptr [ebp-4],eax
00B91010 push esi
int numbers[] = {1,2,3,4,5,6,7,8,9};
00B91011 mov dword ptr [numbers],1
00B91018 mov dword ptr [ebp-24h],2
00B9101F mov dword ptr [ebp-20h],3
00B91026 mov dword ptr [ebp-1Ch],4
00B9102D mov dword ptr [ebp-18h],5
00B91034 mov dword ptr [ebp-14h],6
00B9103B mov dword ptr [ebp-10h],7
00B91042 mov dword ptr [ebp-0Ch],8
00B91049 mov dword ptr [ebp-8],9
...
So this array is created/filled at function execution, no "static" storage involved as such.