Ishay Peled Ishay Peled - 4 months ago 10
C++ Question

Where does C++ keep it's class variables in the resulting ELF file?

This question relates specifically to the x86 architecture,

g++
compiler and
c++
code.

So, I have the following code:

#include <iostream>

int second;

class First {
private:
int hello;
public:
First(int number)
{
hello = number;
}

void printStuff()
{
std::cout<<this->hello<<'\n';
}
};

int main(int argc, char** argv)
{
First *first = new First(argc);
first->printStuff();
second = argc;
return 0;
}


After compiling it like so:

g++ -O0 -g class.cpp -o class


I get the output
class
binary.

Now, I want to know where
hello
is stored, so I do
readelf -s ./class
and the output is:

[ishaypeled@escorpio tmp14]$ readelf -s --wide ./class

Symbol table '.dynsym' contains 13 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSolsEi@GLIBCXX_3.4 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev@GLIBCXX_3.4 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (3)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit@GLIBC_2.2.5 (3)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_c@GLIBCXX_3.4 (2)
8: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
9: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
10: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _Znwm@GLIBCXX_3.4 (2)
11: 00000000004006c0 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev@GLIBCXX_3.4 (2)
12: 0000000000600dc0 272 OBJECT GLOBAL DEFAULT 26 _ZSt4cout@GLIBCXX_3.4 (2)

Symbol table '.symtab' contains 88 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000400200 0 SECTION LOCAL DEFAULT 1
2: 000000000040021c 0 SECTION LOCAL DEFAULT 2
3: 000000000040023c 0 SECTION LOCAL DEFAULT 3
4: 0000000000400260 0 SECTION LOCAL DEFAULT 4
5: 0000000000400288 0 SECTION LOCAL DEFAULT 5
6: 00000000004003c0 0 SECTION LOCAL DEFAULT 6
7: 0000000000400502 0 SECTION LOCAL DEFAULT 7
8: 0000000000400520 0 SECTION LOCAL DEFAULT 8
9: 0000000000400560 0 SECTION LOCAL DEFAULT 9
10: 0000000000400590 0 SECTION LOCAL DEFAULT 10
11: 0000000000400638 0 SECTION LOCAL DEFAULT 11
12: 0000000000400660 0 SECTION LOCAL DEFAULT 12
13: 00000000004006e0 0 SECTION LOCAL DEFAULT 13
14: 00000000004006f0 0 SECTION LOCAL DEFAULT 14
15: 0000000000400944 0 SECTION LOCAL DEFAULT 15
16: 0000000000400950 0 SECTION LOCAL DEFAULT 16
17: 0000000000400958 0 SECTION LOCAL DEFAULT 17
18: 00000000004009b0 0 SECTION LOCAL DEFAULT 18
19: 0000000000600b30 0 SECTION LOCAL DEFAULT 19
20: 0000000000600b40 0 SECTION LOCAL DEFAULT 20
21: 0000000000600b48 0 SECTION LOCAL DEFAULT 21
22: 0000000000600b50 0 SECTION LOCAL DEFAULT 22
23: 0000000000600d50 0 SECTION LOCAL DEFAULT 23
24: 0000000000600d58 0 SECTION LOCAL DEFAULT 24
25: 0000000000600da8 0 SECTION LOCAL DEFAULT 25
26: 0000000000600dc0 0 SECTION LOCAL DEFAULT 26
27: 0000000000000000 0 SECTION LOCAL DEFAULT 27
28: 0000000000000000 0 SECTION LOCAL DEFAULT 28
29: 0000000000000000 0 SECTION LOCAL DEFAULT 29
30: 0000000000000000 0 SECTION LOCAL DEFAULT 30
31: 0000000000000000 0 SECTION LOCAL DEFAULT 31
32: 0000000000000000 0 SECTION LOCAL DEFAULT 32
33: 0000000000000000 0 SECTION LOCAL DEFAULT 33
34: 0000000000000000 0 FILE LOCAL DEFAULT ABS init.c
35: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
36: 0000000000600b48 0 OBJECT LOCAL DEFAULT 21 __JCR_LIST__
37: 0000000000400720 0 FUNC LOCAL DEFAULT 14 deregister_tm_clones
38: 0000000000400760 0 FUNC LOCAL DEFAULT 14 register_tm_clones
39: 00000000004007a0 0 FUNC LOCAL DEFAULT 14 __do_global_dtors_aux
40: 0000000000600ed0 1 OBJECT LOCAL DEFAULT 26 completed.6938
41: 0000000000600b40 0 OBJECT LOCAL DEFAULT 20 __do_global_dtors_aux_fini_array_entry
42: 00000000004007c0 0 FUNC LOCAL DEFAULT 14 frame_dummy
43: 0000000000600b30 0 OBJECT LOCAL DEFAULT 19 __frame_dummy_init_array_entry
44: 0000000000000000 0 FILE LOCAL DEFAULT ABS class.cpp
45: 0000000000400954 1 OBJECT LOCAL DEFAULT 16 _ZStL19piecewise_construct
46: 0000000000600ed8 1 OBJECT LOCAL DEFAULT 26 _ZStL8__ioinit
47: 0000000000400835 62 FUNC LOCAL DEFAULT 14 _Z41__static_initialization_and_destruction_0ii
48: 0000000000400873 21 FUNC LOCAL DEFAULT 14 _GLOBAL__sub_I_second
49: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
50: 0000000000400b28 0 OBJECT LOCAL DEFAULT 18 __FRAME_END__
51: 0000000000600b48 0 OBJECT LOCAL DEFAULT 21 __JCR_END__
52: 0000000000000000 0 FILE LOCAL DEFAULT ABS
53: 0000000000400958 0 NOTYPE LOCAL DEFAULT 17 __GNU_EH_FRAME_HDR
54: 0000000000600d58 0 OBJECT LOCAL DEFAULT 24 _GLOBAL_OFFSET_TABLE_
55: 0000000000600b40 0 NOTYPE LOCAL DEFAULT 19 __init_array_end
56: 0000000000600b30 0 NOTYPE LOCAL DEFAULT 19 __init_array_start
57: 0000000000600b50 0 OBJECT LOCAL DEFAULT 22 _DYNAMIC
58: 0000000000600da8 0 NOTYPE WEAK DEFAULT 25 data_start
59: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSolsEi@@GLIBCXX_3.4
60: 0000000000400940 2 FUNC GLOBAL DEFAULT 14 __libc_csu_fini
61: 0000000000600ed4 4 OBJECT GLOBAL DEFAULT 26 second
62: 00000000004006f0 42 FUNC GLOBAL DEFAULT 14 _start
63: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
64: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
65: 0000000000400944 0 FUNC GLOBAL DEFAULT 15 _fini
66: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitC1Ev@@GLIBCXX_3.4
67: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_2.2.5
68: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit@@GLIBC_2.2.5
69: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_c@@GLIBCXX_3.4
70: 00000000004006c0 0 FUNC GLOBAL DEFAULT UND _ZNSt8ios_base4InitD1Ev@@GLIBCXX_3.4
71: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
72: 0000000000400950 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used
73: 0000000000400888 23 FUNC WEAK DEFAULT 14 _ZN5FirstC1Ei
74: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
75: 0000000000600da8 0 NOTYPE GLOBAL DEFAULT 25 __data_start
76: 00000000004008a0 46 FUNC WEAK DEFAULT 14 _ZN5First10printStuffEv
77: 0000000000400888 23 FUNC WEAK DEFAULT 14 _ZN5FirstC2Ei
78: 0000000000600db8 0 OBJECT GLOBAL HIDDEN 25 __TMC_END__
79: 0000000000600dc0 272 OBJECT GLOBAL DEFAULT 26 _ZSt4cout@@GLIBCXX_3.4
80: 0000000000600db0 0 OBJECT GLOBAL HIDDEN 25 __dso_handle
81: 00000000004008d0 101 FUNC GLOBAL DEFAULT 14 __libc_csu_init
82: 0000000000600db8 0 NOTYPE GLOBAL DEFAULT 26 __bss_start
83: 0000000000600ee0 0 NOTYPE GLOBAL DEFAULT 26 _end
84: 0000000000600db8 0 NOTYPE GLOBAL DEFAULT 25 _edata
85: 0000000000000000 0 FUNC GLOBAL DEFAULT UND _Znwm@@GLIBCXX_3.4
86: 00000000004007e6 79 FUNC GLOBAL DEFAULT 14 main
87: 0000000000400638 0 FUNC GLOBAL DEFAULT 11 _init


For better readability, I also ran this command:

[ishaypeled@escorpio tmp14]$ readelf -s --wide ./class | c++filt

Symbol table '.dynsym' contains 13 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000000000 0 FUNC GLOBAL DEFAULT UND std::basic_ostream<char, std::char_traits<char> >::operator<<(int)@GLIBCXX_3.4 (2)
2: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
3: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
4: 0000000000000000 0 FUNC GLOBAL DEFAULT UND std::ios_base::Init::Init()@GLIBCXX_3.4 (2)
5: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@GLIBC_2.2.5 (3)
6: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit@GLIBC_2.2.5 (3)
7: 0000000000000000 0 FUNC GLOBAL DEFAULT UND std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char)@GLIBCXX_3.4 (2)
8: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
9: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
10: 0000000000000000 0 FUNC GLOBAL DEFAULT UND operator new(unsigned long)@GLIBCXX_3.4 (2)
11: 00000000004006c0 0 FUNC GLOBAL DEFAULT UND std::ios_base::Init::~Init()@GLIBCXX_3.4 (2)
12: 0000000000600dc0 272 OBJECT GLOBAL DEFAULT 26 std::cout@GLIBCXX_3.4 (2)

Symbol table '.symtab' contains 88 entries:
Num: Value Size Type Bind Vis Ndx Name
0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
1: 0000000000400200 0 SECTION LOCAL DEFAULT 1
2: 000000000040021c 0 SECTION LOCAL DEFAULT 2
3: 000000000040023c 0 SECTION LOCAL DEFAULT 3
4: 0000000000400260 0 SECTION LOCAL DEFAULT 4
5: 0000000000400288 0 SECTION LOCAL DEFAULT 5
6: 00000000004003c0 0 SECTION LOCAL DEFAULT 6
7: 0000000000400502 0 SECTION LOCAL DEFAULT 7
8: 0000000000400520 0 SECTION LOCAL DEFAULT 8
9: 0000000000400560 0 SECTION LOCAL DEFAULT 9
10: 0000000000400590 0 SECTION LOCAL DEFAULT 10
11: 0000000000400638 0 SECTION LOCAL DEFAULT 11
12: 0000000000400660 0 SECTION LOCAL DEFAULT 12
13: 00000000004006e0 0 SECTION LOCAL DEFAULT 13
14: 00000000004006f0 0 SECTION LOCAL DEFAULT 14
15: 0000000000400944 0 SECTION LOCAL DEFAULT 15
16: 0000000000400950 0 SECTION LOCAL DEFAULT 16
17: 0000000000400958 0 SECTION LOCAL DEFAULT 17
18: 00000000004009b0 0 SECTION LOCAL DEFAULT 18
19: 0000000000600b30 0 SECTION LOCAL DEFAULT 19
20: 0000000000600b40 0 SECTION LOCAL DEFAULT 20
21: 0000000000600b48 0 SECTION LOCAL DEFAULT 21
22: 0000000000600b50 0 SECTION LOCAL DEFAULT 22
23: 0000000000600d50 0 SECTION LOCAL DEFAULT 23
24: 0000000000600d58 0 SECTION LOCAL DEFAULT 24
25: 0000000000600da8 0 SECTION LOCAL DEFAULT 25
26: 0000000000600dc0 0 SECTION LOCAL DEFAULT 26
27: 0000000000000000 0 SECTION LOCAL DEFAULT 27
28: 0000000000000000 0 SECTION LOCAL DEFAULT 28
29: 0000000000000000 0 SECTION LOCAL DEFAULT 29
30: 0000000000000000 0 SECTION LOCAL DEFAULT 30
31: 0000000000000000 0 SECTION LOCAL DEFAULT 31
32: 0000000000000000 0 SECTION LOCAL DEFAULT 32
33: 0000000000000000 0 SECTION LOCAL DEFAULT 33
34: 0000000000000000 0 FILE LOCAL DEFAULT ABS init.c
35: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
36: 0000000000600b48 0 OBJECT LOCAL DEFAULT 21 __JCR_LIST__
37: 0000000000400720 0 FUNC LOCAL DEFAULT 14 deregister_tm_clones
38: 0000000000400760 0 FUNC LOCAL DEFAULT 14 register_tm_clones
39: 00000000004007a0 0 FUNC LOCAL DEFAULT 14 __do_global_dtors_aux
40: 0000000000600ed0 1 OBJECT LOCAL DEFAULT 26 completed.6938
41: 0000000000600b40 0 OBJECT LOCAL DEFAULT 20 __do_global_dtors_aux_fini_array_entry
42: 00000000004007c0 0 FUNC LOCAL DEFAULT 14 frame_dummy
43: 0000000000600b30 0 OBJECT LOCAL DEFAULT 19 __frame_dummy_init_array_entry
44: 0000000000000000 0 FILE LOCAL DEFAULT ABS class.cpp
45: 0000000000400954 1 OBJECT LOCAL DEFAULT 16 std::piecewise_construct
46: 0000000000600ed8 1 OBJECT LOCAL DEFAULT 26 std::__ioinit
47: 0000000000400835 62 FUNC LOCAL DEFAULT 14 __static_initialization_and_destruction_0(int, int)
48: 0000000000400873 21 FUNC LOCAL DEFAULT 14 _GLOBAL__sub_I_second
49: 0000000000000000 0 FILE LOCAL DEFAULT ABS crtstuff.c
50: 0000000000400b28 0 OBJECT LOCAL DEFAULT 18 __FRAME_END__
51: 0000000000600b48 0 OBJECT LOCAL DEFAULT 21 __JCR_END__
52: 0000000000000000 0 FILE LOCAL DEFAULT ABS
53: 0000000000400958 0 NOTYPE LOCAL DEFAULT 17 __GNU_EH_FRAME_HDR
54: 0000000000600d58 0 OBJECT LOCAL DEFAULT 24 _GLOBAL_OFFSET_TABLE_
55: 0000000000600b40 0 NOTYPE LOCAL DEFAULT 19 __init_array_end
56: 0000000000600b30 0 NOTYPE LOCAL DEFAULT 19 __init_array_start
57: 0000000000600b50 0 OBJECT LOCAL DEFAULT 22 _DYNAMIC
58: 0000000000600da8 0 NOTYPE WEAK DEFAULT 25 data_start
59: 0000000000000000 0 FUNC GLOBAL DEFAULT UND std::basic_ostream<char, std::char_traits<char> >::operator<<(int)@@GLIBCXX_3.4
60: 0000000000400940 2 FUNC GLOBAL DEFAULT 14 __libc_csu_fini
61: 0000000000600ed4 4 OBJECT GLOBAL DEFAULT 26 second
62: 00000000004006f0 42 FUNC GLOBAL DEFAULT 14 _start
63: 0000000000000000 0 NOTYPE WEAK DEFAULT UND __gmon_start__
64: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _Jv_RegisterClasses
65: 0000000000400944 0 FUNC GLOBAL DEFAULT 15 _fini
66: 0000000000000000 0 FUNC GLOBAL DEFAULT UND std::ios_base::Init::Init()@@GLIBCXX_3.4
67: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __libc_start_main@@GLIBC_2.2.5
68: 0000000000000000 0 FUNC GLOBAL DEFAULT UND __cxa_atexit@@GLIBC_2.2.5
69: 0000000000000000 0 FUNC GLOBAL DEFAULT UND std::basic_ostream<char, std::char_traits<char> >& std::operator<< <std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char)@@GLIBCXX_3.4
70: 00000000004006c0 0 FUNC GLOBAL DEFAULT UND std::ios_base::Init::~Init()@@GLIBCXX_3.4
71: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_deregisterTMCloneTable
72: 0000000000400950 4 OBJECT GLOBAL DEFAULT 16 _IO_stdin_used
73: 0000000000400888 23 FUNC WEAK DEFAULT 14 First::First(int)
74: 0000000000000000 0 NOTYPE WEAK DEFAULT UND _ITM_registerTMCloneTable
75: 0000000000600da8 0 NOTYPE GLOBAL DEFAULT 25 __data_start
76: 00000000004008a0 46 FUNC WEAK DEFAULT 14 First::printStuff()
77: 0000000000400888 23 FUNC WEAK DEFAULT 14 First::First(int)
78: 0000000000600db8 0 OBJECT GLOBAL HIDDEN 25 __TMC_END__
79: 0000000000600dc0 272 OBJECT GLOBAL DEFAULT 26 std::cout@@GLIBCXX_3.4
80: 0000000000600db0 0 OBJECT GLOBAL HIDDEN 25 __dso_handle
81: 00000000004008d0 101 FUNC GLOBAL DEFAULT 14 __libc_csu_init
82: 0000000000600db8 0 NOTYPE GLOBAL DEFAULT 26 __bss_start
83: 0000000000600ee0 0 NOTYPE GLOBAL DEFAULT 26 _end
84: 0000000000600db8 0 NOTYPE GLOBAL DEFAULT 25 _edata
85: 0000000000000000 0 FUNC GLOBAL DEFAULT UND operator new(unsigned long)@@GLIBCXX_3.4
86: 00000000004007e6 79 FUNC GLOBAL DEFAULT 14 main
87: 0000000000400638 0 FUNC GLOBAL DEFAULT 11 _init


My question is, where is the variable
first
? I don't see this object in the dump! Note that
second
is there as symbol 61. I expected mangling of
first
, but not for it to disappear altogether...

Anyone?

Answer

example.cpp:

class Clazz {
    int x;              // will live wherever the instance of Clazz is created
public:
    Clazz(const std::initializer_list<int> & data) {}
    Clazz() : x(13) {}  // "13" is either in constructor code, or .rodata
};

// these will end in .data section
// except the list parameter {1, 2, 3}, which is const and lands in .rodata
static int localInt;    // local symbol, will be in .o file only in debug info
int globalInt;          // global symbol
    // btw, both are initialized to 0, as they are defined in .data
static Clazz *classPtr = nullptr;
Clazz classInstance( {1, 2, 3} );

// all global symbols from .data/.rodata/.bss/.text (.code) sections
// will be visible in symbol table of executable (including the "foo" below)

// everything else defined below (except foo) is runtime allocated,
// and can't have any fixed address in symbol table, so it will not show there.

void foo(int param) {   // param is either on stack or in register (ABI specific)
    Clazz localVar;     // localVar instance is living on the stack space
    classPtr = new Clazz({});
    // Instance of Clazz pointed at by classPtr lives in global heap memory
    // If not released by explicit "delete classPtr;" during runtime,
    // it will cause memory leak (avoid using naked pointers like this).
    int localInt;       // localInt lives on stack too, uninitialized = undefined value!
    // On the contrary to *classPtr the localVar is released upon exiting it's scope
}

Neither stack or heap instances are in ELF file, in ELF file is only code capable to manipulate the instance, and to create the instance (either on stack or on heap, either by instancing it as global/local variable, or by new).

So unless you instantiate some type into .data/.bss sections (ie. defining it outside of function, as a global/local of that .cpp file), you can't figure out the where the variable will be kept by looking at symbol table of executable.