This makes a couple of changes to how the assembler works.

- Comments are removed earlier in the scanning, and do not have to be
  accounted for in later regex matches.
- Multiline instructions are allowed if the newline is escaped.
  - This is done to support cases where the target architecture is a VLIW
    where the instructions in one bundle may be spread over multiple lines.
- The class impelementing the OpcodeAssemblerInterface is responsible to
  add any symbols that occur on the same line(s) as instructions. Labels that
  occur on an unescaped line by itself will be handled by SimpleAssembler.
  - If the target ISA is a VLIW, the class implementing the
    OpcodeAssemblerInterface is responsible for breaking the multiple
    instructions up into separate strings and passing each such string to the
    corresponding "slot matcher".

PiperOrigin-RevId: 716315088
Change-Id: I25b0eb1fef92481f4a72c0b7bcec407b50543e1e
diff --git a/mpact/sim/decoder/format.cc b/mpact/sim/decoder/format.cc
index e71bd6b..c602995 100644
--- a/mpact/sim/decoder/format.cc
+++ b/mpact/sim/decoder/format.cc
@@ -282,7 +282,7 @@
 // e.g., two fields were named the same in different formats but referred to
 // different bits.
 void Format::PropagateExtractorsDown() {
-  // Remove the extractor entries with nullptrs and any extractors that
+  // Remove the extractor entries with null ptrs and any extractors that
   // have been promoted.
   auto e_iter = extractors_.begin();
   while (e_iter != extractors_.end()) {
@@ -299,7 +299,7 @@
       continue;
     }
   }
-  // Remove the overlay extractor entries with nullptrs.
+  // Remove the overlay extractor entries with null ptrs.
   auto o_iter = overlay_extractors_.begin();
   while (o_iter != overlay_extractors_.end()) {
     auto cur = o_iter++;
diff --git a/mpact/sim/decoder/instruction_set.cc b/mpact/sim/decoder/instruction_set.cc
index 31448c5..93c61d8 100644
--- a/mpact/sim/decoder/instruction_set.cc
+++ b/mpact/sim/decoder/instruction_set.cc
@@ -844,17 +844,19 @@
       "EncodeFcn encode_fcns[] = {\n"
       "  EncodeNone,\n");
   for (auto &[name, inst_ptr] : instruction_map_) {
+    std::string prefix;
+    std::string suffix;
     auto *opcode = inst_ptr->opcode();
     absl::StrAppend(&array, "  Encode", opcode->pascal_name(), ",\n");
-    absl::StrAppend(&cc_output,
-                    "absl::StatusOr<std::tuple<uint64_t, int>> Encode",
+    absl::StrAppend(&prefix, "absl::StatusOr<std::tuple<uint64_t, int>> Encode",
                     opcode->pascal_name(), "(\n     ", encoder,
                     " *encoder, SlotEnum slot, int entry, OpcodeEnum opcode,\n"
                     "     uint64_t address, const "
                     "std::vector<std::string> &operands,\n"
                     "     ResolverInterface *resolver, "
                     "std::vector<RelocationInfo> &relocations) "
-                    "{\n"
+                    "{\n");
+    absl::StrAppend(&suffix,
                     "  auto res_opcode = encoder->GetOpcodeEncoding(slot, "
                     "entry, opcode, resolver);\n"
                     "  if (!res_opcode.ok()) return res_opcode.status();\n"
@@ -866,19 +868,31 @@
         if (format_info->op_name.empty()) continue;
         auto iter = opcode->op_locator_map().find(format_info->op_name);
         if (iter == opcode->op_locator_map().end()) {
-          absl::StrAppend(&cc_output, "  #error ", format_info->op_name,
+          absl::StrAppend(&suffix, "  #error ", format_info->op_name,
                           " not found in instruction opcodes\n");
           continue;
         }
         auto locator = iter->second;
-        absl::StrAppend(&cc_output,
+        absl::StrAppend(&suffix,
                         GenerateOperandEncoder(position++, format_info->op_name,
                                                locator, opcode));
       }
     }
-    absl::StrAppend(&cc_output,
+    absl::StrAppend(&suffix,
                     "  return std::make_tuple(encoding, bit_size);\n"
                     "}\n\n");
+    absl::StrAppend(&cc_output, prefix,
+                    "  auto num_args = operands.size();\n"
+                    "  if (num_args != ",
+                    position,
+                    ") {\n"
+                    "    return absl::InvalidArgumentError(\n"
+                    "        absl::StrCat(\"Invalid number of operands (\", "
+                    "num_args, \") - expected ",
+                    position,
+                    "\"));\n"
+                    "  }\n",
+                    suffix);
   }
   absl::StrAppend(&array, "};\n\n");
   absl::StrAppend(&cc_output, array, "\n}  // namespace\n\n");
diff --git a/mpact/sim/decoder/slot.cc b/mpact/sim/decoder/slot.cc
index 6f6d417..1c13119 100644
--- a/mpact/sim/decoder/slot.cc
+++ b/mpact/sim/decoder/slot.cc
@@ -371,7 +371,7 @@
 std::tuple<std::string, std::vector<OperandLocator>> Slot::GenerateRegEx(
     const Instruction *inst, std::vector<std::string> &formats) const {
   std::string output = "R\"(";
-  std::string sep = "^";
+  std::string sep = "^\\s*";
   std::vector<OperandLocator> opnd_locators;
   // Iterate over the vector of disasm formats. These will end up concatenated
   // with \s+ separators.
@@ -423,7 +423,7 @@
       }
     }
   }
-  absl::StrAppend(&output, "$)\"");
+  absl::StrAppend(&output, "\\s*$)\"");
   return {output, opnd_locators};
 }
 
diff --git a/mpact/sim/util/asm/BUILD b/mpact/sim/util/asm/BUILD
index 5df423f..1620657 100644
--- a/mpact/sim/util/asm/BUILD
+++ b/mpact/sim/util/asm/BUILD
@@ -27,6 +27,7 @@
     ],
     deps = [
         "@com_github_serge1_elfio//:elfio",
+        "@com_google_absl//absl/functional:any_invocable",
         "@com_google_absl//absl/status",
         "@com_google_absl//absl/status:statusor",
         "@com_google_absl//absl/strings",
diff --git a/mpact/sim/util/asm/opcode_assembler_interface.h b/mpact/sim/util/asm/opcode_assembler_interface.h
index 1c7553b..97bcffe 100644
--- a/mpact/sim/util/asm/opcode_assembler_interface.h
+++ b/mpact/sim/util/asm/opcode_assembler_interface.h
@@ -19,8 +19,10 @@
 #include <string>
 #include <vector>
 
+#include "absl/functional/any_invocable.h"
 #include "absl/status/status.h"
 #include "absl/strings/string_view.h"
+#include "elfio/elf_types.hpp"
 #include "mpact/sim/util/asm/resolver_interface.h"
 
 // This file defines the interface that the opcode assembler must implement. It
@@ -43,10 +45,16 @@
 class OpcodeAssemblerInterface {
  public:
   virtual ~OpcodeAssemblerInterface() = default;
-  // Takes the current address, the text for the assembly instruction, and a
-  // symbol resolver interface.Return ok status if the text is successfully
-  // encoded into the bytes vector.
+  using AddSymbolCallback = absl::AnyInvocable<absl::Status(
+      const std::string &, ELFIO::Elf64_Addr /*value*/,
+      ELFIO::Elf_Xword /*size*/, uint8_t /*type*/, uint8_t /*binding*/,
+      uint8_t /*other*/)>;
+  // Takes the current address, the text for the assembly instruction (including
+  // any label definitions), and a symbol resolver interface.Return ok status if
+  // the text is successfully encoded into the bytes vector. Symbols for any
+  // labels are added using the callback function interface.
   virtual absl::Status Encode(uint64_t address, absl::string_view text,
+                              AddSymbolCallback add_symbol_callback,
                               ResolverInterface *resolver,
                               std::vector<uint8_t> &bytes,
                               std::vector<RelocationInfo> &relocations) = 0;
diff --git a/mpact/sim/util/asm/simple_assembler.cc b/mpact/sim/util/asm/simple_assembler.cc
index 225452b..1622c79 100644
--- a/mpact/sim/util/asm/simple_assembler.cc
+++ b/mpact/sim/util/asm/simple_assembler.cc
@@ -311,12 +311,11 @@
 }  // namespace
 
 SimpleAssembler::SimpleAssembler(absl::string_view comment, int elf_file_class,
-                                 int os_abi, int machine,
                                  OpcodeAssemblerInterface *opcode_assembler_if)
     : elf_file_class_(elf_file_class),
       opcode_assembler_if_(opcode_assembler_if),
-      comment_re_(absl::StrCat("^\\s*(?:", comment, "(.*))?$")),
-      asm_line_re_("^(?:(?:(\\S+)\\s*:)?|\\s)\\s*([^;]*?)?\\s*(?:;(.*))?$"),
+      comment_re_(absl::StrCat("^(.*?)(?:", comment, ".*?)?(\\\\)?$")),
+      asm_line_re_("^(?:(?:(\\S+)\\s*:)?|\\s)\\s*(.*)\\s*$"),
       directive_re_(
           "^\\.(align|bss|bytes|char|cstring|data|global|long|sect"
           "|short|space|string|type|text|uchar|ulong|ushort|uword|word)(?:\\s+("
@@ -325,8 +324,8 @@
           "$") {
   // Configure the ELF file writer.
   writer_.create(elf_file_class_, ELFDATA2LSB);
-  writer_.set_os_abi(os_abi);
-  writer_.set_machine(machine);
+  writer_.set_os_abi(ELFOSABI_NONE);
+  writer_.set_machine(EM_NONE);
   // Create the symbol table section.
   symtab_ = writer_.sections.add(".symtab");
   section_index_map_.insert({symtab_->get_index(), symtab_});
@@ -369,12 +368,36 @@
   // section_address_map_ will keep track of the current location within each
   // section (i.e., the offset within the section of the next
   // instruction/object).
-  std::string line;
   std::string label;
   std::string statement;
   while (is.good() && !is.eof()) {
-    getline(is, line);
-    if (RE2::FullMatch(line, comment_re_)) continue;
+    std::string line;
+    while (true) {
+      std::string tmp;
+      if (!is.good() || is.eof()) break;
+      getline(is, tmp);
+      std::string prefix;
+      std::string suffix;
+      // Remove comments from the input line.
+      if (!RE2::FullMatch(tmp, comment_re_, &prefix, &suffix)) {
+        return absl::InternalError("Failed to parse comment");
+      }
+      tmp = absl::StrCat(prefix, suffix);
+      int len = tmp.length();
+      // If there is an escaped newline then append the line, up to the  '\',
+      // and continue.
+      if ((len >= 1) && (tmp[len - 1] == '\\')) {
+        // Insert the escaped newline that getline removed.
+        absl::StrAppend(&line, tmp, "\n");
+        continue;
+      }
+      absl::StrAppend(&line, tmp);
+      break;
+    }
+    if (line.empty()) continue;
+    // Parse the line into a label and a statement. This is done to determine if
+    // the line contains a label, only a label, or if the statement is directive
+    // or not.
     if (RE2::FullMatch(line, asm_line_re_, &label, &statement)) {
       std::vector<uint8_t> byte_vector;
       std::vector<RelocationInfo> relo_vector;
@@ -383,30 +406,28 @@
           (section == nullptr) ? 0 : section_address_map_[section];
       if (!statement.empty()) {
         absl::Status status;
+        // Pass the full line into the parse functions, they are responsible
+        // for handling the labels in pass one.
         if (statement[0] == '.') {
-          status = ParseAsmDirective(statement, &zero_resolver, byte_vector);
+          status = ParseAsmDirective(line, address, &zero_resolver, byte_vector,
+                                     relo_vector);
         } else {
-          status = ParseAsmStatement(statement, &zero_resolver, byte_vector,
+          status = ParseAsmStatement(line, address, &zero_resolver, byte_vector,
                                      relo_vector);
         }
         if (!status.ok()) return status;
-        // Save the statements for processing in pass two.
+        // Save the statements for processing in pass two (labels are all
+        // processed in pass one).
         lines_.push_back(statement);
-      }
-
-      if (!label.empty()) {
-        // When initially adding symbols, the address is relative to the start
-        // of the containing section. This will be corrected later.
-        if (section == nullptr) {
-          return absl::InvalidArgumentError(absl::StrCat(
-              "Label: '", label, "' defined outside of a section"));
-        }
-        auto size = section_address_map_[section] - address;
+      } else if (!label.empty()) {
+        // This is just a single label definition. Add it to the symbol table.
         auto status =
-            AddSymbol(label, address, size, STT_NOTYPE, STB_LOCAL, 0, section);
+            AddSymbolToCurrentSection(label, address, 0, STT_NOTYPE, 0, 0);
+        if (!status.ok()) return status;
       }
       continue;
     }
+    // Parse failure.
     return absl::AbortedError(absl::StrCat("Parse failure: '", line, "'"));
   }
 
@@ -723,20 +744,22 @@
     std::vector<uint8_t> byte_vector;
     absl::Status status;
     auto *section = current_section_;
+    auto relo_size = relo_vector.size();
+    auto address = section_address_map_[section];
     if (line[0] == '.') {
-      auto status = ParseAsmDirective(line, symbol_resolver_, byte_vector);
+      auto status = ParseAsmDirective(line, address, symbol_resolver_,
+                                      byte_vector, relo_vector);
     } else {
-      auto relo_size = relo_vector.size();
-      auto address = section_address_map_[section];
-      auto status =
-          ParseAsmStatement(line, symbol_resolver_, byte_vector, relo_vector);
-      // Update section information in the relocation vector.
-      for (int i = relo_size; i < relo_vector.size(); ++i) {
-        relo_vector[i].section_index = section->get_index();
-        relo_vector[i].offset = address;
-      }
+      auto status = ParseAsmStatement(line, address, symbol_resolver_,
+                                      byte_vector, relo_vector);
     }
     if (!status.ok()) return status;
+    // Update section information in the relocation vector.
+    for (int i = relo_size; i < relo_vector.size(); ++i) {
+      relo_vector[i].section_index = section->get_index();
+      relo_vector[i].offset = address;
+    }
+    // Go to the next line if there is no data to add to the section.
     if (byte_vector.empty()) continue;
     // Add data to the section, but first make sure it's not bss.
     if (section != bss_section_) {
@@ -759,12 +782,19 @@
 // tokens separated by spaces. The argument is parsed using regular
 // expressions. The byte values are appended to the given vector.
 absl::Status SimpleAssembler::ParseAsmDirective(
-    absl::string_view directive, ResolverInterface *resolver,
-    std::vector<uint8_t> &byte_values) {
+    absl::string_view line, uint64_t address, ResolverInterface *resolver,
+    std::vector<uint8_t> &byte_values,
+    std::vector<RelocationInfo> &relocations) {
   std::string match;
   std::string remainder;
   ELFIO::section *section = current_section_;
   uint64_t size = 0;
+  std::string directive;
+  std::string label;
+  if (!RE2::FullMatch(line, asm_line_re_, &label, &directive)) {
+    return absl::InvalidArgumentError(
+        absl::StrCat("Invalid assembly line: '", line, "'"));
+  }
   if (!RE2::FullMatch(directive, directive_re_, &match, &remainder)) {
     return absl::InvalidArgumentError(
         absl::StrCat("Invalid directive: '", directive, "'"));
@@ -906,6 +936,17 @@
     }
     section_address_map_[section] += size;
   }
+
+  if (!label.empty()) {
+    // When initially adding symbols, the address is relative to the start
+    // of the containing section. This will be corrected later.
+    if (section == nullptr) {
+      return absl::InvalidArgumentError(
+          absl::StrCat("Label: '", label, "' defined outside of a section"));
+    }
+    auto status =
+        AddSymbol(label, address, size, STT_NOTYPE, STB_LOCAL, 0, section);
+  }
   return absl::OkStatus();
 }
 
@@ -913,13 +954,14 @@
 // expected to be a single line of text. The byte values are appended to the
 // given vector.
 absl::Status SimpleAssembler::ParseAsmStatement(
-    absl::string_view statement, ResolverInterface *resolver,
+    absl::string_view line, uint64_t address, ResolverInterface *resolver,
     std::vector<uint8_t> &byte_values,
     std::vector<RelocationInfo> &relocations) {
   // Call the target specific assembler to encode the statement.
   auto status = opcode_assembler_if_->Encode(
-      section_address_map_[current_section_], statement, resolver, byte_values,
-      relocations);
+      address, line,
+      absl::bind_front(&SimpleAssembler::AddSymbolToCurrentSection, this),
+      resolver, byte_values, relocations);
   if (!status.ok()) return status;
   section_address_map_[current_section_] += byte_values.size();
   return absl::OkStatus();
@@ -987,6 +1029,27 @@
   bss_section_ = section;
   section_index_map_.insert({section->get_index(), bss_section_});
 }
+absl::Status SimpleAssembler::AddSymbolToCurrentSection(
+    const std::string &name, ELFIO::Elf64_Addr value, ELFIO::Elf_Xword size,
+    uint8_t type, uint8_t binding, uint8_t other) {
+  return AddSymbol(name, value, size, type, binding, other, current_section_);
+}
+
+absl::Status SimpleAssembler::AddSymbol(const std::string &name,
+                                        ELFIO::Elf64_Addr value,
+                                        ELFIO::Elf_Xword size, uint8_t type,
+                                        uint8_t binding, uint8_t other,
+                                        const std::string &section_name) {
+  ELFIO::section *section = nullptr;
+  if (!section_name.empty()) {
+    section = writer_.sections[section_name];
+    if (section == nullptr) {
+      return absl::InvalidArgumentError(
+          absl::StrCat("Section '", section_name, "' not found"));
+    }
+  }
+  return AddSymbol(name, value, size, type, binding, other, section);
+}
 
 absl::Status SimpleAssembler::AddSymbol(const std::string &name,
                                         ELFIO::Elf64_Addr value,
@@ -995,7 +1058,6 @@
                                         ELFIO::section *section) {
   auto iter = symbol_indices_.find(name);
   if (iter != symbol_indices_.end()) {
-    if (section == nullptr) return absl::OkStatus();
     return absl::AlreadyExistsError(
         absl::StrCat("Symbol '", name, "' already exists"));
   }
diff --git a/mpact/sim/util/asm/simple_assembler.h b/mpact/sim/util/asm/simple_assembler.h
index 82a56fc..44e1d27 100644
--- a/mpact/sim/util/asm/simple_assembler.h
+++ b/mpact/sim/util/asm/simple_assembler.h
@@ -37,13 +37,14 @@
 
 // This file declares the SimpleAssembler class, which provides simple handling
 // of assembly source, including a number of assembly directives. It currently
-// handles three sections: .text, .data, and .bss. It produces an executable
-// ELF file with the text section in its own segment starting at the base
-// address, followed by the data section, and then the bss section. The entry
-// point is set either by calling SetEntryPoint(), or by specifying the entry
-// symbol with the .entry directive inside the text section of the input
-// assembly source. If SetEntryPoint() is called after parsing it overrides the
-// entry point set by the .entry directive.
+// handles three sections: .text, .data, and .bss. It produces either a
+// relocatable file or an executable ELF file with the text section in its own
+// segment starting at the base address, followed by the data section, and then
+// the bss section. For the executable file, the entry point is set by calling
+// SetEntryPoint().
+//
+// Only little-endian ELF files are currently supported.
+
 namespace mpact {
 namespace sim {
 namespace util {
@@ -51,28 +52,39 @@
 
 class SimpleAssembler {
  public:
-  SimpleAssembler(absl::string_view comment, int elf_file_class, int os_abi,
-                  int machine, OpcodeAssemblerInterface *opcode_assembler_if);
+  /*
+  SimpleAssembler(int elf_file_class, absl::string_view terminator_regex,
+                  absl::string_view comment_regex,
+                  OpcodeAssemblerInterface *opcode_assembler_if);
+  */
+  SimpleAssembler(absl::string_view comment, int elf_file_class,
+                  OpcodeAssemblerInterface *opcode_assembler_if);
   SimpleAssembler(const SimpleAssembler &) = delete;
   SimpleAssembler &operator=(const SimpleAssembler &) = delete;
   virtual ~SimpleAssembler();
 
   // Parse the input stream as assembly.
   absl::Status Parse(std::istream &is);
+  // Add the symbol to the symbol table for the current section.
+  absl::Status AddSymbolToCurrentSection(const std::string &name,
+                                         ELFIO::Elf64_Addr value,
+                                         ELFIO::Elf_Xword size, uint8_t type,
+                                         uint8_t binding, uint8_t other);
+  // Add the symbol to the symbol table for the named section.
+  absl::Status AddSymbol(const std::string &name, ELFIO::Elf64_Addr value,
+                         ELFIO::Elf_Xword size, uint8_t type, uint8_t binding,
+                         uint8_t other, const std::string &section_name);
   // Create executable ELF file with the given value as the entry point.
   // The text segment will be laid out starting at base address, followed by
   // the data segment.
   absl::Status CreateExecutable(uint64_t base_address,
                                 const std::string &entry_point);
   absl::Status CreateExecutable(uint64_t base_address, uint64_t entry_point);
-  // Helper function called during symbol accessor arrange_local_symbols() to
-  // swap the local and non-local symbols.
-  void SwapSymbols(ELFIO::Elf_Half non_local, ELFIO::Elf_Half local);
   // Create a relocatable ELF file.
   absl::Status CreateRelocatable();
-  // Write out the ELF file.
+  // Write the ELF file to the given output stream.
   absl::Status Write(std::ostream &os);
-
+  // Access the ELF writer.
   ELFIO::elfio &writer() { return writer_; }
 
  private:
@@ -88,11 +100,12 @@
   // Perform second pass of parsing.
   absl::Status ParsePassTwo(std::vector<RelocationInfo> &relo_vector);
   // Parse and process an assembly directive.
-  absl::Status ParseAsmDirective(absl::string_view directive,
+  absl::Status ParseAsmDirective(absl::string_view line, uint64_t address,
                                  ResolverInterface *resolver,
-                                 std::vector<uint8_t> &byte_values);
+                                 std::vector<uint8_t> &byte_values,
+                                 std::vector<RelocationInfo> &relocations);
   // Parse and process and assembly statement.
-  absl::Status ParseAsmStatement(absl::string_view statement,
+  absl::Status ParseAsmStatement(absl::string_view line, uint64_t address,
                                  ResolverInterface *resolver,
                                  std::vector<uint8_t> &byte_values,
                                  std::vector<RelocationInfo> &relocations);
diff --git a/mpact/sim/util/asm/test/BUILD b/mpact/sim/util/asm/test/BUILD
index 42299da..3c5e77a 100644
--- a/mpact/sim/util/asm/test/BUILD
+++ b/mpact/sim/util/asm/test/BUILD
@@ -104,5 +104,6 @@
         "@com_google_absl//absl/strings",
         "@com_google_absl//absl/types:span",
         "@com_google_googletest//:gtest_main",
+        "@com_googlesource_code_re2//:re2",
     ],
 )
diff --git a/mpact/sim/util/asm/test/riscv64x_asm_test.cc b/mpact/sim/util/asm/test/riscv64x_asm_test.cc
index a50e97e..91d9d93 100644
--- a/mpact/sim/util/asm/test/riscv64x_asm_test.cc
+++ b/mpact/sim/util/asm/test/riscv64x_asm_test.cc
@@ -34,6 +34,7 @@
 #include "mpact/sim/util/asm/simple_assembler.h"
 #include "mpact/sim/util/asm/test/riscv64x_bin_encoder_interface.h"
 #include "mpact/sim/util/asm/test/riscv64x_encoder.h"
+#include "re2/re2.h"
 
 // This file contains tests for the simple assembler using a very reduced
 // subset of the RISC-V ISA.
@@ -50,11 +51,20 @@
 // This class implements the OpcodeAssemblerInterface using the slot matcher.
 class RiscV64XAssembler : public OpcodeAssemblerInterface {
  public:
-  RiscV64XAssembler(Riscv64xSlotMatcher* matcher) : matcher_(matcher) {};
+  RiscV64XAssembler(Riscv64xSlotMatcher* matcher)
+      : label_re_("^(\\S+)\\s*:"), matcher_(matcher) {};
   ~RiscV64XAssembler() override = default;
   absl::Status Encode(uint64_t address, absl::string_view text,
+                      AddSymbolCallback add_symbol_callback,
                       ResolverInterface* resolver, std::vector<uint8_t>& bytes,
                       std::vector<RelocationInfo>& relocations) override {
+    // First check to see if there is a label, if so, add it to the symbol table
+    // with the current address.
+    std::string label;
+    if (RE2::Consume(&text, label_re_, &label)) {
+      auto status = add_symbol_callback(label, address, 0, STT_NOTYPE, 0, 0);
+      if (!status.ok()) return status;
+    }
     // Call the slot matcher to get the encoded value.
     auto res = matcher_->Encode(address, text, 0, resolver, relocations);
     if (!res.status().ok()) return res.status();
@@ -72,6 +82,7 @@
   }
 
  private:
+  RE2 label_re_;
   Riscv64xSlotMatcher* matcher_;
 };
 
@@ -132,8 +143,9 @@
       : matcher_(&bin_encoder_interface_), riscv_64x_assembler_(&matcher_) {
     CHECK_OK(matcher_.Initialize());
     // Create the assembler.
-    assembler_ = new SimpleAssembler(";", ELFCLASS64, ELFOSABI_LINUX, EM_RISCV,
-                                     &riscv_64x_assembler_);
+    assembler_ = new SimpleAssembler(";", ELFCLASS64, &riscv_64x_assembler_);
+    assembler_->writer().set_os_abi(ELFOSABI_LINUX);
+    assembler_->writer().set_machine(EM_RISCV);
     std::istringstream source(*kTestAssembly);
     // Parse the assembly code.
     auto status = assembler_->Parse(source);