From abe548019d645e8c13708b7ac2391f2a38d37dd9 Mon Sep 17 00:00:00 2001 From: Robert Pengelly Date: Fri, 7 Nov 2025 19:25:51 +0000 Subject: [PATCH] Create static and non-static Mach-O executables --- ld.h | 2 + lib.c | 35 +++++++++------ macho.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++----- macho.h | 7 +++ 4 files changed, 150 insertions(+), 24 deletions(-) diff --git a/ld.h b/ld.h index f85d8ea..5901f96 100644 --- a/ld.h +++ b/ld.h @@ -44,6 +44,8 @@ struct ld_state { #define LD_EMULATION_I386_ELKS 0x05 #define LD_EMULATION_I386_PE 0x06 +#define LD_EMULATION_MACHO 0x07 + #define LD_FORMAT_COM 0x00 #define LD_FORMAT_MZ 0x01 diff --git a/lib.c b/lib.c index ba38e27..de203f1 100644 --- a/lib.c +++ b/lib.c @@ -10,6 +10,7 @@ #include "ld.h" #include "lib.h" +#include "macho.h" #include "mz.h" #include "pe.h" #include "report.h" @@ -26,12 +27,13 @@ struct options_with_use { static struct options_with_use emulation_table[] = { - { 0, 0, 0 }, - { &mz_print_help, &mz_check_option, &mz_use_option }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { &pe_print_help, &pe_check_option, &pe_use_option } + { 0, 0, 0 }, + { &mz_print_help, &mz_check_option, &mz_use_option }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { 0, 0, 0 }, + { &pe_print_help, &pe_check_option, &pe_use_option }, + { &macho_print_help, &macho_check_option, &macho_use_option }, }; @@ -91,7 +93,7 @@ static void print_usage (void) { fprintf (stderr, " -m EMULATION Set emulation. (default none)\n"); fprintf (stderr, " Supported emualtions are:\n"); fprintf (stderr, " i386aout, i386coff, i386elks, i386pe\n"); - fprintf (stderr, " ia16_elks, ia16_mz\n"); + fprintf (stderr, " ia16_elks, ia16_mz, macho\n"); fprintf (stderr, " -q, --emit-relocs Generate relocations in final output.\n"); fprintf (stderr, " -s, --strip-all Ignored.\n"); @@ -194,6 +196,13 @@ static void use_option (const char *cmd_arg, int idx, const char *optarg) { } + if (xstrcasecmp (optarg, "macho") == 0) { + + state->emulation = LD_EMULATION_MACHO; + break; + + } + report_at (program_name, 0, REPORT_ERROR, "unrecognised emulation mode '%s'", optarg); exit (EXIT_FAILURE); @@ -309,9 +318,9 @@ static void use_option (const char *cmd_arg, int idx, const char *optarg) { state->format = LD_FORMAT_AMD64_MACHO; - /*if (state->emulation == LD_EMULATION_NONE) { - state->emulation = LD_EMULATION_AND64_MACHO; - }*/ + if (state->emulation == LD_EMULATION_NONE) { + state->emulation = LD_EMULATION_MACHO; + } break; @@ -321,9 +330,9 @@ static void use_option (const char *cmd_arg, int idx, const char *optarg) { state->format = LD_FORMAT_AARCH64_MACHO; - /*if (state->emulation == LD_EMULATION_NONE) { - state->emulation = LD_EMULATION_AND64_MACHO; - }*/ + if (state->emulation == LD_EMULATION_NONE) { + state->emulation = LD_EMULATION_MACHO; + } break; diff --git a/macho.c b/macho.c index f6d6a47..17d8e80 100644 --- a/macho.c +++ b/macho.c @@ -12,6 +12,111 @@ #include "report.h" #include "section.h" +unsigned long _static = 0; +#define LD_OPTION_STATIC 1 + +static struct ld_option opts[] = { + + { "-static", LD_OPTION_TYPE_LONG, LD_OPTION_STATIC, LD_OPTION_NO_ARG }, + { 0, 0, 0, 0 } + +}; + +int macho_check_option (const char *cmd_arg, int argc, char **argv, int *optind, const char **optarg) { + + struct ld_option *popt; + + for (popt = opts; ; popt++) { + + const char *p1 = popt->name; + const char *r1 = cmd_arg; + + if (!p1) { + break; + } + + if (!strstart (p1, &r1)) { + + if (popt->type == LD_OPTION_TYPE_LONG) { + + if (*r1 != '-') { + continue; + } + + p1 = popt->name + 1; + r1 = cmd_arg; + + if (!strstart (p1, &r1)) { + continue; + } + + } else { + continue; + } + + } + + (*optarg) = r1; + + if (popt->flgs & LD_OPTION_HAS_ARG) { + + if (*r1 == '\0') { + + if ((*optind) >= argc) { + + report_at (program_name, 0, REPORT_ERROR, "argument to '%s' is missing", cmd_arg); + exit (EXIT_FAILURE); + + } + + (*optarg) = argv[(*optind)++]; + + } + + } else if (*r1 != '\0') { + continue; + } + + return popt->idx; + + } + + return -1; + +} + +void macho_use_option (const char *cmd_arg, int idx, const char *optarg) { + + (void) optarg; + + switch (idx) { + + case LD_OPTION_STATIC: { + + _static = 1; + break; + + } + + default: { + + report_at (program_name, 0, REPORT_ERROR, "unsupported option '%s'", cmd_arg); + exit (EXIT_FAILURE); + + } + + } + +} + +void macho_print_help (void) { + + fprintf (stderr, "macho:\n\n"); + fprintf (stderr, " -static Produces a Mach-O file that does not use the dyld.\n"); + +} + + #define PAGE_SIZE 0x4000 struct part_reloc { @@ -723,8 +828,8 @@ void read_macho_object (const char *filename, unsigned char *data, unsigned long #define section_in_data_seg(section) \ (!((section)->flags & SECTION_FLAG_CODE)) -static struct section *first_data_section; -static uint64_t first_data_section_alignment; +static struct section *first_data_section = 0; +static uint64_t first_data_section_alignment = 0; void macho_before_link (void) { @@ -1091,14 +1196,15 @@ void macho_write (const char *filename) { 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); - - integer_to_array (MH_NOUNDEFS, header.flags, 4, 0); } else if (state->format == LD_FORMAT_AARCH64_MACHO) { - integer_to_array (MH_CPU_TYPE_ARM64, header.cpu_type, 4, 0); - integer_to_array (MH_NOUNDEFS | MH_DYLDLINK | MH_TWOLEVEL | MH_PIE, header.flags, 4, 0); + } + if (!_static) { + 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); @@ -1129,7 +1235,7 @@ void macho_write (const char *filename) { sizeof_commands += sizeof (segment_cmd); num_commands++; - if (state->format == LD_FORMAT_AARCH64_MACHO) { + if (!_static) { sizeof_commands += sizeof (dyld_chained_fixups_command); num_commands++; @@ -1168,7 +1274,7 @@ void macho_write (const char *filename) { sizeof_commands += sizeof (main_command); num_commands++; - } else if (state->format == LD_FORMAT_AMD64_MACHO) { + } else { sizeof_commands += sizeof (symtab_cmd); num_commands++; @@ -1218,7 +1324,7 @@ void macho_write (const char *filename) { data_size = ALIGN (data_size, PAGE_SIZE); - if (state->format == LD_FORMAT_AARCH64_MACHO) { + if (!_static) { data_size += sizeof (dyld_chained_fixups_header); data_size += sizeof (dyld_chained_starts_in_image) + (NUM_SEGS - 1) * 4 + 4; @@ -1357,6 +1463,8 @@ void macho_write (const char *filename) { if (section->flags & SECTION_FLAG_CODE) { integer_to_array ((0x80000000 | S_REGULAR), section_64.flags, 4, 0); + } else if (strcmp (section->name, "__cstring") == 0) { + integer_to_array (S_CSTRING_LITERALS, section_64.flags, 4, 0); } vm_addr = array_to_integer (segment_cmd.vm_addr, 8, 0); @@ -1503,7 +1611,7 @@ void macho_write (const char *filename) { memcpy (pos, &segment_cmd, sizeof (segment_cmd)); pos += sizeof (segment_cmd); - if (state->format == LD_FORMAT_AARCH64_MACHO) { + if (!_static) { 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); @@ -1721,7 +1829,7 @@ void macho_write (const char *filename) { 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) { + } else { integer_to_array (LC_SYMTAB, symtab_cmd.command, 4, 0); integer_to_array (sizeof (symtab_cmd), symtab_cmd.command_size, 4, 0); diff --git a/macho.h b/macho.h index 6d5b5bc..acec872 100644 --- a/macho.h +++ b/macho.h @@ -96,6 +96,7 @@ struct section_64 { #define S_REGULAR 0x0400 #define S_ZEROFILL 0x0001 +#define S_CSTRING_LITERALS 0x0002 struct nlist_64 { @@ -350,4 +351,10 @@ uint64_t macho_get_first_section_rva (void); void macho_before_link (void); void macho_write (const char *filename); + +int macho_check_option (const char *cmd_arg, int argc, char **argv, int *optind, const char **optarg); + +void macho_print_help (void); +void macho_use_option (const char *cmd_arg, int idx, const char *optarg); + #endif /* _MACHO_H */ -- 2.34.1