[PATCH 2/3] jit: Add support for weak linkage

Petter Tomner tomner@kth.se
Sun Aug 8 15:20:17 GMT 2021


This patch has a test case for weak linkage as well as modification of helper functions. Essentially it produces two object files, one with weak and one with normal symbols, and a main which prints the values of those two symbols and a cehck to ensure that the normal symbols' values are printed.

2021-08-08	Petter Tomner	<tomner@kth.se>

gcc/testsuite/
	* all-non-failing-tests.h : "weak_symbols" added to test list
	* harness.h : Macro flag to be able to provide own test_jit()
	* jit.exp : Helper functions with support for 2+ outfiles
	* test-compile-weak-symbols.c : New test case
	* verify-weak-linkage.c : main function for linking to obj. files.
---
 gcc/testsuite/jit.dg/all-non-failing-tests.h  |  12 +-
 gcc/testsuite/jit.dg/harness.h                |   5 +
 gcc/testsuite/jit.dg/jit.exp                  |  69 ++++++
 .../jit.dg/test-compile-weak-symbols.c        | 207 ++++++++++++++++++
 gcc/testsuite/jit.dg/verify-weak-linkage.c    |  21 ++
 5 files changed, 313 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/jit.dg/test-compile-weak-symbols.c
 create mode 100644 gcc/testsuite/jit.dg/verify-weak-linkage.c

diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index 84ef54a0386..4da34905a3d 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -105,6 +105,13 @@
 #undef create_code
 #undef verify_code
 
+/* test-compile-weak-symbols.c */
+#define create_code create_code_weak_symbols
+#define verify_code verify_code_weak_symbols
+#include "test-compile-weak-symbols.c"
+#undef create_code
+#undef verify_code
+
 /* test-compound-assignment.c */
 #define create_code create_code_compound_assignment
 #define verify_code verify_code_compound_assignment
@@ -454,7 +461,10 @@ const struct testcase testcases[] = {
    verify_code_version},
   {"volatile",
    create_code_volatile,
-   verify_code_volatile}
+   verify_code_volatile},
+  {"weak_symbols",
+   create_code_weak_symbols,
+   verify_code_weak_symbols}
 };
 
 const int num_testcases = (sizeof (testcases) / sizeof (testcases[0]));
diff --git a/gcc/testsuite/jit.dg/harness.h b/gcc/testsuite/jit.dg/harness.h
index 6b59fb57aae..84c248303f4 100644
--- a/gcc/testsuite/jit.dg/harness.h
+++ b/gcc/testsuite/jit.dg/harness.h
@@ -331,6 +331,10 @@ dump_reproducer (gcc_jit_context *ctxt, const char *argv0)
   free (reproducer_name);
 }
 
+static void
+test_jit (const char *argv0, void *user_data);
+
+#ifndef TEST_PROVIDES_TEST_JIT
 /* Run one iteration of the test.  */
 static void
 test_jit (const char *argv0, void *user_data)
@@ -383,6 +387,7 @@ test_jit (const char *argv0, void *user_data)
   if (logfile)
     fclose (logfile);
 }
+#endif /* #ifndef TEST_PROVIDES_TEST_JIT */
 #endif /* #ifndef TEST_ESCHEWS_TEST_JIT */
 
 /* We want to prefix all unit test results with the test, but dejagnu.exp's
diff --git a/gcc/testsuite/jit.dg/jit.exp b/gcc/testsuite/jit.dg/jit.exp
index 9af87f9c6ad..f26970a41e6 100644
--- a/gcc/testsuite/jit.dg/jit.exp
+++ b/gcc/testsuite/jit.dg/jit.exp
@@ -692,6 +692,19 @@ proc jit-verify-output-file-was-created { args } {
     }
 }
 
+proc jit-verify-output-files-were-created { args } {
+    verbose "jit-verify-output-files-were-created: $args"
+
+    foreach output_filename $args {
+        # Verify that the expected files was written out
+        if { [file exists $output_filename] == 1} {
+        pass "$output_filename exists"
+        } else {
+        fail "$output_filename does not exist"
+        }
+    }
+}
+
 # Verify that the given file exists, and is executable.
 # Attempt to execute it, and verify that its stdout matches
 # the given regex.
@@ -840,6 +853,62 @@ proc jit-verify-object { args } {
     jit-run-executable ${executable_from_obj} ${dg-output-text}
 }
 
+# Compile 'sources' and link in 'objects' and execute the program 
+# and check that its output matches 'expected_output'.
+#
+# The path to the JIT test source folder is prepended to each
+# word in 'source'.
+#
+# For use with test-compile-weak-symbols.c testcase.
+proc jit-verify-sources-objects { expected_output sources objects } {
+    global srcdir
+    global subdir
+
+    verbose "jit-verify-objects: $expected_output $sources $objects"
+    set dg-output-text $expected_output
+
+    # prepend the path to the folder with the JIT tests
+    # to each source
+    set rel_path "$srcdir/$subdir/"
+    set srcs [lmap i $sources { string cat $rel_path $i }]
+    verbose "sources full path: ${srcs}"
+
+    upvar 2 name name
+    verbose "name: $name"
+
+    upvar 2 prog prog
+    verbose "prog: $prog"
+
+    # Name the linked executable as the first source
+    # with ".exe" appended.
+    set executable_from_obj [lindex $sources 0].exe
+    verbose "  executable_from_obj: ${executable_from_obj}"
+
+    # Invoke the driver to link the .o file to the .exe
+    set comp_output [gcc_target_compile \
+            "${srcs} ${objects}" \
+             ${executable_from_obj} \
+             "executable" \
+             "{}"]
+    if ![jit_check_compile \
+         "$name" \
+         "link of ${executable_from_obj}" \
+         ${executable_from_obj} \
+         $comp_output] then {
+      return
+    }
+
+    # Verify that the executable was created.
+    if { [file exists $executable_from_obj] == 1} {
+    pass "$executable_from_obj exists"
+    } else {
+    fail "$executable_from_obj does not exist"
+    }
+
+    # Run it and verify that the output matches the regex.
+    jit-run-executable ${executable_from_obj} ${dg-output-text}
+}
+
 # Assuming that a .so file has been written out named
 # OUTPUT_FILENAME, build a test executable to use it,
 # and try to run the result.
diff --git a/gcc/testsuite/jit.dg/test-compile-weak-symbols.c b/gcc/testsuite/jit.dg/test-compile-weak-symbols.c
new file mode 100644
index 00000000000..5a746850341
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-compile-weak-symbols.c
@@ -0,0 +1,207 @@
+/* Essentially the goal of the test is to create a two object files:
+
+   weaksymtest_foobar_weak.o:
+    int __attribute__((weak)) weaksymtest_foo() {return 1;}
+    int __attribute__((weak)) weaksymtest_bar[] = {1};
+
+   weaksymtest_foobar.o:   
+    int weaksymtest_foo() {return 2;}
+    int weaksymtest_bar[] = {2};
+
+   and then link them together and verify that the weak symbol is actually 
+   weak and not the one used after linking.
+
+   Since multiple outfiles are needed this test uses TEST_COMPILING_TO_FILE
+   in a slightly different way then the other tests. It provides its own
+   test_jit() via TEST_PROVIDES_TEST_JIT.
+   
+   This test is dependent on verify-weak-linkage.c which is a main function
+   with declarations of foo and bar and that outputs foo() and bar[0] to 
+   stdout. */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+/* When included in all-non-failing-tests.h with COMBINED_TEST defined 
+   this testfile does not produce any output files. */
+#ifndef COMBINED_TEST
+#define TEST_COMPILING_TO_FILE
+#define TEST_PROVIDES_TEST_JIT
+#include "harness.h"
+#undef TEST_PROVIDES_TEST_JIT
+#else
+#include "harness.h"
+#endif
+
+extern void
+create_code_weak_or_normal (gcc_jit_context *ctxt, int create_weak);
+
+typedef int (*fooptr)(void);
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+  (void) ctxt; /* Not used */
+
+  fooptr foo = gcc_jit_result_get_code (result, "weaksymtest_foo");
+  int *bar = gcc_jit_result_get_global (result, "weaksymtest_bar");
+
+  /* Just do a simple test accessing the weak symbols from the
+     JIT context */
+  CHECK_VALUE (*bar, 1);
+  CHECK_VALUE (foo(), 1);
+}
+
+/* Do not provide test_jit() when included in all-non-failing-test.h */
+#ifndef COMBINED_TEST
+/* Runs one iteration of the test. */
+static void
+test_jit (const char *argv0, void *user_data)
+{
+  gcc_jit_context *ctxt_normal, *ctxt_weak;
+  FILE *logfile_normal, *logfile_weak;
+  char *argv0_weak, *argv0_normal;
+
+  (void) user_data; /* Not used */
+
+  argv0_weak = concat_strings (argv0, ".weak");
+  argv0_normal = concat_strings (argv0, ".normal");
+
+  unlink ("weaksymtest_foobar_weak.o");
+  unlink ("weaksymtest_foobar.o");
+  
+  ctxt_weak = gcc_jit_context_acquire ();
+  ctxt_normal = gcc_jit_context_acquire ();
+  if (!ctxt_normal || !ctxt_weak)
+    {
+      fail ("gcc_jit_context_acquire failed");
+      return;
+    }
+  
+  logfile_weak = set_up_logging (ctxt_weak, argv0_weak);
+  logfile_normal = set_up_logging (ctxt_normal, argv0_normal);
+
+  set_options (ctxt_normal, argv0_normal);
+  set_options (ctxt_weak, argv0_weak);
+
+  free (argv0_weak); argv0_weak = 0;
+  free (argv0_normal); argv0_normal = 0;
+
+  create_code_weak_or_normal (ctxt_normal, 0);
+  create_code_weak_or_normal (ctxt_weak, 1);
+
+  /* Note that argv0 is used instead of argv0_weak since 
+     jit-dg-test expects a certain name of the dumpfile. */
+  dump_reproducer (ctxt_weak, argv0);
+
+  gcc_jit_context_compile_to_file (ctxt_normal,
+           GCC_JIT_OUTPUT_KIND_OBJECT_FILE,
+           "weaksymtest_foobar_n.o");
+  gcc_jit_context_compile_to_file (ctxt_weak,
+           GCC_JIT_OUTPUT_KIND_OBJECT_FILE,
+           "weaksymtest_foobar_w.o");
+
+  /* ld treats weak symbols in shared libraries like
+     normal symbols unless env.var. LD_DYNAMIC_WEAK is set,
+     so dynamic libraries are a bit awkward to test in
+     a unit test like we do here. However it is easy 
+     to check manually that the symbols are weak with 
+     objdump etc. */
+#if 0
+  unlink ("weaksymtest_foobar_weak.so");
+  unlink ("weaksymtest_foobar.so");
+  gcc_jit_context_compile_to_file (ctxt_weak,
+                  GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY,
+                  "libweaksymtest_foobar_w.so");
+  gcc_jit_context_compile_to_file (ctxt_normal,
+                  GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY,
+                  "libweaksymtest_foobar_n.so");
+#endif
+
+  /* For checking wether the c-like dump looks ok */
+#if 0
+  unlink("libweaksymtest_foobar_w.c");
+  gcc_jit_context_dump_to_file (ctxt_weak, "libweaksymtest_foobar_w.c", 0);
+#endif
+
+  CHECK_NO_ERRORS (ctxt_normal);
+  CHECK_NO_ERRORS (ctxt_weak);
+
+  gcc_jit_result *result_weak = gcc_jit_context_compile (ctxt_weak);
+  CHECK_NON_NULL (result_weak);
+  /* Just does some simple access and value check of the weak symbols */
+  CHECK_NO_ERRORS (ctxt_weak);
+  verify_code (ctxt_weak, result_weak);
+
+  gcc_jit_result_release (result_weak);
+
+  gcc_jit_context_release (ctxt_normal);
+  gcc_jit_context_release (ctxt_weak);
+
+  if (logfile_normal)
+    fclose (logfile_normal);
+  if (logfile_weak)
+    fclose (logfile_weak);
+}
+#endif /* #ifndef COMBINED_TEST */
+
+extern void
+create_code_weak_or_normal (gcc_jit_context *ctxt, int create_weak)
+{
+  enum gcc_jit_function_kind fn_kind;
+  enum gcc_jit_global_kind var_kind;
+  int value;
+  int arr[1];
+
+  if (create_weak) 
+    {
+      fn_kind = GCC_JIT_FUNCTION_EXPORTED_WEAK;
+      var_kind = GCC_JIT_GLOBAL_EXPORTED_WEAK;
+      value = 1;
+    } 
+  else 
+    {
+      fn_kind = GCC_JIT_FUNCTION_EXPORTED;
+      var_kind = GCC_JIT_GLOBAL_EXPORTED;
+      value = 2;
+    }
+
+  /* int __attribute__((weak)) foo() { return 1;}
+     int foo() { return 2;} */
+  gcc_jit_type *int_type = 
+    gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+  gcc_jit_function *foo = 
+    gcc_jit_context_new_function (ctxt, 0, fn_kind, int_type, 
+    "weaksymtest_foo", 0,0,0);
+  gcc_jit_block *block1 =
+    gcc_jit_function_new_block (foo, "block1");
+  gcc_jit_block_end_with_return (block1, 0, 
+    gcc_jit_context_new_rvalue_from_int (ctxt, int_type, value));
+  
+  /* int __attribute__((weak)) bar[] = {1};
+     int bar[] = {2}; */
+  gcc_jit_lvalue *bar = gcc_jit_context_new_global (ctxt, 0, var_kind, 
+    gcc_jit_context_new_array_type (ctxt, 0, int_type, 1), "weaksymtest_bar");
+  
+  arr[0] = value;
+  gcc_jit_global_set_initializer (bar, (const void *)arr, sizeof(int));
+}
+
+/* This function is used in all-non-failing-test.h and just creates the
+   weak context */
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+  (void) user_data;
+  create_code_weak_or_normal (ctxt, 1);
+}
+
+/* { dg-final { jit-verify-output-files-were-created "weaksymtest_foobar_w.o" "weaksymtest_foobar_n.o"} } */
+
+/* jit-verify-sources-objects compiles "verify-weak-linkage.c" with the object files
+   and checks that the stdout of the resulting executable matches "2\n2\n" which 
+   indicates that the weak symbols are not used. */
+
+/* { dg-final { jit-verify-sources-objects "2\\n2\\n" "verify-weak-linkage.c" "weaksymtest_foobar_w.o weaksymtest_foobar_n.o"} } */
diff --git a/gcc/testsuite/jit.dg/verify-weak-linkage.c b/gcc/testsuite/jit.dg/verify-weak-linkage.c
new file mode 100644
index 00000000000..c3ac1b9a50d
--- /dev/null
+++ b/gcc/testsuite/jit.dg/verify-weak-linkage.c
@@ -0,0 +1,21 @@
+/* For use with jit-verify-sources-objects
+   used by test-compile-weak-symbols.c
+
+   This file is linked to two object files . One with
+   weak symbols, one with normal. It prints the value 
+   of bar[0] and foo() and should print 2\n2\n if the
+   weak symbols are not linked in. */
+
+#include <stdio.h>
+
+extern int weaksymtest_bar[1];
+int weaksymtest_foo();
+
+int
+main (int argc, char **argv)
+{
+  printf ("%d\n", weaksymtest_foo());
+  printf ("%d\n", weaksymtest_bar[0]);
+  return 0;
+}
+
-- 
2.20.1



More information about the Gcc-patches mailing list