OSDN Git Service

Implemented global redzones.
authorThomas Lively <tlively@google.com>
Mon, 13 Jun 2016 18:23:29 +0000 (11:23 -0700)
committerThomas Lively <tlively@google.com>
Mon, 13 Jun 2016 18:23:29 +0000 (11:23 -0700)
BUG=https://bugs.chromium.org/p/nativeclient/issues/detail?id=4374
R=kschimpf@google.com

Review URL: https://codereview.chromium.org/2054943002 .

Makefile.standalone
src/IceASanInstrumentation.cpp [new file with mode: 0644]
src/IceASanInstrumentation.h [new file with mode: 0644]
src/IceCompileServer.cpp
src/IceDefs.h
src/IceGlobalContext.cpp
src/IceGlobalInits.h
src/IceInstrumentation.cpp
src/IceInstrumentation.h
tests_lit/asan_tests/globalredzones.ll [new file with mode: 0644]

index 6c40903..4a9470d 100644 (file)
@@ -282,6 +282,7 @@ SB_LDFLAGS := $(LINKOPTLEVEL) $(LD_EXTRA)
 # List the target-specific source files first, which generally take longer to
 # compile, in the hope of improving parallel build time.
 SRCS = \
+  IceASanInstrumentation.cpp \
   IceAssemblerARM32.cpp \
   IceInstrumentation.cpp \
   IceInstARM32.cpp \
diff --git a/src/IceASanInstrumentation.cpp b/src/IceASanInstrumentation.cpp
new file mode 100644 (file)
index 0000000..c0b87dc
--- /dev/null
@@ -0,0 +1,114 @@
+//===- subzero/src/IceASanInstrumentation.cpp - ASan ------------*- C++ -*-===//
+//
+//                        The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Implements the AddressSanitizer instrumentation class.
+///
+//===----------------------------------------------------------------------===//
+
+#include "IceASanInstrumentation.h"
+
+#include "IceBuildDefs.h"
+#include "IceGlobalInits.h"
+
+#include <sstream>
+
+namespace Ice {
+
+namespace {
+constexpr SizeT RzSize = 32;
+const std::string RzPrefix = "__$rz";
+const llvm::NaClBitcodeRecord::RecordVector RzContents =
+    llvm::NaClBitcodeRecord::RecordVector(RzSize, 'R');
+} // end of anonymous namespace
+
+// Create redzones between all global variables, ensuring that the initializer
+// types of the redzones and their associated globals match so that they are
+// laid out together in memory.
+void ASanInstrumentation::instrumentGlobals(VariableDeclarationList &Globals) {
+  if (BuildDefs::minimal() || DidInsertRedZones)
+    return;
+
+  VariableDeclarationList NewGlobals;
+  // Global holding pointers to all redzones
+  auto *RzArray = VariableDeclaration::create(&NewGlobals);
+  // Global holding the size of RzArray
+  auto *RzArraySizeVar = VariableDeclaration::create(&NewGlobals);
+  SizeT RzArraySize = 0;
+
+  RzArray->setName(Ctx, nextRzName());
+  RzArraySizeVar->setName(Ctx, nextRzName());
+  RzArray->setIsConstant(true);
+  RzArraySizeVar->setIsConstant(true);
+  NewGlobals.push_back(RzArray);
+  NewGlobals.push_back(RzArraySizeVar);
+
+  for (VariableDeclaration *Global : Globals) {
+    VariableDeclaration *RzLeft = createRz(&NewGlobals, RzArray, RzArraySize, Global);
+    VariableDeclaration *RzRight = createRz(&NewGlobals, RzArray, RzArraySize, Global);
+    NewGlobals.push_back(RzLeft);
+    NewGlobals.push_back(Global);
+    NewGlobals.push_back(RzRight);
+  }
+
+  // update the contents of the RzArraySize global
+  llvm::NaClBitcodeRecord::RecordVector SizeContents;
+  for (unsigned i = 0; i < sizeof(RzArraySize); i++) {
+    SizeContents.emplace_back(RzArraySize % (1 << CHAR_BIT));
+    RzArraySize >>= CHAR_BIT;
+  }
+  RzArraySizeVar->addInitializer(
+      VariableDeclaration::DataInitializer::create(&NewGlobals, SizeContents));
+
+  // Replace old list of globals, without messing up arena allocators
+  Globals.clear();
+  Globals.merge(&NewGlobals);
+  DidInsertRedZones = true;
+
+  // Log the new set of globals
+  if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_GlobalInit)) {
+    OstreamLocker _(Ctx);
+    Ctx->getStrDump() << "========= Instrumented Globals =========\n";
+    for (VariableDeclaration *Global : Globals) {
+      Global->dump(Ctx->getStrDump());
+    }
+  }
+}
+
+std::string ASanInstrumentation::nextRzName() {
+  if (BuildDefs::minimal())
+    return "";
+  std::stringstream Name;
+  Name << RzPrefix << RzNum++;
+  return Name.str();
+}
+
+VariableDeclaration *
+ASanInstrumentation::createRz(VariableDeclarationList *List,
+                              VariableDeclaration *RzArray, SizeT &RzArraySize,
+                              VariableDeclaration *Global) {
+  if (BuildDefs::minimal())
+    return nullptr;
+  auto *Rz = VariableDeclaration::create(List);
+  Rz->setName(Ctx, nextRzName());
+  if (Global->hasNonzeroInitializer()) {
+    Rz->addInitializer(
+        VariableDeclaration::DataInitializer::create(List, RzContents));
+  } else {
+    Rz->addInitializer(
+        VariableDeclaration::ZeroInitializer::create(List, RzSize));
+  }
+  Rz->setIsConstant(Global->getIsConstant());
+  RzArray->addInitializer(VariableDeclaration::RelocInitializer::create(
+      List, Rz, RelocOffsetArray(0)));
+  ++RzArraySize;
+  return Rz;
+}
+
+} // end of namespace Ice
diff --git a/src/IceASanInstrumentation.h b/src/IceASanInstrumentation.h
new file mode 100644 (file)
index 0000000..ee20e7d
--- /dev/null
@@ -0,0 +1,48 @@
+//===- subzero/src/IceASanInstrumentation.h - AddressSanitizer --*- C++ -*-===//
+//
+//                        The Subzero Code Generator
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Declares the AddressSanitizer instrumentation class.
+///
+/// This class is responsible for inserting redzones around global and stack
+/// variables, inserting code responsible for poisoning those redzones, and
+/// performing any other instrumentation necessary to implement
+/// AddressSanitizer.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef SUBZERO_SRC_ICEASANINSTRUMENTATION_H
+#define SUBZERO_SRC_ICEASANINSTRUMENTATION_H
+
+#include "IceGlobalInits.h"
+#include "IceInstrumentation.h"
+
+namespace Ice {
+
+class ASanInstrumentation : public Instrumentation {
+  ASanInstrumentation() = delete;
+  ASanInstrumentation(const ASanInstrumentation &) = delete;
+  ASanInstrumentation &operator=(const ASanInstrumentation &) = delete;
+
+public:
+  ASanInstrumentation(GlobalContext *Ctx) : Instrumentation(Ctx) {}
+  void instrumentGlobals(VariableDeclarationList &Globals) override;
+
+private:
+  std::string nextRzName();
+  VariableDeclaration *createRz(VariableDeclarationList *List,
+                                VariableDeclaration *RzArray,
+                                SizeT &RzArraySize,
+                                VariableDeclaration *Global);
+  bool DidInsertRedZones = false;
+  uint32_t RzNum = 0;
+};
+} // end of namespace Ice
+
+#endif // SUBZERO_SRC_ICEASANINSTRUMENTATION_H
index 19b19f8..b1f168c 100644 (file)
@@ -14,6 +14,7 @@
 
 #include "IceCompileServer.h"
 
+#include "IceASanInstrumentation.h"
 #include "IceClFlags.h"
 #include "IceELFStreamer.h"
 #include "IceGlobalContext.h"
@@ -244,7 +245,7 @@ void CLCompileServer::run() {
 
   // TODO(tlively): Make this instantiate an instrumentation subclass
   if (!BuildDefs::minimal() && getFlags().getSanitizeAddresses()) {
-    std::unique_ptr<Instrumentation> Instr(new Instrumentation(Ctx.get()));
+    std::unique_ptr<Instrumentation> Instr(new ASanInstrumentation(Ctx.get()));
     Ctx->setInstrumentation(std::move(Instr));
   }
 
index d7ef288..2c09ba9 100644 (file)
@@ -177,7 +177,7 @@ public:
   }
 
   // This do nothing method is invoked when a global variable is created, but it
-  // will not be emitted. If we ever need to track the created variabled, having
+  // will not be emitted. If we ever need to track the created variable, having
   // this hook is handy.
   void willNotBeEmitted(VariableDeclaration *) {}
 
index 0d53127..a1e817b 100644 (file)
@@ -488,7 +488,7 @@ void GlobalContext::lowerGlobals(const std::string &SectionSuffix) {
   }
 
   if (!BuildDefs::minimal() && Instrumentor)
-    Instrumentor->instrumentGlobals();
+    Instrumentor->instrumentGlobals(Globals);
 
   DataLowering->lowerGlobals(Globals, SectionSuffix);
   if (ProfileBlockInfos.empty() && DisposeGlobalVariablesAfterLowering) {
index 378d5d7..e951734 100644 (file)
@@ -279,7 +279,7 @@ public:
         : Initializer(DataInitializerKind), ContentsSize(Values.size()),
           // ugh, we should actually do new char[], but this may involve
           // implementation-specific details. Given that Contents is arena
-          // allocated, and never detele[]d, just use char --
+          // allocated, and never delete[]d, just use char --
           // AllocOwner->allocate_array will allocate a buffer with the right
           // size.
           Contents(new (VDL->allocate_initializer<char>(ContentsSize)) char) {
index 383e151..0d56100 100644 (file)
@@ -47,61 +47,61 @@ void Instrumentation::instrumentInst(LoweringContext &Context) {
   assert(!Context.atEnd());
   Inst *Instr = iteratorToInst(Context.getCur());
   switch (Instr->getKind()) {
-    case Inst::Alloca:
-      instrumentAlloca(Context, llvm::cast<InstAlloca>(Instr));
-      break;
-    case Inst::Arithmetic:
-      instrumentArithmetic(Context, llvm::cast<InstArithmetic>(Instr));
-      break;
-    case Inst::Br:
-      instrumentBr(Context, llvm::cast<InstBr>(Instr));
-      break;
-    case Inst::Call:
-      instrumentCall(Context, llvm::cast<InstCall>(Instr));
-      break;
-    case Inst::Cast:
-      instrumentCast(Context, llvm::cast<InstCast>(Instr));
-      break;
-    case Inst::ExtractElement:
-      instrumentExtractElement(Context, llvm::cast<InstExtractElement>(Instr));
-      break;
-    case Inst::Fcmp:
-      instrumentFcmp(Context, llvm::cast<InstFcmp>(Instr));
-      break;
-    case Inst::Icmp:
-      instrumentIcmp(Context, llvm::cast<InstIcmp>(Instr));
-      break;
-    case Inst::InsertElement:
-      instrumentInsertElement(Context, llvm::cast<InstInsertElement>(Instr));
-      break;
-    case Inst::IntrinsicCall:
-      instrumentIntrinsicCall(Context, llvm::cast<InstIntrinsicCall>(Instr));
-      break;
-    case Inst::Load:
-      instrumentLoad(Context, llvm::cast<InstLoad>(Instr));
-      break;
-    case Inst::Phi:
-      instrumentPhi(Context, llvm::cast<InstPhi>(Instr));
-      break;
-    case Inst::Ret:
-      instrumentRet(Context, llvm::cast<InstRet>(Instr));
-      break;
-    case Inst::Select:
-      instrumentSelect(Context, llvm::cast<InstSelect>(Instr));
-      break;
-    case Inst::Store:
-      instrumentStore(Context, llvm::cast<InstStore>(Instr));
-      break;
-    case Inst::Switch:
-      instrumentSwitch(Context, llvm::cast<InstSwitch>(Instr));
-      break;
-    case Inst::Unreachable:
-      instrumentUnreachable(Context, llvm::cast<InstUnreachable>(Instr));
-      break;
-    default:
-      // Only instrument high-level ICE instructions
-      assert(false && "Instrumentation encountered an unexpected instruction");
-      break;
+  case Inst::Alloca:
+    instrumentAlloca(Context, llvm::cast<InstAlloca>(Instr));
+    break;
+  case Inst::Arithmetic:
+    instrumentArithmetic(Context, llvm::cast<InstArithmetic>(Instr));
+    break;
+  case Inst::Br:
+    instrumentBr(Context, llvm::cast<InstBr>(Instr));
+    break;
+  case Inst::Call:
+    instrumentCall(Context, llvm::cast<InstCall>(Instr));
+    break;
+  case Inst::Cast:
+    instrumentCast(Context, llvm::cast<InstCast>(Instr));
+    break;
+  case Inst::ExtractElement:
+    instrumentExtractElement(Context, llvm::cast<InstExtractElement>(Instr));
+    break;
+  case Inst::Fcmp:
+    instrumentFcmp(Context, llvm::cast<InstFcmp>(Instr));
+    break;
+  case Inst::Icmp:
+    instrumentIcmp(Context, llvm::cast<InstIcmp>(Instr));
+    break;
+  case Inst::InsertElement:
+    instrumentInsertElement(Context, llvm::cast<InstInsertElement>(Instr));
+    break;
+  case Inst::IntrinsicCall:
+    instrumentIntrinsicCall(Context, llvm::cast<InstIntrinsicCall>(Instr));
+    break;
+  case Inst::Load:
+    instrumentLoad(Context, llvm::cast<InstLoad>(Instr));
+    break;
+  case Inst::Phi:
+    instrumentPhi(Context, llvm::cast<InstPhi>(Instr));
+    break;
+  case Inst::Ret:
+    instrumentRet(Context, llvm::cast<InstRet>(Instr));
+    break;
+  case Inst::Select:
+    instrumentSelect(Context, llvm::cast<InstSelect>(Instr));
+    break;
+  case Inst::Store:
+    instrumentStore(Context, llvm::cast<InstStore>(Instr));
+    break;
+  case Inst::Switch:
+    instrumentSwitch(Context, llvm::cast<InstSwitch>(Instr));
+    break;
+  case Inst::Unreachable:
+    instrumentUnreachable(Context, llvm::cast<InstUnreachable>(Instr));
+    break;
+  default:
+    // Only instrument high-level ICE instructions
+    assert(false && "Instrumentation encountered an unexpected instruction");
+    break;
   }
 }
 
index abd5d08..a7e099b 100644 (file)
@@ -41,102 +41,35 @@ class Instrumentation {
 
 public:
   Instrumentation(GlobalContext *Ctx) : Ctx(Ctx) {}
-  virtual void instrumentGlobals() {};
+  virtual void instrumentGlobals(VariableDeclarationList &) {}
   void instrumentFunc(Cfg *Func);
 
 private:
   void instrumentInst(LoweringContext &Context);
-  virtual void instrumentFuncStart(LoweringContext &Context) {
-    (void) Context;
-  }
-  virtual void instrumentAlloca(LoweringContext &Context,
-                                const class InstAlloca *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentArithmetic(LoweringContext &Context,
-                                    const class InstArithmetic *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentBr(LoweringContext &Context,
-                            const class InstBr *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentCall(LoweringContext &Context,
-                              const class InstCall *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentCast(LoweringContext &Context,
-                              const class InstCast *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentExtractElement(LoweringContext &Context,
-                                        const class InstExtractElement *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentFcmp(LoweringContext &Context,
-                              const class InstFcmp *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentIcmp(LoweringContext &Context,
-                              const class InstIcmp *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentInsertElement(LoweringContext &Context,
-                                       const class InstInsertElement *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentIntrinsicCall(LoweringContext &Context,
-                                       const class InstIntrinsicCall *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentLoad(LoweringContext &Context,
-                              const class InstLoad *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentPhi(LoweringContext &Context,
-                             const class InstPhi *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentRet(LoweringContext &Context,
-                             const class InstRet *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentSelect(LoweringContext &Context,
-                                const class InstSelect *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentStore(LoweringContext &Context,
-                               const class InstStore *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentSwitch(LoweringContext &Context,
-                                const class InstSwitch *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentUnreachable(LoweringContext &Context,
-                                     const class InstUnreachable *Instr) {
-    (void) Context;
-    (void) Instr;
-  }
-  virtual void instrumentLocalVars(Cfg *Func) {
-    (void) Func;
-  }
+  virtual void instrumentFuncStart(LoweringContext &) {}
+  virtual void instrumentAlloca(LoweringContext &, const class InstAlloca *) {}
+  virtual void instrumentArithmetic(LoweringContext &,
+                                    const class InstArithmetic *) {}
+  virtual void instrumentBr(LoweringContext &, const class InstBr *) {}
+  virtual void instrumentCall(LoweringContext &, const class InstCall *) {}
+  virtual void instrumentCast(LoweringContext &, const class InstCast *) {}
+  virtual void instrumentExtractElement(LoweringContext &,
+                                        const class InstExtractElement *) {}
+  virtual void instrumentFcmp(LoweringContext &, const class InstFcmp *) {}
+  virtual void instrumentIcmp(LoweringContext &, const class InstIcmp *) {}
+  virtual void instrumentInsertElement(LoweringContext &,
+                                       const class InstInsertElement *) {}
+  virtual void instrumentIntrinsicCall(LoweringContext &,
+                                       const class InstIntrinsicCall *) {}
+  virtual void instrumentLoad(LoweringContext &, const class InstLoad *) {}
+  virtual void instrumentPhi(LoweringContext &, const class InstPhi *) {}
+  virtual void instrumentRet(LoweringContext &, const class InstRet *) {}
+  virtual void instrumentSelect(LoweringContext &, const class InstSelect *) {}
+  virtual void instrumentStore(LoweringContext &, const class InstStore *) {}
+  virtual void instrumentSwitch(LoweringContext &, const class InstSwitch *) {}
+  virtual void instrumentUnreachable(LoweringContext &,
+                                     const class InstUnreachable *) {}
+  virtual void instrumentLocalVars(Cfg *) {}
 
 protected:
   GlobalContext *Ctx;
diff --git a/tests_lit/asan_tests/globalredzones.ll b/tests_lit/asan_tests/globalredzones.ll
new file mode 100644 (file)
index 0000000..a4052e7
--- /dev/null
@@ -0,0 +1,92 @@
+; Test of global redzone layout
+
+; REQUIRES: allow_dump
+
+; RUN: %p2i -i %s --args -threads=0 -fsanitize-address \
+; RUN:     | %iflc FileCheck %s
+; RUN: %p2i -i %s --args -verbose=global_init,inst -threads=0 \
+; RUN:     -fsanitize-address | %iflc FileCheck --check-prefix=DUMP %s
+
+; The array of redzones
+
+; DUMP-LABEL: ========= Instrumented Globals =========
+; DUMP: @__$rz0 = internal constant <{ i32, i32, i32, i32, i32, i32 }>
+; DUMP:         <{ i32 ptrtoint ([32 x i8]* @__$rz2 to i32), i32 ptrtoint ([32 x i8]* @__$rz3 to i32),
+; DUMP:         i32 ptrtoint ([32 x i8]* @__$rz4 to i32), i32 ptrtoint ([32 x i8]* @__$rz5 to i32),
+; DUMP:         i32 ptrtoint ([32 x i8]* @__$rz6 to i32), i32 ptrtoint ([32 x i8]* @__$rz7 to i32) }>
+; DUMP-NEXT: @__$rz1 = internal constant [4 x i8] c"\06\00\00\00"                                                                                                 
+
+; CHECK-LABEL: .type   __$rz0,%object
+; CHECK-NEXT: .section   .rodata
+; CHECK-NEXT: __$rz0:
+; CHECK-NEXT: .long   __$rz2
+; CHECK-NEXT: .long   __$rz3
+; CHECK-NEXT: .long   __$rz4
+; CHECK-NEXT: .long   __$rz5
+; CHECK-NEXT: .long   __$rz6
+; CHECK-NEXT: .long   __$rz7
+; CHECK-LABEL: .type   __$rz1,%object
+; CHECK-NEXT: .section   .rodata
+; CHECK-NEXT: __$rz1:
+; CHECK-NEXT: .byte   6
+; CHECK-NEXT: .byte   0
+; CHECK-NEXT: .byte   0
+; CHECK-NEXT: .byte   0
+
+; A zero-initialized global
+@zeroInitGlobal = internal global [32 x i8] zeroinitializer
+
+; DUMP-NEXT: @__$rz2 = internal global [32 x i8] zeroinitializer
+; DUMP-NEXT: @zeroInitGlobal = internal global [32 x i8] zeroinitializer
+; DUMP-NEXT: @__$rz3 = internal global [32 x i8] zeroinitializer
+
+; CHECK-LABEL: .type   __$rz2,%object
+; CHECK-NEXT: .section   .bss
+; CHECK-NEXT: __$rz2:
+; CHECK-LABEL: .type   zeroInitGlobal,%object
+; CHECK-NEXT: .section   .bss
+; CHECK-NEXT: zeroInitGlobal:
+; CHECK-LABEL: .type   __$rz3,%object
+; CHECK-NEXT: .section   .bss
+; CHECK-NEXT: __$rz3:
+
+; A constant-initialized global
+@constInitGlobal = internal constant [32 x i8] c"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
+
+; CHECK-LABEL: .type   __$rz4,%object
+; CHECK-NEXT: .section   .rodata
+; CHECK-NEXT: __$rz4:
+; CHECK-LABEL: .type   constInitGlobal,%object
+; CHECK-NEXT: .section   .rodata
+; CHECK-NEXT: constInitGlobal:
+; CHECK-LABEL: .type   __$rz5,%object
+; CHECK-NEXT: .section   .rodata
+; CHECK-NEXT: __$rz5:
+
+; DUMP-NEXT: @__$rz4 = internal constant [32 x i8] c"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"
+; DUMP-NEXT: @constInitGlobal = internal constant [32 x i8] c"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
+; DUMP-NEXT: @__$rz5 = internal constant [32 x i8] c"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"
+
+; A regular global
+@regInitGlobal = internal global [32 x i8] c"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
+
+; DUMP-NEXT: @__$rz6 = internal global [32 x i8] c"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"
+; DUMP-NEXT: @regInitGlobal = internal global [32 x i8] c"ABCDEFGHIJKLMNOPQRSTUVWXYZ012345"
+; DUMP-NEXT: @__$rz7 = internal global [32 x i8] c"RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR"
+
+; CHECK-LABEL: .type   __$rz6,%object
+; CHECK-NEXT: .section   .data
+; CHECK-NEXT: __$rz6:
+; CHECK-LABEL: .type   regInitGlobal,%object
+; CHECK-NEXT: .section   .data
+; CHECK-NEXT: regInitGlobal:
+; CHECK-LABEL: .type   __$rz7,%object
+; CHECK-NEXT: .section   .data
+; CHECK-NEXT: __$rz7:
+
+define internal void @func() {
+  ret void
+}
+
+; DUMP-LABEL: define internal void @func() {
+; CHECK-LABEL: func:
\ No newline at end of file