Create static and non-static Mach-O executables
authorRobert Pengelly <robertapengelly@hotmail.com>
Fri, 7 Nov 2025 19:25:51 +0000 (19:25 +0000)
committerRobert Pengelly <robertapengelly@hotmail.com>
Fri, 7 Nov 2025 19:25:51 +0000 (19:25 +0000)
ld.h
lib.c
macho.c
macho.h

diff --git a/ld.h b/ld.h
index f85d8eafb9d1583161dcae6d10a72d31d87dfec0..5901f9659b5449e21e78b9f77399a78224878fce 100644 (file)
--- 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 ba38e27fbbe38676bbc4205588d95961005ec599..de203f17d91ce1b25c1108235429406d8de2160d 100644 (file)
--- 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 f6d6a4788ef93ff35e5e2de973b4cb5ad4630bd5..17d8e80ab0005568b884382515acaa55bf6971bd 100644 (file)
--- a/macho.c
+++ b/macho.c
 #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 6d5b5bc0d6bc049da3d6f79c5adfcff3c5f1349a..acec872639f4945b601f33967fe0a0d2fa32161f 100644 (file)
--- 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 */