The Mess We Are In
This is a sort of a tribute to Joe Armstrong.
#include <iostream> int main() { std::cout << "Hello, World!" << std::endl; }
clang++ -m64 -march=native -std=c++20 -stdlib=libc++ -O3 a.cpp
ldd ./a.out
linux-vdso.so.1 (0x00007ffc46ed5000) libc++.so.1 => /usr/lib64/libc++.so.1 (0x00007fa8c2449000) libc++abi.so.1 => /usr/lib64/libc++abi.so.1 (0x00007fa8c2405000) libunwind.so.8 => /usr/lib64/libunwind.so.8 (0x00007fa8c23e7000) libm.so.6 => /lib64/libm.so.6 (0x00007fa8c230d000) libc.so.6 => /lib64/libc.so.6 (0x00007fa8c2136000) /lib64/ld-linux-x86-64.so.2 (0x00007fa8c257e000) liblzma.so.5 => /lib64/liblzma.so.5 (0x00007fa8c20ff000)
Gentoo uses the wrong libunwind, but it does not matter.
objdump -d a.out
a.out: file format elf64-x86-64
Disassembly of section .text:
0000000000001ed0 <_start>:
1ed0: f3 0f 1e fa endbr64
1ed4: 31 ed xorl %ebp, %ebp
1ed6: 49 89 d1 movq %rdx, %r9
1ed9: 5e popq %rsi
1eda: 48 89 e2 movq %rsp, %rdx
1edd: 48 83 e4 f0 andq $-16, %rsp
1ee1: 50 pushq %rax
1ee2: 54 pushq %rsp
1ee3: 45 31 c0 xorl %r8d, %r8d
1ee6: 31 c9 xorl %ecx, %ecx
1ee8: 48 8d 3d 81 00 00 00 leaq 129(%rip), %rdi # 0x1f70 <main>
1eef: ff 15 db 17 00 00 callq *6107(%rip) # 0x36d0 <memset+0x36d0>
1ef5: f4 hlt
1ef6: cc int3
1ef7: cc int3
1ef8: cc int3
1ef9: cc int3
1efa: cc int3
1efb: cc int3
1efc: cc int3
1efd: cc int3
1efe: cc int3
1eff: cc int3
1f00: 80 3d d1 28 00 00 00 cmpb $0, 10449(%rip) # 0x47d8 <memset+0x47d8>
1f07: 75 24 jne 0x1f2d <_start+0x5d>
1f09: c6 05 c8 28 00 00 01 movb $1, 10440(%rip) # 0x47d8 <memset+0x47d8>
1f10: 48 83 3d c8 17 00 00 00 cmpq $0, 6088(%rip) # 0x36e0 <memset+0x36e0>
1f18: 74 13 je 0x1f2d <_start+0x5d>
1f1a: 48 8d 3d 3f ee ff ff leaq -4545(%rip), %rdi # 0xd60 <__EH_FRAME_LIST_END__>
1f21: 48 8d 35 b8 28 00 00 leaq 10424(%rip), %rsi # 0x47e0 <memset+0x47e0>
1f28: e9 63 04 00 00 jmp 0x2390 <__register_frame_info@plt>
1f2d: c3 retq
1f2e: 66 90 nop
1f30: 50 pushq %rax
1f31: 80 3d e8 28 00 00 00 cmpb $0, 10472(%rip) # 0x4820 <memset+0x4820>
1f38: 75 34 jne 0x1f6e <_start+0x9e>
1f3a: c6 05 df 28 00 00 01 movb $1, 10463(%rip) # 0x4820 <memset+0x4820>
1f41: 48 83 3d 9f 17 00 00 00 cmpq $0, 6047(%rip) # 0x36e8 <memset+0x36e8>
1f49: 74 0c je 0x1f57 <_start+0x87>
1f4b: 48 8b 3d be 27 00 00 movq 10174(%rip), %rdi # 0x4710 <__dso_handle>
1f52: e8 49 04 00 00 callq 0x23a0 <__cxa_finalize@plt>
1f57: 48 83 3d 91 17 00 00 00 cmpq $0, 6033(%rip) # 0x36f0 <memset+0x36f0>
1f5f: 74 0d je 0x1f6e <_start+0x9e>
1f61: 48 8d 3d f8 ed ff ff leaq -4616(%rip), %rdi # 0xd60 <__EH_FRAME_LIST_END__>
1f68: 58 popq %rax
1f69: e9 42 04 00 00 jmp 0x23b0 <__deregister_frame_info@plt>
1f6e: 58 popq %rax
1f6f: c3 retq
0000000000001f70 <main>:
1f70: 55 pushq %rbp
1f71: 53 pushq %rbx
1f72: 48 83 ec 18 subq $24, %rsp
1f76: 64 48 8b 04 25 28 00 00 00 movq %fs:40, %rax
1f7f: 48 89 44 24 10 movq %rax, 16(%rsp)
1f84: 48 8b 3d 6d 17 00 00 movq 5997(%rip), %rdi # 0x36f8 <memset+0x36f8>
1f8b: 48 8d 35 12 ed ff ff leaq -4846(%rip), %rsi # 0xca4 <_IO_stdin_used+0x4>
1f92: ba 0d 00 00 00 movl $13, %edx
1f97: e8 94 00 00 00 callq 0x2030 <_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m>
1f9c: 48 89 c3 movq %rax, %rbx
1f9f: 48 8b 00 movq (%rax), %rax
1fa2: 48 8b 70 e8 movq -24(%rax), %rsi
1fa6: 48 01 de addq %rbx, %rsi
1fa9: 48 8d 6c 24 08 leaq 8(%rsp), %rbp
1fae: 48 89 ef movq %rbp, %rdi
1fb1: e8 0a 04 00 00 callq 0x23c0 <_ZNKSt3__18ios_base6getlocEv@plt>
1fb6: 48 8b 35 43 17 00 00 movq 5955(%rip), %rsi # 0x3700 <memset+0x3700>
1fbd: 48 89 ef movq %rbp, %rdi
1fc0: e8 0b 04 00 00 callq 0x23d0 <_ZNKSt3__16locale9use_facetERNS0_2idE@plt>
1fc5: 48 8b 08 movq (%rax), %rcx
1fc8: 48 89 c7 movq %rax, %rdi
1fcb: be 0a 00 00 00 movl $10, %esi
1fd0: ff 51 38 callq *56(%rcx)
1fd3: 89 c5 movl %eax, %ebp
1fd5: 48 8d 7c 24 08 leaq 8(%rsp), %rdi
1fda: e8 01 04 00 00 callq 0x23e0 <_ZNSt3__16localeD1Ev@plt>
1fdf: 40 0f be f5 movsbl %bpl, %esi
1fe3: 48 89 df movq %rbx, %rdi
1fe6: e8 05 04 00 00 callq 0x23f0 <_ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE3putEc@plt>
1feb: 48 89 df movq %rbx, %rdi
1fee: e8 0d 04 00 00 callq 0x2400 <_ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE5flushEv@plt>
1ff3: 64 48 8b 04 25 28 00 00 00 movq %fs:40, %rax
1ffc: 48 3b 44 24 10 cmpq 16(%rsp), %rax
2001: 75 09 jne 0x200c <main+0x9c>
2003: 31 c0 xorl %eax, %eax
2005: 48 83 c4 18 addq $24, %rsp
2009: 5b popq %rbx
200a: 5d popq %rbp
200b: c3 retq
200c: e8 ff 03 00 00 callq 0x2410 <__stack_chk_fail@plt>
2011: 48 89 c3 movq %rax, %rbx
2014: 48 8d 7c 24 08 leaq 8(%rsp), %rdi
2019: e8 c2 03 00 00 callq 0x23e0 <_ZNSt3__16localeD1Ev@plt>
201e: 48 89 df movq %rbx, %rdi
2021: e8 fa 03 00 00 callq 0x2420 <_Unwind_Resume@plt>
2026: cc int3
2027: cc int3
2028: cc int3
2029: cc int3
202a: cc int3
202b: cc int3
202c: cc int3
202d: cc int3
202e: cc int3
202f: cc int3
0000000000002030 <_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m>:
2030: 55 pushq %rbp
2031: 41 57 pushq %r15
2033: 41 56 pushq %r14
2035: 41 55 pushq %r13
2037: 41 54 pushq %r12
2039: 53 pushq %rbx
203a: 48 83 ec 28 subq $40, %rsp
203e: 49 89 d6 movq %rdx, %r14
2041: 49 89 f7 movq %rsi, %r15
2044: 48 89 fb movq %rdi, %rbx
2047: 64 48 8b 04 25 28 00 00 00 movq %fs:40, %rax
2050: 48 89 44 24 20 movq %rax, 32(%rsp)
2055: 48 8d 7c 24 08 leaq 8(%rsp), %rdi
205a: 48 89 de movq %rbx, %rsi
205d: e8 ce 03 00 00 callq 0x2430 <_ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE6sentryC1ERS3_@plt>
2062: 80 7c 24 08 00 cmpb $0, 8(%rsp)
2067: 0f 84 ab 00 00 00 je 0x2118 <_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m+0xe8>
206d: 48 8b 03 movq (%rbx), %rax
2070: 48 8b 40 e8 movq -24(%rax), %rax
2074: 4c 8d 24 03 leaq (%rbx,%rax), %r12
2078: 4c 8b 6c 03 28 movq 40(%rbx,%rax), %r13
207d: 8b 6c 03 08 movl 8(%rbx,%rax), %ebp
2081: 8b 84 03 90 00 00 00 movl 144(%rbx,%rax), %eax
2088: 83 f8 ff cmpl $-1, %eax
208b: 75 47 jne 0x20d4 <_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m+0xa4>
208d: 48 8d 7c 24 18 leaq 24(%rsp), %rdi
2092: 4c 89 e6 movq %r12, %rsi
2095: e8 26 03 00 00 callq 0x23c0 <_ZNKSt3__18ios_base6getlocEv@plt>
209a: 48 8b 35 5f 16 00 00 movq 5727(%rip), %rsi # 0x3700 <memset+0x3700>
20a1: 48 8d 7c 24 18 leaq 24(%rsp), %rdi
20a6: e8 25 03 00 00 callq 0x23d0 <_ZNKSt3__16locale9use_facetERNS0_2idE@plt>
20ab: 48 8b 08 movq (%rax), %rcx
20ae: 48 89 c7 movq %rax, %rdi
20b1: be 20 00 00 00 movl $32, %esi
20b6: ff 51 38 callq *56(%rcx)
20b9: 88 44 24 07 movb %al, 7(%rsp)
20bd: 48 8d 7c 24 18 leaq 24(%rsp), %rdi
20c2: e8 19 03 00 00 callq 0x23e0 <_ZNSt3__16localeD1Ev@plt>
20c7: 0f be 44 24 07 movsbl 7(%rsp), %eax
20cc: 41 89 84 24 90 00 00 00 movl %eax, 144(%r12)
20d4: 81 e5 b0 00 00 00 andl $176, %ebp
20da: 4d 01 fe addq %r15, %r14
20dd: 83 fd 20 cmpl $32, %ebp
20e0: 4c 89 fa movq %r15, %rdx
20e3: 49 0f 44 d6 cmoveq %r14, %rdx
20e7: 44 0f be c8 movsbl %al, %r9d
20eb: 4c 89 ef movq %r13, %rdi
20ee: 4c 89 fe movq %r15, %rsi
20f1: 4c 89 f1 movq %r14, %rcx
20f4: 4d 89 e0 movq %r12, %r8
20f7: e8 b4 00 00 00 callq 0x21b0 <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_>
20fc: 48 85 c0 testq %rax, %rax
20ff: 75 17 jne 0x2118 <_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m+0xe8>
2101: 48 8b 03 movq (%rbx), %rax
2104: 48 8b 40 e8 movq -24(%rax), %rax
2108: 48 8d 3c 03 leaq (%rbx,%rax), %rdi
210c: 8b 74 03 20 movl 32(%rbx,%rax), %esi
2110: 83 ce 05 orl $5, %esi
2113: e8 28 03 00 00 callq 0x2440 <_ZNSt3__18ios_base5clearEj@plt>
2118: 48 8d 7c 24 08 leaq 8(%rsp), %rdi
211d: e8 2e 03 00 00 callq 0x2450 <_ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE6sentryD1Ev@plt>
2122: 64 48 8b 04 25 28 00 00 00 movq %fs:40, %rax
212b: 48 3b 44 24 20 cmpq 32(%rsp), %rax
2130: 75 61 jne 0x2193 <_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m+0x163>
2132: 48 89 d8 movq %rbx, %rax
2135: 48 83 c4 28 addq $40, %rsp
2139: 5b popq %rbx
213a: 41 5c popq %r12
213c: 41 5d popq %r13
213e: 41 5e popq %r14
2140: 41 5f popq %r15
2142: 5d popq %rbp
2143: c3 retq
2144: eb 0f jmp 0x2155 <_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m+0x125>
2146: 49 89 c6 movq %rax, %r14
2149: 48 8d 7c 24 18 leaq 24(%rsp), %rdi
214e: e8 8d 02 00 00 callq 0x23e0 <_ZNSt3__16localeD1Ev@plt>
2153: eb 03 jmp 0x2158 <_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m+0x128>
2155: 49 89 c6 movq %rax, %r14
2158: 48 8d 7c 24 08 leaq 8(%rsp), %rdi
215d: e8 ee 02 00 00 callq 0x2450 <_ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE6sentryD1Ev@plt>
2162: eb 03 jmp 0x2167 <_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m+0x137>
2164: 49 89 c6 movq %rax, %r14
2167: 4c 89 f7 movq %r14, %rdi
216a: e8 f1 02 00 00 callq 0x2460 <__cxa_begin_catch@plt>
216f: 48 8b 03 movq (%rbx), %rax
2172: 48 8b 78 e8 movq -24(%rax), %rdi
2176: 48 01 df addq %rbx, %rdi
2179: e8 f2 02 00 00 callq 0x2470 <_ZNSt3__18ios_base33__set_badbit_and_consider_rethrowEv@plt>
217e: e8 fd 02 00 00 callq 0x2480 <__cxa_end_catch@plt>
2183: 64 48 8b 04 25 28 00 00 00 movq %fs:40, %rax
218c: 48 3b 44 24 20 cmpq 32(%rsp), %rax
2191: 74 9f je 0x2132 <_ZNSt3__124__put_character_sequenceIcNS_11char_traitsIcEEEERNS_13basic_ostreamIT_T0_EES7_PKS4_m+0x102>
2193: e8 78 02 00 00 callq 0x2410 <__stack_chk_fail@plt>
2198: 48 89 c3 movq %rax, %rbx
219b: e8 e0 02 00 00 callq 0x2480 <__cxa_end_catch@plt>
21a0: 48 89 df movq %rbx, %rdi
21a3: e8 78 02 00 00 callq 0x2420 <_Unwind_Resume@plt>
21a8: 48 89 c7 movq %rax, %rdi
21ab: e8 90 01 00 00 callq 0x2340 <__clang_call_terminate>
00000000000021b0 <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_>:
21b0: 55 pushq %rbp
21b1: 41 57 pushq %r15
21b3: 41 56 pushq %r14
21b5: 41 55 pushq %r13
21b7: 41 54 pushq %r12
21b9: 53 pushq %rbx
21ba: 48 83 ec 38 subq $56, %rsp
21be: 64 48 8b 04 25 28 00 00 00 movq %fs:40, %rax
21c7: 48 89 44 24 30 movq %rax, 48(%rsp)
21cc: 48 85 ff testq %rdi, %rdi
21cf: 0f 84 1c 01 00 00 je 0x22f1 <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0x141>
21d5: 4d 89 c6 movq %r8, %r14
21d8: 49 89 cf movq %rcx, %r15
21db: 49 89 d4 movq %rdx, %r12
21de: 49 89 fd movq %rdi, %r13
21e1: 44 89 4c 24 0c movl %r9d, 12(%rsp)
21e6: 48 89 c8 movq %rcx, %rax
21e9: 48 29 f0 subq %rsi, %rax
21ec: 49 8b 48 18 movq 24(%r8), %rcx
21f0: 31 db xorl %ebx, %ebx
21f2: 48 29 c1 subq %rax, %rcx
21f5: 48 0f 4f d9 cmovgq %rcx, %rbx
21f9: 48 89 d5 movq %rdx, %rbp
21fc: 48 29 f5 subq %rsi, %rbp
21ff: 48 85 ed testq %rbp, %rbp
2202: 7e 16 jle 0x221a <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0x6a>
2204: 49 8b 45 00 movq (%r13), %rax
2208: 4c 89 ef movq %r13, %rdi
220b: 48 89 ea movq %rbp, %rdx
220e: ff 50 60 callq *96(%rax)
2211: 48 39 e8 cmpq %rbp, %rax
2214: 0f 85 d7 00 00 00 jne 0x22f1 <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0x141>
221a: 48 85 db testq %rbx, %rbx
221d: 0f 8e 94 00 00 00 jle 0x22b7 <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0x107>
2223: 4c 89 74 24 10 movq %r14, 16(%rsp)
2228: 48 83 fb 17 cmpq $23, %rbx
222c: 73 0e jae 0x223c <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0x8c>
222e: 8d 04 1b leal (%rbx,%rbx), %eax
2231: 88 44 24 18 movb %al, 24(%rsp)
2235: 4c 8d 74 24 19 leaq 25(%rsp), %r14
223a: eb 26 jmp 0x2262 <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0xb2>
223c: 48 8d 6b 10 leaq 16(%rbx), %rbp
2240: 48 83 e5 f0 andq $-16, %rbp
2244: 48 89 ef movq %rbp, %rdi
2247: e8 44 02 00 00 callq 0x2490 <_Znwm@plt>
224c: 49 89 c6 movq %rax, %r14
224f: 48 89 44 24 28 movq %rax, 40(%rsp)
2254: 48 83 cd 01 orq $1, %rbp
2258: 48 89 6c 24 18 movq %rbp, 24(%rsp)
225d: 48 89 5c 24 20 movq %rbx, 32(%rsp)
2262: 8b 44 24 0c movl 12(%rsp), %eax
2266: 0f b6 f0 movzbl %al, %esi
2269: 4c 89 f7 movq %r14, %rdi
226c: 48 89 da movq %rbx, %rdx
226f: e8 2c 02 00 00 callq 0x24a0 <memset@plt>
2274: 41 c6 04 1e 00 movb $0, (%r14,%rbx)
2279: f6 44 24 18 01 testb $1, 24(%rsp)
227e: 74 07 je 0x2287 <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0xd7>
2280: 48 8b 74 24 28 movq 40(%rsp), %rsi
2285: eb 05 jmp 0x228c <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0xdc>
2287: 48 8d 74 24 19 leaq 25(%rsp), %rsi
228c: 4c 8b 74 24 10 movq 16(%rsp), %r14
2291: 49 8b 45 00 movq (%r13), %rax
2295: 4c 89 ef movq %r13, %rdi
2298: 48 89 da movq %rbx, %rdx
229b: ff 50 60 callq *96(%rax)
229e: 48 89 c5 movq %rax, %rbp
22a1: f6 44 24 18 01 testb $1, 24(%rsp)
22a6: 74 0a je 0x22b2 <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0x102>
22a8: 48 8b 7c 24 28 movq 40(%rsp), %rdi
22ad: e8 fe 01 00 00 callq 0x24b0 <_ZdlPv@plt>
22b2: 48 39 dd cmpq %rbx, %rbp
22b5: 75 3a jne 0x22f1 <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0x141>
22b7: 4d 29 e7 subq %r12, %r15
22ba: 4d 85 ff testq %r15, %r15
22bd: 7e 15 jle 0x22d4 <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0x124>
22bf: 49 8b 45 00 movq (%r13), %rax
22c3: 4c 89 ef movq %r13, %rdi
22c6: 4c 89 e6 movq %r12, %rsi
22c9: 4c 89 fa movq %r15, %rdx
22cc: ff 50 60 callq *96(%rax)
22cf: 4c 39 f8 cmpq %r15, %rax
22d2: 75 1d jne 0x22f1 <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0x141>
22d4: 49 c7 46 18 00 00 00 00 movq $0, 24(%r14)
22dc: 64 48 8b 04 25 28 00 00 00 movq %fs:40, %rax
22e5: 48 3b 44 24 30 cmpq 48(%rsp), %rax
22ea: 74 18 je 0x2304 <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0x154>
22ec: e8 1f 01 00 00 callq 0x2410 <__stack_chk_fail@plt>
22f1: 45 31 ed xorl %r13d, %r13d
22f4: 64 48 8b 04 25 28 00 00 00 movq %fs:40, %rax
22fd: 48 3b 44 24 30 cmpq 48(%rsp), %rax
2302: 75 e8 jne 0x22ec <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0x13c>
2304: 4c 89 e8 movq %r13, %rax
2307: 48 83 c4 38 addq $56, %rsp
230b: 5b popq %rbx
230c: 41 5c popq %r12
230e: 41 5d popq %r13
2310: 41 5e popq %r14
2312: 41 5f popq %r15
2314: 5d popq %rbp
2315: c3 retq
2316: 48 89 c3 movq %rax, %rbx
2319: f6 44 24 18 01 testb $1, 24(%rsp)
231e: 74 0a je 0x232a <_ZNSt3__116__pad_and_outputIcNS_11char_traitsIcEEEENS_19ostreambuf_iteratorIT_T0_EES6_PKS4_S8_S8_RNS_8ios_baseES4_+0x17a>
2320: 48 8b 7c 24 28 movq 40(%rsp), %rdi
2325: e8 86 01 00 00 callq 0x24b0 <_ZdlPv@plt>
232a: 48 89 df movq %rbx, %rdi
232d: e8 ee 00 00 00 callq 0x2420 <_Unwind_Resume@plt>
2332: cc int3
2333: cc int3
2334: cc int3
2335: cc int3
2336: cc int3
2337: cc int3
2338: cc int3
2339: cc int3
233a: cc int3
233b: cc int3
233c: cc int3
233d: cc int3
233e: cc int3
233f: cc int3
0000000000002340 <__clang_call_terminate>:
2340: 50 pushq %rax
2341: e8 1a 01 00 00 callq 0x2460 <__cxa_begin_catch@plt>
2346: e8 75 01 00 00 callq 0x24c0 <_ZSt9terminatev@plt>
234b: cc int3
Disassembly of section .init:
000000000000234c <_init>:
234c: f3 0f 1e fa endbr64
2350: 48 83 ec 08 subq $8, %rsp
2354: 48 8b 05 7d 13 00 00 movq 4989(%rip), %rax # 0x36d8 <memset+0x36d8>
235b: 48 85 c0 testq %rax, %rax
235e: 74 02 je 0x2362 <_init+0x16>
2360: ff d0 callq *%rax
2362: 48 83 c4 08 addq $8, %rsp
2366: c3 retq
Disassembly of section .fini:
0000000000002368 <_fini>:
2368: f3 0f 1e fa endbr64
236c: 48 83 ec 08 subq $8, %rsp
2370: 48 83 c4 08 addq $8, %rsp
2374: c3 retq
Disassembly of section .plt:
0000000000002380 <.plt>:
2380: ff 35 a2 23 00 00 pushq 9122(%rip) # 0x4728 <memset+0x4728>
2386: ff 25 a4 23 00 00 jmpq *9124(%rip) # 0x4730 <memset+0x4730>
238c: 0f 1f 40 00 nopl (%rax)
0000000000002390 <__register_frame_info@plt>:
2390: ff 25 a2 23 00 00 jmpq *9122(%rip) # 0x4738 <memset+0x4738>
2396: 68 00 00 00 00 pushq $0
239b: e9 e0 ff ff ff jmp 0x2380 <.plt>
00000000000023a0 <__cxa_finalize@plt>:
23a0: ff 25 9a 23 00 00 jmpq *9114(%rip) # 0x4740 <memset+0x4740>
23a6: 68 01 00 00 00 pushq $1
23ab: e9 d0 ff ff ff jmp 0x2380 <.plt>
00000000000023b0 <__deregister_frame_info@plt>:
23b0: ff 25 92 23 00 00 jmpq *9106(%rip) # 0x4748 <memset+0x4748>
23b6: 68 02 00 00 00 pushq $2
23bb: e9 c0 ff ff ff jmp 0x2380 <.plt>
00000000000023c0 <_ZNKSt3__18ios_base6getlocEv@plt>:
23c0: ff 25 8a 23 00 00 jmpq *9098(%rip) # 0x4750 <memset+0x4750>
23c6: 68 03 00 00 00 pushq $3
23cb: e9 b0 ff ff ff jmp 0x2380 <.plt>
00000000000023d0 <_ZNKSt3__16locale9use_facetERNS0_2idE@plt>:
23d0: ff 25 82 23 00 00 jmpq *9090(%rip) # 0x4758 <memset+0x4758>
23d6: 68 04 00 00 00 pushq $4
23db: e9 a0 ff ff ff jmp 0x2380 <.plt>
00000000000023e0 <_ZNSt3__16localeD1Ev@plt>:
23e0: ff 25 7a 23 00 00 jmpq *9082(%rip) # 0x4760 <memset+0x4760>
23e6: 68 05 00 00 00 pushq $5
23eb: e9 90 ff ff ff jmp 0x2380 <.plt>
00000000000023f0 <_ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE3putEc@plt>:
23f0: ff 25 72 23 00 00 jmpq *9074(%rip) # 0x4768 <memset+0x4768>
23f6: 68 06 00 00 00 pushq $6
23fb: e9 80 ff ff ff jmp 0x2380 <.plt>
0000000000002400 <_ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE5flushEv@plt>:
2400: ff 25 6a 23 00 00 jmpq *9066(%rip) # 0x4770 <memset+0x4770>
2406: 68 07 00 00 00 pushq $7
240b: e9 70 ff ff ff jmp 0x2380 <.plt>
0000000000002410 <__stack_chk_fail@plt>:
2410: ff 25 62 23 00 00 jmpq *9058(%rip) # 0x4778 <memset+0x4778>
2416: 68 08 00 00 00 pushq $8
241b: e9 60 ff ff ff jmp 0x2380 <.plt>
0000000000002420 <_Unwind_Resume@plt>:
2420: ff 25 5a 23 00 00 jmpq *9050(%rip) # 0x4780 <memset+0x4780>
2426: 68 09 00 00 00 pushq $9
242b: e9 50 ff ff ff jmp 0x2380 <.plt>
0000000000002430 <_ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE6sentryC1ERS3_@plt>:
2430: ff 25 52 23 00 00 jmpq *9042(%rip) # 0x4788 <memset+0x4788>
2436: 68 0a 00 00 00 pushq $10
243b: e9 40 ff ff ff jmp 0x2380 <.plt>
0000000000002440 <_ZNSt3__18ios_base5clearEj@plt>:
2440: ff 25 4a 23 00 00 jmpq *9034(%rip) # 0x4790 <memset+0x4790>
2446: 68 0b 00 00 00 pushq $11
244b: e9 30 ff ff ff jmp 0x2380 <.plt>
0000000000002450 <_ZNSt3__113basic_ostreamIcNS_11char_traitsIcEEE6sentryD1Ev@plt>:
2450: ff 25 42 23 00 00 jmpq *9026(%rip) # 0x4798 <memset+0x4798>
2456: 68 0c 00 00 00 pushq $12
245b: e9 20 ff ff ff jmp 0x2380 <.plt>
0000000000002460 <__cxa_begin_catch@plt>:
2460: ff 25 3a 23 00 00 jmpq *9018(%rip) # 0x47a0 <memset+0x47a0>
2466: 68 0d 00 00 00 pushq $13
246b: e9 10 ff ff ff jmp 0x2380 <.plt>
0000000000002470 <_ZNSt3__18ios_base33__set_badbit_and_consider_rethrowEv@plt>:
2470: ff 25 32 23 00 00 jmpq *9010(%rip) # 0x47a8 <memset+0x47a8>
2476: 68 0e 00 00 00 pushq $14
247b: e9 00 ff ff ff jmp 0x2380 <.plt>
0000000000002480 <__cxa_end_catch@plt>:
2480: ff 25 2a 23 00 00 jmpq *9002(%rip) # 0x47b0 <memset+0x47b0>
2486: 68 0f 00 00 00 pushq $15
248b: e9 f0 fe ff ff jmp 0x2380 <.plt>
0000000000002490 <_Znwm@plt>:
2490: ff 25 22 23 00 00 jmpq *8994(%rip) # 0x47b8 <memset+0x47b8>
2496: 68 10 00 00 00 pushq $16
249b: e9 e0 fe ff ff jmp 0x2380 <.plt>
00000000000024a0 <memset@plt>:
24a0: ff 25 1a 23 00 00 jmpq *8986(%rip) # 0x47c0 <memset+0x47c0>
24a6: 68 11 00 00 00 pushq $17
24ab: e9 d0 fe ff ff jmp 0x2380 <.plt>
00000000000024b0 <_ZdlPv@plt>:
24b0: ff 25 12 23 00 00 jmpq *8978(%rip) # 0x47c8 <memset+0x47c8>
24b6: 68 12 00 00 00 pushq $18
24bb: e9 c0 fe ff ff jmp 0x2380 <.plt>
00000000000024c0 <_ZSt9terminatev@plt>:
24c0: ff 25 0a 23 00 00 jmpq *8970(%rip) # 0x47d0 <memset+0x47d0>
24c6: 68 13 00 00 00 pushq $19
24cb: e9 b0 fe ff ff jmp 0x2380 <.plt>
There are some facts to consider.
A context switch could actually occur right in between any two successive assembly instructions, unless the code is wrapped into “critical sections” using appropriate syscalls to instruct an OS explicitly not to.
Thread suspension are resuming are context switches.
Which any shared mutable state (which is what imperative means) there is no guarantee that after resuming (switching of an execution context back to the next assembly instruction) the state has not been partially modified by other thread.
There is in principle no solution to sharing of a mutable state, it is just wrong. This is as fundamental as membranes of biological cells.
A few more facts
- The fucking
JVMis written in an imperative C++98 - It uses
libstdc++.soas its runtime (imperative) - JVM implements high-level concurrency primitives on top of that.
- The architecture of JVM is multithreaded imperative code.
- JDK compiles imperative Java into an imperative bytecode
- JVM compiles imperative bytecode into imperative machine code
You don’t see subtle bugs just because you are ignorant and intentionally not looking.
If your solution relies on Mutexes and Critical Sections, then it is just multiple threads busy-waiting on locks.
Concurrent code and data must be structured differently – in memory, by the runtime and by the language primitives.
Actual abstraction barriers must separate the data and only asynchronous structured message-passing can occur in code.
This requires a proper runtime support for sending and receiving of messages (with structural pattern-matching) and for the “mailboxes” (transactional, append-only storage), etc.
Just a bunch libraries on top of an imperative runtime won’t work. It will only seem to work. The runtime must itself be properly partitioned (structured).
Only Erlang guys did everything right – a principle-based research from the ground up (up to erts).
Shared concurrency for imperative code is a myth. Period.
The solutions
There are mathematically-sound theoretical solutions.
Referential transparency
This is the fundamental property of all binding, both of symbols and within the compound and structured data - once bound everything stays forever - does not change behind your back.
This is the whole point of pure-functional languages like Haskell. All the
effort is to preserve and even guarantee this referential transparency property.
These guarantees have various qualitative implications. The most important is the emergent declarative nature of resulting expressions, so they operationally have the same properties as mathematical formulas, expressions of pure logic, finite state machines and can be transformed (without any loss of information) into abstract syntax trees and acyclic graphs in general.
This is the ideal which Haskell community zealously seek to attain.
At most one mutable reference
This is another principal theoretical solution, which is partial referential transparency so to speak. The state has to be encapsulated into a closure, which is traditionally called a ref.
A ref or a reference is just an ADT, and the explicit abstraction barrier keeps the state “invisible” to the pure expressions. They only declare what eventually to do be done with it, whatever it actually might be.
It is remarkable that an Abstract Data Type is the fundamental building block here.
Generalized Abstraction barriers
There are emergent /standard idioms to establish and maintain actual abstraction barriers.
- type-classes allow to define abstract data types on the basis of behaviors or
sets of required interfaces to be implemented (to be an
Xis to quack like anXand walk like anX). Monad (in the context of programming languages) is “even more generic” type-class for defining Abstract Data Types, which in turn are abstraction barriers, partitions or abstract “membranes”. It is a “standard shape or form” for an ADT, which itself is also an /instance of a particular type-class (a set of required interfaces).
And also form (an instance of) a Monad (type-class). And this is literally it.
Keeping state “inside a Monad” (behind an abstraction barrier) is how a type-system-level guarantees of “safety” (yes, of non-broken referential transparency) could be obtained.
In languages other than Haskell care should be taken of maintaining at most one mutable reference. In Haskell there is no mutation possible in principle (only shadowing and extending).
Async
The most adequate case for using a Monad (which is, again, just an ADT, an instance of a standard type-class) is to separate pure functions form async procedures, which are fundamentally different forms of computation.
(An async procedure requires an implicit distinct execution context and special signalling for returning its result).
A monad (as a “generic” type-class) is the way to define abstraction barrier between pure mathematical functions and asynchronous procedures.
A vertical arrow
The fundamental principle is that values could be passed strictly in only one
direction - into an async context, and never “back”, which has a deep relation
with the concept of an “arrow”, found at the “core of everything” (a -> b).
The point is that these async procedures could be composed just like ordinary
pure functions (using nesting, which is the only way a composition could be
defined declaratively), but behind its abstraction barrier, using a distinct
composition operator (not just our pure .) or “inside of a Monad” as they prefer to say.
And a horizontal arrow
Think of introducing a vertical arrow for “lifting of values” (which will never
“come back” to the pure realm which they have left - notice this finest
esoteric prose) and a “lifted” (or specialized for this particular context) .,
which is traditionally bound to a >>=, and suggest an arrow, which imply a
direction (of a single step of any process).
And, again, this notion of a “vertical arrow”, which crosses an abstraction barrier (it is a Kleisli arrow after all) in only one direction, is “it”.
an ADT for ADTs
A Monad, as you see, is a “lift” (a vertical error) for values and “composition” (specialized dot) for computations in this particular instance or a context.
So one “lift” values (using Kleisli arrows) into a specific context and compose “computations” defined (and evaluated) with means of the same pure language, but behind a type-system ensured and guaranteed to be sound actual abstraction barrier.
This is general-enough (as general, in fact, as untyped Lambda Calculus) because it is, again, just an ADT for ADTs or nesting of ADTs. It corresponds to the fundamental notion of “AND ALSO” (an instance of) quacks like a duck.
Comosition of type-classes
Whole type-classes can be composed (to form a new whole), using instantiation (implementing an interface within an ADT module) instead of some explicit type-level combinators (the type-system will maintain its own context to track who implements what), and this is, for the third time in this essay, “it” again.
Everything boils down to partitions, nesting and arrows - proper abstractions, generalized form Molecular Biology and What Is.
Erlang
Erlang, being dynamically but strongly-typed language, reinforces abstraction barriers at interfaces (where else?). User-facing code is a pure-functional language, augmented with a minimum of carefully crafted concurrency primitives.
One can think of an actor as a tail-recursive function, which passes the state in a parameter (thus ensuring the at most one mutable reference property).
Asynchronous send function (the ! infix operator) always succeeds and could be
seen as an identity function on the data argument (think that it could be
/partially applied to the “address” first).
The reseive expression is just like case (pattern-matching) expression on an
implicit parameter, which is has messages as values.
To be fair, these concurrency primitives are NOT strictly pure-functional, but the referential-transparency property is preserved - same input (/including the same contents of a mailbox) - same output. Always.
The spawn primitive is definitely not a function, so it is a plain hack.
However, it is fully-deterministic within the context of the whole Erlang node.
Types are written in an additional DSL and checked by a specialized tools, which is also a proper design.
Behaviors
These building blocks (at the levels of libraries) can be thought off as sets of mutually-recursive generic functions (within a module), being parameterized by “callbacks” which contain user’s code.
This is the very same fundamental abstraction by parameterization principle, applied at the level of interfaces.
The functions (a callback is just a function) send and receive messages according to well-defined protocol.
Any protocol, in turn, is just an informally stated explicit set of rules to be implemented (followed).
At a system (OTP) level there are protocols (with rely on universal message-passing) everywhere. This is how telecommunication hardware (systems) has been build.
Erlang is simply a great language. It is well-researched and well-designed both at the user-facing (syntax, semantics) level and at the level of a properly designed standard library (OTP) and the partitioned /runtime system (written in Erlang itself and some portable C).
It takes time, like with any art form, to understand appreciate the details as well as the principles everything is based upon. Erlang is a marvel of craftsmanship.