#include "ld.h"
#include "lib.h"
+#include "macho.h"
#include "pe.h"
#include "reloc.h"
#include "report.h"
#include "section.h"
+#include "stdint.h"
#include "symbol.h"
+static uint64_t generic_read (struct section_part *part, struct reloc_entry *rel) {
+
+ uint64_t result;
+ int endianess = 0;
+
+ switch (rel->howto->size) {
+
+ case 8:
+
+ result = array_to_integer (part->content + rel->offset, 8, endianess);
+ break;
+
+ case 4:
+
+ result = array_to_integer (part->content + rel->offset, 4, endianess);
+ break;
+
+ case 3:
+
+ result = array_to_integer (part->content + rel->offset, 3, endianess);
+ break;
+
+ case 2:
+
+ result = array_to_integer (part->content + rel->offset, 2, endianess);
+ break;
+
+ case 1:
+
+ result = array_to_integer (part->content + rel->offset, 1, endianess);
+ break;
+
+ default:
+
+ report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "invalid relocation size");
+ exit (EXIT_FAILURE);
+
+ }
+
+ return result;
+
+}
+
+static void generic_write (struct section_part *part, struct reloc_entry *rel, uint64_t result) {
+
+ int endianess = 0;
+
+ switch (rel->howto->size) {
+
+ case 8:
+
+ integer_to_array (result, part->content + rel->offset, 8, endianess);
+ break;
+
+ case 4:
+
+ integer_to_array (result, part->content + rel->offset, 4, endianess);
+ break;
+
+ case 3:
+
+ integer_to_array (result, part->content + rel->offset, 3, endianess);
+ break;
+
+ case 2:
+
+ integer_to_array (result, part->content + rel->offset, 2, endianess);
+ break;
+
+ case 1:
+
+ integer_to_array (result, part->content + rel->offset, 1, endianess);
+ break;
+
+ default:
+
+ report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "invalid relocation size");
+ exit (EXIT_FAILURE);
+
+ }
+
+}
+
+static void reloc_generic_add (struct section_part *part, struct reloc_entry *rel, struct symbol *symbol) {
+
+ uint64_t result, saved;
+
+ saved = generic_read (part, rel);
+ result = rel->addend;
+
+ if (rel->howto->pc_rel || rel->howto->no_base) {
+ result += symbol_get_value_no_base (symbol);
+ } else {
+ result += symbol_get_value_with_base (symbol);
+ }
+
+ if (rel->howto->pc_rel) {
+
+ result -= part->rva + rel->offset;
+ result -= rel->howto->size;
+
+ }
+
+ if (rel->howto->size < (int) sizeof (result)) {
+
+ uint64_t mask = (((uint64_t) 1) << (CHAR_BIT * rel->howto->size)) - 1;
+ result &= mask;
+
+ }
+
+ if (rel->howto->final_right_shift) {
+
+ /* If the result was negative, it should remain negative even after the final right shift. */
+ uint64_t sign_bit = result & (((uint64_t) 1) << (rel->howto->size * 8 - 1));
+
+ result >>= rel->howto->final_right_shift;
+ result |= sign_bit;
+
+ }
+
+ generic_write (part, rel, saved + result);
+
+}
+
+static void reloc_generic_subtract (struct section_part *part, struct reloc_entry *rel, struct symbol *symbol) {
+
+ uint64_t result, saved;
+
+ saved = generic_read (part, rel);
+ result = rel->addend;
+
+ if (rel->howto->pc_rel || rel->howto->no_base) {
+ result += symbol_get_value_no_base (symbol);
+ } else {
+ result += symbol_get_value_with_base (symbol);
+ }
+
+ if (rel->howto->pc_rel) {
+
+ result -= part->rva + rel->offset;
+ result -= rel->howto->size;
+
+ }
+
+ if (rel->howto->size < (int) sizeof (result)) {
+
+ uint64_t mask = (((uint64_t) 1) << (CHAR_BIT * rel->howto->size)) - 1;
+ result &= mask;
+
+ }
+
+ if (rel->howto->final_right_shift) {
+
+ /* If the result was negative, it should remain negative even after the final right shift. */
+ uint64_t sign_bit = result & (((uint64_t) 1) << (rel->howto->size * 8 - 1));
+
+ result >>= rel->howto->final_right_shift;
+ result |= sign_bit;
+
+ }
+
+ generic_write (part, rel, saved - result);
+
+}
+
+static void reloc_aarch64_hi21_page_pcrel (struct section_part *part, struct reloc_entry *rel, struct symbol *symbol) {
+
+ uint64_t bottom_2_bits = 0, result;
+ unsigned long field;
+
+ result = (symbol_get_value_with_base (symbol) + rel->addend) & ~(uint64_t) 0xfff;
+ result -= (state->base_address + part->rva + rel->offset) & ~(uint64_t) 0xfff;
+
+ if ((bottom_2_bits = result & 0x3000)) {
+
+ result &= ~bottom_2_bits;
+ bottom_2_bits >>= 12;
+
+ }
+
+ result >>= 9;
+
+ /**
+ * If the result is negative, those 2 bits are already set,
+ * so they must be cleared before putting the real bottom 2 bits there.
+ */
+ result &= ~(((uint64_t) 0x03) << 29);
+ result |= bottom_2_bits << 29;
+
+ field = array_to_integer (part->content + rel->offset, 4, 0);
+ field = ((field & ~(uint64_t) rel->howto->dst_mask) | (((field & rel->howto->dst_mask) + result) & rel->howto->dst_mask));
+
+ integer_to_array (field, part->content + rel->offset, 4, 0);
+
+}
+
+static void reloc_aarch64_generic (struct section_part *part, struct reloc_entry *rel, struct symbol *symbol) {
+
+ uint64_t result = rel->addend, field;
+ result += symbol_get_value_with_base (symbol);
+
+ if (rel->howto->pc_rel) {
+ result -= state->base_address + part->rva + rel->offset;
+ }
+
+ result >>= rel->howto->final_right_shift;
+ result <<= rel->howto->final_left_shift;
+
+ switch (rel->howto->size) {
+
+ case 8:
+
+ field = array_to_integer (part->content + rel->offset, 8, 0);
+ break;
+
+ case 4:
+
+ field = array_to_integer (part->content + rel->offset, 4, 0);
+ break;
+
+ case 2:
+
+ field = array_to_integer (part->content + rel->offset, 2, 0);
+ break;
+
+ default:
+
+ report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "invalid relocation size");
+ exit (EXIT_FAILURE);
+
+ }
+
+ field = ((field & ~(uint64_t) rel->howto->dst_mask) | (((field & rel->howto->dst_mask) + result) & rel->howto->dst_mask));
+
+ switch (rel->howto->size) {
+
+ case 8:
+
+ integer_to_array (field, part->content + rel->offset, 8, 0);
+ break;
+
+ case 4:
+
+ integer_to_array (field, part->content + rel->offset, 4, 0);
+ break;
+
+ case 2:
+
+ integer_to_array (field, part->content + rel->offset, 2, 0);
+ break;
+
+ default:
+
+ report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "invalid relocation size");
+ exit (EXIT_FAILURE);
+
+ }
+
+}
+
struct reloc_howto reloc_howtos[RELOC_TYPE_END] = {
{ 0, 0, 0, 0, 0, "RELOC_TYPE_IGNORED", 0, 0 },
{ 2, 1, 0, 0, 0, "RELOC_TYPE_PC16", 0, 0 },
{ 1, 1, 0, 0, 0, "RELOC_TYPE_PC8", 0, 0 },
- { 4, 0, 1, 0, 0, "RELOC_TYPE_32_NO_BASE", 0, 0 }
+ { 4, 0, 1, 0, 0, "RELOC_TYPE_32_NO_BASE", 0, 0 },
+
+ { 8, 0, 0, 0, &reloc_generic_add, "RELOC_TYPE_64_ADD", 0, 0 },
+ { 4, 0, 0, 0, &reloc_generic_add, "RELOC_TYPE_32_ADD", 0, 0 },
+ { 3, 0, 0, 0, &reloc_generic_add, "RELOC_TYPE_24_ADD", 0, 0 },
+ { 2, 0, 0, 0, &reloc_generic_add, "RELOC_TYPE_16_ADD", 0, 0 },
+ { 1, 0, 0, 0, &reloc_generic_add, "RELOC_TYPE_8_ADD", 0, 0 },
+
+ { 8, 0, 0, 0, &reloc_generic_subtract, "RELOC_TYPE_64_SUB", 0, 0 },
+ { 4, 0, 0, 0, &reloc_generic_subtract, "RELOC_TYPE_32_SUB", 0, 0 },
+ { 3, 0, 0, 0, &reloc_generic_subtract, "RELOC_TYPE_24_SUB", 0, 0 },
+ { 2, 0, 0, 0, &reloc_generic_subtract, "RELOC_TYPE_16_SUB", 0, 0 },
+ { 1, 0, 0, 0, &reloc_generic_subtract, "RELOC_TYPE_8_SUB", 0, 0 },
+
+ { 4, 1, 0, 9, &reloc_aarch64_hi21_page_pcrel, "RELOC_TYPE_AARCH64_ADR_PREL_PG_HI21", 0x60ffffe0, 0 },
+ { 4, 0, 0, 0, &reloc_aarch64_generic, "RELOC_TYPE_AARCH64_ADD_ABS_LO12_NC", 0x3ffc00, 10 },
+ { 4, 0, 0, 0, &reloc_aarch64_generic, "RELOC_TYPE_AARCH64_LDST8_ABS_LO12_NC", 0x3ffc00, 10 },
+ { 4, 0, 0, 1, &reloc_aarch64_generic, "RELOC_TYPE_AARCH64_LDST16_ABS_LO12_NC", 0x1ffc00, 10 },
+ { 4, 0, 0, 2, &reloc_aarch64_generic, "RELOC_TYPE_AARCH64_LDST32_ABS_LO12_NC", 0xffc00, 10 },
+ { 4, 0, 0, 3, &reloc_aarch64_generic, "RELOC_TYPE_AARCH64_LDST64_ABS_LO12_NC", 0x7fc00, 10 },
+ { 4, 0, 0, 4, &reloc_aarch64_generic, "RELOC_TYPE_AARCH64_LDST128_ABS_LO12_NC", 0x3fc00, 10 },
+ { 4, 1, 0, 2, &reloc_aarch64_generic, "RELOC_TYPE_AARCH64_JUMP26", 0x3ffffff, 0 },
+ { 4, 1, 0, 2, &reloc_aarch64_generic, "RELOC_TYPE_AARCH64_CALL26", 0x3ffffff, 0 }
};
struct section *section;
struct section_part *part;
- unsigned long rva = 0;
+ uint64_t rva = 0;
if (state->format == LD_FORMAT_I386_PE) {
rva = pe_get_first_section_rva ();
+ } else if (state->format == LD_FORMAT_AMD64_MACHO || state->format == LD_FORMAT_AARCH64_MACHO) {
+ rva = macho_get_first_section_rva ();
}
for (section = all_sections; section; section = section->next) {
if (part->next && part->next->alignment > 1) {
- unsigned long new_rva = ALIGN (rva + part->content_size, part->next->alignment);
+ uint64_t new_rva = ALIGN (rva + part->content_size, part->next->alignment);
if (new_rva != rva + part->content_size) {
static void reloc_generic (struct section_part *part, struct reloc_entry *rel, struct symbol *symbol) {
unsigned char opcode = (part->content + rel->offset - 1)[0];
- unsigned long result = 0, size = rel->howto->size, offset = rel->offset;
+ uint64_t result = 0, size = rel->howto->size, offset = rel->offset;
switch (size) {
if ((unsigned long) size < sizeof (result)) {
- unsigned long mask = (((unsigned long) 1) << (CHAR_BIT * size)) - 1;
+ unsigned long mask = (((uint64_t) 1) << (CHAR_BIT * size)) - 1;
result &= mask;
}
- result >>= rel->howto->final_right_shift;
+ if (rel->howto->final_right_shift) {
+
+ uint64_t sign_bit = result & (((uint64_t) 1) << (rel->howto->size * 8 - 1));
+ result >>= rel->howto->final_right_shift;
+
+ result |= sign_bit;
- /*printf ("%lx\n", n_type);*/
+ }
if (state->emulation == LD_EMULATION_IA16_ELKS || state->emulation == LD_EMULATION_IA16_MZ) {
if (!state->entry_symbol_name) {
- if (state->format == LD_FORMAT_I386_AOUT || state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_IA16_ELKS) {
+ if (state->format == LD_FORMAT_I386_AOUT || state->format == LD_FORMAT_I386_ELKS || state->format == LD_FORMAT_IA16_ELKS || state->format == LD_FORMAT_AMD64_MACHO || state->format == LD_FORMAT_AARCH64_MACHO) {
state->entry_symbol_name = xstrdup ("_start");
--- /dev/null
+/******************************************************************************
+ * @file macho.c
+ *****************************************************************************/
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ld.h"
+#include "lib.h"
+#include "macho.h"
+#include "report.h"
+#include "section.h"
+
+struct part_reloc {
+
+ struct section_part *part;
+ struct reloc_entry *reloc_entry;
+
+};
+
+static struct part_reloc addend_part_reloc = { 0 };
+
+static void apply_addend_reloc (struct reloc_entry *reloc, struct section_part *part) {
+
+ if (!addend_part_reloc.reloc_entry) return;
+
+ if (part != addend_part_reloc.part) {
+ report_at (program_name, 0, REPORT_WARNING, "%s: ARM64_RELOC_ADDEND is in different" " section than relocation it applies to", addend_part_reloc.part->of->filename);
+ }
+
+ if (reloc->offset != addend_part_reloc.reloc_entry->offset) {
+ report_at (program_name, 0, REPORT_WARNING, "%s: ARM64_RELOC_ADDEND has different offset than relocation it applies to", addend_part_reloc.part->of->filename);
+ }
+
+ reloc->addend = addend_part_reloc.reloc_entry->addend;
+ addend_part_reloc.reloc_entry = 0;
+
+}
+
+#define CHECK_READ(memory_position, size_to_read) \
+ do \
+ if (((memory_position) - data + (size_to_read) > data_size) || \
+ (memory_position) < data) { \
+ report_at (program_name, 0, REPORT_FATAL_ERROR, \
+ "%s: corrupt input file", filename); \
+ exit (EXIT_FAILURE); \
+ } \
+ while (0)
+
+static void translate_relocation (struct reloc_entry *reloc, struct macho_relocation_info *input_reloc, struct section_part *part) {
+
+ unsigned long r_symbolnum = array_to_integer (input_reloc->r_symbolnum, 4, 0);
+
+ unsigned long field;
+ unsigned int size, pcrel, type;
+
+ if ((r_symbolnum >> 27) & 1) {
+ reloc->symbol = part->of->symbol_arr + (r_symbolnum & 0xffffff);
+ } else {
+
+ if (r_symbolnum == 0) {
+
+ report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "local input_reloc->r_symbolnum %#lx is not yet supported", r_symbolnum & 0xffffff);
+ exit (EXIT_FAILURE);
+
+ }
+
+ reloc->symbol = part->of->symbol_arr + part->of->symbol_cnt - (r_symbolnum & 0xffffff);
+
+ }
+
+ reloc->offset = array_to_integer (input_reloc->r_address, 4, 0);
+ reloc->r_symbolnum = r_symbolnum;
+
+ size = 1U << ((r_symbolnum >> 25) & 3);
+
+ pcrel = (r_symbolnum >> 24) & 1;
+ type = r_symbolnum >> 28;
+
+ if (state->format == LD_FORMAT_AMD64_MACHO) {
+
+ switch (size) {
+
+ case 8:
+
+ if (!pcrel && type == AMD64_RELOC_UNSIGNED) {
+ reloc->howto = &reloc_howtos[RELOC_TYPE_64];
+ } else {
+ goto unsupported;
+ }
+
+ break;
+
+ case 4:
+
+ if (pcrel) {
+
+ if (type == AMD64_RELOC_SIGNED) {
+
+ reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+
+ if (reloc->symbol->flags & SYMBOL_FLAG_SECTION_SYMBOL) {
+
+ field = array_to_integer (part->content + reloc->offset, 4, 0);
+
+ field -= reloc->symbol->part->rva - reloc->offset - 4;
+ integer_to_array (field, part->content + reloc->offset, 4, 0);
+
+ }
+
+ } else if (type == AMD64_RELOC_BRANCH) {
+ reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+ } else if (type == AMD64_RELOC_GOT_LOAD) {
+
+ reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+
+ if (part->content[reloc->offset - 2] != 0x8b) {
+
+ report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: not yet supported x64 GOT instruction", part->of->filename);
+ exit (EXIT_FAILURE);
+
+ }
+
+ part->content[reloc->offset - 2] = 0x8d;
+
+ } else if (type == AMD64_RELOC_GOT) {
+
+ uint64_t addend, helper_offset;
+
+ if (part->content[reloc->offset - 1] != 0x05 || part->content[reloc->offset - 2] != 0x03 || part->content[reloc->offset - 3] != 0x48) {
+
+ report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "%s: not yet supported x64 GOT instruction", part->of->filename);
+ exit (EXIT_FAILURE);
+
+ }
+
+ part->content[reloc->offset - 3] = 0x90;
+ part->content[reloc->offset - 2] = 0x90;
+ part->content[reloc->offset - 1] = 0xe8;
+
+ field = array_to_integer (part->content + reloc->offset, 4, 0);
+ addend = field;
+
+ field = part->content_size - reloc->offset - 4;
+ integer_to_array (field, part->content + reloc->offset, 4, 0);
+
+ helper_offset = part->content_size;
+ part->content_size += 13;
+
+ part->content = xrealloc (part->content, part->content_size);
+ memcpy (part->content + helper_offset,
+ "\x51"
+ "\x48\x8D\x0D\x00\x00\x00\x00"
+ "\x48\x01\xC8"
+ "\x59"
+ "\xC3",
+ 13);
+
+ reloc->offset = helper_offset + 4;
+ integer_to_array (addend, part->content + reloc->offset, 4, 0);
+
+ reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+
+ } else if (type == AMD64_RELOC_SIGNED_1 || type == AMD64_RELOC_SIGNED_2 || type == AMD64_RELOC_SIGNED_4) {
+ reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+ } else {
+ goto unsupported;
+ }
+
+ } else {
+
+ if (type == AMD64_RELOC_UNSIGNED) {
+ reloc->howto = &reloc_howtos[RELOC_TYPE_32];
+ } else if (type == AMD64_RELOC_SUBTRACTOR) {
+ reloc->howto = &reloc_howtos[RELOC_TYPE_32_SUB];
+ } else {
+ goto unsupported;
+ }
+
+ }
+
+ break;
+
+ default:
+
+ goto unsupported;
+
+ }
+
+ return;
+
+ }
+
+ if (state->format == LD_FORMAT_AARCH64_MACHO) {
+
+ switch (size) {
+
+ case 8:
+
+ if (!pcrel && type == ARM64_RELOC_UNSIGNED) {
+ reloc->howto = &reloc_howtos[RELOC_TYPE_64];
+ } else {
+ goto unsupported;
+ }
+
+ break;
+
+ case 4:
+
+ if (pcrel) {
+
+ if (type == ARM64_RELOC_BRANCH26) {
+
+ reloc->howto = &reloc_howtos[RELOC_TYPE_AARCH64_CALL26];
+ apply_addend_reloc (reloc, part);
+
+ } else if (type == ARM64_RELOC_PAGE21) {
+
+ reloc->howto = &reloc_howtos[RELOC_TYPE_AARCH64_ADR_PREL_PG_HI21];
+ apply_addend_reloc (reloc, part);
+
+ } else if (type == ARM64_RELOC_GOT_LOAD_PAGE21) {
+ reloc->howto = &reloc_howtos[RELOC_TYPE_AARCH64_ADR_PREL_PG_HI21];
+ } else {
+ goto unsupported;
+ }
+ } else {
+
+ if (type == ARM64_RELOC_PAGEOFF12) {
+
+ if (part->content[reloc->offset + 3] == 0x39) {
+ reloc->howto = &reloc_howtos[RELOC_TYPE_AARCH64_LDST8_ABS_LO12_NC];
+ } else if (part->content[reloc->offset + 3] == 0x79) {
+ reloc->howto = &reloc_howtos[RELOC_TYPE_AARCH64_LDST16_ABS_LO12_NC]; /*strh*/
+ } else if (part->content[reloc->offset + 3] == 0xB9) {
+ reloc->howto = &reloc_howtos[RELOC_TYPE_AARCH64_LDST32_ABS_LO12_NC];
+ } else if (part->content[reloc->offset + 3] == 0xF9 || part->content[reloc->offset + 3] == 0xFD) {
+ reloc->howto = &reloc_howtos[RELOC_TYPE_AARCH64_LDST64_ABS_LO12_NC];
+ } else if (part->content[reloc->offset + 3] == 0x3D) {
+ reloc->howto = &reloc_howtos[RELOC_TYPE_AARCH64_LDST128_ABS_LO12_NC];
+ } else {
+ reloc->howto = &reloc_howtos[RELOC_TYPE_AARCH64_ADD_ABS_LO12_NC];
+ }
+
+ apply_addend_reloc (reloc, part);
+
+ } else if (type == ARM64_RELOC_GOT_LOAD_PAGEOFF12) {
+
+ field = array_to_integer (part->content + reloc->offset, 4, 0);
+ field &= ~0x68400000;
+
+ integer_to_array (field, part->content + reloc->offset, 4, 0);
+ reloc->howto = &reloc_howtos[RELOC_TYPE_AARCH64_ADD_ABS_LO12_NC];
+
+ } else if (type == ARM64_RELOC_ADDEND) {
+
+ reloc->symbol = NULL;
+ reloc->addend = r_symbolnum & 0xffffff;
+ reloc->howto = &reloc_howtos[RELOC_TYPE_IGNORED];
+
+ addend_part_reloc.reloc_entry = reloc;
+ addend_part_reloc.part = part;
+
+ } else {
+ goto unsupported;
+ }
+
+ }
+
+ break;
+
+ default:
+
+ goto unsupported;
+
+ }
+
+ return;
+
+ }
+
+unsupported:
+
+ report_at (program_name, 0, REPORT_WARNING, "%s: ignoring not yet supported relocation with size %u, pcrel %u and type %#x", part->of->filename, size, pcrel, type);
+ reloc->howto = &reloc_howtos[RELOC_TYPE_IGNORED];
+
+}
+
+#define UNNAMED_SYMBOL_NAME "(unnamed)"
+
+void read_macho_object (const char *filename, unsigned char *data, unsigned long data_size) {
+
+ unsigned char *pos = (unsigned char *) data;
+ struct macho_header_64 *header;
+
+ struct section_part **part_p_array = 0, *bss_part;
+ struct object_file *of = 0;
+
+ struct segment_command_64 *segment_cmd;
+ struct section_64 *section_64;
+ struct symtab_command *symtab_cmd;
+
+ struct section_part *part;
+ struct section *section;
+
+ struct section *bss_section = 0;
+ long bss_section_number = 0;
+
+ char *section_name, *segment_name, *string_table;
+ unsigned long num_symbols = 0, num_sections = 0;
+
+ unsigned long sizeof_cmds, cmd_size, i, j, k;
+ struct load_command *load_command;
+
+ unsigned long num_cmds, num_sects, num_syms, n_strx, cpu_type;
+ unsigned char *sym_pos;
+
+ struct nlist_64 *nlist_64;
+ struct symbol *old_symbol, *symbol;
+
+ struct macho_relocation_info *reloc_info;
+ unsigned char *rel_pos;
+
+ CHECK_READ (pos, sizeof (*header));
+
+ header = (struct macho_header_64 *) pos;
+ pos += sizeof (*header);
+
+ cpu_type = array_to_integer (header->cpu_type, 4, 0);
+
+ if (cpu_type != MH_CPU_TYPE_AMD64 && cpu_type != MH_CPU_TYPE_ARM64) {
+
+ report_at (program_name, 0, REPORT_ERROR, "%s: unrecognized cputype %#lx", filename, cpu_type);
+ return;
+
+ }
+
+ sizeof_cmds = array_to_integer (header->sizeof_cmds, 4, 0);
+
+ if (array_to_integer (header->file_type, 4, 0) != MH_OBJECT) {
+
+ report_at (program_name, 0, REPORT_ERROR, "%s: file type is not MH_OBJECT", filename);
+ return;
+
+ }
+
+ num_cmds = array_to_integer (header->num_cmds, 4, 0);
+ CHECK_READ (pos, num_cmds);
+
+ for (i = 0; i < num_cmds; i++) {
+
+ load_command = (struct load_command *) pos;
+
+ if (pos - data + sizeof (*load_command) > sizeof (*header) + sizeof_cmds) {
+
+ report_at (program_name, 0, REPORT_ERROR, "%s: invalid header size of commands / number of commands", filename);
+ return;
+
+ }
+
+ cmd_size = array_to_integer (load_command->command_size, 4, 0);
+
+ if (pos - data + cmd_size > sizeof (*header) + sizeof_cmds) {
+
+ report_at (program_name, 0, REPORT_ERROR, "%s: invalid load command command size", filename);
+ return;
+
+ }
+
+ if (array_to_integer (load_command->command, 4, 0) == LC_SYMTAB) {
+
+ symtab_cmd = (struct symtab_command *) pos;
+
+ if (sizeof (*symtab_cmd) > array_to_integer (symtab_cmd->command_size, 4, 0)) {
+
+ report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: symtab command command size too small", filename);
+ exit (EXIT_FAILURE);
+
+ }
+
+ if (num_symbols && array_to_integer (symtab_cmd->num_symbols, 4, 0)) {
+
+ report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: more than 1 non-empty symbol table per object file", filename);
+ exit (EXIT_FAILURE);
+
+ }
+
+ num_symbols = array_to_integer (symtab_cmd->num_symbols, 4, 0);
+
+ } else if (array_to_integer (load_command->command, 4, 0) == LC_SEGMENT_64) {
+
+ segment_cmd = (struct segment_command_64 *) pos;
+
+ if (num_sections && array_to_integer (segment_cmd->num_sects, 4, 0)) {
+
+ report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: more than 1 non-empty segment command per object file", filename);
+ exit (EXIT_FAILURE);
+
+ }
+
+ num_sections = array_to_integer (segment_cmd->num_sects, 4, 0);
+
+ }
+
+ pos += cmd_size;
+
+ }
+
+ of = object_file_make (filename, num_symbols + num_sections);
+ pos = (unsigned char *) (data + sizeof (*header));
+
+ for (i = 0; i < num_cmds; i++) {
+
+ load_command = (struct load_command *) pos;
+
+ if (array_to_integer (load_command->command, 4, 0) == LC_SEGMENT_64) {
+
+ segment_cmd = (struct segment_command_64 *) pos;
+
+ if (!(num_sects = array_to_integer (segment_cmd->num_sects, 4, 0))) {
+
+ pos += array_to_integer (load_command->command_size, 4, 0);
+ continue;
+
+ }
+
+ part_p_array = xmalloc ((num_sects + 1) * sizeof (*part_p_array));
+
+ if (sizeof (*segment_cmd) + num_sects * sizeof (*section_64) > array_to_integer (segment_cmd->command_size, 4, 0)) {
+
+ report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: segment command command size and number of sections mismatch", filename);
+ exit (EXIT_FAILURE);
+
+ }
+
+ for (j = 0; j < num_sects; j++) {
+
+ section_64 = (struct section_64 *) (pos + sizeof (*segment_cmd) + j * sizeof (*section_64));
+
+ section_name = xstrndup (section_64->sect_name, sizeof (section_64->sect_name));
+ segment_name = xstrndup (section_64->seg_name, sizeof (section_64->seg_name));
+
+ section = section_find_or_make (section_name);
+ free (section_name);
+
+ if (1LU << array_to_integer (section_64->align, 4, 0) > section->section_alignment) {
+ section->section_alignment = 1LU << array_to_integer (section_64->align, 4, 0);
+ }
+
+ if (strcmp (segment_name, "__TEXT") == 0) {
+
+ unsigned long flags = array_to_integer (section_64->flags, 4, 0);
+ section->flags = SECTION_FLAG_ALLOC | SECTION_FLAG_LOAD | SECTION_FLAG_READONLY;
+
+ if ((flags & S_REGULAR)) {
+ section->flags |= SECTION_FLAG_CODE;
+ }
+
+ } else if (strcmp (segment_name, "__DATA") == 0) {
+
+ unsigned long flags = array_to_integer (section_64->flags, 4, 0);
+
+ if (strcmp (section->name, "__const") == 0) {
+ section->flags = SECTION_FLAG_ALLOC | SECTION_FLAG_LOAD | SECTION_FLAG_READONLY;
+ } else if ((flags & 0xff) == S_ZEROFILL) {
+
+ section->flags = SECTION_FLAG_ALLOC;
+ section->is_bss = 1;
+
+ bss_section_number = j + 1;
+ bss_section = section;
+
+ } else {
+ section->flags = SECTION_FLAG_ALLOC | SECTION_FLAG_LOAD | SECTION_FLAG_DATA;
+ }
+
+ } else {
+ section->flags = SECTION_FLAG_ALLOC | SECTION_FLAG_LOAD | SECTION_FLAG_READONLY;
+ }
+
+ free (segment_name);
+
+ part = section_part_new (section, of);
+ part->rva = array_to_integer (section_64->addr, 8, 0);
+
+ part->content_size = array_to_integer (section_64->size, 8, 0);
+ part->alignment = 1LU << array_to_integer (section_64->align, 4, 0);
+
+ if (!section->is_bss) {
+
+ unsigned char *content_pos = (unsigned char *) data + array_to_integer (section_64->offset, 4, 0);
+
+ part->content = xmalloc (part->content_size);
+ memcpy (part->content, content_pos, part->content_size);
+
+ }
+
+ section_append_section_part (section, part);
+ part_p_array[j + 1] = part;
+
+ }
+
+ }
+
+ pos += array_to_integer (load_command->command_size, 4, 0);
+
+ }
+
+ pos = (unsigned char *) (data + sizeof (*header));
+
+ for (i = 0; i < num_cmds; i++) {
+
+ load_command = (struct load_command *) pos;
+
+ if (array_to_integer (load_command->command, 4, 0) == LC_SYMTAB) {
+
+ symtab_cmd = (struct symtab_command *) pos;
+
+ if (!(num_syms = array_to_integer (symtab_cmd->num_symbols, 4, 0))) {
+
+ pos += array_to_integer (load_command->command_size, 4, 0);
+ continue;
+
+ }
+
+ string_table = (char *) data + array_to_integer (symtab_cmd->string_offset, 4, 0);
+ CHECK_READ (data + array_to_integer (symtab_cmd->string_offset, 4, 0), array_to_integer (symtab_cmd->string_size, 4, 0));
+
+ sym_pos = (unsigned char *) data + array_to_integer (symtab_cmd->symbol_offset, 4, 0);
+ CHECK_READ (sym_pos, sizeof (*nlist_64) * num_syms);
+
+ for (j = 0; j < num_syms; j++) {
+
+ symbol = of->symbol_arr + j;
+ nlist_64 = (struct nlist_64 *) (sym_pos + j * sizeof (*nlist_64));
+
+ if ((n_strx = array_to_integer (nlist_64->n_strx, 4, 0)) < array_to_integer (symtab_cmd->string_size, 4, 0)) {
+
+ if (string_table[n_strx] == '\0') {
+ symbol->name = xstrdup (UNNAMED_SYMBOL_NAME);
+ } else {
+ symbol->name = xstrdup (string_table + n_strx);
+ }
+
+ } else {
+
+ report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid index into string table", filename);
+ exit (EXIT_FAILURE);
+
+ }
+
+ symbol->value = array_to_integer (nlist_64->n_value, 8, 0);
+
+ if ((nlist_64->n_type[0] & MACHO_N_STAB) || (nlist_64->n_type[0] & MACHO_N_PEXT)) {
+
+ report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "+++%s: not yet supported symbol n_type: %#x", filename, nlist_64->n_type[0]);
+ exit (EXIT_FAILURE);
+
+ }
+
+ if ((nlist_64->n_type[0] & MACHO_N_TYPE) == MACHO_N_UNDF) {
+
+ if (symbol->value) {
+
+ old_symbol = symbol_find (symbol->name);
+
+ if (!old_symbol || symbol_is_undefined (old_symbol)) {
+
+ if (!bss_section) {
+
+ bss_section = section_find_or_make ("__bss");
+
+ bss_section->flags = SECTION_FLAG_ALLOC;
+ bss_section->is_bss = 1;
+
+ bss_section_number = num_sections ? num_sections : 1;
+
+ }
+
+ bss_part = section_part_new (bss_section, of);
+ section_append_section_part (bss_section, bss_part);
+
+ bss_part->content_size = symbol->size = symbol->value;
+
+ symbol->part = bss_part;
+ symbol->value = 0;
+ symbol->section_number = bss_section_number;
+
+ } else {
+
+ if (symbol->value > old_symbol->size) {
+ old_symbol->part->content_size = old_symbol->size = symbol->value;
+ }
+
+ symbol->value = 0;
+ symbol->part = 0;
+
+ }
+
+ } else {
+
+ symbol->section_number = UNDEFINED_SECTION_NUMBER;
+ symbol->part = 0;
+
+ }
+
+ } else if ((nlist_64->n_type[0] & MACHO_N_TYPE) == MACHO_N_SECT) {
+
+ if (nlist_64->n_sect[0] > num_sections) {
+
+ report_at (__FILE__, __LINE__, REPORT_ERROR, "%s: invalid symbol n_sect: %u", filename, nlist_64->n_sect[0]);
+ symbol->part = 0;
+
+ } else {
+ symbol->value -= part_p_array[nlist_64->n_sect[0]]->rva;
+ }
+
+ symbol->section_number = nlist_64->n_sect[0];
+ symbol->part = part_p_array[nlist_64->n_sect[0]];
+
+ } else {
+
+ report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "+++%s: not yet supported symbol n_type: %#x", filename, nlist_64->n_type[0]);
+ exit (EXIT_FAILURE);
+
+ }
+
+ if (nlist_64->n_type[0] & MACHO_N_EXT) {
+ symbol_record_external_symbol (symbol);
+ }
+
+ }
+
+ break;
+
+ }
+
+ pos += array_to_integer (load_command->command_size, 4, 0);
+
+ }
+
+ for (i = 1; i < num_sections + 1; i++) {
+
+ symbol = of->symbol_arr + of->symbol_cnt - i;
+
+ part = part_p_array[i];
+ symbol->name = xstrdup (part->section->name);
+
+ symbol->flags |= SYMBOL_FLAG_SECTION_SYMBOL;
+ symbol->value = 0;
+ symbol->size = 0;
+ symbol->part = part;
+ symbol->section_number = i;
+
+ }
+
+ pos = (unsigned char *) (data + sizeof (*header));
+
+ for (i = 0; i < num_cmds; i++) {
+
+ load_command = (struct load_command *) pos;
+
+ if (array_to_integer (load_command->command, 4, 0) == LC_SEGMENT_64) {
+
+ segment_cmd = (struct segment_command_64 *) pos;
+
+ if (!(num_sects = array_to_integer (segment_cmd->num_sects, 4, 0))) {
+
+ pos += array_to_integer (load_command->command_size, 4, 0);
+ continue;
+
+ }
+
+ for (j = 0; j < num_sects; j++) {
+
+ section_64 = (struct section_64 *) (pos + sizeof (*segment_cmd) + j * sizeof (*section_64));
+
+ {
+
+ part = part_p_array[j + 1];
+
+ if ((part->reloc_cnt = array_to_integer (section_64->num_reloc, 4, 0))) {
+
+ rel_pos = data + array_to_integer (section_64->rel_off, 4, 0);
+ CHECK_READ (rel_pos, part->reloc_cnt * sizeof (*reloc_info));
+
+ part->reloc_arr = xmalloc (part->reloc_cnt * sizeof (*part->reloc_arr));
+
+ for (k = 0; k < part->reloc_cnt; k++) {
+
+ reloc_info = (struct macho_relocation_info *) (rel_pos + sizeof (*reloc_info) * k);
+ translate_relocation (part->reloc_arr + k, reloc_info, part);
+
+ }
+
+ }
+
+ }
+
+ }
+
+ }
+
+ pos += array_to_integer (load_command->command_size, 4, 0);
+
+ }
+
+ free (part_p_array);
+
+ if (addend_part_reloc.reloc_entry) {
+ report_at (program_name, 0, REPORT_WARNING, "%s: ARM64_RELOC_ADDEND without following relocation", filename);
+ }
+
+}
+
+#define section_in_text_seg(section) \
+ ((section)->flags & SECTION_FLAG_CODE)
+
+#define section_in_data_seg(section) \
+ (!((section)->flags & SECTION_FLAG_CODE))
+
+#define PAGE_SIZE 0x4000
+
+static struct section *first_data_section;
+static uint64_t first_data_section_alignment;
+
+void macho_before_link (void) {
+
+ struct section *section, *next_section;
+
+ struct section *text_sections = 0;
+ struct section **last_text_section_p = &text_sections;
+
+ struct section *data_sections = 0;
+ struct section **last_data_section_p = &data_sections;
+
+ struct section *bss_sections = 0;
+ struct section **last_bss_section_p = &bss_sections;
+
+ for (section = all_sections; section; section = next_section) {
+
+ next_section = section->next;
+ section->next = 0;
+
+ if (section_in_text_seg (section)) {
+
+ *last_text_section_p = section;
+ last_text_section_p = §ion->next;
+
+ } else if (!section->is_bss) {
+
+ *last_data_section_p = section;
+ last_data_section_p = §ion->next;
+
+ } else {
+
+ *last_bss_section_p = section;
+ last_bss_section_p = §ion->next;
+
+ }
+
+ }
+
+ *last_text_section_p = data_sections;
+
+ if (data_sections) {
+ *last_data_section_p = bss_sections;
+ } else {
+ *last_text_section_p = bss_sections;
+ }
+
+ all_sections = text_sections;
+
+ if ((first_data_section = *last_text_section_p)) {
+
+ first_data_section_alignment = first_data_section->section_alignment;
+ first_data_section->section_alignment = PAGE_SIZE;
+
+ }
+
+}
+
+uint64_t macho_get_first_section_rva (void) {
+ return PAGE_SIZE;
+}
+
+#define FLOOR_TO(to_floor, floor) \
+ ((to_floor) / (floor) * (floor))
+
+static int part_reloc_compare (const void *a, const void *b) {
+
+ const struct part_reloc *apr, *bpr;
+ uint64_t arva, brva;
+
+ apr = a;
+ bpr = b;
+
+ arva = apr->part->rva + apr->reloc_entry->offset;
+ brva = bpr->part->rva + bpr->reloc_entry->offset;
+
+ if (arva < brva) {
+ return -1;
+ }
+
+ if (arva > brva) {
+ return 1;
+ }
+
+ return 0;
+
+}
+
+#define NUM_SEGS 4
+
+struct chained_fixup_starts {
+
+ unsigned short *page_starts;
+ unsigned short page_count;
+
+};
+
+unsigned long minos_version = 0x000B0000LU; /* "11.0.0" */
+
+static void calculate_chained_fixups (struct chained_fixup_starts *cfs, int doing_data) {
+
+ struct section *section;
+ struct section_part *part;
+
+ struct part_reloc *part_rels = 0, *p;
+ unsigned long num_relocs = 0, i;
+
+ uint64_t seg_rva = 0;
+
+ if (doing_data) {
+
+ for (section = all_sections; section; section = section->next) {
+
+ if (section_in_data_seg (section)) {
+
+ seg_rva = section->rva;
+ break;
+
+ }
+
+ }
+
+ }
+
+ for (section = all_sections; section; section = section->next) {
+
+ if ((doing_data && !section_in_data_seg (section)) || (!doing_data && !section_in_text_seg (section))) {
+ continue;
+ }
+
+ for (part = section->first_part; part; part = part->next) {
+
+ struct reloc_entry *relocs = part->reloc_arr;
+
+ for (i = 0; i < part->reloc_cnt; i++) {
+
+ if (relocs[i].howto != &reloc_howtos[RELOC_TYPE_64]) {
+ continue;
+ }
+
+ num_relocs++;
+
+ }
+
+ }
+
+ }
+
+ if (!num_relocs) {
+ return;
+ }
+
+ p = part_rels = xmalloc (sizeof (*part_rels) * num_relocs);
+
+ for (section = all_sections; section; section = section->next) {
+
+ if ((doing_data && !section_in_data_seg (section)) || (!doing_data && !section_in_text_seg (section))) {
+ continue;
+ }
+
+ for (part = section->first_part; part; part = part->next) {
+
+ struct reloc_entry *relocs = part->reloc_arr;
+
+ for (i = 0; i < part->reloc_cnt; i++) {
+
+ if (relocs[i].howto != &reloc_howtos[RELOC_TYPE_64]) {
+ continue;
+ }
+
+ p->reloc_entry = &relocs[i];
+ p->part = part;
+
+ p++;
+
+ }
+
+ }
+
+ }
+
+ qsort (part_rels, num_relocs, sizeof (*part_rels), &part_reloc_compare);
+
+ {
+ uint64_t max_rva = part_rels[num_relocs - 1].part->rva + part_rels[num_relocs - 1].reloc_entry->offset;
+
+ max_rva = ALIGN (max_rva, PAGE_SIZE);
+ cfs->page_count = (max_rva - seg_rva) / PAGE_SIZE;
+ }
+
+ cfs->page_starts = xmalloc (sizeof *(cfs->page_starts) * cfs->page_count);
+
+ for (i = 0, p = part_rels; (i < cfs->page_count) && (p < part_rels + num_relocs); i++) {
+
+ uint64_t p_rva = p->part->rva + p->reloc_entry->offset;
+
+ if (seg_rva + (i + 1) * PAGE_SIZE <= p_rva) {
+
+ cfs->page_starts[i] = DYLD_CHAINED_PTR_START_NONE;
+ continue;
+
+ }
+
+ cfs->page_starts[i] = p_rva & (PAGE_SIZE - 1);
+
+ for (; p < part_rels + num_relocs; p++) {
+
+ uint64_t result = array_to_integer (p->part->content + p->reloc_entry->offset, 8, 0);
+ result -= state->base_address;
+
+#if !defined (NO_LONG_LONG) || ULONG_MAX > 4294967295UL
+
+ result &= 0xfffffffff;
+
+ if (p + 1 != part_rels + num_relocs) {
+
+ uint64_t rva1, rva2;
+
+ rva1 = p->part->rva + p->reloc_entry->offset;
+ rva2 = p[1].part->rva + p[1].reloc_entry->offset;
+
+ if (FLOOR_TO (rva1, PAGE_SIZE) != FLOOR_TO (rva2, PAGE_SIZE)) {
+
+ integer_to_array (result, p->part->content + p->reloc_entry->offset, 8, 0);
+
+ p++;
+ break;
+
+ }
+
+ result |= (((rva2 - rva1) / 4) & 0xfff) << 51;
+
+ }
+
+#endif
+
+ integer_to_array (result, p->part->content + p->reloc_entry->offset, 8, 0);
+
+ }
+
+ }
+
+ free (part_rels);
+
+}
+
+static unsigned long num_function_starts_symbols = 0;
+static uint64_t *function_starts_addresses_p = 0;
+
+static void function_starts_symbol_callback (struct symbol *symbol) {
+
+ if (!symbol->part || !(symbol->part->section->flags & SECTION_FLAG_CODE)) {
+ return;
+ }
+
+ num_function_starts_symbols++;
+
+}
+
+static void function_starts_symbol_callback2 (struct symbol *symbol) {
+
+ if (!symbol->part || !(symbol->part->section->flags & SECTION_FLAG_CODE)) {
+ return;
+ }
+
+ *function_starts_addresses_p = symbol_get_value_no_base (symbol);
+ function_starts_addresses_p++;
+
+}
+
+static int function_starts_address_compare (const void *a, const void *b) {
+
+ if (*(const uint64_t *) a < *(const uint64_t *) b) {
+ return -1;
+ }
+
+ if (*(const uint64_t *) a > *(const uint64_t *) b) {
+ return 1;
+ }
+
+ return 0;
+
+}
+
+#define PROT_READ 0x01
+#define PROT_WRITE 0x02
+#define PROT_EXECUTE 0x04
+
+static int log_base2 (uint64_t val) {
+
+ int ret = 0;
+
+ if (!val) {
+ return ret;
+ }
+
+ for (val >>= 1; val; val >>= 1) {
+ ret++;
+ }
+
+ return ret;
+
+}
+
+#define SDK_VERSION 0x000D0300LU /* "13.3.0" */
+
+void macho_write (const char *filename) {
+
+ struct chained_fixup_starts chained_fixups[NUM_SEGS] = { { 0 } };
+ struct macho_header_64 header = { 0 };
+
+ FILE *fp;
+
+ unsigned long data_size = 0, content_offset = 0, sizeof_commands = 0, num_commands = 0, file_offset = 0;
+ unsigned char *saved_pos, *content, *data, *pos;
+
+ struct segment_command_64 segment_cmd = { 0 };
+ struct section *section;
+ struct section_64 section_64 = { 0 };
+ struct symtab_command symtab_cmd = { 0 };
+
+ struct function_starts function_starts_command = { 0 };
+ struct nlist_64 nlist_64 = { 0 };
+ struct main_command main_command = { 0 };
+ struct dylib_command dylib_command = { 0 };
+
+ struct version_min version_min = { 0 };
+ struct data_in_code data_in_code = { 0 };
+ struct source_version source_version = { 0 };
+
+ struct dysymtab_command dysymtab = { 0 };
+ struct dylinker_command dylinker = { 0 };
+
+ struct dyld_exports_trie dyld_exports_trie = { 0 };
+ struct dyld_chained_fixups_header dyld_chained_fixups_header = { 0 };
+ struct dyld_chained_fixups_command dyld_chained_fixups_command = { 0 };
+ struct dyld_chained_starts_in_image dyld_chained_starts_in_image = { 0 };
+ struct dyld_chained_starts_in_segment dyld_chained_starts_in_segment = { 0 };
+
+ unsigned long function_starts_size = 0, command_size, num_sects, vm_addr, vm_size;
+ unsigned char *function_starts = 0;
+
+ struct unixthread_command unixthread = { 0 };
+ struct amd64_thread_state64 thread_state64 = { 0 };
+
+ uint64_t data_segment_offset = 0, symbol_offset = 0;
+
+ if (!(fp = fopen (filename, "wb"))) {
+
+ report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", filename);
+ return;
+
+ }
+
+ data_size += sizeof (header);
+
+ if (first_data_section) {
+ first_data_section->section_alignment = first_data_section_alignment;
+ }
+
+ integer_to_array (MH_MAGIC_64, header.magic, 4, 0);
+ integer_to_array (MH_EXECUTE, header.file_type, 4, 0);
+
+ if (state->format == LD_FORMAT_AMD64_MACHO) {
+
+ integer_to_array (MH_CPU_TYPE_AMD64, header.cpu_type, 4, 0);
+ integer_to_array (MH_CPU_SUBTYPE_I386_ALL, header.cpu_subtype, 4, 0);
+
+ } else if (state->format == LD_FORMAT_AARCH64_MACHO) {
+ integer_to_array (MH_CPU_TYPE_ARM64, header.cpu_type, 4, 0);
+ }
+
+ if (state->format == LD_FORMAT_AARCH64_MACHO) {
+ integer_to_array (MH_NOUNDEFS | MH_DYLDLINK | MH_TWOLEVEL | MH_PIE, header.flags, 4, 0);
+ } else {
+ integer_to_array (MH_NOUNDEFS, header.flags, 4, 0);
+ }
+
+ sizeof_commands += sizeof (segment_cmd);
+ num_commands++;
+
+ sizeof_commands += sizeof (segment_cmd);
+ num_commands++;
+
+ for (section = all_sections; section; section = section->next) {
+
+ if (section_in_text_seg (section)) {
+ sizeof_commands += sizeof (section_64);
+ }
+
+ }
+
+ sizeof_commands += sizeof (segment_cmd);
+ num_commands++;
+
+ for (section = all_sections; section; section = section->next) {
+
+ if (section_in_data_seg (section)) {
+ sizeof_commands += sizeof (section_64);
+ }
+
+ }
+
+ sizeof_commands += sizeof (segment_cmd);
+ num_commands++;
+
+ if (state->format == LD_FORMAT_AARCH64_MACHO) {
+
+ sizeof_commands += sizeof (dyld_chained_fixups_command);
+ num_commands++;
+
+ sizeof_commands += sizeof (dyld_exports_trie);
+ num_commands++;
+
+ sizeof_commands += sizeof (dysymtab);
+ num_commands++;
+
+#define DYLINKER_STRING "/usr/lib/dyld"
+
+ sizeof_commands += ALIGN (sizeof (dylinker) + sizeof (DYLINKER_STRING), 8);
+ num_commands++;
+
+ sizeof_commands += sizeof (function_starts_command);
+ num_commands++;
+
+ sizeof_commands += sizeof (symtab_cmd);
+ num_commands++;
+
+#define DYLIB_STRING "/usr/lib/libSystem.B.dylib"
+
+ sizeof_commands += ALIGN (sizeof (dylib_command) + sizeof (DYLIB_STRING), 8);
+ num_commands++;
+
+ sizeof_commands += sizeof (version_min);
+ num_commands++;
+
+ sizeof_commands += sizeof (source_version);
+ num_commands++;
+
+ sizeof_commands += sizeof (data_in_code);
+ num_commands++;
+
+ sizeof_commands += sizeof (main_command);
+ num_commands++;
+
+ } else if (state->format == LD_FORMAT_AMD64_MACHO) {
+
+ sizeof_commands += sizeof (symtab_cmd);
+ num_commands++;
+
+ sizeof_commands += sizeof (unixthread) + sizeof (thread_state64);
+ num_commands++;
+
+ }
+
+ integer_to_array (num_commands, header.num_cmds, 4, 0);
+ integer_to_array (sizeof_commands, header.sizeof_cmds, 4, 0);
+
+ data_size = all_sections ? all_sections->rva : PAGE_SIZE;
+ content_offset = data_size;
+
+ for (section = all_sections; section; section = section->next) {
+
+ if (section_in_text_seg (section)) {
+
+ if (!section->is_bss) {
+
+ data_size = ALIGN (data_size, section->section_alignment);
+ data_size += section->total_size;
+
+ }
+
+ }
+
+ }
+
+ data_size = ALIGN (data_size, PAGE_SIZE);
+
+ for (section = all_sections; section; section = section->next) {
+
+ if (section_in_data_seg (section)) {
+
+ if (!section->is_bss) {
+
+ data_size = ALIGN (data_size, section->section_alignment);
+ data_size += section->total_size;
+
+ }
+
+ }
+
+ }
+
+ data_size = ALIGN (data_size, PAGE_SIZE);
+
+ if (state->format == LD_FORMAT_AARCH64_MACHO) {
+
+ data_size += sizeof (dyld_chained_fixups_header);
+ data_size += sizeof (dyld_chained_starts_in_image) + (NUM_SEGS - 1) * 4 + 4;
+
+ calculate_chained_fixups (&chained_fixups[2], 1);
+
+ if (chained_fixups[2].page_count) {
+
+ data_size += sizeof (dyld_chained_starts_in_segment);
+ data_size += chained_fixups[2].page_count * 2 - 2;
+
+ data_size = ALIGN (data_size, 4);
+
+ }
+
+ data_size += sizeof (dyld_chained_starts_in_image);
+ data_size += 0x980;
+
+ num_function_starts_symbols = 0;
+ symbols_for_each_global (&function_starts_symbol_callback);
+
+ {
+
+ unsigned char *p;
+
+ uint64_t *addresses, prev_rva;
+ unsigned long i;
+
+ addresses = xmalloc (sizeof (*addresses) * num_function_starts_symbols);
+
+ function_starts_addresses_p = addresses;
+ symbols_for_each_global (&function_starts_symbol_callback2);
+
+ qsort (addresses, num_function_starts_symbols, sizeof (*addresses), &function_starts_address_compare);
+ function_starts = xmalloc (num_function_starts_symbols * (sizeof (uint64_t) * CHAR_BIT / 7 + 1));
+
+ prev_rva = 0;
+ p = function_starts;
+
+ for (i = 0; i < num_function_starts_symbols; i++) {
+
+ uint64_t diff = addresses[i] - prev_rva;
+
+ while (diff) {
+
+ *p = diff & 0x7f;
+
+ if ((diff >>= 7)) {
+ *p |= 0x80;
+ }
+
+ p++;
+
+ }
+
+ prev_rva = addresses[i];
+
+ }
+
+ data_size += function_starts_size = p - function_starts;
+ free (addresses);
+
+ }
+
+#define MH_HEADER_SYMBOL_NAME "__mh_execute_header"
+
+ data_size += sizeof (nlist_64);
+ data_size += 4 + sizeof (MH_HEADER_SYMBOL_NAME);
+
+ }
+
+ pos = (data = xmalloc (data_size));
+ content = pos + content_offset;
+
+ memcpy (pos, &header, sizeof (header));
+ pos += sizeof (header);
+
+ memset (&segment_cmd, 0, sizeof (segment_cmd));
+
+ integer_to_array (LC_SEGMENT_64, segment_cmd.command, 4, 0);
+ integer_to_array (sizeof (segment_cmd), segment_cmd.command_size, 4, 0);
+
+ strcpy (segment_cmd.seg_name, "__PAGEZERO");
+ integer_to_array (state->base_address, segment_cmd.vm_size, 8, 0);
+
+ memcpy (pos, &segment_cmd, sizeof (segment_cmd));
+ pos += sizeof (segment_cmd);
+
+ vm_addr = 0;
+ vm_size = 0;
+
+ memset (&segment_cmd, 0, sizeof (segment_cmd));
+ integer_to_array (LC_SEGMENT_64, segment_cmd.command, 4, 0);
+
+ command_size = sizeof (segment_cmd);
+ num_sects = 0;
+
+ strcpy (segment_cmd.seg_name, "__TEXT");
+ integer_to_array (state->base_address, segment_cmd.vm_addr, 8, 0);
+
+ integer_to_array (PROT_READ | PROT_EXECUTE, segment_cmd.max_prot, 4, 0);
+ integer_to_array (PROT_READ | PROT_EXECUTE, segment_cmd.init_prot, 4, 0);
+
+ saved_pos = pos;
+ pos += sizeof (segment_cmd);
+
+ for (section = all_sections; section; section = section->next) {
+
+ memset (§ion_64, 0, sizeof (section_64));
+
+ if (section_in_text_seg (section)) {
+
+ command_size += sizeof (section_64);
+ num_sects++;
+
+ memcpy (section_64.sect_name, section->name,
+ (strlen (section->name) >= sizeof (section_64.sect_name)) ?
+ sizeof (section_64.seg_name) : strlen (section->name));
+
+ if (section_64.sect_name[0] == '.') {
+
+ memmove (section_64.sect_name + 2, section_64.sect_name + 1, sizeof (section_64.sect_name) - 2);
+ section_64.sect_name[0] = section_64.sect_name[1] = '_';
+
+ }
+
+ strcpy (section_64.seg_name, "__TEXT");
+
+ integer_to_array (state->base_address + section->rva, section_64.addr, 8, 0);
+ integer_to_array (section->total_size, section_64.size, 8, 0);
+ integer_to_array (log_base2 (section->section_alignment), section_64.align, 4, 0);
+
+ if (section->flags & SECTION_FLAG_CODE) {
+ integer_to_array ((0x80000000 | S_REGULAR), section_64.flags, 4, 0);
+ }
+
+ vm_addr = array_to_integer (segment_cmd.vm_addr, 8, 0);
+ vm_size = state->base_address + section->rva + section->total_size - vm_addr;
+
+ if (!section->is_bss) {
+
+ content = data + ALIGN (content - data, section->section_alignment);
+ integer_to_array (content - data, section_64.offset, 4, 0);
+
+ section_write (section, content);
+ content += section->total_size;
+
+ }
+
+ memcpy (pos, §ion_64, sizeof (section_64));
+ pos += sizeof (section_64);
+
+ }
+
+ }
+
+ integer_to_array (command_size, segment_cmd.command_size, 4, 0);
+ integer_to_array (num_sects, segment_cmd.num_sects, 4, 0);
+ integer_to_array (ALIGN (vm_size, PAGE_SIZE), segment_cmd.vm_size, 8, 0);
+
+ content = data + ALIGN (content - data, PAGE_SIZE);
+
+ file_offset = array_to_integer (segment_cmd.file_off, 8, 0);
+ integer_to_array (content - data - file_offset, segment_cmd.file_size, 8, 0);
+
+ memcpy (saved_pos, &segment_cmd, sizeof (segment_cmd));
+
+ vm_addr = 0;
+ vm_size = 0;
+
+ memset (&segment_cmd, 0, sizeof (segment_cmd));
+ integer_to_array (LC_SEGMENT_64, segment_cmd.command, 4, 0);
+
+ command_size = sizeof (segment_cmd);
+ num_sects = 0;
+
+ strcpy (segment_cmd.seg_name, "__DATA");
+ integer_to_array (content - data, segment_cmd.file_off, 8, 0);
+
+ integer_to_array (PROT_READ | PROT_WRITE, segment_cmd.max_prot, 4, 0);
+ integer_to_array (PROT_READ | PROT_WRITE, segment_cmd.init_prot, 4, 0);
+
+ saved_pos = pos;
+ pos += sizeof (segment_cmd);
+
+ for (section = all_sections; section; section = section->next) {
+
+ memset (§ion_64, 0, sizeof (section_64));
+
+ if (section_in_data_seg (section)) {
+
+ if (!(vm_addr = array_to_integer (segment_cmd.vm_addr, 8, 0))) {
+
+ vm_addr = state->base_address + section->rva;
+ integer_to_array (vm_addr, segment_cmd.vm_addr, 8, 0);
+
+ }
+
+ command_size += sizeof (section_64);
+ num_sects++;
+
+ memcpy (section_64.sect_name, section->name,
+ (strlen (section->name) >= sizeof (section_64.sect_name)) ?
+ sizeof (section_64.seg_name) : strlen (section->name));
+
+ if (section_64.sect_name[0] == '.') {
+
+ memmove (section_64.sect_name + 2, section_64.sect_name + 1, sizeof (section_64.sect_name) - 2);
+ section_64.sect_name[0] = section_64.sect_name[1] = '_';
+
+ }
+
+ strcpy (section_64.seg_name, "__DATA");
+
+ integer_to_array (state->base_address + section->rva, section_64.addr, 8, 0);
+ integer_to_array (section->total_size, section_64.size, 8, 0);
+ integer_to_array (log_base2 (section->section_alignment), section_64.align, 4, 0);
+
+ if (!(section->flags & SECTION_FLAG_LOAD)) {
+ integer_to_array (S_ZEROFILL, section_64.flags, 4, 0);
+ }
+
+ vm_size = state->base_address + section->rva + section->total_size - vm_addr;
+
+ if (!section->is_bss) {
+
+ content = data + ALIGN (content - data, section->section_alignment);
+ integer_to_array (content - data, section_64.offset, 4, 0);
+
+ section_write (section, content);
+ content += section->total_size;
+
+ }
+
+ memcpy (pos, §ion_64, sizeof (section_64));
+ pos += sizeof (section_64);
+
+ }
+
+ }
+
+ integer_to_array (command_size, segment_cmd.command_size, 4, 0);
+ integer_to_array (num_sects, segment_cmd.num_sects, 4, 0);
+ integer_to_array (ALIGN (vm_size, PAGE_SIZE), segment_cmd.vm_size, 8, 0);
+
+ content = data + ALIGN (content - data, PAGE_SIZE);
+
+ file_offset = array_to_integer (segment_cmd.file_off, 8, 0);
+ integer_to_array (content - data - file_offset, segment_cmd.file_size, 8, 0);
+
+ memcpy (saved_pos, &segment_cmd, sizeof (segment_cmd));
+ data_segment_offset = array_to_integer (segment_cmd.file_off, 8, 0);
+
+ vm_addr = array_to_integer (segment_cmd.vm_addr, 8, 0);
+ vm_size = array_to_integer (segment_cmd.vm_size, 8, 0);
+
+ memset (&segment_cmd, 0, sizeof (segment_cmd));
+
+ integer_to_array (LC_SEGMENT_64, segment_cmd.command, 4, 0);
+ integer_to_array (sizeof (segment_cmd), segment_cmd.command_size, 4, 0);
+
+ strcpy (segment_cmd.seg_name, "__LINKEDIT");
+
+ vm_addr += vm_size;
+ integer_to_array (vm_addr, segment_cmd.vm_addr, 8, 0);
+
+ vm_size = data_size - (content - data);
+ integer_to_array (ALIGN (vm_size, PAGE_SIZE), segment_cmd.vm_size, 8, 0);
+
+ integer_to_array (PROT_READ, segment_cmd.max_prot, 4, 0);
+ integer_to_array (PROT_READ, segment_cmd.init_prot, 4, 0);
+
+ file_offset = content - data;
+
+ integer_to_array (file_offset, segment_cmd.file_off, 8, 0);
+ integer_to_array (data_size - file_offset, segment_cmd.file_size, 8, 0);
+
+ memcpy (pos, &segment_cmd, sizeof (segment_cmd));
+ pos += sizeof (segment_cmd);
+
+ if (state->format == LD_FORMAT_AARCH64_MACHO) {
+
+ integer_to_array (LC_DYLD_CHAINED_FIXUPS, dyld_chained_fixups_command.command, 4, 0);
+ integer_to_array (sizeof (dyld_chained_fixups_command), dyld_chained_fixups_command.command_size, 4, 0);
+ integer_to_array (content - data, dyld_chained_fixups_command.data_offset, 4, 0);
+
+ {
+
+ unsigned char *saved = content, *starts;
+
+ memset (&dyld_chained_fixups_header, 0, sizeof (dyld_chained_fixups_header));
+ integer_to_array (DYLD_CHAINED_IMPORT, dyld_chained_fixups_header.imports_format, 4, 0);
+
+ content += sizeof (dyld_chained_fixups_header);
+ integer_to_array (content - saved, dyld_chained_fixups_header.starts_offset, 4, 0);
+
+ starts = content;
+
+ integer_to_array (NUM_SEGS, content, 4, 0);
+ integer_to_array (0, content + 4, 4, 0);
+ integer_to_array (0, content + 8, 4, 0);
+ integer_to_array (0, content + 12, 4, 0);
+ integer_to_array (0, content + 16, 4, 0);
+ integer_to_array (0, content + 20, 4, 0);
+
+ content += 24;
+
+ if (chained_fixups[2].page_count) {
+
+ struct chained_fixup_starts *cfs = &chained_fixups[2];
+
+ unsigned long count, size;
+ int i;
+
+ integer_to_array (content - starts, starts + 12, 4, 0);
+
+ integer_to_array (sizeof (dyld_chained_starts_in_segment), dyld_chained_starts_in_segment.size, 4, 0);
+ integer_to_array (PAGE_SIZE, dyld_chained_starts_in_segment.page_size, 2, 0);
+ integer_to_array (6, dyld_chained_starts_in_segment.pointer_format, 2, 0);
+ integer_to_array (data_segment_offset, dyld_chained_starts_in_segment.segment_offset, 8, 0);
+ integer_to_array (0, dyld_chained_starts_in_segment.max_valid_pointer, 4, 0);
+ integer_to_array (cfs->page_count, dyld_chained_starts_in_segment.page_count, 2, 0);
+ integer_to_array (cfs->page_starts[0], dyld_chained_starts_in_segment.page_start, 2, 0);
+
+ count = array_to_integer (dyld_chained_starts_in_segment.page_count, 2, 0);
+
+ size = array_to_integer (dyld_chained_starts_in_segment.size, 2, 0);
+ size += count * 2 - 2;
+
+ integer_to_array (ALIGN (size, 4), dyld_chained_starts_in_segment.size, 4, 0);
+
+ memcpy (content, &dyld_chained_starts_in_segment, sizeof (dyld_chained_starts_in_segment));
+ content += sizeof (dyld_chained_starts_in_segment);
+
+ for (i = 1; i < cfs->page_count; i++) {
+
+ integer_to_array (cfs->page_starts[i], content, 2, 0);
+ content += 2;
+
+ }
+
+ content = data + ALIGN (content - data, 4);
+ free (cfs->page_starts);
+
+ }
+
+ integer_to_array (content - saved, dyld_chained_fixups_header.imports_offset, 4, 0);
+ integer_to_array (content - saved, dyld_chained_fixups_header.symbols_offset, 4, 0);
+
+ integer_to_array (0, content, 4, 0);
+ content += 4;
+
+ integer_to_array (0, content, 4, 0);
+ content += 4;
+
+ memcpy (saved, &dyld_chained_fixups_header, sizeof (dyld_chained_fixups_header));
+
+ }
+
+ integer_to_array (content - data - array_to_integer (dyld_chained_fixups_command.data_offset, 4, 0), dyld_chained_fixups_command.data_size, 4, 0);
+
+ memcpy (pos, &dyld_chained_fixups_command, sizeof (dyld_chained_fixups_command));
+ pos += array_to_integer (dyld_chained_fixups_command.command_size, 4, 0);
+
+ integer_to_array (LC_DYLD_EXPORTS_TRIE, dyld_exports_trie.command, 4, 0);
+ integer_to_array (sizeof (dyld_exports_trie), dyld_exports_trie.command_size, 4, 0);
+ integer_to_array (content - data, dyld_exports_trie.data_offset, 4, 0);
+
+ {
+
+ unsigned char *saved = content;
+
+ content[0] = 0;
+ content[1] = 1;
+ content += 2;
+
+ strcpy ((char *) content, MH_HEADER_SYMBOL_NAME);
+ content += sizeof (MH_HEADER_SYMBOL_NAME);
+
+ content[0] = content - saved + 1;
+ content[1] = 2;
+
+ content = saved + 0x980;
+
+ }
+
+ integer_to_array (content - data - array_to_integer (dyld_exports_trie.data_offset, 4, 0), dyld_exports_trie.data_size, 4, 0);
+
+ memcpy (pos, &dyld_exports_trie, sizeof (dyld_exports_trie));
+ pos += array_to_integer (dyld_exports_trie.command_size, 4, 0);
+
+ integer_to_array (LC_LOAD_DYLINKER, dylinker.command, 4, 0);
+ integer_to_array (ALIGN (sizeof (dylinker) + sizeof (DYLINKER_STRING), 8), dylinker.command_size, 4, 0);
+ integer_to_array (sizeof (dylinker), dylinker.name_offset, 4, 0);
+
+ memcpy (pos, &dylinker, sizeof (dylinker));
+
+ strcpy ((char *) pos + sizeof (dylinker), DYLINKER_STRING);
+ pos += array_to_integer (dylinker.command_size, 4, 0);
+
+ integer_to_array (LC_FUNCTION_STARTS, function_starts_command.command, 4, 0);
+ integer_to_array (sizeof (function_starts_command), function_starts_command.command_size, 4, 0);
+ integer_to_array (content - data, function_starts_command.data_offset, 4, 0);
+
+ memcpy (content, function_starts, function_starts_size);
+
+ content += function_starts_size;
+ free (function_starts);
+
+ integer_to_array (content - data - array_to_integer (function_starts_command.data_offset, 4, 0), function_starts_command.data_size, 4, 0);
+
+ memcpy (pos, &function_starts_command, sizeof (function_starts_command));
+ pos += array_to_integer (function_starts_command.command_size, 4, 0);
+
+ integer_to_array (LC_SYMTAB, symtab_cmd.command, 4, 0);
+ integer_to_array (sizeof (symtab_cmd), symtab_cmd.command_size, 4, 0);
+
+ symbol_offset = content - data;
+
+ integer_to_array (symbol_offset, symtab_cmd.symbol_offset, 4, 0);
+ integer_to_array (0, symtab_cmd.num_symbols, 4, 0);
+
+ integer_to_array (4, nlist_64.n_strx, 4, 0);
+
+ nlist_64.n_type[0] = MACHO_N_SECT | MACHO_N_EXT;
+ nlist_64.n_sect[0] = 1;
+
+ integer_to_array (0x10, nlist_64.n_desc, 2, 0);
+ integer_to_array (state->base_address, nlist_64.n_value, 8, 0);
+
+ memcpy (content, &nlist_64, sizeof (nlist_64));
+ content += sizeof (nlist_64);
+
+ integer_to_array (array_to_integer (symtab_cmd.num_symbols, 4, 0) + 1, symtab_cmd.num_symbols, 4, 0);
+ integer_to_array (content - data, symtab_cmd.string_offset, 4, 0);
+
+ memset (content, '\0', 4);
+ content += 4;
+
+ strcpy ((char *) content, MH_HEADER_SYMBOL_NAME);
+ content += sizeof (MH_HEADER_SYMBOL_NAME);
+
+ integer_to_array (content - data - array_to_integer (symtab_cmd.string_offset, 4, 0), symtab_cmd.string_size, 4, 0);
+
+ memcpy (pos, &symtab_cmd, sizeof (symtab_cmd));
+ pos += array_to_integer (symtab_cmd.command_size, 4, 0);
+
+ integer_to_array (LC_DYSYMTAB, dysymtab.cmd, 4, 0);
+ integer_to_array (sizeof (dysymtab), dysymtab.cmdsize, 4, 0);
+ integer_to_array (1, dysymtab.nextdefsym, 4, 0);
+ integer_to_array (1, dysymtab.iundefsym, 4, 0);
+
+ memcpy (pos, &dysymtab, sizeof (dysymtab));
+ pos += array_to_integer (dysymtab.cmdsize, 4, 0);
+
+ integer_to_array (LC_VERSION_MIN, version_min.command, 4, 0);
+ integer_to_array (sizeof (version_min), version_min.command_size, 4, 0);
+ integer_to_array (minos_version, version_min.version, 4, 0);
+ integer_to_array (SDK_VERSION, version_min.sdk, 4, 0);
+
+ memcpy (pos, &version_min, sizeof (version_min));
+ pos += array_to_integer (version_min.command_size, 4, 0);
+
+ integer_to_array (LC_LOAD_DYLIB, dylib_command.command, 4, 0);
+ integer_to_array (ALIGN (sizeof (dylib_command) + sizeof (DYLIB_STRING), 8), dylib_command.command_size, 4, 0);
+ integer_to_array (sizeof (dylib_command), dylib_command.name_offset, 4, 0);
+ integer_to_array (2, dylib_command.timestamp, 4, 0);
+ integer_to_array (0x05276403, dylib_command.current_version, 4, 0);
+ integer_to_array (0x00010000, dylib_command.compatibility_version, 4, 0);
+
+ memcpy (pos, &dylib_command, sizeof (dylib_command));
+ strcpy ((char *) pos + sizeof (dylib_command), DYLIB_STRING);
+
+ pos += array_to_integer (dylib_command.command_size, 4, 0);
+
+ integer_to_array (LC_SOURCE_VERSION, source_version.command, 4, 0);
+ integer_to_array (sizeof (source_version), source_version.command_size, 4, 0);
+ integer_to_array (0, source_version.version, 8, 0);
+
+ memcpy (pos, &source_version, sizeof (source_version));
+ pos += array_to_integer (source_version.command_size, 4, 0);
+
+ integer_to_array (LC_DATA_IN_CODE, data_in_code.command, 4, 0);
+ integer_to_array (sizeof (data_in_code), data_in_code.command_size, 4, 0);
+ integer_to_array (symbol_offset, data_in_code.data_offset, 4, 0);
+ integer_to_array (0, data_in_code.data_size, 4, 0);
+
+ memcpy (pos, &data_in_code, sizeof (data_in_code));
+ pos += array_to_integer (data_in_code.command_size, 4, 0);
+
+ integer_to_array (LC_MAIN, main_command.command, 4, 0);
+ integer_to_array (sizeof (main_command), main_command.command_size, 4, 0);
+ integer_to_array (state->entry_point, main_command.entry_offset, 8, 0);
+ integer_to_array (0, main_command.stack_size, 8, 0);
+
+ memcpy (pos, &main_command, sizeof (main_command));
+ pos += array_to_integer (main_command.command_size, 4, 0);
+
+ } else if (state->format == LD_FORMAT_AMD64_MACHO) {
+
+ integer_to_array (LC_SYMTAB, symtab_cmd.command, 4, 0);
+ integer_to_array (sizeof (symtab_cmd), symtab_cmd.command_size, 4, 0);
+
+ memcpy (pos, &symtab_cmd, sizeof (symtab_cmd));
+ pos += array_to_integer (symtab_cmd.command_size, 4, 0);
+
+ integer_to_array (LC_UNIXTHREAD, unixthread.command, 4, 0);
+ integer_to_array (sizeof (unixthread) + sizeof (thread_state64), unixthread.command_size, 4, 0);
+ integer_to_array (0x04, unixthread.flavor, 4, 0);
+ integer_to_array (0x2A, unixthread.count, 4, 0);
+
+ memcpy (pos, &unixthread, sizeof (unixthread));
+
+ integer_to_array (state->base_address + state->entry_point, thread_state64.rip, 8, 0);
+ memcpy (pos + sizeof (unixthread), &thread_state64, sizeof (thread_state64));
+
+ pos += array_to_integer (unixthread.command_size, 4, 0);
+
+ }
+
+ if (fwrite (data, data_size, 1, fp) != 1) {
+ report_at (program_name, 0, REPORT_ERROR, "failed to write data to '%s'", filename);
+ }
+
+ free (data);
+ fclose (fp);
+
+}