@@ -47,6 +47,7 @@ typedef Elf32_Phdr Elf_Phdr;
4747#elif defined(__APPLE__ )
4848# include <mach-o/dyld.h>
4949# include <mach-o/getsect.h>
50+ # include <mach-o/fat.h>
5051# if defined(__LP64__ )
5152typedef struct mach_header_64 mach_header ;
5253typedef struct segment_command_64 segment_command ;
@@ -253,12 +254,15 @@ int micro_fileinfo_init(void) {
253254/**
254255 * In windows, this struct is stored as RC_DATA, with id PHP_MICRO_SFXSIZE_ID
255256 * In ELF, this struct is located at .sfxsize section
256- * In Mach-O, this struct is located at __DATA,__micro_sfxsize section
257+ * In Mach-O, for common macho, this struct is located at __DATA,__micro_sfxsize section
258+ * In Mach-O, for fat macho, this struct is located at
259+ * start of the CPU_TYPE_X86 fat arch binary + 0x1000 (4096 is minimal size for a stub executable)
257260 * If sections not set,
258261 * size will be:
259262 * Windows uses the end of the last section, this supports UPX
260263 * ELF uses the end of the last section or last program header segment, this do not support UPX
261264 * Mach-O uses the end of __LINKEDIT
265+ * Mach-O fat binary uses the end of the last fat arch
262266 * limit will be 0 (no limit)
263267 */
264268typedef struct _micro_sfxsize_section_t {
@@ -405,6 +409,64 @@ int _micro_init_sfxsize(void) {
405409
406410 return SUCCESS ;
407411#elif defined(__APPLE__ )
412+ // get file header first
413+ const char * self_path = micro_get_filename ();
414+
415+ int fd = open (self_path , O_RDONLY );
416+ if (fd < 0 ) {
417+ fprintf (stderr , "cannot open self file: %s\n" , self_path );
418+ return FAILURE ;
419+ }
420+
421+ // get file header
422+ uint32_t magic ;
423+ if (sizeof (uint32_t ) != read (fd , & magic , sizeof (uint32_t ))) {
424+ fprintf (stderr , "cannot read file header magic: %s\n" , self_path );
425+ return FAILURE ;
426+ }
427+ if (magic == FAT_MAGIC || magic == FAT_CIGAM ) {
428+ // fat file
429+ uint32_t nfat_arch ;
430+ if (sizeof (uint32_t ) != read (fd , & nfat_arch , sizeof (uint32_t ))) {
431+ fprintf (stderr , "cannot read fat header nfat_arch: %s\n" , self_path );
432+ return FAILURE ;
433+ }
434+ nfat_arch = ntohl (nfat_arch );
435+ _final_sfxsize = 0 ;
436+ for (int i = 0 ; i < nfat_arch ; i ++ ) {
437+ struct fat_arch fat_arch ;
438+ if (sizeof (fat_arch ) != read (fd , & fat_arch , sizeof (fat_arch ))) {
439+ fprintf (stderr , "cannot read fat arch: %s\n" , self_path );
440+ return FAILURE ;
441+ }
442+ // set to the end of the last fat arch
443+ uint32_t archOffset = ntohl (fat_arch .offset );
444+ uint32_t archSize = ntohl (fat_arch .size );
445+ _final_sfxsize = archOffset + archSize ;
446+ if (fat_arch .cputype == htonl ((cpu_type_t )CPU_TYPE_X86 )) {
447+ // 0x1000 is minimal size for a stub executable
448+ // this will skip the stub executable
449+ if (lseek (fd , archOffset + 0x1000 , SEEK_SET ) != archOffset + 0x1000 ) {
450+ fprintf (stderr , "cannot seek to fat macho: %s\n" , self_path );
451+ return FAILURE ;
452+ }
453+ uint32_t sfxsizeSectionSize = archSize - 0x1000 ;
454+ if (sfxsizeSectionSize > sizeof (micro_sfxsize_section_t )) {
455+ sfxsizeSectionSize = sizeof (micro_sfxsize_section_t );
456+ }
457+ if (sfxsizeSectionSize != read (fd , & sfxsizeSection , sfxsizeSectionSize )) {
458+ fprintf (stderr , "cannot read fat macho: %s\n" , self_path );
459+ return FAILURE ;
460+ }
461+ read_sfxsize_section (sfxsizeSectionSize );
462+ dbgprintf ("using fat macho arch CPU_TYPE_X86: %zd, %zd\n" , _final_sfxsize , _sfxsize_limit );
463+ return SUCCESS ;
464+ }
465+ }
466+
467+ dbgprintf ("using end of fat macho: %zd, %zd\n" , _final_sfxsize , _sfxsize_limit );
468+ return SUCCESS ;
469+ }
408470 // get mach header
409471 mach_header * header = (mach_header * )_dyld_get_image_header (0 );
410472 const segment_command * linkedit = NULL ;
0 commit comments