[kernel] Hide version string from compiler

kVersionString is filled in outside of the source file that defines
this variable. The compiler during lto picked up that because it is
const the size should always be 3, but this isn't actually the case.
By just hiding any provenance information about the return value of
version_string from the compiler we force it to actually call
strlen at runtime with the real value.

Fixed: 103245
Change-Id: I40291d02f29bb091c4316737b7d6b6c07efc6824
Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/693800
Reviewed-by: Roland McGrath <mcgrathr@google.com>
Commit-Queue: Alex Brachet <abrachet@google.com>
Fuchsia-Auto-Submit: Alex Brachet <abrachet@google.com>
diff --git a/zircon/kernel/lib/version/BUILD.gn b/zircon/kernel/lib/version/BUILD.gn
index 05958a2..b0364a2 100644
--- a/zircon/kernel/lib/version/BUILD.gn
+++ b/zircon/kernel/lib/version/BUILD.gn
@@ -63,11 +63,15 @@
   }
 } else {
   zx_library("version") {
-    sources = [ "version.cc" ]
+    sources = [
+      "version-string.S",
+      "version.cc",
+    ]
     defines = [ "ARCH=\"$current_cpu\"" ]
     public_deps = [ ":version-string.h($default_toolchain)" ]
     public_configs = [ ":gen.config" ]
     deps = [
+      "//zircon/kernel/lib/arch",
       "//zircon/kernel/lib/console",
       "//zircon/kernel/lib/init",
     ]
diff --git a/zircon/kernel/lib/version/version-string.S b/zircon/kernel/lib/version/version-string.S
new file mode 100644
index 0000000..4623f9d
--- /dev/null
+++ b/zircon/kernel/lib/version/version-string.S
@@ -0,0 +1,17 @@
+// Copyright 2022 The Fuchsia Authors
+//
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file or at
+// https://opensource.org/licenses/MIT
+
+#include <lib/arch/asm.h>
+#include <lib/version/version-string.h>
+
+// This is in assembly so that LTO cannot constant fold this value away.
+// Importantly, this data gets filled in later post build so the value
+// that LTO see's at link time is not the value that will be here at
+// runtime despite this variable being marked const in C++.
+
+.object kVersionString, rodata, global
+.space VERSION_STRING_SIZE
+.end_object
diff --git a/zircon/kernel/lib/version/version.cc b/zircon/kernel/lib/version/version.cc
index 03c12f2b..fdbf3b1a 100644
--- a/zircon/kernel/lib/version/version.cc
+++ b/zircon/kernel/lib/version/version.cc
@@ -23,7 +23,7 @@
 // This is allocated with sufficient size to be filled in later.  The contents
 // have to be nonzero so they get allocated but don't otherwise matter.  See
 // kernel-image.inc for more details.
-extern "C" const char kVersionString[VERSION_STRING_SIZE] = "...";
+extern "C" const char kVersionString[VERSION_STRING_SIZE];
 
 namespace {