Use ASM unknown function trampolines on GN
authorJohn Bauman <jbauman@google.com>
Thu, 8 Aug 2024 17:47:05 +0000 (17:47 +0000)
committerCharles Giessen <46324611+charles-lunarg@users.noreply.github.com>
Mon, 12 Aug 2024 18:20:22 +0000 (13:20 -0500)
The GN build doesn't currently support unknown function trampolines. To
fix that, we can use the assembly trampolines. To generate
the asm_offset assembly file, we can build it in a static library and
pass -S to it; that causes the assembly file to be copied into the .a
file. The python script can then extract it. This requires access to the
"ar" executable, so this mechanism is only used if a path to ar is
specified in //build_overrides/vulkan_loader.gni.

To fix incremental builds, "gen_defines.asm" must be included using
"#include", not ".include", since .include isn't a preprocessor
directive and isn't picked up by clang's depfile creation.

BUILD.gn
loader/unknown_ext_chain_gas_aarch.S
loader/unknown_ext_chain_gas_x86.S
scripts/gn/secondary/build_overrides/vulkan_loader.gni
scripts/parse_asm_values.py

index 6fd8719451ad51335cc950fe6da31fc0258e0778..10c483c547d1da4b985b377fab52690debbb8ff6 100644 (file)
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -36,9 +36,7 @@ if (is_win) {
 }
 
 config("vulkan_internal_config") {
-  defines = [
-    "VK_ENABLE_BETA_EXTENSIONS",
-  ]
+  defines = [ "VK_ENABLE_BETA_EXTENSIONS" ]
   if (is_clang || !is_win) {
     cflags = [
       "-Wno-conversion",
@@ -99,6 +97,52 @@ if (!is_android) {
   } else {
     library_type = "static_library"
   }
+  support_unknown_function_handling = false
+  if (ar_path != "" && !is_win && (current_cpu == "arm64" || current_cpu == "x86_64")) {
+    support_unknown_function_handling = true
+    static_library("asm_offset") {
+      sources = [ "loader/asm_offset.c" ]
+      deps = [
+        "$vulkan_headers_dir:vulkan_headers",
+      ]
+
+      if (is_fuchsia) {
+        deps += [
+          ":dlopen_fuchsia",
+        ]
+      }
+
+      # Output raw assembly instead of compiled object file. The assembly will be included as a member of the output ar file.
+      cflags = [ "-S" ]
+      configs += [ ":vulkan_internal_config" ]
+      configs += [ ":vulkan_loader_config" ]
+    }
+
+    action("gen_defines") {
+      script = "scripts/parse_asm_values.py"
+      deps = [ ":asm_offset" ]
+
+      inputs = [
+        "$target_out_dir/libasm_offset.a",
+        ar_path,
+      ]
+      if (current_cpu == "arm64") {
+        cpu = "aarch64"
+      } else {
+        cpu = "x86_64"
+      }
+      args = [
+        rebase_path("$target_gen_dir/gen_defines.asm", root_build_dir),
+        rebase_path("$target_out_dir/libasm_offset.a", root_build_dir),
+        "GAS",
+        "Clang",
+        cpu,
+        rebase_path(ar_path, root_build_dir),
+        "libasm_offset.asm_offset.c.o",
+      ]
+      outputs = [ "$target_gen_dir/gen_defines.asm" ]
+    }
+  }
 
   target(library_type, "libvulkan") {
     sources = [
@@ -135,8 +179,6 @@ if (!is_android) {
       "loader/unknown_function_handling.h",
       "loader/unknown_function_handling.c",
       "loader/vk_loader_layer.h",
-
-      # TODO(jmadill): Use assembler where available.
       "loader/vk_loader_platform.h",
       "loader/wsi.c",
       "loader/wsi.h",
@@ -217,6 +259,19 @@ if (!is_android) {
 
       runtime_deps = [ "//sdk/lib/fdio:fdio_sdk" ]
     }
+    if (support_unknown_function_handling) {
+      if (current_cpu == "arm64") {
+        sources += [ "loader/unknown_ext_chain_gas_aarch.S" ]
+      } else if (current_cpu == "x86_64") {
+        sources += [ "loader/unknown_ext_chain_gas_x86.S" ]
+      } else {
+        assert(false, "Unexpected CPU $current_cpu")
+      }
+
+      defines += ["UNKNOWN_FUNCTIONS_SUPPORTED=1"]
+      deps += [ ":gen_defines" ]
+      include_dirs = [ "$target_gen_dir" ]
+    }
   }
 }
 
index 1176be30fb85d54c920066df6e7013e7aa81a15c..a78a32d34c735b0b96cb42d94f6495d444107b37 100644 (file)
@@ -24,7 +24,7 @@
 // VkPhysicalDevice or a dispatchable object it can unwrap the object, possibly overwriting the wrapped physical device, and then
 // jump to the next function in the call chain
 
-.include "gen_defines.asm"
+#include "gen_defines.asm"
 
 /*
  * References:
@@ -56,6 +56,7 @@
 .macro PhysDevExtTramp num
 .global vkPhysDevExtTramp\num
 #if defined(__ELF__)
+ .type vkPhysDevExtTramp\num, @function
  .hidden vkPhysDevExtTramp\num
 #endif
 .balign 4
@@ -77,6 +78,7 @@ vkPhysDevExtTramp\num:
 .macro PhysDevExtTermin num
 .global vkPhysDevExtTermin\num
 #if defined(__ELF__)
+ .type vkPhysDevExtTermin\num, @function
  .hidden vkPhysDevExtTermin\num
 #endif
 .balign 4
index de5a920308275dabb08f7b4c381c3f07e1a4b8fa..5ee02051208a9f465ab174e4b9e4e7aca07f5298 100644 (file)
@@ -33,7 +33,7 @@
 #endif
 
 .intel_syntax noprefix
-.include "gen_defines.asm"
+#include "gen_defines.asm"
 
 .ifdef X86_64
 
index c826fc11286264b508af0e9240ad78b7e059ebbe..4cf8e827989e6054f26599465743c622bdd75e0f 100644 (file)
@@ -21,3 +21,5 @@ vulkan_gen_subdir = ""
 # Vulkan loader build options
 vulkan_loader_shared = true
 
+# Path to ar or llvm-ar
+ar_path = ""
index cab5ef9dc6cf269d293ecf360773c3bdf446c817..172a3633972bd207cecf2f9fe3241d87db2d1ad8 100644 (file)
@@ -25,6 +25,8 @@ import sys
 import os.path
 from os.path import exists
 import re
+import subprocess
+import traceback
 
 
 # Where to write the "gen_defines.asm" file
@@ -57,12 +59,23 @@ defines = ["VULKAN_LOADER_ERROR_BIT",
             "DISPATCH_OFFSET_ICD_TERM",
             "EXT_OFFSET_DEVICE_DISPATCH" ]
 
-try:
-    with open(source_asm_file, 'r') as f:
-        asm_intermediate_file = f.read()
-except IOError:
-    print("Could not open assembler file:", source_asm_file)
-    sys.exit(1)
+if os.path.splitext(source_asm_file)[1] == ".a":
+    try:
+        ar_path = sys.argv[6]
+        asm_archive_member = sys.argv[7]
+        subprocess_result = subprocess.Popen([ar_path, "p", source_asm_file, asm_archive_member], stdout=subprocess.PIPE)
+        asm_intermediate_file = subprocess_result.stdout.read().decode("utf-8")
+    except IOError:
+        print("Could not open assembler archive file:", source_asm_file)
+        traceback.print_exc()
+        sys.exit(1)
+else:
+    try:
+        with open(source_asm_file, 'r') as f:
+            asm_intermediate_file = f.read()
+    except IOError:
+        print("Could not open assembler file:", source_asm_file)
+        sys.exit(1)
 
 with open(destination_file, "w", encoding="utf-8") as dest:
     if assembler_type == "MASM":