Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
[mc] Add stack-cleaning compiler wrappers
authorGabriel Corona <gabriel.corona@loria.fr>
Tue, 7 Oct 2014 09:26:45 +0000 (11:26 +0200)
committerGabriel Corona <gabriel.corona@loria.fr>
Mon, 3 Nov 2014 09:42:22 +0000 (10:42 +0100)
This compiler wrappers clear each satck frame before using it in order
to avoid issues with unitialized variables in SimGridMC state
comparison.

Compiling with those compiler is much slower.

tools/stack-cleaner/README [new file with mode: 0644]
tools/stack-cleaner/as [new file with mode: 0755]
tools/stack-cleaner/c++ [new file with mode: 0755]
tools/stack-cleaner/cc [new file with mode: 0755]
tools/stack-cleaner/clean-stack-filter [new file with mode: 0755]

diff --git a/tools/stack-cleaner/README b/tools/stack-cleaner/README
new file mode 100644 (file)
index 0000000..0aa98f8
--- /dev/null
@@ -0,0 +1,21 @@
+Provides stack-cleaning compilers for x86_64:
+
+ * as
+ * cc
+ * c++
+
+Each of them modify the generated/given X86_64 assembly by prepending
+stack-cleanup code to each function:
+
+       movq $QSIZE, %r11
+.Lloop:
+        movq $0, OFFSET(%rsp,%r11,8)
+        subq $1, %r11
+        jne  .Lloop
+
+The modification of the assembly is done by the clean-stack-filter
+program.
+
+If the underlying compiler is clang, it might be necessary to add the
+-no-integrated-as flag in order to force the usage of an external
+assembler.
diff --git a/tools/stack-cleaner/as b/tools/stack-cleaner/as
new file mode 100755 (executable)
index 0000000..dcdb491
--- /dev/null
@@ -0,0 +1,57 @@
+#!/usr/bin/ruby
+# Wrapper around the real `as` which adds filtering capabilities.
+
+require "tempfile"
+require "fileutils"
+
+def wrapped_as(argv)
+
+  args=[]
+  input=nil
+
+  i = 0
+  while i<argv.size
+    case argv[i]
+    when "-o", "-I"
+      args.push(argv[i])
+      args.push(argv[i+1])
+      i = i + 1
+    when /^-/
+      args.push(argv[i])
+    else
+      if input
+        exit 1
+      else
+        input = argv[i]
+      end
+    end
+    i = i + 1
+  end
+
+  if input==nil
+    # We dont handle pipe yet:
+    exit 1
+  end
+
+  # Generate temp file
+  tempfile = Tempfile.new("as-filter")
+  unless system(File.dirname($0) + "/clean-stack-filter", 0 => input, 1 => tempfile)
+    status=$?.exitstatus
+    FileUtils.rm tempfile
+    exit status
+  end
+  args.push(tempfile.path)
+
+  # Call the real assembler:
+  res = system("as", *args)
+  status = if res != nil
+             $?.exitstatus
+           else
+             1
+           end
+  FileUtils.rm tempfile
+  exit status
+
+end
+
+wrapped_as(ARGV)
diff --git a/tools/stack-cleaner/c++ b/tools/stack-cleaner/c++
new file mode 100755 (executable)
index 0000000..516d36c
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+path="$(dirname $0)"
+exec "${FILTER_CXX:-c++}" -B "$path" "$@"
diff --git a/tools/stack-cleaner/cc b/tools/stack-cleaner/cc
new file mode 100755 (executable)
index 0000000..3cfd378
--- /dev/null
@@ -0,0 +1,3 @@
+#!/bin/sh
+path="$(dirname $0)"
+exec "${FILTER_CC:-cc}" -B "$path" "$@"
diff --git a/tools/stack-cleaner/clean-stack-filter b/tools/stack-cleaner/clean-stack-filter
new file mode 100755 (executable)
index 0000000..8c5c01c
--- /dev/null
@@ -0,0 +1,61 @@
+#!/usr/bin/perl -w
+# Transform assembly in order to clean each stack frame for X86_64.
+
+use strict;
+$SIG{__WARN__} = sub { die @_ };
+
+
+# Whether we are still scanning the content of a function:
+our $scanproc = 0;
+
+# Save lines of the function:
+our $lines = "";
+
+# Size of the stack for this function:
+our $size = 0;
+
+
+# Counter for assigning unique ids to labels:
+our $id=0;
+
+sub emit_code {
+    my $qsize = $size / 8;
+    my $offset = - $size - 8;
+
+    if($size != 0) {
+      print("\tmovabsq \$$qsize, %r11\n");
+      print(".Lstack_cleaner_loop$id:\n");
+      print("\tmovq    \$0, $offset(%rsp,%r11,8)\n");
+      print("\tsubq    \$1, %r11\n");
+      print("\tjne     .Lstack_cleaner_loop$id\n");
+    }
+
+    print $lines;
+
+    $id = $id + 1;
+    $size = 0;
+    $lines = "";
+    $scanproc = 0;
+}
+
+while (<>) {
+  if ($scanproc) {
+      $lines = $lines . $_;
+      if (m/^[ \t]*.cfi_endproc$/) {
+         emit_code();
+      } elsif (m/^[ \t]*pushq/) {
+         $size += 8;
+      } elsif (m/^[ \t]*subq[\t *]\$([0-9]*),[ \t]*%rsp$/) {
+          my $val = $1;
+          $val = oct($val) if $val =~ /^0/;
+          $size += $val;
+          emit_code();
+      }
+  } elsif (m/^[ \t]*.cfi_startproc$/) {
+      print $_;
+
+      $scanproc = 1;
+  } else {
+      print $_;
+  }
+}