otool -L 相当のことをやる
Mach-O のフォーマットや Universal Binary のフォーマットを調べながら、otool -L 相当 (Linux でいうところの ldd) を自前でやってみた。
あ、ちなみに自分の cputype は i386 だと決めうちしてます。
#include <stdio.h> #include <stdlib.h> #include <mach-o/loader.h> #include <mach-o/fat.h> #define SWAP32(a) ((a)<<24|((a)&0x0000FF00)<<8|((a)&0x00FF0000)>>8|(a)>>24) int main(int argc, char *argv[]) { uint32_t magic, mh_offset; FILE *fp; int i, j; struct fat_header fh; struct fat_arch fa; struct mach_header mh; struct load_command lc; struct dylib_command dc; for (i = 1; i < argc; i++) { printf("%s:\n", argv[i]); fp = fopen(argv[i], "r"); if (fp == NULL) { perror("fopen"); continue; } fread(&magic, 4, 1, fp); fseek(fp, 0, SEEK_SET); switch (magic) { case FAT_MAGIC: case FAT_CIGAM: fread(&fh, sizeof(struct fat_header), 1, fp); mh_offset = 0; if (magic == FAT_CIGAM) { fh.nfat_arch = SWAP32(fh.nfat_arch); } for (j = 0; j < fh.nfat_arch; j++) { fread(&fa, sizeof(struct fat_arch), 1, fp); if (magic == FAT_CIGAM) { fa.cputype = SWAP32(fa.cputype); fa.offset = SWAP32(fa.offset); } if (fa.cputype == CPU_TYPE_I386) { /* my cpu found */ mh_offset = fa.offset; break; } } if (mh_offset == 0) { /* my cpu was not found */ break; } fseek(fp, mh_offset, SEEK_SET); /* fall through */ case MH_MAGIC: fread(&mh, sizeof(struct mach_header), 1, fp); if (mh.magic != MH_MAGIC) { puts("\tnot Mach-O file"); break; } for (j = 0; j < mh.ncmds; j++) { fread(&lc, sizeof(struct load_command), 1, fp); fseek(fp, -sizeof(struct load_command), SEEK_CUR); if (lc.cmd == LC_LOAD_DYLIB) { fread(&dc, sizeof(struct dylib_command), 1, fp); size_t bufsize = lc.cmdsize - sizeof(struct dylib_command); char *buf = malloc(bufsize); fread(buf, 1, bufsize, fp); printf("\t%s (compatibility version %u.%u.%u, current version %u.%u.%u)\n", buf, (dc.dylib.compatibility_version & 0x00FF0000)>>16, (dc.dylib.compatibility_version & 0x0000FF00)>>8, dc.dylib.compatibility_version & 0x000000FF, (dc.dylib.current_version & 0x00FF0000)>>16, (dc.dylib.current_version & 0x0000FF00)>>8, dc.dylib.current_version & 0x000000FF ); free(buf); } else { fseek(fp, lc.cmdsize, SEEK_CUR); } } break; default: puts("\tnot Mach-O file"); } fclose(fp); } return 0; }
使用例
$ ./a.out a.out =zsh /etc/passwd a.out: /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.1.1) /bin/zsh: /usr/lib/libiconv.2.dylib (compatibility version 7.0.0, current version 7.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 111.0.0) /usr/lib/libncurses.5.4.dylib (compatibility version 5.4.0, current version 5.4.0) /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0) /etc/passwd: not Mach-O file