main()
"Good, but non-essential" — progarchives.com
int main() {}
$ gcc -Os empty.c -o c/empty
$ g++ -Os empty.cpp -o cpp/empty
$ ls -l c/empty cpp/empty
7976 c/empty
7976 cpp/empty
$ objdump --no-show-raw-insn -dC cpp/empty
$ readelf -a cpp/empty
.text
— code.rodata
— read-only data.data
— read/write data.bss
— zero-initialised datamain()
struct Foo {
static int numFoos;
Foo() {
numFoos++;
}
~Foo() {
numFoos--;
}
};
int Foo::numFoos;
Foo globalFoo;
int main() {
std::cout << "numFoos = "
<< Foo::numFoos << "\n";
}
$ g++ -O0 -g global.cpp -o global
$ ./global
numFoos = 1
#0 Foo::Foo (this=0x601050 <global>) at global.cpp:6
#1 0x000000000040079d in __static_initialization_and_destruction_0 (
__initialize_p=1, __priority=65535) at global.cpp:14
#2 0x00000000004007b3 in _GLOBAL__sub_I_global.cpp(void) () at global.cpp:18
#3 0x000000000040082d in __libc_csu_init ()
#4 0x00007ffff70c1b28 in __libc_start_main (main=0x400702 <main()>, argc=1,
... at ../csu/libc-start.c:266
#5 0x000000000040064a in _start ()
// Paraphrased from glibc/csu/elf-init.c
typedef void (*init_func)(int, char **, char **);
extern init_func __init_array_start[];
extern init_func __init_array_end[];
int __libc_csu_init(int argc, char **argv, char **envp) {
const size_t size = __init_array_end - __init_array_start;
for (size_t i = 0; i < size; i++)
(*__init_array_start[i])(argc, argv, envp);
}
__init_array_start
?__init_array_end
?
.section .init_array,"aw"
.align 8
.quad _GLOBAL__sub_I_Foo::numFoos
.text
What does it do?
.o
files
// hello.cpp
extern const char *getMessage();
void greet() {
std::cout << getMessage() << "\n";
}
int main() {
greet();
}
// message.cpp
const char *getMessage() {
return "Hello world";
}
$ g++ -Os -o hello.o hello.cpp
$ g++ -Os -o message.o message.cpp
$ g++ -Os -o hello message.o hello.o
$ ./hello
Hello world
$ file hello hello.o message.o
hello: ELF 64-bit LSB executable, x86-64,
dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2,
for GNU/Linux 3.2.0, not stripped
hello.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
message.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), not stripped
$ objdump -dC hello.o
$ objdump --reloc -dC hello.o
$ objdump --syms -C hello.o
$ objdump --syms -C message.o
getMessage()
"Hello world"
greet()
main()
greet() {}
getMessage()
main()
"Hello world"
$ g++ -o /dev/null -x c /dev/null -Wl,--verbose
.init_array :
{
PROVIDE_HIDDEN (__init_array_start = .);
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP (*(.init_array EXCLUDE_FILE (
*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
PROVIDE_HIDDEN (__init_array_end = .);
}
init_array
init_array
init_array
and calls each-Wl,--gc-sections
-ffunction-sections
, -fdata-sections
$ ls -l dynamic/hello static/hello
8,688 dynamic/hello*
2,406,632 static/hello*
$ g++ -Os -o message.o message.cpp
$ g++ -shared -o libhello.so message.o
$ g++ -Os -o hello hello.o
$ g++ -Os -o hello.o hello.cpp -L. -lhello
$ ./hello
Hello world
$ readelf --dynamic --program-headers dynamic-dso/hello
getMessage()@plt:
0x4006b0: jmpq *0x200962(%rip) # 0x601018
0x4006b6: pushq $0x0
0x4006bb: jmpq 0x4006a0 ; ultimately resolves symbol 0
...
0x601018: .quad 0x4006b6
getMessage()@plt:
0x4006b0: jmpq *0x200962(%rip) # 0x601018
0x4006b6: pushq $0x0
0x4006bb: jmpq 0x4006a0
...
0x601018: .quad 0x7ffff7bd35d5 ; now resolved to getMessage()
LD_BIND_NOW
(and -Wl,-znow
)ldd
and LD_DEBUG
LD_PRELOAD