#include <iostream>
// This program prints "Hello World!"
int hello = printf("Hello World!");
int main(int argc, char** argv) {}
#include <iostream>
// Outputs: "123main()"
int one = printf("1");
int two = printf("2");
int main() {
printf("main()");
}
int three = printf("3");
The initialization of global variables requiring some setup might need what's referred to as a "global constructor". We can get $ clang++ empty_main.cpp -Wglobal-constructors
1.cpp:3:5: warning: declaration requires a global constructor [-Wglobal-constructors]
int hello = printf("Hello World!");
^ ~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.
section .text
global _start
_start:
mov rax, 60 ; set exit system call
xor rdi, rdi ; set exit status to 0
syscall ; call system call
On Linux, ELF "Executable and Linkable Format" specifies that the program's entry point is the main: # @main
xor eax, eax
ret
_GLOBAL__sub_I_example.cpp: # @_GLOBAL__sub_I_example.cpp
push rbx
lea rbx, [rip + std::__ioinit]
mov rdi, rbx
call std::ios_base::Init::Init()@PLT
mov rdi, qword ptr [rip + std::ios_base::Init::~Init()@GOTPCREL]
lea rdx, [rip + __dso_handle]
mov rsi, rbx
call __cxa_atexit@PLT
lea rdi, [rip + .L.str]
xor eax, eax
call printf@PLT
mov dword ptr [rip + hello], eax
pop rbx
ret
hello:
.long 0 # 0x0
.L.str:
.asciz "Hello World!"
You might observe that linux-vdso.so.1 (0x00007ffe2638c000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0x00007f72fde00000)
libm.so.6 => /usr/lib/libm.so.6 (0x00007f72fdd18000)
libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (0x00007f72fe09b000)
libc.so.6 => /usr/lib/libc.so.6 (0x00007f72fdb31000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007f72fe0f5000)
#include <iostream>
// Compiles successfully but the linker will complain
// because glibc wants to call main()
int hello = printf("Hello World!");
#include <iostream>
// The program prints "Hello World!"
__attribute__((constructor)) void fake_init()
{
printf("Hello World!\n");
}
int main() {}
A global constructor can be created by initializing an object in a global scope, this forces this object's constructor to be called.
#include <iostream>
int main() {}
// Calls X's constructor due to "a" being declared
// The program prints "Hello"
struct X {
X() { printf("Hello"); }
} a;
Questions? Comments? Insults? Send me an email! moc.snetramcirdec@cirdec
Created: 2023-01-20 - Last Edited: 2023-01-22
Please consider joining the mailing list to receive an email when a new article is posted. 😎