4 * Open Hack'Ware BIOS MACH-O executable file loader
6 * Copyright (c) 2004-2005 Jocelyn Mayer
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License V2
10 * as published by the Free Software Foundation
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 /* MACH-O executable loader */
29 /* CPU type definitions */
30 typedef enum cpu_type_t {
36 CPU_TYPE_MC98000 = 10,
39 CPU_TYPE_MC88000 = 13,
43 CPU_TYPE_POWERPC = 18,
47 typedef enum cpu_subtype_any_t {
48 CPU_SUBTYPE_MULTIPLE = -1,
49 CPU_SUBTYPE_LITTLE_ENDIAN = 0,
50 CPU_SUBTYPE_BIG_ENDIAN = 1,
54 typedef enum cpu_subtype_ppc_t {
55 CPU_SUBTYPE_PPC_ALL = 0,
56 CPU_SUBTYPE_PPC_601 = 1,
57 CPU_SUBTYPE_PPC_602 = 2,
58 CPU_SUBTYPE_PPC_603 = 3,
59 CPU_SUBTYPE_PPC_603e = 4,
60 CPU_SUBTYPE_PPC_603ev = 5,
61 CPU_SUBTYPE_PPC_604 = 6,
62 CPU_SUBTYPE_PPC_604e = 7,
63 CPU_SUBTYPE_PPC_620 = 8,
64 CPU_SUBTYPE_PPC_750 = 9,
65 CPU_SUBTYPE_PPC_7400 = 10,
66 CPU_SUBTYPE_PPC_7450 = 11,
69 /* Fat header definition */
70 #define FAT_MAGIC 0xCAFEBABE
72 typedef struct fat_head_t {
77 typedef struct fat_arch_t {
79 cpu_subtype_ppc_t cpu_subtype;
85 /* Mach-O binary definitions */
86 #define MACH_O_MAGIC 0xFEEDFACE
88 typedef enum filetype_t {
103 MH_BINDATLOAD = 0x08,
107 typedef struct mach_head_t {
110 cpu_subtype_ppc_t subtype;
111 filetype_t file_type;
117 typedef enum load_cmd_t {
122 LC_UNIXTHREAD = 0x05,
123 LC_LOADFVMLIB = 0x06,
129 LC_LOAD_DYLIB = 0x0C,
131 LC_LOAD_DYLINKER = 0x0E,
132 LC_ID_DYLINKER = 0x0F,
133 LC_PREBOUND_DYLIB = 0x10,
137 typedef struct mach_load_cmd_t {
142 typedef struct mach_string_t {
152 typedef struct mach_segment_t {
153 unsigned char segname[16];
156 uint32_t file_offset;
168 S_CSTRING_LITERALS = 0x2,
169 S_4BYTE_LITERALS = 0x3,
170 S_8BYTE_LITERALS = 0x4,
171 S_LITERAL_POINTERS = 0x5,
172 S_NON_LAZY_SYMBOL_POINTERS = 0x6,
173 S_LAZY_SYMBOL_POINTERS = 0x7,
174 S_SYMBOL_STUBS = 0x8,
175 S_MOD_INIT_FUNC_POINTERS = 0x9,
179 S_ATTR_PURE_INSTRUCTIONS = 0x80000000,
180 S_ATTR_SOME_INSTRUCTIONS = 0x00000400,
181 S_ATTR_EXT_RELOC = 0x00000200,
182 S_ATTR_LOC_RELOC = 0x00000100,
185 typedef struct mach_section_t {
186 unsigned char sectname[16];
187 unsigned char segname[16];
192 uint32_t reloc_offset;
199 typedef struct mach_symtab_t {
206 typedef struct mach_symseg_t {
211 typedef struct mach_unixth_t {
214 /* This is supposed to be a stack.
215 * Let's assume it's less than 1kB (arbitrary !)
220 typedef struct mach_fvmlib_t {
222 uint32_t minor_version;
223 uint32_t header_addr;
226 typedef struct mach_fvmfile_t {
231 typedef struct mach_dysymtab_t {
232 uint32_t ilocal_syms;
233 uint32_t nlocal_syms;
236 uint32_t iundef_syms;
237 uint32_t nundef_syms;
240 uint32_t modtab_offset;
242 uint32_t extsym_offset;
244 uint32_t indirect_offset;
246 uint32_t ext_reloc_offset;
248 uint32_t local_reloc_offset;
249 uint32_t nlocal_reloc;
252 typedef struct mach_dylib_t {
255 uint32_t cur_version;
256 uint32_t compat_version;
259 typedef struct mach_prebound_t {
262 unsigned char linked_modules[256];
265 int exec_load_macho (inode_t *file, void **dest, void **entry, void **end,
269 mach_load_cmd_t lcmd;
272 void *address, *first, *last;
273 uint32_t k, j, best, offset;
277 file_seek(file, loffset);
278 if (fs_read(file, &fhdr, sizeof(fat_head_t)) < 0) {
279 ERROR("Cannot load fat header...\n");
282 fhdr.magic = get_be32(&fhdr.magic);
283 if (fhdr.magic != FAT_MAGIC)
285 fhdr.nfat_arch = get_be32(&fhdr.nfat_arch);
286 DPRINTF("FAT file: %d archs\n", fhdr.nfat_arch);
287 /* Find the best architecture */
290 for (k = 0; k < fhdr.nfat_arch; k++) {
291 if (fs_read(file, &fahdr, sizeof(fat_arch_t)) < 0) {
292 ERROR("Cannot load fat arch header\n");
295 fahdr.cpu_type = get_be32(&fahdr.cpu_type);
296 if (fahdr.cpu_type != CPU_TYPE_POWERPC)
298 fahdr.cpu_subtype = get_be32(&fahdr.cpu_subtype);
299 fahdr.offset = get_be32(&fahdr.offset);
300 fahdr.size = get_be32(&fahdr.size);
301 fahdr.align = get_be32(&fahdr.align);
302 switch (fahdr.cpu_subtype) {
303 case CPU_SUBTYPE_PPC_750:
305 offset = fahdr.offset;
307 case CPU_SUBTYPE_PPC_ALL:
308 if (best == (uint32_t)-1) {
309 offset = fahdr.offset;
313 case CPU_SUBTYPE_PPC_603:
314 case CPU_SUBTYPE_PPC_603e:
315 case CPU_SUBTYPE_PPC_603ev:
316 case CPU_SUBTYPE_PPC_604:
317 case CPU_SUBTYPE_PPC_604e:
319 offset = fahdr.offset;
325 if (best == (uint32_t)-1) {
326 ERROR("No matching PPC FAT arch\n");
329 DPRINTF("Use FAT arch %d at %08x %08x\n", best, offset, loffset);
335 file_seek(file, loffset);
336 if (fs_read(file, &mhdr, sizeof(mach_head_t)) < 0) {
337 ERROR("Cannot load MACH-O header...\n");
340 mhdr.magic = get_be32(&mhdr.magic);
341 if (mhdr.magic != MACH_O_MAGIC) {
342 ERROR("Not a MACH-O file\n");
345 mhdr.cpu_type = get_be32(&mhdr.cpu_type);
346 mhdr.subtype = get_be32(&mhdr.subtype);
347 mhdr.file_type = get_be32(&mhdr.file_type);
348 mhdr.nb_cmds = get_be32(&mhdr.nb_cmds);
349 mhdr.cmds_size = get_be32(&mhdr.cmds_size);
350 mhdr.flags = get_be32(&mhdr.flags);
351 DPRINTF("MACHO-O file cpu %d %d file type %08x %d cmds size %08x flags "
352 "%08x\n", mhdr.cpu_type, mhdr.subtype, mhdr.file_type,
353 mhdr.nb_cmds, mhdr.cmds_size, mhdr.flags);
354 offset = sizeof(mach_head_t);
358 for (k = 0; k < mhdr.nb_cmds; k++) {
359 file_seek(file, loffset + offset);
360 if (fs_read(file, &lcmd, sizeof(mach_load_cmd_t)) < 0) {
361 ERROR("Unable to load MACH-O cmd %d\n", k);
364 lcmd.cmd = get_be32(&lcmd.cmd);
365 lcmd.cmd_size = get_be32(&lcmd.cmd_size);
366 DPRINTF("Cmd %d : %08x size %08x (%08x %08x)\n", k, lcmd.cmd,
367 lcmd.cmd_size, offset, offset + loffset);
370 /* To be loaded for execution */
372 mach_segment_t segment;
373 mach_section_t section;
376 pos = offset + sizeof(mach_load_cmd_t);
377 if (fs_read(file, &segment, sizeof(mach_segment_t)) < 0) {
378 ERROR("Cannot load MACH-O segment\n");
381 pos += sizeof(mach_segment_t);
382 segment.vmaddr = get_be32(&segment.vmaddr);
383 segment.vmsize = get_be32(&segment.vmsize);
384 segment.file_offset = get_be32(&segment.file_offset);
385 segment.file_size = get_be32(&segment.file_size);
386 segment.max_prot = get_be32(&segment.max_prot);
387 segment.init_prot = get_be32(&segment.init_prot);
388 segment.nsects = get_be32(&segment.nsects);
389 segment.flags = get_be32(&segment.flags);
390 DPRINTF("MACH-O segment addr %08x size %08x off %08x fsize "
391 "%08x ns %d fl %08x\n", segment.vmaddr, segment.vmsize,
392 segment.file_offset, segment.file_size,
393 segment.nsects, segment.flags);
394 for (j = 0; j < segment.nsects; j++) {
395 file_seek(file, loffset + pos);
396 if (fs_read(file, §ion, sizeof(mach_section_t)) < 0) {
397 ERROR("Cannot load MACH-O section\n");
400 pos += sizeof(mach_section_t);
401 section.vmaddr = get_be32(§ion.vmaddr);
402 section.size = get_be32(§ion.size);
403 section.offset = get_be32(§ion.offset);
404 section.align = get_be32(§ion.align);
405 section.reloc_offset = get_be32(§ion.reloc_offset);
406 section.nreloc = get_be32(§ion.nreloc);
407 section.flags = get_be32(§ion.flags);
408 section.res1 = get_be32(§ion.res1);
409 section.res2 = get_be32(§ion.res2);
410 DPRINTF("MACH-O section vmaddr %08x size %08x off %08x "
411 "flags %08x\n", section.vmaddr, section.size,
412 section.offset, section.flags);
413 switch (section.flags & SECTION_TYPE) {
415 case S_CSTRING_LITERALS:
416 case S_4BYTE_LITERALS:
417 case S_8BYTE_LITERALS:
418 case S_LITERAL_POINTERS:
419 case S_NON_LAZY_SYMBOL_POINTERS:
420 case S_LAZY_SYMBOL_POINTERS:
422 case S_MOD_INIT_FUNC_POINTERS:
423 DPRINTF("Load section of type %d from %08x to %08x"
424 " %08x\n", section.flags, section.offset,
425 section.vmaddr, section.size);
426 file_seek(file, section.offset + loffset);
427 address = (void *)section.vmaddr;
428 if (address < first && address != NULL)
430 if (address + section.size > last)
431 last = address + section.size;
432 if (fs_read(file, address, section.size) < 0) {
433 ERROR("Cannot load MACH-O section %d %d...\n",
439 DPRINTF("Fill zero section to %08x %08x\n",
440 section.vmaddr, section.size);
441 address = (void *)section.vmaddr;
442 if (address < first && address != NULL)
444 if (address + section.size > last)
445 last = address + section.size;
446 memset(address, 0, section.size);
449 ERROR("Unknown MACH-O section type: %d\n",
463 /* To be loaded for execution */
465 mach_unixth_t unixth;
467 if (fs_read(file, &unixth, sizeof(mach_unixth_t)) < 0) {
468 ERROR("Cannot load MACH-O UNIX thread\n");
471 DPRINTF("Set entry point to %08x\n", unixth.data[0]);
472 *entry = (void *)unixth.data[0];
487 printf("Prepage command\n");
495 case LC_LOAD_DYLINKER:
496 /* To be loaded for execution */
500 case LC_PREBOUND_DYLIB:
506 printf("unknown MACH-O command (%d %d)\n", k, lcmd.cmd);
509 offset += lcmd.cmd_size;
513 // if (entry_set == 0)