diff --git a/bootstrap/build.c b/bootstrap/build.c
index 22474cb..6a9e6f0 100644
--- a/bootstrap/build.c
+++ b/bootstrap/build.c
@@ -145,6 +145,8 @@ fn void compile_c(const CompileOptions *const options, char** envp)
         memcpy(vb_add(args, array_length(static_options)), static_options, sizeof(static_options));
     }
 
+    *vb_add(args, 1) = "-DSILENT";
+
     if (options->compiler == clang)
     {
         *vb_add(args, 1) = "-MJ";
@@ -364,14 +366,13 @@ fn void run_tests(Arena* arena, TestOptions const * const test_options, char** e
     }
 }
 
-int main(int argc, char* argv[], char** envp)
+fn void entry_point(int argc, char* argv[], char* envp[])
 {
     if (argc < 2)
     {
         print("Expected some arguments\n");
-        return 1;
+        fail();
     }
-    // calibrate_cpu_timer();
 
     CompilerBackend preferred_compiler_backend = COMPILER_BACKEND_COUNT;
     Command command = COMMAND_COUNT;
@@ -437,7 +438,7 @@ int main(int argc, char* argv[], char** envp)
     if (command == COMMAND_COUNT && !source_file_path.pointer)
     {
         print("Expected a command\n");
-        return 1;
+        fail();
     }
 
     if (command == COMMAND_COUNT)
@@ -461,12 +462,8 @@ int main(int argc, char* argv[], char** envp)
             fail();
         }
 
-        Linkage linkage = 
-#if defined(__linux__)
-            LINKAGE_STATIC;
-#else
-            LINKAGE_DYNAMIC;
-#endif
+        // Test always with dynamic linkage because it's more trustworthy
+        Linkage linkage = LINKAGE_DYNAMIC;
 
         compile_and_run(&(CompileOptions) {
             .in_path = compiler_source_path,
@@ -481,8 +478,13 @@ int main(int argc, char* argv[], char** envp)
     case COMMAND_RUN_TESTS:
         {
             Arena* arena = arena_init_default(KB(64));
-            Linkage all_linkages[] = { LINKAGE_DYNAMIC, LINKAGE_STATIC };
-            static_assert(array_length(all_linkages) == LINKAGE_COUNT);
+            Linkage all_linkages[] = {
+                LINKAGE_DYNAMIC,
+#ifdef __linux__
+                LINKAGE_STATIC
+#endif
+            };
+
             OptimizationMode all_optimization_modes[] = {
                 O0,
                 O1,
diff --git a/bootstrap/lib.h b/bootstrap/lib.h
index fc65ab4..2ddd879 100644
--- a/bootstrap/lib.h
+++ b/bootstrap/lib.h
@@ -97,15 +97,34 @@ FOR_N(_i, 0, ((set)->arr.capacity + 63) / 64) FOR_BIT(it, _i*64, (set)->arr.poin
         b = temp;\
     } while (0)
 
-fn u64 timestamp()
+fn 
+#if LINK_LIBC
+struct timespec
+#else
+u64 
+#endif
+timestamp()
 {
+#if LINK_LIBC
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    return ts;
+#else
 #if defined(__x86_64__)
     return __rdtsc();
 #else
     return 0;
 #endif
+#endif
 }
 
+#if LINK_LIBC
+global struct timespec cpu_resolution;
+#else
+global u64 cpu_frequency;
+#endif
+
+
 may_be_unused fn void print(const char* format, ...);
 
 may_be_unused fn u16 cast_u32_to_u16(u32 source, const char* name, int line)
@@ -435,6 +454,75 @@ may_be_unused fn s32 cast_s64_to_s32(s64 source, const char* name, int line)
     const global u64 page_size = KB(4);
 #endif
 
+typedef enum TimeUnit
+{
+    TIME_UNIT_NANOSECONDS,
+    TIME_UNIT_MICROSECONDS,
+    TIME_UNIT_MILLISECONDS,
+    TIME_UNIT_SECONDS,
+} TimeUnit;
+
+fn f64 resolve_timestamp(
+#if LINK_LIBC
+        struct timespec start, struct timespec end,
+#else
+        u64 start, u64 end,
+#endif
+        TimeUnit time_unit)
+{
+#if LINK_LIBC
+    assert(end.tv_sec >= start.tv_sec);
+    struct timespec result = {
+        .tv_sec = end.tv_sec - start.tv_sec,
+        .tv_nsec = end.tv_nsec - start.tv_nsec,
+    };
+
+    auto ns_in_a_sec = 1000000000;
+    if (result.tv_nsec < 0)
+    {
+        result.tv_sec -= 1;
+        result.tv_nsec += ns_in_a_sec;
+    }
+
+    auto ns = result.tv_sec * ns_in_a_sec + result.tv_nsec;
+    switch (time_unit)
+    {
+    case TIME_UNIT_NANOSECONDS:
+        return (f64)ns;
+    case TIME_UNIT_MICROSECONDS:
+        return ns / 1000.0;
+    case TIME_UNIT_MILLISECONDS:
+        return ns / 1000000.0;
+    case TIME_UNIT_SECONDS:
+        return ns / 1000000000.0;
+    }
+#else
+    assert(end >= start);
+    auto ticks = end - start;
+    f64 s = (f64)(end - start);
+    if (cpu_frequency)
+    {
+        s = s / (f64)cpu_frequency;
+
+        switch (time_unit)
+        {
+            case TIME_UNIT_NANOSECONDS:
+                return s / 1000000000.0;
+            case TIME_UNIT_MICROSECONDS:
+                return s / 1000000.0;
+            case TIME_UNIT_MILLISECONDS:
+                return s / 1000.0;
+            case TIME_UNIT_SECONDS:
+                return s;
+        }
+    }
+    else
+    {
+        // warning: rdtsc frequency not queried (returning ticks as are)
+        return s;
+    }
+#endif
+}
 
 const may_be_unused global u8 brace_open = '{';
 const may_be_unused global u8 brace_close = '}';
@@ -1425,10 +1513,11 @@ may_be_unused fn u64 os_timer_get()
     return result;
 }
 
-global u64 cpu_frequency;
-
 may_be_unused fn void calibrate_cpu_timer()
 {
+#if LINK_LIBC
+    // clock_getres(CLOCK_MONOTONIC, &cpu_resolution);
+#else
     u64 miliseconds_to_wait = 100;
     u64 cpu_start = timestamp();
     u64 os_frequency = os_timer_freq();
@@ -1445,6 +1534,7 @@ may_be_unused fn void calibrate_cpu_timer()
     u64 cpu_end = timestamp();
     u64 cpu_elapsed = cpu_end - cpu_start;
     cpu_frequency = os_frequency * cpu_elapsed / os_elapsed;
+#endif
 }
 
 fn u8* reserve(u64 size)
@@ -1538,7 +1628,6 @@ fn u32 format_decimal(String buffer, u64 decimal)
     }
 }
 
-#define SILENT (0)
 STRUCT(SmallIntResult)
 {
     u64 mantissa;
@@ -2210,7 +2299,7 @@ fn void write_float_decimal(String buffer, u64* value, u64 count)
 
 may_be_unused fn void print(const char* format, ...)
 {
-#if SILENT == 0
+#ifndef SILENT
         u8 stack_buffer[4096];
         va_list args;
         va_start(args, format);
@@ -2463,7 +2552,24 @@ may_be_unused fn void print(const char* format, ...)
                                                 }
                                                 else
                                                 {
-                                                    __builtin_trap();
+                                                    auto dp_uoffset = (u64)dp_offset;
+                                                    if (dp_uoffset >= olength)
+                                                    {
+                                                        write_float_decimal(s_get_slice(u8, buffer, buffer_i, buffer.length), &output, olength);
+                                                        buffer_i += olength;
+                                                        auto length = dp_uoffset - olength;
+                                                        auto memset_slice = s_get_slice(u8, buffer, buffer_i, buffer_i + length);
+                                                        memset(memset_slice.pointer, 0, length);
+                                                        buffer_i += length;
+                                                    }
+                                                    else
+                                                    {
+                                                        write_float_decimal(s_get_slice(u8, buffer, buffer_i + dp_uoffset + 1, buffer.length), &output, olength - dp_uoffset);
+                                                        buffer.pointer[buffer_i + dp_uoffset] = '.';
+                                                        auto dp_index = buffer_i + dp_uoffset + 1;
+                                                        write_float_decimal(s_get_slice(u8, buffer, buffer_i, buffer.length), &output, dp_uoffset);
+                                                        buffer_i += olength + 1;
+                                                    }
                                                 }
                                             } break;
                                     }
@@ -2692,7 +2798,7 @@ fn void run_command(CStringSlice arguments, char* envp[])
         trap();
     }
 
-    u64 start_ns = timestamp();
+    auto start_timestamp = timestamp();
 
     if (pid == 0)
     {
@@ -2712,7 +2818,7 @@ fn void run_command(CStringSlice arguments, char* envp[])
         int status = 0;
         int options = 0;
         pid_t result = syscall_waitpid(pid, &status, options);
-        u64 end_ns = timestamp();
+        auto end_timestamp = timestamp();
         int success = 0;
         if (result == pid)
         {
@@ -2736,14 +2842,15 @@ fn void run_command(CStringSlice arguments, char* envp[])
             fail();
         }
 
-        if (cpu_frequency)
-        {
-            auto ticks = end_ns - start_ns;
-            auto ticks_f = (f64)ticks;
-            auto time_frequency_f = (f64)cpu_frequency;
-            auto s = ticks_f / time_frequency_f;
-            print("Command run successfully in {f64} s\n", s);
-        }
+        auto ms = resolve_timestamp(start_timestamp, end_timestamp, TIME_UNIT_MILLISECONDS);
+        auto ticks =
+#if LINK_LIBC
+            0
+#else
+            cpu_frequency != 0
+#endif
+            ;
+        print("Command run successfully in {f64} {cstr}\n", ms, ticks ? "ticks" : "ms");
     }
 }
 
@@ -2840,3 +2947,36 @@ may_be_unused fn Hash32 hash64_fib_end(Hash64 hash)
     auto result = truncate(Hash32, (hash * 11400714819323198485ull) >> 32);
     return result;
 }
+
+fn void entry_point(int argc, char* argv[], char* envp[]);
+
+#if LINK_LIBC
+int main(int argc, char* argv[], char* envp[])
+{
+    entry_point(argc, argv, envp);
+    return 0;
+}
+#else
+[[gnu::naked]] [[noreturn]] void _start()
+{
+    __asm__ __volatile__(
+            "\nxor %ebp, %ebp"
+            "\npopq %rdi"
+            "\nmov %rsp, %rsi"
+            "\nand $~0xf, %rsp"
+            "\npushq %rsp"
+            "\npushq $0"
+            "\ncallq static_entry_point"
+            "\nud2\n"
+       );
+}
+
+void static_entry_point(int argc, char* argv[])
+{
+    char** envp = (char**)&argv[argc + 1];
+    calibrate_cpu_timer();
+    entry_point(argc, argv, envp);
+    syscall_exit(0);
+}
+
+#endif
diff --git a/bootstrap/main.c b/bootstrap/main.c
index ff5202a..ee04012 100644
--- a/bootstrap/main.c
+++ b/bootstrap/main.c
@@ -61,7 +61,7 @@ fn String file_read(Arena* arena, String path)
 
 fn void print_string(String message)
 {
-#if SILENT == 0
+#ifndef SILENT
         ssize_t result = syscall_write(1, message.pointer, message.length);
         assert(result >= 0);
         assert((u64)result == message.length);
@@ -12538,21 +12538,6 @@ fn void print_ir(Thread* restrict thread)
     }
 }
 
-#if LINK_LIBC == 0
-[[gnu::naked]] [[noreturn]] void _start()
-{
-    __asm__ __volatile__(
-            "\nxor %ebp, %ebp"
-            "\npopq %rdi"
-            "\nmov %rsp, %rsi"
-            "\nand $~0xf, %rsp"
-            "\npushq %rsp"
-            "\npushq $0"
-            "\ncallq entry_point"
-            "\nud2\n"
-       );
-}
-#endif
 
 fn void dwarf_playground(Thread* thread)
 {
@@ -12817,22 +12802,12 @@ fn void dwarf_playground(Thread* thread)
     assert(*debug_info_bytes.pointer == 0);
 }
 
-#if LINK_LIBC
-int main(int argc, const char* argv[], char* envp[])
+fn void entry_point(int argc, char* argv[], char* envp[])
 {
-#else
-void entry_point(int argc, const char* argv[])
-{
-    char** envp = (char**)&argv[argc + 1];
-    unused(envp);
-#endif
 #if DO_UNIT_TESTS
     unit_tests();
 #endif
 
-    // calibrate_cpu_timer();
-
-
     Arena* global_arena = arena_init(MB(2), KB(64), KB(64));
 
     {
@@ -12890,13 +12865,10 @@ void entry_point(int argc, const char* argv[])
     else
     {
         code_generation(thread, (CodegenOptions) {
-            .test_name = test_name,
-            .backend = compiler_backend,
-        }, envp);
+                .test_name = test_name,
+                .backend = compiler_backend,
+                }, envp);
     }
 
     thread_clear(thread);
-#if LINK_LIBC == 0
-    syscall_exit(0);
-#endif
 }