Skip to content

Commit f594d6f

Browse files
committed
add support for fat macho
1 parent 4972537 commit f594d6f

1 file changed

Lines changed: 63 additions & 1 deletion

File tree

php_micro_fileinfo.c

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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__)
5152
typedef struct mach_header_64 mach_header;
5253
typedef 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
*/
264268
typedef 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

Comments
 (0)