{"action":"created","comment":{"url":"https://api.github.com/repos/WebAssembly/wabt/pulls/comments/92906457","pull_request_review_id":13428332,"id":92906457,"diff_hunk":"@@ -0,0 +1,909 @@\n+/*\n+ * Copyright 2016 WebAssembly Community Group participants\n+ *\n+ * Licensed under the Apache License, Version 2.0 (the \"License\");\n+ * you may not use this file except in compliance with the License.\n+ * You may obtain a copy of the License at\n+ *\n+ *     http://www.apache.org/licenses/LICENSE-2.0\n+ *\n+ * Unless required by applicable law or agreed to in writing, software\n+ * distributed under the License is distributed on an \"AS IS\" BASIS,\n+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n+ * See the License for the specific language governing permissions and\n+ * limitations under the License.\n+ */\n+\n+#include \"allocator.h\"\n+#include \"binary-reader.h\"\n+#include \"binary-writer.h\"\n+#include \"option-parser.h\"\n+#include \"stream.h\"\n+#include \"vector.h\"\n+#include \"writer.h\"\n+\n+#define PROGRAM_NAME \"wasm-link\"\n+#define NOPE WASM_OPTION_NO_ARGUMENT\n+#define YEP WASM_OPTION_HAS_ARGUMENT\n+\n+enum {\n+  FLAG_VERBOSE,\n+  FLAG_OUTPUT,\n+  FLAG_HELP,\n+  NUM_FLAGS\n+};\n+\n+static const char s_description[] =\n+    \"  link one or more wasm binary modules into a single binary module.\"\n+    \"\\n\"\n+    \"  $ wasm-link m1.wasm m2.wasm -o out.wasm\\n\";\n+\n+static WasmOption s_options[] = {\n+    {FLAG_VERBOSE, 'v', \"verbose\", NULL, NOPE,\n+     \"use multiple times for more info\"},\n+    {FLAG_OUTPUT, 'o', \"output\", \"FILE\", YEP,\n+     \"output wasm binary file\"},\n+    {FLAG_HELP, 'h', \"help\", NULL, NOPE, \"print this help message\"},\n+};\n+WASM_STATIC_ASSERT(NUM_FLAGS == WASM_ARRAY_SIZE(s_options));\n+\n+\n+typedef const char* String;\n+WASM_DEFINE_VECTOR(string, String);\n+\n+static WasmBool s_verbose;\n+static const char* s_outfile = \"a.wasm\";\n+static StringVector s_infiles;\n+static WasmAllocator* s_allocator;\n+static WasmFileWriter s_log_stream_writer;\n+static WasmStream s_log_stream;\n+\n+static void on_option(struct WasmOptionParser* parser,\n+                      struct WasmOption* option,\n+                      const char* argument) {\n+  switch (option->id) {\n+    case FLAG_VERBOSE:\n+      s_verbose++;\n+      wasm_init_file_writer_existing(&s_log_stream_writer, stdout);\n+      wasm_init_stream(&s_log_stream, &s_log_stream_writer.base, NULL);\n+      break;\n+\n+    case FLAG_OUTPUT:\n+      s_outfile = argument;\n+      break;\n+\n+    case FLAG_HELP:\n+      wasm_print_help(parser, PROGRAM_NAME);\n+      exit(0);\n+      break;\n+  }\n+}\n+\n+static void on_argument(struct WasmOptionParser* parser, const char* argument) {\n+  *wasm_append_string(s_allocator, &s_infiles) = argument;\n+}\n+\n+static void on_option_error(struct WasmOptionParser* parser,\n+                            const char* message) {\n+  WASM_FATAL(\"%s\\n\", message);\n+}\n+\n+static void parse_options(int argc, char** argv) {\n+  WasmOptionParser parser;\n+  WASM_ZERO_MEMORY(parser);\n+  parser.description = s_description;\n+  parser.options = s_options;\n+  parser.num_options = WASM_ARRAY_SIZE(s_options);\n+  parser.on_option = on_option;\n+  parser.on_argument = on_argument;\n+  parser.on_error = on_option_error;\n+  wasm_parse_options(&parser, argc, argv);\n+\n+  if (!s_infiles.size) {\n+    wasm_print_help(&parser, PROGRAM_NAME);\n+    WASM_FATAL(\"No inputs files specified.\\n\");\n+  }\n+}\n+\n+typedef struct DataSegment {\n+  uint32_t memory_index;\n+  uint32_t offset;\n+  const uint8_t* data;\n+  size_t size;\n+} DataSegment;\n+WASM_DEFINE_VECTOR(data_segment, DataSegment);\n+\n+typedef struct Reloc {\n+  WasmRelocType type;\n+  size_t offset;\n+} Reloc;\n+WASM_DEFINE_VECTOR(reloc, Reloc);\n+\n+struct InputBinary;\n+\n+typedef struct SectionDataCustom {\n+  WasmBool linked;\n+  WasmStringSlice name;\n+} SectionDataCustom;\n+\n+typedef struct Section {\n+  struct InputBinary* binary; /* The binary to which this section belongs */\n+  RelocVector relocations; /* The relocations for this section */\n+\n+  WasmBinarySection type;\n+  size_t size;\n+  size_t offset;\n+\n+  size_t payload_size;\n+  size_t payload_offset;\n+\n+  /* For known sections, the count of the number of elements in the section */\n+  uint32_t count;\n+\n+  union {\n+    /* CUSTOM section data */\n+    SectionDataCustom data_custom;\n+    /* DATA section data */\n+    DataSegmentVector data_segments;\n+    /* MEMORY section data */\n+    WasmLimits memory_limits;\n+  };\n+\n+  /* The offset at which this section appears within the combined output\n+   * section. */\n+  size_t output_payload_offset;\n+} Section;\n+WASM_DEFINE_VECTOR(section, Section);\n+\n+typedef Section* SectionPtr;\n+WASM_DEFINE_VECTOR(section_ptr, SectionPtr);\n+\n+typedef struct InputBinary {\n+  uint8_t* data;\n+  size_t size;\n+  SectionVector sections;\n+  Section* current_section;\n+\n+  uint32_t type_index_offset;\n+  uint32_t function_index_offset;\n+  uint32_t imported_function_index_offset;\n+  uint32_t global_index_offset;\n+  uint32_t imported_global_index_offset;\n+  uint32_t indirect_function_index_offset;\n+  uint32_t memory_page_count;\n+  uint32_t memory_page_offset;\n+\n+  uint32_t num_func_imports;\n+  uint32_t num_global_imports;\n+  uint32_t table_elem_count;\n+  uint32_t elem_entry_count;\n+} InputBinary;\n+WASM_DEFINE_VECTOR(binary, InputBinary);\n+\n+typedef struct Context {\n+  WasmStream stream;\n+  InputBinaryVector inputs;\n+  uint32_t total_function_imports;\n+  uint32_t total_global_imports;\n+  ssize_t current_section_payload_offset;\n+} Context;\n+\n+void wasm_destroy_section(WasmAllocator* allocator, Section* section) {\n+  wasm_destroy_reloc_vector(allocator, &section->relocations);\n+  switch (section->type) {\n+    case WASM_BINARY_SECTION_DATA:\n+      wasm_destroy_data_segment_vector(allocator, &section->data_segments);\n+      break;\n+    default:\n+      break;\n+  }\n+}\n+\n+void wasm_destroy_binary(WasmAllocator* allocator, InputBinary* binary) {\n+  WASM_DESTROY_VECTOR_AND_ELEMENTS(allocator, binary->sections, section);\n+  wasm_free(allocator, binary->data);\n+}\n+\n+static WasmResult on_reloc(WasmRelocType type,\n+                           uint32_t section,\n+                           uint32_t offset,\n+                           void* user_data) {\n+  InputBinary* binary = user_data;\n+  Section* sec = &binary->sections.data[section-1];\n+  if (offset > sec->size) {\n+    WASM_FATAL(\"invalid relocation offset: %#x\\n\", offset);\n+  }\n+\n+  Reloc* reloc = wasm_append_reloc(s_allocator, &sec->relocations);\n+  reloc->type = type;\n+  reloc->offset = offset;\n+\n+  return WASM_OK;\n+}\n+\n+static WasmResult on_import_func(uint32_t index,\n+                                 uint32_t sig_index,\n+                                 void* user_data) {\n+  InputBinary* binary = user_data;\n+  binary->num_func_imports++;\n+  return WASM_OK;\n+}\n+\n+static WasmResult on_import_global(uint32_t index,\n+                                   WasmType type, WasmBool mutable,\n+                                   void* user_data) {\n+  InputBinary* binary = user_data;\n+  binary->num_global_imports++;\n+  return WASM_OK;\n+}\n+\n+static WasmResult begin_section(WasmBinaryReaderContext* ctx,\n+                                WasmBinarySection section_type,\n+                                uint32_t size) {\n+  InputBinary* binary = ctx->user_data;\n+  Section* sec = wasm_append_section(s_allocator, &binary->sections);\n+  binary->current_section = sec;\n+  sec->type = section_type;\n+  sec->size = size;\n+  sec->offset = ctx->offset;\n+  sec->binary = binary;\n+\n+  if (sec->type != WASM_BINARY_SECTION_CUSTOM &&\n+      sec->type != WASM_BINARY_SECTION_START) {\n+    size_t bytes_read = wasm_read_u32_leb128(&binary->data[sec->offset],\n+                                             &binary->data[binary->size],\n+                                             &sec->count);\n+    sec->payload_offset = sec->offset + bytes_read;\n+    sec->payload_size = sec->size - bytes_read;\n+  }\n+  return WASM_OK;\n+}\n+\n+static WasmResult begin_custom_section(WasmBinaryReaderContext* ctx,\n+                                       uint32_t size,\n+                                       WasmStringSlice section_name) {\n+  InputBinary* binary = ctx->user_data;\n+  Section* sec = binary->current_section;\n+  sec->data_custom.name = section_name;\n+\n+  // Modify section size and offset to not include the name itself.\n+  size_t delta = ctx->offset - sec->offset;\n+  sec->offset = sec->offset + delta;\n+  sec->size = sec->size - delta;\n+  sec->payload_offset = sec->offset;\n+  sec->payload_size = sec->size;\n+\n+  // Special handling for certain CUSTOM sections\n+  if (wasm_string_slice_eq(&section_name, \"name\")) {\n+    size_t bytes_read = wasm_read_u32_leb128(&binary->data[sec->offset],\n+                                             &binary->data[binary->size],\n+                                             &sec->count);\n+    sec->payload_offset += bytes_read;\n+    sec->payload_size -= bytes_read;\n+\n+    // We don't currently support merging name sections unless they contain\n+    // a name for every function.\n+    uint32_t i;\n+    for (i = 0; i < binary->sections.size; i++) {\n+      if (binary->sections.data[i].type == WASM_BINARY_SECTION_FUNCTION) {\n+        if (binary->sections.data[i].count != sec->count) {\n+          WASM_FATAL(\n+              \"name section count (%d) does not match function count (%d)\\n\",\n+              sec->count, binary->sections.data[i].count);\n+        }\n+      }\n+    }\n+  }\n+\n+  return WASM_OK;\n+}\n+\n+static WasmResult on_table(uint32_t index,\n+                           WasmType elem_type,\n+                           const WasmLimits* elem_limits,\n+                           void* user_data) {\n+  if (elem_limits->has_max && (elem_limits->max != elem_limits->initial))\n+    WASM_FATAL(\"Tables with max > initial not supported by wasm-link\\n\");\n+\n+  InputBinary* binary = user_data;\n+  binary->table_elem_count = elem_limits->initial;\n+  return WASM_OK;\n+}\n+\n+static WasmResult on_elem_segment_function_index_count(\n+    WasmBinaryReaderContext* ctx,\n+    uint32_t index,\n+    uint32_t count) {\n+  InputBinary* binary = ctx->user_data;\n+  Section* sec = binary->current_section;\n+\n+  // Modify the payload to include only the actualy function indexes\n+  size_t delta = ctx->offset - sec->payload_offset;\n+  sec->payload_offset += delta;\n+  sec->payload_size -= delta;\n+  sec->binary->elem_entry_count += count;\n+  return WASM_OK;\n+}\n+\n+static WasmResult on_memory(uint32_t index,\n+                            const WasmLimits* page_limits,\n+                            void* user_data) {\n+  InputBinary* binary = user_data;\n+  Section* sec = binary->current_section;\n+  sec->memory_limits = *page_limits;\n+  binary->memory_page_count = page_limits->initial;\n+  return WASM_OK;\n+}\n+\n+static WasmResult begin_data_segment(uint32_t index,\n+                                     uint32_t memory_index,\n+                                     void* user_data) {\n+  InputBinary* binary = user_data;\n+  Section* sec = binary->current_section;\n+  DataSegment* segment = wasm_append_data_segment(s_allocator, &sec->data_segments);\n+  segment->memory_index = memory_index;\n+  return WASM_OK;\n+}\n+\n+static WasmResult on_init_expr_i32_const_expr(uint32_t index,\n+                                              uint32_t value,\n+                                              void* user_data) {\n+  InputBinary* binary = user_data;\n+  Section* sec = binary->current_section;\n+  if (sec->type != WASM_BINARY_SECTION_DATA)\n+    return WASM_OK;\n+  DataSegment* segment = &sec->data_segments.data[sec->data_segments.size-1];\n+  segment->offset = value;\n+  return WASM_OK;\n+}\n+\n+static WasmResult on_data_segment_data(uint32_t index,\n+                                       const void* src_data,\n+                                       uint32_t size,\n+                                       void* user_data) {\n+  InputBinary* binary = user_data;\n+  Section* sec = binary->current_section;\n+  DataSegment* segment = &sec->data_segments.data[sec->data_segments.size-1];\n+  segment->data = src_data;\n+  segment->size = size;\n+  return WASM_OK;\n+}\n+\n+static WasmResult read_binary(uint8_t* data,\n+                              size_t size,\n+                              InputBinary* input_info) {\n+  input_info->data = data;\n+  input_info->size = size;\n+\n+  WasmBinaryReader reader;\n+  WASM_ZERO_MEMORY(reader);\n+\n+  static WasmBinaryReader s_binary_reader = {\n+      .begin_section = begin_section,\n+      .begin_custom_section = begin_custom_section,\n+\n+      .on_reloc = on_reloc,\n+\n+      .on_import_func = on_import_func,\n+      .on_import_global = on_import_global,\n+\n+      .on_table = on_table,\n+\n+      .on_memory = on_memory,\n+\n+      .begin_data_segment = begin_data_segment,\n+      .on_init_expr_i32_const_expr = on_init_expr_i32_const_expr,\n+      .on_data_segment_data = on_data_segment_data,\n+\n+      .on_elem_segment_function_index_count =\n+          on_elem_segment_function_index_count,\n+  };\n+\n+  reader = s_binary_reader;\n+  reader.user_data = input_info;\n+\n+  WasmReadBinaryOptions read_options = WASM_READ_BINARY_OPTIONS_DEFAULT;\n+  return wasm_read_binary(s_allocator, data, size, &reader, 1, &read_options);\n+}\n+\n+static void apply_relocation(Section* section, Reloc* r) {\n+  InputBinary* binary = section->binary;\n+  uint8_t* section_data = &binary->data[section->offset];\n+  size_t section_size = section->size;\n+\n+  uint32_t cur_value = 0;\n+  wasm_read_u32_leb128(section_data + r->offset,\n+                       section_data + section_size, &cur_value);\n+\n+  uint32_t offset = 0;\n+  switch (r->type) {\n+    case WASM_RELOC_FUNC_INDEX:\n+      if (cur_value >= binary->num_func_imports) {\n+        offset = binary->function_index_offset;\n+      } else {\n+        offset = binary->imported_function_index_offset;\n+      }\n+      break;\n+    case WASM_RELOC_GLOBAL_INDEX:\n+      if (cur_value >= binary->num_global_imports) {\n+        offset = binary->global_index_offset;\n+      } else {\n+        offset = binary->imported_global_index_offset;\n+      }\n+      break;\n+    case WASM_RELOC_TYPE_INDEX:\n+      offset = binary->type_index_offset;\n+      break;\n+    default:\n+      WASM_FATAL(\"unhandled relocation type: %d\\n\", r->type);\n+      break;\n+  }\n+\n+  cur_value += offset;\n+  wasm_write_fixed_u32_leb128_raw(section_data + r->offset,\n+                                  section_data + section_size, cur_value);\n+}\n+\n+static void apply_relocations(Section* section) {\n+  if (!section->relocations.size)\n+    return;\n+\n+  // Perform relocations in-place\n+  size_t i;\n+  for (i = 0; i < section->relocations.size; i++) {\n+    Reloc* reloc = &section->relocations.data[i];\n+    apply_relocation(section, reloc);\n+  }\n+}\n+\n+static void write_section_payload(Context* ctx, Section* sec) {\n+  assert(ctx->current_section_payload_offset != -1);\n+\n+  sec->output_payload_offset =\n+      ctx->stream.offset - ctx->current_section_payload_offset;\n+\n+  uint8_t* payload = &sec->binary->data[sec->payload_offset];\n+  wasm_write_data(&ctx->stream, payload, sec->payload_size, \"section content\");\n+}\n+\n+#define FIXUP_SIZE \\\n+  wasm_write_fixed_u32_leb128_at(stream, fixup_offset, stream->offset - start, \\\n+                                 \"fixup size\");\n+\n+#define WRITE_UNKNOWN_SIZE \\\n+  uint32_t fixup_offset = stream->offset; \\\n+  wasm_write_fixed_u32_leb128(stream, 0, \"unknown size\"); \\\n+  ctx->current_section_payload_offset = ctx->stream.offset; \\\n+  uint32_t start = stream->offset;\n+\n+static void write_combined_custom_section(Context* ctx,\n+                                          SectionPtrVector* sections,\n+                                          WasmStringSlice* name) {\n+  // Write this section, along with all the following sections with the\n+  // same name.\n+  size_t i;\n+  size_t total_size = 0;\n+  size_t total_count = 0;\n+\n+  // Reloc sections are handles seperatedly.\n+  if (wasm_string_slice_startswith(name, \"reloc\"))\n+      return;\n+\n+  WasmBool has_count = wasm_string_slice_eq(name, \"name\");\n+\n+  // First pass to calculate total size and count\n+  for (i = 0; i < sections->size; i++) {\n+    Section* sec = sections->data[i];\n+    if (!wasm_string_slices_are_equal(name, &sec->data_custom.name))\n+      continue;\n+    total_size += sec->payload_size;\n+    if (has_count)\n+      total_count += sec->count;\n+  }\n+\n+  WasmStream* stream = &ctx->stream;\n+  wasm_write_u8(stream, WASM_BINARY_SECTION_CUSTOM, \"section code\");\n+  WRITE_UNKNOWN_SIZE;\n+  wasm_write_str(stream, name->start, name->length, WASM_PRINT_CHARS,\n+                 \"custom section name\");\n+  wasm_write_u32_leb128(stream, total_count, \"element count\");\n+\n+  for (i = 0; i < sections->size; i++) {\n+    Section* sec = sections->data[i];\n+    if (!wasm_string_slices_are_equal(name, &sec->data_custom.name))\n+      continue;\n+    apply_relocations(sec);\n+    write_section_payload(ctx, sec);\n+    sec->data_custom.linked = WASM_TRUE;\n+  }\n+\n+  FIXUP_SIZE;\n+}\n+\n+static void write_combined_table_section(Context* ctx,\n+                                         SectionPtrVector* sections) {\n+\n+  // Total section size includes the element count leb123 which is\n+  // always 1 in the current spec\n+  uint32_t table_count = 1;\n+  uint32_t flags = WASM_BINARY_LIMITS_HAS_MAX_FLAG;\n+  uint32_t elem_count = 0;\n+\n+  size_t i;\n+  for (i = 0; i < sections->size; i++) {\n+    Section* sec = sections->data[i];\n+    elem_count += sec->binary->table_elem_count;\n+  }\n+\n+  uint32_t section_size = 1;  // For the table type (WASM_TYPE_ANYFUNC)\n+  section_size += wasm_u32_leb128_length(table_count);\n+  section_size += wasm_u32_leb128_length(flags);\n+  section_size += wasm_u32_leb128_length(elem_count);\n+  section_size += wasm_u32_leb128_length(elem_count);\n+\n+  WasmStream* stream = &ctx->stream;\n+  wasm_write_u32_leb128(stream, section_size, \"section size\");\n+  wasm_write_u32_leb128(stream, table_count, \"table count\");\n+  wasm_write_type(stream, WASM_TYPE_ANYFUNC);\n+  wasm_write_u32_leb128(stream, flags, \"table elem flags\");\n+  wasm_write_u32_leb128(stream, elem_count, \"table initial length\");\n+  wasm_write_u32_leb128(stream, elem_count, \"table max length\");\n+}\n+\n+static void write_combined_elem_section(Context* ctx,\n+                                        SectionPtrVector* sections) {\n+  WasmStream* stream = &ctx->stream;\n+  WRITE_UNKNOWN_SIZE;\n+\n+  size_t i;\n+  uint32_t total_elem_count = 0;\n+  for (i = 0; i < sections->size; i++) {\n+    Section* sec = sections->data[i];\n+    total_elem_count += sec->binary->table_elem_count;\n+  }\n+\n+  wasm_write_u32_leb128(stream, 1, \"segment count\");\n+  wasm_write_u32_leb128(stream, 0, \"table index\");\n+  wasm_write_opcode(&ctx->stream, WASM_OPCODE_I32_CONST);\n+  wasm_write_i32_leb128(&ctx->stream, 0, \"elem init literal\");\n+  wasm_write_opcode(&ctx->stream, WASM_OPCODE_END);\n+  wasm_write_u32_leb128(stream, total_elem_count, \"num elements\");\n+\n+  ctx->current_section_payload_offset = stream->offset;\n+\n+  for (i = 0; i < sections->size; i++) {\n+    Section* sec = sections->data[i];\n+    apply_relocations(sec);\n+    write_section_payload(ctx, sec);\n+  }\n+\n+  FIXUP_SIZE;\n+}\n+\n+static void write_combined_memory_section(Context* ctx,\n+                                          SectionPtrVector* sections) {\n+  WasmStream* stream = &ctx->stream;\n+  WRITE_UNKNOWN_SIZE;\n+\n+  wasm_write_u32_leb128(stream, 1, \"memory count\");\n+\n+  WasmLimits limits;\n+  WASM_ZERO_MEMORY(limits);\n+  limits.has_max = WASM_TRUE;\n+  uint32_t i;\n+  for (i = 0; i < sections->size; i++) {\n+    SectionPtr sec = sections->data[i];\n+    limits.initial += sec->memory_limits.initial;\n+    limits.max = limits.initial;\n+  }\n+  wasm_write_limits(stream, &limits);\n+\n+  FIXUP_SIZE;\n+}\n+\n+static void write_combined_function_section(Context* ctx,\n+                                            SectionPtrVector* sections,\n+                                            uint32_t total_count) {\n+  WasmStream* stream = &ctx->stream;\n+  WRITE_UNKNOWN_SIZE;\n+\n+  wasm_write_u32_leb128(stream, total_count, \"element count\");\n+\n+  size_t i;\n+  for (i = 0; i < sections->size; i++) {\n+    SectionPtr sec = sections->data[i];\n+    uint32_t count = sec->count;\n+    uint32_t input_offset = 0;\n+    uint32_t sig_index = 0;\n+    const uint8_t* start = &sec->binary->data[sec->payload_offset];\n+    const uint8_t* end =\n+        &sec->binary->data[sec->payload_offset + sec->payload_size];\n+    while (count--) {\n+      input_offset += wasm_read_u32_leb128(start+input_offset, end, &sig_index);\n+      sig_index += sec->binary->type_index_offset;\n+      wasm_write_u32_leb128(stream, sig_index, \"sig\");\n+    }\n+  }\n+\n+  FIXUP_SIZE;\n+}\n+\n+static void write_data_segment(WasmStream* stream,\n+                               DataSegment* segment,\n+                               uint32_t offset) {\n+  assert(segment->memory_index == 0);\n+  wasm_write_u32_leb128(stream, segment->memory_index, \"memory index\");\n+  wasm_write_opcode(stream, WASM_OPCODE_I32_CONST);\n+  wasm_write_u32_leb128(stream, segment->offset + offset, \"offset\");\n+  wasm_write_opcode(stream, WASM_OPCODE_END);\n+  wasm_write_u32_leb128(stream, segment->size, \"segment size\");\n+  wasm_write_data(stream, segment->data, segment->size, \"segment data\");\n+}\n+\n+static void write_combined_data_section(Context* ctx,\n+                                        SectionPtrVector* sections,\n+                                        uint32_t total_count) {\n+  WasmStream* stream = &ctx->stream;\n+  WRITE_UNKNOWN_SIZE;\n+\n+  wasm_write_u32_leb128(stream, total_count, \"element count\");\n+  size_t i, j;\n+  for (i = 0; i < sections->size; i++) {\n+    Section* sec = sections->data[i];\n+    for (j = 0; j < sec->data_segments.size; j++) {\n+      DataSegment* segment = &sec->data_segments.data[j];\n+      write_data_segment(stream, segment,\n+                         sec->binary->memory_page_offset * WASM_PAGE_SIZE);\n+    }\n+  }\n+\n+  FIXUP_SIZE;\n+}\n+\n+static void write_combined_reloc_section(Context* ctx,\n+                                         WasmBinarySection type,\n+                                         SectionPtrVector* sections,\n+                                         uint32_t section_index) {\n+  size_t i, j;\n+  uint32_t total_relocs = 0;\n+\n+  // First pass to know total reloc count\n+  for (i = 0; i < sections->size; i++) {\n+    Section* sec = sections->data[i];\n+    total_relocs += sec->relocations.size;\n+  }\n+\n+  if (!total_relocs)\n+    return;\n+\n+  char section_name[128];\n+  sprintf(section_name, \"%s.%s\", WASM_BINARY_SECTION_RELOC,\n+          wasm_get_section_name(type));\n+\n+  WasmStream* stream = &ctx->stream;\n+  wasm_write_u8(stream, WASM_BINARY_SECTION_CUSTOM, \"section code\");\n+  WRITE_UNKNOWN_SIZE;\n+  wasm_write_str(stream, section_name, strlen(section_name),\n+                 WASM_PRINT_CHARS, \"reloc section name\");\n+  wasm_write_u32_leb128(&ctx->stream, section_index, \"reloc section\");\n+  wasm_write_u32_leb128(&ctx->stream, total_relocs, \"num relocs\");\n+\n+  for (i = 0; i < sections->size; i++) {\n+    Section* sec = sections->data[i];\n+    RelocVector* relocs = &sec->relocations;\n+    for (j = 0; j < relocs->size; j++) {\n+      wasm_write_u32_leb128(&ctx->stream, relocs->data[j].type, \"reloc type\");\n+      uint32_t new_offset = relocs->data[j].offset + sec->output_payload_offset;\n+      wasm_write_u32_leb128(&ctx->stream, new_offset, \"reloc offset\");\n+    }\n+  }\n+\n+  FIXUP_SIZE;\n+}\n+\n+static WasmBool write_combined_section(Context* ctx,\n+                                       WasmBinarySection type,","path":"src/tools/wasm-link.c","position":705,"original_position":705,"commit_id":"6c46a83e53e298d4fbd27028aedf123f7f0869ad","original_commit_id":"6c46a83e53e298d4fbd27028aedf123f7f0869ad","user":{"login":"binji","id":1245315,"avatar_url":"https://avatars.githubusercontent.com/u/1245315?v=3","gravatar_id":"","url":"https://api.github.com/users/binji","html_url":"https://github.com/binji","followers_url":"https://api.github.com/users/binji/followers","following_url":"https://api.github.com/users/binji/following{/other_user}","gists_url":"https://api.github.com/users/binji/gists{/gist_id}","starred_url":"https://api.github.com/users/binji/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/binji/subscriptions","organizations_url":"https://api.github.com/users/binji/orgs","repos_url":"https://api.github.com/users/binji/repos","events_url":"https://api.github.com/users/binji/events{/privacy}","received_events_url":"https://api.github.com/users/binji/received_events","type":"User","site_admin":false},"body":"nit: I've been calling this section_code elsewhere, since type is pretty overloaded (though section_code is a little confusing too, considering there is a code section...)","created_at":"2016-12-17T00:05:12Z","updated_at":"2016-12-17T00:22:11Z","html_url":"https://github.com/WebAssembly/wabt/pull/228#discussion_r92906457","pull_request_url":"https://api.github.com/repos/WebAssembly/wabt/pulls/228","_links":{"self":{"href":"https://api.github.com/repos/WebAssembly/wabt/pulls/comments/92906457"},"html":{"href":"https://github.com/WebAssembly/wabt/pull/228#discussion_r92906457"},"pull_request":{"href":"https://api.github.com/repos/WebAssembly/wabt/pulls/228"}}},"pull_request":{"url":"https://api.github.com/repos/WebAssembly/wabt/pulls/228","id":95108312,"html_url":"https://github.com/WebAssembly/wabt/pull/228","diff_url":"https://github.com/WebAssembly/wabt/pull/228.diff","patch_url":"https://github.com/WebAssembly/wabt/pull/228.patch","issue_url":"https://api.github.com/repos/WebAssembly/wabt/issues/228","number":228,"state":"open","locked":false,"title":"Add support for linkable modules","user":{"login":"sbc100","id":515813,"avatar_url":"https://avatars.githubusercontent.com/u/515813?v=3","gravatar_id":"","url":"https://api.github.com/users/sbc100","html_url":"https://github.com/sbc100","followers_url":"https://api.github.com/users/sbc100/followers","following_url":"https://api.github.com/users/sbc100/following{/other_user}","gists_url":"https://api.github.com/users/sbc100/gists{/gist_id}","starred_url":"https://api.github.com/users/sbc100/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/sbc100/subscriptions","organizations_url":"https://api.github.com/users/sbc100/orgs","repos_url":"https://api.github.com/users/sbc100/repos","events_url":"https://api.github.com/users/sbc100/events{/privacy}","received_events_url":"https://api.github.com/users/sbc100/received_events","type":"User","site_admin":false},"body":"This change adds support for writing wasm modules such\r\nthat they are compatible with the proposed linking spec:\r\nhttps://github.com/WebAssembly/tool-conventions/blob/master/Linking.md\r\n\r\nBasically this means that wast2wasm will generate and extra\r\n'reloc' section and will pad any LEBs in the code section\r\nthat might require relocation.\r\n\r\nThis mode is activated by passing the -c flag to wast2wasm.\r\n\r\nAlso, start work on wasm-link which should be able to link\r\nsuch modules together.","created_at":"2016-11-24T02:28:30Z","updated_at":"2016-12-17T00:22:11Z","closed_at":null,"merged_at":null,"merge_commit_sha":"89c42aef25404b8e7f15809ee5717758979ac2da","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/WebAssembly/wabt/pulls/228/commits","review_comments_url":"https://api.github.com/repos/WebAssembly/wabt/pulls/228/comments","review_comment_url":"https://api.github.com/repos/WebAssembly/wabt/pulls/comments{/number}","comments_url":"https://api.github.com/repos/WebAssembly/wabt/issues/228/comments","statuses_url":"https://api.github.com/repos/WebAssembly/wabt/statuses/6c46a83e53e298d4fbd27028aedf123f7f0869ad","head":{"label":"WebAssembly:add_wasm_link","ref":"add_wasm_link","sha":"6c46a83e53e298d4fbd27028aedf123f7f0869ad","user":{"login":"WebAssembly","id":11578470,"avatar_url":"https://avatars.githubusercontent.com/u/11578470?v=3","gravatar_id":"","url":"https://api.github.com/users/WebAssembly","html_url":"https://github.com/WebAssembly","followers_url":"https://api.github.com/users/WebAssembly/followers","following_url":"https://api.github.com/users/WebAssembly/following{/other_user}","gists_url":"https://api.github.com/users/WebAssembly/gists{/gist_id}","starred_url":"https://api.github.com/users/WebAssembly/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/WebAssembly/subscriptions","organizations_url":"https://api.github.com/users/WebAssembly/orgs","repos_url":"https://api.github.com/users/WebAssembly/repos","events_url":"https://api.github.com/users/WebAssembly/events{/privacy}","received_events_url":"https://api.github.com/users/WebAssembly/received_events","type":"Organization","site_admin":false},"repo":{"id":42467830,"name":"wabt","full_name":"WebAssembly/wabt","owner":{"login":"WebAssembly","id":11578470,"avatar_url":"https://avatars.githubusercontent.com/u/11578470?v=3","gravatar_id":"","url":"https://api.github.com/users/WebAssembly","html_url":"https://github.com/WebAssembly","followers_url":"https://api.github.com/users/WebAssembly/followers","following_url":"https://api.github.com/users/WebAssembly/following{/other_user}","gists_url":"https://api.github.com/users/WebAssembly/gists{/gist_id}","starred_url":"https://api.github.com/users/WebAssembly/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/WebAssembly/subscriptions","organizations_url":"https://api.github.com/users/WebAssembly/orgs","repos_url":"https://api.github.com/users/WebAssembly/repos","events_url":"https://api.github.com/users/WebAssembly/events{/privacy}","received_events_url":"https://api.github.com/users/WebAssembly/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/WebAssembly/wabt","description":"The WebAssembly Binary Toolkit","fork":false,"url":"https://api.github.com/repos/WebAssembly/wabt","forks_url":"https://api.github.com/repos/WebAssembly/wabt/forks","keys_url":"https://api.github.com/repos/WebAssembly/wabt/keys{/key_id}","collaborators_url":"https://api.github.com/repos/WebAssembly/wabt/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/WebAssembly/wabt/teams","hooks_url":"https://api.github.com/repos/WebAssembly/wabt/hooks","issue_events_url":"https://api.github.com/repos/WebAssembly/wabt/issues/events{/number}","events_url":"https://api.github.com/repos/WebAssembly/wabt/events","assignees_url":"https://api.github.com/repos/WebAssembly/wabt/assignees{/user}","branches_url":"https://api.github.com/repos/WebAssembly/wabt/branches{/branch}","tags_url":"https://api.github.com/repos/WebAssembly/wabt/tags","blobs_url":"https://api.github.com/repos/WebAssembly/wabt/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/WebAssembly/wabt/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/WebAssembly/wabt/git/refs{/sha}","trees_url":"https://api.github.com/repos/WebAssembly/wabt/git/trees{/sha}","statuses_url":"https://api.github.com/repos/WebAssembly/wabt/statuses/{sha}","languages_url":"https://api.github.com/repos/WebAssembly/wabt/languages","stargazers_url":"https://api.github.com/repos/WebAssembly/wabt/stargazers","contributors_url":"https://api.github.com/repos/WebAssembly/wabt/contributors","subscribers_url":"https://api.github.com/repos/WebAssembly/wabt/subscribers","subscription_url":"https://api.github.com/repos/WebAssembly/wabt/subscription","commits_url":"https://api.github.com/repos/WebAssembly/wabt/commits{/sha}","git_commits_url":"https://api.github.com/repos/WebAssembly/wabt/git/commits{/sha}","comments_url":"https://api.github.com/repos/WebAssembly/wabt/comments{/number}","issue_comment_url":"https://api.github.com/repos/WebAssembly/wabt/issues/comments{/number}","contents_url":"https://api.github.com/repos/WebAssembly/wabt/contents/{+path}","compare_url":"https://api.github.com/repos/WebAssembly/wabt/compare/{base}...{head}","merges_url":"https://api.github.com/repos/WebAssembly/wabt/merges","archive_url":"https://api.github.com/repos/WebAssembly/wabt/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/WebAssembly/wabt/downloads","issues_url":"https://api.github.com/repos/WebAssembly/wabt/issues{/number}","pulls_url":"https://api.github.com/repos/WebAssembly/wabt/pulls{/number}","milestones_url":"https://api.github.com/repos/WebAssembly/wabt/milestones{/number}","notifications_url":"https://api.github.com/repos/WebAssembly/wabt/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/WebAssembly/wabt/labels{/name}","releases_url":"https://api.github.com/repos/WebAssembly/wabt/releases{/id}","deployments_url":"https://api.github.com/repos/WebAssembly/wabt/deployments","created_at":"2015-09-14T18:14:23Z","updated_at":"2016-12-16T04:35:59Z","pushed_at":"2016-12-16T23:12:44Z","git_url":"git://github.com/WebAssembly/wabt.git","ssh_url":"git@github.com:WebAssembly/wabt.git","clone_url":"https://github.com/WebAssembly/wabt.git","svn_url":"https://github.com/WebAssembly/wabt","homepage":"","size":6172,"stargazers_count":116,"watchers_count":116,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":18,"mirror_url":null,"open_issues_count":9,"forks":18,"open_issues":9,"watchers":116,"default_branch":"master"}},"base":{"label":"WebAssembly:master","ref":"master","sha":"8d0fcc1fe04fd3497795a01c692667d7d47f3441","user":{"login":"WebAssembly","id":11578470,"avatar_url":"https://avatars.githubusercontent.com/u/11578470?v=3","gravatar_id":"","url":"https://api.github.com/users/WebAssembly","html_url":"https://github.com/WebAssembly","followers_url":"https://api.github.com/users/WebAssembly/followers","following_url":"https://api.github.com/users/WebAssembly/following{/other_user}","gists_url":"https://api.github.com/users/WebAssembly/gists{/gist_id}","starred_url":"https://api.github.com/users/WebAssembly/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/WebAssembly/subscriptions","organizations_url":"https://api.github.com/users/WebAssembly/orgs","repos_url":"https://api.github.com/users/WebAssembly/repos","events_url":"https://api.github.com/users/WebAssembly/events{/privacy}","received_events_url":"https://api.github.com/users/WebAssembly/received_events","type":"Organization","site_admin":false},"repo":{"id":42467830,"name":"wabt","full_name":"WebAssembly/wabt","owner":{"login":"WebAssembly","id":11578470,"avatar_url":"https://avatars.githubusercontent.com/u/11578470?v=3","gravatar_id":"","url":"https://api.github.com/users/WebAssembly","html_url":"https://github.com/WebAssembly","followers_url":"https://api.github.com/users/WebAssembly/followers","following_url":"https://api.github.com/users/WebAssembly/following{/other_user}","gists_url":"https://api.github.com/users/WebAssembly/gists{/gist_id}","starred_url":"https://api.github.com/users/WebAssembly/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/WebAssembly/subscriptions","organizations_url":"https://api.github.com/users/WebAssembly/orgs","repos_url":"https://api.github.com/users/WebAssembly/repos","events_url":"https://api.github.com/users/WebAssembly/events{/privacy}","received_events_url":"https://api.github.com/users/WebAssembly/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/WebAssembly/wabt","description":"The WebAssembly Binary Toolkit","fork":false,"url":"https://api.github.com/repos/WebAssembly/wabt","forks_url":"https://api.github.com/repos/WebAssembly/wabt/forks","keys_url":"https://api.github.com/repos/WebAssembly/wabt/keys{/key_id}","collaborators_url":"https://api.github.com/repos/WebAssembly/wabt/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/WebAssembly/wabt/teams","hooks_url":"https://api.github.com/repos/WebAssembly/wabt/hooks","issue_events_url":"https://api.github.com/repos/WebAssembly/wabt/issues/events{/number}","events_url":"https://api.github.com/repos/WebAssembly/wabt/events","assignees_url":"https://api.github.com/repos/WebAssembly/wabt/assignees{/user}","branches_url":"https://api.github.com/repos/WebAssembly/wabt/branches{/branch}","tags_url":"https://api.github.com/repos/WebAssembly/wabt/tags","blobs_url":"https://api.github.com/repos/WebAssembly/wabt/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/WebAssembly/wabt/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/WebAssembly/wabt/git/refs{/sha}","trees_url":"https://api.github.com/repos/WebAssembly/wabt/git/trees{/sha}","statuses_url":"https://api.github.com/repos/WebAssembly/wabt/statuses/{sha}","languages_url":"https://api.github.com/repos/WebAssembly/wabt/languages","stargazers_url":"https://api.github.com/repos/WebAssembly/wabt/stargazers","contributors_url":"https://api.github.com/repos/WebAssembly/wabt/contributors","subscribers_url":"https://api.github.com/repos/WebAssembly/wabt/subscribers","subscription_url":"https://api.github.com/repos/WebAssembly/wabt/subscription","commits_url":"https://api.github.com/repos/WebAssembly/wabt/commits{/sha}","git_commits_url":"https://api.github.com/repos/WebAssembly/wabt/git/commits{/sha}","comments_url":"https://api.github.com/repos/WebAssembly/wabt/comments{/number}","issue_comment_url":"https://api.github.com/repos/WebAssembly/wabt/issues/comments{/number}","contents_url":"https://api.github.com/repos/WebAssembly/wabt/contents/{+path}","compare_url":"https://api.github.com/repos/WebAssembly/wabt/compare/{base}...{head}","merges_url":"https://api.github.com/repos/WebAssembly/wabt/merges","archive_url":"https://api.github.com/repos/WebAssembly/wabt/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/WebAssembly/wabt/downloads","issues_url":"https://api.github.com/repos/WebAssembly/wabt/issues{/number}","pulls_url":"https://api.github.com/repos/WebAssembly/wabt/pulls{/number}","milestones_url":"https://api.github.com/repos/WebAssembly/wabt/milestones{/number}","notifications_url":"https://api.github.com/repos/WebAssembly/wabt/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/WebAssembly/wabt/labels{/name}","releases_url":"https://api.github.com/repos/WebAssembly/wabt/releases{/id}","deployments_url":"https://api.github.com/repos/WebAssembly/wabt/deployments","created_at":"2015-09-14T18:14:23Z","updated_at":"2016-12-16T04:35:59Z","pushed_at":"2016-12-16T23:12:44Z","git_url":"git://github.com/WebAssembly/wabt.git","ssh_url":"git@github.com:WebAssembly/wabt.git","clone_url":"https://github.com/WebAssembly/wabt.git","svn_url":"https://github.com/WebAssembly/wabt","homepage":"","size":6172,"stargazers_count":116,"watchers_count":116,"language":"C","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":18,"mirror_url":null,"open_issues_count":9,"forks":18,"open_issues":9,"watchers":116,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/WebAssembly/wabt/pulls/228"},"html":{"href":"https://github.com/WebAssembly/wabt/pull/228"},"issue":{"href":"https://api.github.com/repos/WebAssembly/wabt/issues/228"},"comments":{"href":"https://api.github.com/repos/WebAssembly/wabt/issues/228/comments"},"review_comments":{"href":"https://api.github.com/repos/WebAssembly/wabt/pulls/228/comments"},"review_comment":{"href":"https://api.github.com/repos/WebAssembly/wabt/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/WebAssembly/wabt/pulls/228/commits"},"statuses":{"href":"https://api.github.com/repos/WebAssembly/wabt/statuses/6c46a83e53e298d4fbd27028aedf123f7f0869ad"}}}}
{"actor":{"display_login":"binji"}}