7

In classic Mac apps the main app and sometimes some other files belonging to the app have "resource forks" which are in a special binary file format. Each resource has a 4-byte type field, usually ASCII, and the type of field that holds the actual Motorola 680x0 machine code is the CODE resource.

But they seem to have a special format and don't begin with the first 68k instruction from what I can tell.

In my searching I've found the resource fork's fields documented so I can iterate through the individual resources, but when I get a CODE resource I have not been able to locate documentation on their internal structure.

Do CODE resources begin with a small header, with an offset field or a length field, etc?

I have found several mentions that the first CODE resource is special. I think it contains fixups to adjust the absolute references in the machine code to point to the actual memory addresses where the OS loads the application.

So perhaps there are two CODE resource formats that I'm looking for.

2

2 Answers 2

6

Every resource begins with a 32-bit size field before the resource data itself.

For the CODE resource data itself I found resource_dasm, which is an open source project on GitHub. It includes these definitions in ResourceFile.cc:

struct Code0ResourceHeader {
  be_uint32_t above_a5_size;
  be_uint32_t below_a5_size;
  be_uint32_t jump_table_size; // Should be == resource_size - 0x10
  be_uint32_t jump_table_offset;

  struct MethodEntry {
    be_uint16_t offset; // Need to add 4 to this apparently
    be_uint16_t push_opcode;
    be_int16_t resource_id; // id of target CODE resource
    be_uint16_t trap_opcode; // Disassembles as `trap _LoadSeg`
  } __attribute__((packed));

  MethodEntry entries[0];
} __attribute__((packed));

struct CodeResourceHeader {
  be_uint16_t first_jump_table_entry;
  be_uint16_t num_jump_table_entries;
} __attribute__((packed));

struct CodeResourceFarHeader {
  be_uint16_t entry_offset; // 0xFFFF
  be_uint16_t unused; // 0x0000
  be_uint32_t near_entry_start_a5_offset;
  be_uint32_t near_entry_count;
  be_uint32_t far_entry_start_a5_offset;
  be_uint32_t far_entry_count;
  be_uint32_t a5_relocation_data_offset;
  be_uint32_t a5;
  be_uint32_t pc_relocation_data_offset;
  be_uint32_t load_address;
  be_uint32_t reserved; // 0x00000000
} __attribute__((packed));

These are for "standard" CODE resources. From other bits and pieces I've read, it seems that certain compilers and/or certain apps also contain CODE resources in their own formats that they must load manually instead of being loaded by the Mac's OS.

So "CODE0" has one format and "CODE" two formats. The normal format for the near model and a special format for the far model. If the first 16-bit field of the CODE resource is 0xffff then it's the format for the far model. Otherwise it's in the normal near model format.

The far model is also described with the term "32-bit-everywhere". I think this hints at the earliest Mac operating systems using the high 8 bits of addresses for flags or such since the original 68000 CPU only used 24 bits for addresses. When later 680x0 CPUs came out they used the full 32 bits and the Mac operating system would have adapted to it.

As noted in other comments and answers the structure is documented in Chapter 10, "Classic 68K Runtime Architecture" of "Mac OS Runtime Architectures For System 7 Through Mac OS 9". There's a lot of information in there besides the description of the records in the file. The parts I was looking for are:

For the format of CODE resource #0:

  • Page 10-9, Figure 10-3 "The 'CODE'0 resource"
  • Page 10-10, Figure 10-4 "An unloaded jump table entry"

For the format of normal CODE resources:

  • Page 10-12, Figure 10-6 "Near model segment header"
  • Page 10-24, Figure 10-11 "The far model segment header"

I can't find where or if this document covers the general format of the resource as beginning with a 32-bit integer size field, so I'm glad I figured that out.

If all you want is to locate the m68k machine code, then:

Iterate through the resources, look for CODE resources, skipping the one numbered 0. For the others, check the 16-bit field at offset 0x04. If it's 0xffff then the code starts at offset 0x2c, otherwise the code starts at offset 0x08.

Note that execution does not necessarily start at the beginning of the code block, for exported code entry points you need to see the jump table in CODE 0. It seems common for there to be some data before the first code.

4

As @KelvinSherlock mentioned in a comment on your question, Chapter 10 of Mac OS Runtime Architectures covers all of this in depth including the special format of the 'CODE' resource with ID 0 that contains the segment map/jump table.

There's no need to reverse-engineer any of it yourself, it's all specified in sufficient depth for developers to create tools to work with them.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .