Định dạng Mach-O (Mach Object) là gì? Nguồn gốc, cấu trúc và đặc tả kỹ thuật

Tóm tắt

Mach-O (Mach Object) là định dạng tệp nhị phân được sử dụng trong hệ sinh thái Apple để biểu diễn mã đối tượng, tệp thực thi, thư viện dùng chung và những loại ảnh nhị phân khác. Mach-O cung cấp một hệ thống cấu trúc để mô tả kiến trúc bộ xử lý, loại tệp, các vùng mã lệnh và dữ liệu, thông tin ký hiệu, tái định vị, liên kết động và những yêu cầu phục vụ quá trình nạp chương trình.

Khác với định dạng ELF (Executable and Linkable Format), vốn sử dụng hệ thống header dành cho section và program segment, Mach-O tổ chức một phần lớn thông tin điều khiển thông qua các lệnh nạp (Load Commands). Những lệnh này cho biết các vùng nào của tệp phải được ánh xạ vào bộ nhớ, thư viện nào cần được nạp và các cấu trúc liên kết bổ sung được lưu ở đâu.

Nguồn gốc Mach-O gắn với hệ sinh thái Mach, các hệ điều hành NeXT và quá trình hình thành Mac OS X. Qua nhiều thế hệ, định dạng này được mở rộng để phục vụ nhiều kiến trúc phần cứng, đặc biệt là PowerPC, x86-64 và ARM64.

Bài viết khảo sát lịch sử phát triển của Mach-O, cấu trúc nhị phân, các loại header, load command, segment, section, bảng ký hiệu, relocation, cơ chế liên kết động, universal binary, quá trình nạp và thực thi, cùng những quy định liên quan đến chữ ký mã trên các nền tảng Apple.

Bài viết sử dụng những định nghĩa trong mã nguồn XNU và tài liệu của Apple làm căn cứ chính cho phần mô tả cấu trúc. Các ví dụ về địa chỉ, bố cục và kết quả công cụ được trình bày dưới dạng minh họa khi không phải là dữ liệu trích xuất từ một tệp Mach-O thực tế.

Từ khóa: Mach-O; Mach Object; định dạng nhị phân; tệp thực thi; Apple; macOS; XNU; dyld; load command; segment; section; relocation; universal binary; ABI.


1. Mach-O là gì?

1.1. Định nghĩa

Mach-O là một định dạng tệp đối tượng và ảnh nhị phân, được dùng để lưu trữ những thông tin mà bộ liên kết, bộ nạp và hệ điều hành cần sử dụng trong quá trình xây dựng hoặc thực thi chương trình.

Tùy thuộc vào mục đích, tệp Mach-O có thể chứa:

  • Mã máy đã được biên dịch.
  • Dữ liệu tĩnh và dữ liệu chỉ đọc.
  • Các vùng bộ nhớ cần khởi tạo.
  • Bảng ký hiệu.
  • Thông tin tái định vị.
  • Thông tin liên kết với thư viện động.
  • Thông tin về điểm vào chương trình.
  • Chữ ký mã và siêu dữ liệu nền tảng.

Mach-O là định dạng nhị phân, không phải ngôn ngữ lập trình, tập lệnh CPU hay một loại mã máy riêng.

Mã máy được chứa trong tệp Mach-O vẫn phụ thuộc vào kiến trúc bộ xử lý, chẳng hạn x86-64 hoặc ARM64.

1.2. Mach-O được sử dụng ở đâu?

Mach-O xuất hiện trong nhiều sản phẩm nhị phân của Apple:

Loại sản phẩm Vai trò
Tệp đối tượng .o Đầu vào hoặc đầu ra trung gian của quá trình liên kết
Tệp thực thi Chứa chương trình để hệ điều hành nạp và khởi chạy
Thư viện động .dylib Cung cấp mã và dữ liệu cho chương trình khác
Bundle nhị phân Thành phần mã có thể được nạp theo cơ chế phù hợp
Tệp dSYM Có thể chứa ảnh Mach-O phục vụ thông tin gỡ lỗi
Ảnh nhị phân hệ thống Một số thành phần của hệ điều hành và môi trường thực thi

Mach-O được sử dụng trên macOS, iOS, iPadOS, watchOS, tvOS và những nền tảng Apple có liên quan, dù quyền thực thi và các quy định kỹ thuật của mỗi nền tảng có thể khác nhau.

1.3. Mach-O và tệp ứng dụng .app

Một ứng dụng macOS thường được đóng gói dưới dạng một thư mục bundle có phần mở rộng .app.

Ví dụ:

Example.app/
└── Contents/
    ├── Info.plist
    ├── MacOS/
    │   └── Example
    └── Resources/

Trong ví dụ này:

  • Example.app là gói ứng dụng.
  • Info.plist chứa siêu dữ liệu ứng dụng.
  • Contents/MacOS/Example có thể là tệp thực thi Mach-O.

Vì vậy, **Mach-O là định dạng của tệp nhị phân bên trong ứng dụng, không phải định dạng của toàn bộ thư mục .app.**


2. Nguồn gốc và lịch sử phát triển

2.1. Mối liên hệ với hệ thống Mach

Tên Mach-O bắt nguồn từ Mach Object.

Mach là một họ thiết kế nhân hệ điều hành được nghiên cứu tại Đại học Carnegie Mellon trong những năm 1980, với các cơ chế như tác vụ, luồng, bộ nhớ ảo và giao tiếp giữa tiến trình.

Mach-O gắn với lịch sử hệ điều hành dựa trên Mach, đặc biệt là các hệ thống NeXT và sau này là Darwin, nền tảng hệ thống của Mac OS X.

Cần lưu ý rằng Mach-O không phải một phần của tập lệnh CPU, cũng không đồng nghĩa với kiến trúc nhân Mach.

Nhân hệ điều hành và định dạng tệp thực thi là hai thành phần khác nhau, dù có quan hệ chặt chẽ trong quá trình nạp và quản lý chương trình.

2.2. NeXTSTEP và sự chuyển tiếp sang Mac OS X

NeXTSTEP là hệ điều hành do NeXT phát triển, kết hợp các thành phần dựa trên Mach và những đặc điểm của hệ thống Unix.

Mach-O được gắn với hệ sinh thái NeXT và tiếp tục giữ vai trò quan trọng trong dòng hệ điều hành phát triển từ công nghệ này.

Sau khi Apple mua lại NeXT vào năm 1997, nhiều thành phần công nghệ của NeXT trở thành cơ sở cho thế hệ hệ điều hành Mac OS X.

Mach-O tiếp tục được sử dụng làm định dạng nhị phân quan trọng trong nền tảng mới.

Mac OS X 10.0 được phát hành năm 2001, đánh dấu sự xuất hiện thương mại của thế hệ hệ điều hành này.

2.3. Quá trình mở rộng theo kiến trúc CPU

Mach-O đã được sử dụng qua nhiều giai đoạn chuyển đổi phần cứng.

Giai đoạn Kiến trúc tiêu biểu Ý nghĩa
Hệ thống NeXT Motorola 68k, x86 và những kiến trúc được hỗ trợ khác Giai đoạn lịch sử của môi trường Mach/NeXT
Mac OS X thời kỳ đầu PowerPC Mach-O trong hệ sinh thái Macintosh mới
Chuyển sang Intel x86, x86-64 Hỗ trợ thế hệ máy Mac Intel
Chuyển sang Apple silicon ARM64 Hỗ trợ kiến trúc ARM64 trên máy Mac

Sự tồn tại của nhiều kiến trúc đã thúc đẩy việc sử dụng các tệp nhị phân đa kiến trúc, thường được gọi là universal binary.

2.4. Mach-O 32 bit và 64 bit

Mach-O có cấu trúc header dành cho cả kiến trúc 32 bit và 64 bit.

Hai loại này không chỉ khác nhau về kích thước con trỏ, mà còn có các cấu trúc mô tả segment và section khác nhau.

Ví dụ, định nghĩa chính thức sử dụng:

struct mach_header;
struct mach_header_64;

Tương ứng với các loại tệp Mach-O 32 bit và 64 bit.

Các trường địa chỉ và kích thước bộ nhớ trong những cấu trúc segment 64 bit được biểu diễn bằng kiểu dữ liệu rộng hơn.


3. Cấu trúc tổng thể của tệp Mach-O

3.1. Mô hình tổ chức

Một tệp Mach-O thông thường có thể được hình dung như sau:

┌─────────────────────────────────┐
│ Mach Header                     │
│ - Magic                         │
│ - CPU Type                      │
│ - File Type                     │
│ - Number of Load Commands       │
├─────────────────────────────────┤
│ Load Commands                   │
│ - Segment Commands              │
│ - Symbol Table Information      │
│ - Dynamic Linking Information   │
│ - Entry Point Information       │
├─────────────────────────────────┤
│ Nội dung các Segment            │
│ - Machine Code                  │
│ - Read-only Data                │
│ - Writable Data                 │
├─────────────────────────────────┤
│ Link-edit Data                  │
│ - Symbols                       │
│ - Fixups / Bindings             │
│ - Other Metadata                │
├─────────────────────────────────┤
│ Code Signature, nếu có          │
└─────────────────────────────────┘

Đây là sơ đồ khái quát nhằm giúp người đọc hình dung các nhóm thông tin.

Không phải tất cả vùng dữ liệu đều nằm thành những khối liên tiếp theo đúng thứ tự minh họa. Vị trí thực tế được xác định bằng các trường offset, kích thước và quy tắc của từng cấu trúc.

3.2. Ba thành phần cấu trúc cơ bản

Có thể tiếp cận Mach-O qua ba thành phần chính.

Mach Header

Xác định định dạng, kiến trúc CPU, loại tệp và thông tin tổng quát về danh sách lệnh nạp.

Load Commands

Mô tả các cấu trúc quan trọng của ảnh nhị phân và cung cấp thông tin để bộ nạp, bộ liên kết hoặc công cụ phân tích xử lý tệp.

Segments và Sections

Tổ chức mã máy, dữ liệu và những vùng bộ nhớ cần ánh xạ hoặc xử lý.

Các thành phần khác như bảng ký hiệu và thông tin fixup được tham chiếu thông qua những cấu trúc phù hợp, thay vì bắt buộc có một bảng section toàn cục riêng như trong ELF.


4. Mach Header

4.1. Header 64 bit

Trong tệp header chính thức mach-o/loader.h, Apple định nghĩa:

struct mach_header_64 {
    uint32_t magic;
    cpu_type_t cputype;
    cpu_subtype_t cpusubtype;
    uint32_t filetype;
    uint32_t ncmds;
    uint32_t sizeofcmds;
    uint32_t flags;
    uint32_t reserved;
};

Ở đây, cpu_type_t và cpu_subtype_t được biểu diễn bằng kiểu số nguyên 32 bit theo các định nghĩa liên quan.

Kích thước của mach_header_64 là 32 byte.

4.2. Bố cục từng trường

Offset Trường Kích thước Ý nghĩa
0x00 magic 4 byte Giá trị nhận diện định dạng
0x04 cputype 4 byte Loại CPU
0x08 cpusubtype 4 byte Phân loại chi tiết CPU
0x0C filetype 4 byte Loại tệp Mach-O
0x10 ncmds 4 byte Số lượng load command
0x14 sizeofcmds 4 byte Tổng số byte của load commands
0x18 flags 4 byte Những cờ mô tả thuộc tính ảnh
0x1C reserved 4 byte Trường dự trữ

Tổng kích thước:

Header 32 bit có bảy trường đầu tiên và không có trường reserved, nên có kích thước 28 byte.

4.3. Magic Number

Mach-O dùng những giá trị nhận diện để xác định loại header và thứ tự byte.

Hằng số Giá trị
MH_MAGIC 0xFEEDFACE
MH_CIGAM 0xCEFAEDFE
MH_MAGIC_64 0xFEEDFACF
MH_CIGAM_64 0xCFFAEDFE

Các giá trị CIGAM là dạng đảo thứ tự byte của những giá trị tương ứng.

Ví dụ, trên hệ little-endian, giá trị 32 bit 0xFEEDFACF được lưu thành chuỗi byte:

CF FA ED FE

Vì vậy, khi đọc một tệp nhị phân, cần xem xét chuỗi byte thực tế và cách giải mã endianness, thay vì chỉ đối chiếu văn bản hexa một cách máy móc.

4.4. Loại tệp (File Type)

Trường filetype xác định mục đích của ảnh Mach-O.

Hằng số Giá trị Ý nghĩa
MH_OBJECT 0x1 Tệp đối tượng có thể tái định vị
MH_EXECUTE 0x2 Tệp thực thi
MH_CORE 0x4 Ảnh core
MH_DYLIB 0x6 Thư viện dùng chung động
MH_DYLINKER 0x7 Bộ liên kết động
MH_BUNDLE 0x8 Bundle nhị phân có thể liên kết động
MH_DSYM 0xA Ảnh phục vụ dữ liệu gỡ lỗi
MH_KEXT_BUNDLE 0xB Một dạng bundle mở rộng nhân có tính lịch sử và giới hạn nền tảng
MH_FILESET 0xC Ảnh chứa tập hợp các Mach-O theo cấu trúc fileset

Các hằng số này được định nghĩa trong mach-o/loader.h.

Không phải mọi loại tệp đều có thể được khởi chạy trực tiếp như một chương trình ứng dụng.


5. Lệnh nạp (Load Commands)

5.1. Khái niệm

Load command là một thành phần thiết yếu của Mach-O.

Sau Mach header là danh sách các load command, mỗi lệnh mô tả một loại thông tin phục vụ liên kết, ánh xạ bộ nhớ, nạp chương trình hoặc quản lý siêu dữ liệu.

Apple định nghĩa cấu trúc cơ sở:

struct load_command {
    uint32_t cmd;
    uint32_t cmdsize;
};

Hai trường này có tổng kích thước 8 byte.

  • cmd: Mã xác định loại load command.
  • cmdsize: Kích thước toàn bộ command, bao gồm cả dữ liệu phụ thuộc nếu có.

Để tìm command tiếp theo, chương trình đọc nhị phân sử dụng cmdsize nhằm tính vị trí mới.

5.2. Quy tắc căn chỉnh

Theo định nghĩa của Apple:

  • Trong Mach-O 32 bit, kích thước mỗi load command phải là bội số của 4 byte.
  • Trong Mach-O 64 bit, kích thước mỗi load command phải là bội số của 8 byte.

Những byte đệm cần thiết được đặt về 0.

Ví dụ, nếu một command 64 bit chứa 27 byte dữ liệu thực tế, tổng kích thước phải được làm tròn phù hợp với yêu cầu căn chỉnh.

Việc xử lý cmdsize không hợp lệ là một vấn đề quan trọng đối với trình đọc Mach-O, bởi một giá trị sai có thể khiến bộ phân tích truy cập vượt giới hạn dữ liệu đầu vào.

5.3. Các load command quan trọng

Load Command Chức năng
LC_SEGMENT Mô tả segment 32 bit
LC_SEGMENT_64 Mô tả segment 64 bit
LC_SYMTAB Thông tin bảng ký hiệu và bảng chuỗi
LC_DYSYMTAB Thông tin ký hiệu liên quan đến liên kết động theo cơ chế truyền thống
LC_LOAD_DYLIB Khai báo phụ thuộc thư viện động
LC_ID_DYLIB Nhận diện thư viện động
LC_LOAD_DYLINKER Khai báo bộ liên kết động
LC_MAIN Thông tin điểm vào của tệp thực thi
LC_RPATH Bổ sung đường dẫn tìm thư viện
LC_UUID Mã định danh của ảnh nhị phân
LC_CODE_SIGNATURE Vị trí dữ liệu chữ ký mã
LC_BUILD_VERSION Thông tin nền tảng, phiên bản hệ điều hành tối thiểu và SDK
LC_DYLD_EXPORTS_TRIE Vị trí cấu trúc xuất ký hiệu dạng trie
LC_DYLD_CHAINED_FIXUPS Thông tin fixup dạng chuỗi
LC_FILESET_ENTRY Thông tin thành phần trong ảnh fileset

Không phải tệp Mach-O nào cũng chứa tất cả các lệnh trên.

Ví dụ, tệp đối tượng MH_OBJECT có yêu cầu khác với ảnh thực thi MH_EXECUTE.

5.4. Load command bắt buộc đối với dyld

Mach-O sử dụng cờ LC_REQ_DYLD với giá trị:

#define LC_REQ_DYLD 0x80000000

Cờ này đánh dấu những loại load command mà bộ liên kết động cần hiểu để xử lý ảnh đúng cách.

Theo mô tả trong mã nguồn Apple, nếu dyld gặp một load command được đánh dấu bắt buộc nhưng không nhận biết được, nó có thể từ chối sử dụng ảnh đó.

Cơ chế này cho phép định dạng phát triển thêm những yêu cầu mới mà không mặc nhiên chấp nhận ảnh thực thi có ngữ nghĩa không được hỗ trợ.


6. Segment và Section

6.1. Segment là gì?

Segment mô tả một vùng của tệp nhị phân được ánh xạ vào không gian địa chỉ của tiến trình.

Đối với Mach-O 64 bit, Apple định nghĩa:

struct segment_command_64 {
    uint32_t cmd;
    uint32_t cmdsize;
    char segname[16];
    uint64_t vmaddr;
    uint64_t vmsize;
    uint64_t fileoff;
    uint64_t filesize;
    vm_prot_t maxprot;
    vm_prot_t initprot;
    uint32_t nsects;
    uint32_t flags;
};

Kích thước phần cố định của cấu trúc này là 72 byte.

Nếu segment chứa các section, những bản ghi section_64 được đặt tiếp sau cấu trúc segment trong cùng load command.

6.2. Các trường của Segment Command 64 bit

Trường Kích thước Ý nghĩa
cmd 4 byte Loại command
cmdsize 4 byte Kích thước command và các section đi kèm
segname 16 byte Tên segment
vmaddr 8 byte Địa chỉ bộ nhớ ảo
vmsize 8 byte Kích thước trong bộ nhớ
fileoff 8 byte Vị trí nội dung segment trong tệp
filesize 8 byte Kích thước nội dung lưu trong tệp
maxprot 4 byte Quyền bộ nhớ tối đa
initprot 4 byte Quyền bộ nhớ ban đầu
nsects 4 byte Số section
flags 4 byte Các cờ của segment

Trong nhiều trường hợp:

Phần bộ nhớ lớn hơn lượng dữ liệu lưu trong tệp có thể được hệ thống cấp phát với giá trị ban đầu bằng 0 theo quy định của cơ chế nạp.

6.3. Section là gì?

Section là đơn vị tổ chức mã, dữ liệu hoặc siêu dữ liệu bên trong segment.

Một cấu trúc section_64 có các trường chính:

struct section_64 {
    char sectname[16];
    char segname[16];
    uint64_t addr;
    uint64_t size;
    uint32_t offset;
    uint32_t align;
    uint32_t reloff;
    uint32_t nreloc;
    uint32_t flags;
    uint32_t reserved1;
    uint32_t reserved2;
    uint32_t reserved3;
};

Kích thước cấu trúc cố định là 80 byte.

Các trường quan trọng:

Trường Chức năng
sectname Tên section
segname Tên segment chứa section
addr Địa chỉ bộ nhớ ảo của section
size Kích thước section
offset Offset dữ liệu trong tệp, đối với loại section có nội dung lưu trong tệp
align Số mũ của yêu cầu căn chỉnh
reloff Offset thông tin relocation
nreloc Số bản ghi relocation
flags Loại section và các thuộc tính
reserved1–3 Các trường bổ sung, có ý nghĩa tùy loại section

6.4. Các segment thường gặp

Segment Nội dung điển hình
__PAGEZERO Vùng địa chỉ thấp không được ánh xạ, hỗ trợ hạn chế truy cập con trỏ null
__TEXT Mã thực thi và dữ liệu chỉ đọc hoặc tương ứng với cấu trúc liên kết
__DATA Dữ liệu có thể ghi và các cấu trúc liên quan
__DATA_CONST Dữ liệu cần xử lý trong quá trình liên kết động nhưng có thể được bảo vệ sau đó
__LINKEDIT Dữ liệu hỗ trợ liên kết, ký hiệu, fixup và các cấu trúc khác

Danh sách này chỉ là những tên phổ biến, không phải toàn bộ các segment hợp lệ.

Bố cục thực tế có thể thay đổi theo phiên bản hệ điều hành, trình biên dịch, linker và kiến trúc CPU.

6.5. Các section thường gặp

Trong segment __TEXT:

Section Nội dung
__text Mã máy
__cstring Chuỗi ký tự kiểu C
__const Một số dữ liệu hằng
__stubs Những đoạn mã hỗ trợ gọi hàm hoặc liên kết, nếu có

Trong segment dữ liệu:

Section Nội dung
__data Dữ liệu có giá trị khởi tạo
__bss Dữ liệu chưa khởi tạo
__common Một số đối tượng dữ liệu theo cơ chế truyền thống
__la_symbol_ptr Vùng con trỏ ký hiệu theo cơ chế liên kết truyền thống

Tên và vị trí section không phải là một giao diện chung bất biến cho mọi thế hệ Mach-O.


7. Bảng ký hiệu và cơ chế tái định vị

7.1. Bảng ký hiệu (Symbol Table)

Mach-O hỗ trợ bảng ký hiệu để mô tả các hàm, đối tượng dữ liệu và những tên cần sử dụng trong quá trình liên kết hoặc phân tích nhị phân.

Load command LC_SYMTAB sử dụng cấu trúc:

struct symtab_command {
    uint32_t cmd;
    uint32_t cmdsize;
    uint32_t symoff;
    uint32_t nsyms;
    uint32_t stroff;
    uint32_t strsize;
};

Các trường cung cấp:

  • Vị trí bắt đầu bảng ký hiệu.
  • Số lượng bản ghi.
  • Vị trí bảng chuỗi.
  • Kích thước bảng chuỗi.

Đối với Mach-O 64 bit, một bản ghi ký hiệu truyền thống sử dụng cấu trúc nlist_64, với các trường như n_strx, n_type, n_sect, n_desc và n_value.

Kích thước của nlist_64 là 16 byte.

7.2. Phân giải ký hiệu

Giả sử chương trình gọi hàm calculate từ một thư viện khác.

Ở thời điểm biên dịch, định nghĩa của calculate có thể chưa nằm trong đơn vị đang được xử lý.

Bộ liên kết có trách nhiệm xác định ký hiệu tương ứng, theo những quy tắc về tính hiển thị, phạm vi liên kết và cơ chế nhập/xuất.

Đối với thư viện động, một phần thông tin có thể tiếp tục được sử dụng bởi dyld khi chương trình nạp hoặc thực thi.

7.3. Tái định vị

Tái định vị là quá trình xử lý các địa chỉ hoặc tham chiếu chưa thể xác định đầy đủ khi mã đối tượng được tạo ra.

Trong tệp MH_OBJECT, thông tin relocation có thể được lưu trong những bản ghi và được tham chiếu bởi các trường reloff, nreloc của section.

Loại relocation phụ thuộc vào kiến trúc CPU.

Ví dụ, cách xử lý lệnh gọi hàm và tham chiếu địa chỉ trên x86-64 không giống ARM64, bởi hai kiến trúc có cách mã hóa lệnh và phạm vi địa chỉ tương đối khác nhau.

7.4. Tái định vị và fixup có giống nhau không?

Hai thuật ngữ có quan hệ gần gũi nhưng không nên sử dụng hoàn toàn thay thế cho nhau.

  • Relocation: Thường nói đến bản ghi và phép xử lý cần thiết để điều chỉnh tham chiếu địa chỉ trong quá trình liên kết hoặc nạp.
  • Fixup: Thuật ngữ tổng quát chỉ vị trí hoặc thao tác cần điều chỉnh trong ảnh nhị phân; trong Mach-O hiện đại còn chỉ những cấu trúc dữ liệu cụ thể phục vụ dyld.

Một tệp đối tượng Mach-O có thể chứa các relocation truyền thống, trong khi một tệp thực thi hoặc thư viện động có thể sử dụng dữ liệu fixup được mã hóa bằng cấu trúc khác.


8. Liên kết động trong Mach-O

8.1. Bộ liên kết động dyld

dyld là thành phần quan trọng trong cơ chế liên kết động của hệ sinh thái Apple.

Khi một chương trình phụ thuộc vào thư viện động, những thông tin liên quan được ghi lại trong ảnh Mach-O để hệ thống có thể xác định thư viện cần thiết và xử lý những tham chiếu nhị phân.

Ví dụ, Mach-O có thể chứa các load command:

LC_LOAD_DYLIB
LC_LOAD_DYLINKER
LC_RPATH

Các command này lần lượt liên quan đến phụ thuộc thư viện, bộ liên kết động và đường dẫn tìm kiếm thư viện.

8.2. Rebase và Bind

Hai thao tác quan trọng khi xử lý ảnh nhị phân động là:

Tái cơ sở địa chỉ

Điều chỉnh các con trỏ hoặc tham chiếu khi ảnh được bố trí tại địa chỉ khác với địa chỉ cơ sở giả định.

Liên kết ký hiệu

Giải quyết tham chiếu đến ký hiệu được cung cấp bởi ảnh hoặc thư viện khác.

Trong tài liệu mã nguồn dyld, Apple mô tả sự khác biệt giữa rebase và bind trong cơ chế xây dựng shared cache: rebase áp dụng cho con trỏ hướng đến vị trí trong cùng ảnh; bind áp dụng cho tham chiếu đến thư viện khác.

8.3. Fixup dạng chuỗi (Chained Fixups)

Mach-O hiện đại hỗ trợ cấu trúc được nhận diện bằng load command:

LC_DYLD_CHAINED_FIXUPS

Command này chỉ đến dữ liệu fixup được tổ chức theo cơ chế chuỗi.

Thay vì chỉ sử dụng những danh sách relocation truyền thống, cấu trúc chained fixups cho phép mô tả và xử lý các vị trí cần điều chỉnh bằng định dạng phù hợp với các yêu cầu liên kết động hiện đại.

Các chi tiết bao gồm:

  • Thông tin bắt đầu chuỗi fixup.
  • Các định dạng con trỏ.
  • Các mục nhập ký hiệu.
  • Những trường liên quan đến rebase hoặc bind.
  • Những biến thể phục vụ các kiến trúc và yêu cầu bảo mật khác nhau.

Cần lưu ý rằng chained fixups không phải là cấu trúc bắt buộc có trong mọi tệp Mach-O thuộc mọi thời kỳ.

8.4. Cấu trúc xuất ký hiệu dạng Trie

Load command:

LC_DYLD_EXPORTS_TRIE

chỉ đến một cấu trúc dùng để biểu diễn thông tin xuất ký hiệu.

Trie là cấu trúc dữ liệu dạng cây có thể tận dụng phần tiền tố chung giữa những chuỗi tên.

Cơ chế này cho phép tổ chức thông tin xuất ký hiệu bằng một cách khác với việc chỉ sử dụng bảng ký hiệu truyền thống.

8.5. dyld Shared Cache

Hệ sinh thái Apple còn sử dụng bộ nhớ đệm thư viện dùng chung (dyld Shared Cache) để tổ chức những thư viện hệ thống và phục vụ cơ chế nạp hiệu quả hơn.

Đây không đơn thuần là một tệp Mach-O riêng lẻ.

Shared cache có định dạng và siêu dữ liệu riêng, có thể chứa hoặc tổ chức nhiều ảnh thư viện Mach-O theo những quy tắc phù hợp với trình nạp.

Nó có thể thực hiện các bước chuẩn bị và tối ưu liên kết để giảm công việc cần thực hiện khi ứng dụng khởi chạy.

Vì vậy, không nên coi cấu trúc dyld shared cache là phần mở rộng trực tiếp bắt buộc của mỗi tệp Mach-O.


9. Tệp nhị phân đa kiến trúc (Universal Binary)

9.1. Khái niệm

Universal binary là loại tệp có thể chứa những phiên bản mã máy cho nhiều kiến trúc CPU.

Ví dụ, một ứng dụng macOS có thể hỗ trợ:

  • x86-64, dành cho Mac Intel.
  • ARM64, dành cho Mac sử dụng Apple silicon.

Thay vì phân phối hai tệp thực thi riêng biệt, hệ thống xây dựng có thể đóng gói những phiên bản đã được biên dịch vào cùng một universal binary.

9.2. Universal Binary và Mach-O đơn kiến trúc

Universal binary thường được gọi là Fat Binary.

Nó có một cấu trúc chứa bên ngoài với thông tin mô tả các thành phần kiến trúc, mỗi thành phần có thể là một ảnh Mach-O riêng.

Ví dụ:

┌───────────────────────────────┐
│ Fat Header                    │
├───────────────────────────────┤
│ Architecture Table            │
│ ├─ x86_64                     │
│ └─ arm64                      │
├───────────────────────────────┤
│ Mach-O Slice: x86_64          │
├───────────────────────────────┤
│ Mach-O Slice: arm64           │
└───────────────────────────────┘

Mỗi slice có cấu trúc Mach-O tương ứng với kiến trúc của nó.

Cần lưu ý rằng bảng kiến trúc không thay thế header bên trong mỗi slice.

9.3. Cấu trúc Fat Header

Các định nghĩa truyền thống sử dụng những cấu trúc như:

struct fat_header {
    uint32_t magic;
    uint32_t nfat_arch;
};

Trong đó:

  • magic: Giá trị nhận diện định dạng fat.
  • nfat_arch: Số lượng bản ghi kiến trúc.

Một bản ghi kiến trúc dạng 32 bit:

struct fat_arch {
    cpu_type_t cputype;
    cpu_subtype_t cpusubtype;
    uint32_t offset;
    uint32_t size;
    uint32_t align;
};

Bản ghi này có kích thước 20 byte.

Các dạng fat 64 bit sử dụng những cấu trúc riêng với offset và kích thước rộng hơn.

9.4. Công cụ lipo

Apple cung cấp công cụ lipo để thao tác với các tệp nhị phân đa kiến trúc.

Ví dụ:

lipo -archs program

Hiển thị danh sách kiến trúc có trong tệp.

lipo -info program

Hiển thị thông tin tổng quát.

lipo -thin arm64 program -output program-arm64

Trích xuất slice ARM64 nếu có.

lipo -create program-x86_64 program-arm64 \
    -output program-universal

Kết hợp các ảnh tương thích thành universal binary.

Theo tài liệu Apple, việc tạo universal macOS binary cho Apple silicon và Intel sử dụng hai bản mã máy dành cho arm64 và x86_64, sau đó có thể kết hợp bằng lipo.

9.5. Vai trò trong lịch sử Apple

Universal binary có ý nghĩa đặc biệt trong các giai đoạn Apple chuyển đổi kiến trúc bộ xử lý.

Từ PowerPC sang Intel và sau đó từ Intel sang Apple silicon, cách đóng gói nhiều phiên bản mã máy giúp phần mềm có thể hỗ trợ các thế hệ thiết bị khác nhau.

Tuy nhiên, universal binary không tự động chuyển đổi mã máy giữa các kiến trúc.

Mỗi slice phải được biên dịch cho kiến trúc đích tương ứng.


10. Điểm vào và quá trình nạp chương trình

10.1. Điểm vào (Entry Point)

Một chương trình thực thi cần cung cấp thông tin để hệ thống xác định nơi bắt đầu quá trình chạy.

Trong Mach-O, một cơ chế hiện đại sử dụng:

LC_MAIN

Cấu trúc tương ứng:

struct entry_point_command {
    uint32_t cmd;
    uint32_t cmdsize;
    uint64_t entryoff;
    uint64_t stacksize;
};

Các trường chính:

Trường Chức năng
cmd Nhận diện LC_MAIN
cmdsize Kích thước command
entryoff Offset điểm vào theo quy ước của command
stacksize Kích thước stack ban đầu được yêu cầu, nếu khác 0

Trong mô hình sử dụng LC_MAIN, entryoff được mô tả theo offset liên quan đến segment __TEXT.

Không nên mặc nhiên hiểu đây là địa chỉ ảo tuyệt đối của hàm main.

10.2. Chu trình nạp tổng quát

Một chu trình thực thi Mach-O có thể được trình bày ở mức khái quát:

Tệp Mach-O
     │
     ▼
Kiểm tra định dạng và kiến trúc
     │
     ▼
Đọc Header và Load Commands
     │
     ▼
Thiết lập các vùng bộ nhớ
     │
     ▼
Xử lý thông tin nạp và liên kết động
     │
     ▼
Chuẩn bị môi trường thực thi
     │
     ▼
Chuyển quyền điều khiển đến mã khởi động
     │
     ▼
Chương trình thực thi

Các bước này không phải lúc nào cũng diễn ra thành chuỗi tuần tự đơn giản.

Một phần công việc thuộc về nhân hệ điều hành, một phần thuộc về dyld, runtime hoặc những cơ chế khởi động khác.

10.3. Mach-O và ASLR

Ngẫu nhiên hóa bố trí không gian địa chỉ (Address Space Layout Randomization – ASLR) là kỹ thuật bảo mật giúp thay đổi vị trí nạp của các vùng bộ nhớ.

Một ảnh Mach-O được thiết kế phù hợp có thể được nạp với độ dịch địa chỉ so với địa chỉ cơ sở dự kiến.

Các tham chiếu cần điều chỉnh sẽ được xử lý theo thông tin fixup và quy tắc của nền tảng.

Tuy nhiên, Mach-O chỉ là một thành phần của cơ chế này. Khả năng áp dụng ASLR còn phụ thuộc vào hệ điều hành, thuộc tính nhị phân, kiến trúc và những chính sách liên quan.


11. Chữ ký mã và các yêu cầu bảo mật

11.1. Chữ ký mã (Code Signing)

Mach-O có thể chứa thông tin về chữ ký mã thông qua load command:

LC_CODE_SIGNATURE

Command này chỉ đến vùng dữ liệu chứa thông tin chữ ký.

Bản thân command không có nghĩa tất cả các byte chữ ký đều nằm trong cấu trúc command; nó cung cấp vị trí và kích thước của dữ liệu tương ứng.

11.2. Vai trò của chữ ký mã

Chữ ký mã có thể được sử dụng để:

  • Kiểm tra tính toàn vẹn của mã.
  • Xác định thông tin danh tính ký mã theo cơ chế nền tảng.
  • Hỗ trợ những chính sách bảo mật của hệ điều hành.
  • Phục vụ quy trình phân phối và thực thi phần mềm.

Yêu cầu về chữ ký mã khác nhau giữa các nền tảng Apple và các loại mã thực thi.

Không nên xem việc một tệp có LC_CODE_SIGNATURE là điều kiện đủ để kết luận tệp đó sẽ được hệ điều hành cho phép chạy.

11.3. Quan hệ giữa định dạng và bảo mật

Mach-O lưu trữ dữ liệu và siêu dữ liệu cần thiết.

Việc kiểm tra chữ ký, áp dụng chính sách bảo mật và quyết định cho phép thực thi thuộc về những cơ chế của hệ điều hành và môi trường thực thi.

Do đó, một tệp Mach-O hợp lệ về mặt cấu trúc chưa chắc đã hợp lệ về mặt chính sách thực thi.


12. So sánh Mach-O, ELF và PE/COFF

12.1. Bảng so sánh tổng quát

Tiêu chí Mach-O ELF PE/COFF
Hệ sinh thái tiêu biểu Apple Linux và nhiều hệ Unix Windows
Nhận diện Magic Number ELF Magic MZ/PE và COFF
Header chính Mach Header ELF Header DOS/PE/COFF Header
Mô tả ánh xạ Segment Load Commands Program Headers Section Table và cơ chế ảnh PE
Tổ chức mã và dữ liệu Segments và Sections Segments và Sections Sections
Thông tin ký hiệu Mach-O Symbol Table và dữ liệu liên kết ELF Symbol Tables COFF Symbols và PE Export/Import
Liên kết động dyld và dữ liệu Mach-O Bộ nạp liên kết động ELF Windows Loader
Đa kiến trúc Fat/Universal Binary Thông thường một ảnh ELF cho một kiến trúc Thông thường một ảnh PE cho một kiến trúc
Thông tin phiên bản nền tảng Các load command phù hợp ABI, note và cơ chế riêng của nền tảng Header, subsystem và metadata liên quan

12.2. Khác biệt về triết lý cấu trúc

Mach-O nổi bật bởi hệ thống load command, trong đó nhiều loại dữ liệu quan trọng được khai báo thông qua các command có kiểu riêng.

ELF nhấn mạnh hai cách nhìn:

  • Cách nhìn liên kết với section header.
  • Cách nhìn thực thi với program header.

PE tổ chức ảnh thực thi bằng hệ thống header, bảng section và những data directory chỉ đến các cấu trúc như import, export và relocation.

Ba định dạng đều có khả năng biểu diễn chương trình thực thi, nhưng chúng không có cấu trúc nhị phân hoán đổi trực tiếp cho nhau.

12.3. Có thể đổi Mach-O thành ELF bằng cách sửa header không?

Không thể thực hiện một cách tổng quát chỉ bằng việc thay magic number hoặc thay header.

Bởi các định dạng còn khác nhau ở:

  • Cấu trúc section và segment.
  • Loại relocation.
  • Quy ước ký hiệu.
  • Cách mô tả phụ thuộc thư viện.
  • ABI và quy ước thực thi.
  • Điểm vào chương trình.
  • Cơ chế nạp của hệ điều hành.

Nếu cần chuyển một chương trình từ macOS sang Linux, giải pháp thông thường là biên dịch và liên kết lại cho ABI và định dạng đích, đồng thời xử lý những phụ thuộc vào API của hệ điều hành.


13. Phân tích tệp Mach-O bằng công cụ thực tế

13.1. Tạo chương trình thử nghiệm

Tạo tệp hello.c:

#include <stdio.h>

int mainvoid {
    puts("Hello, Mach-O!");
    return 0;
}

Trên macOS có cài đặt công cụ biên dịch phù hợp:

clang hello.c -o hello

Kết quả thường là tệp thực thi Mach-O cho kiến trúc được chọn.

13.2. Nhận diện định dạng

Sử dụng:

file hello

Công cụ có thể hiển thị thông tin như loại định dạng, kiến trúc và đặc điểm của tệp.

Không nên cố định một chuỗi kết quả cụ thể, vì kết quả phụ thuộc vào kiến trúc máy, hệ điều hành và tùy chọn biên dịch.

13.3. Đọc Mach Header

Sử dụng:

otool -hv hello

Thông tin thường bao gồm:

  • Magic Number.
  • CPU Type.
  • CPU Subtype.
  • File Type.
  • Số lượng load command.
  • Tổng kích thước load commands.
  • Các cờ.

13.4. Đọc Load Commands

Sử dụng:

otool -l hello

Đây là lệnh quan trọng để khảo sát cấu trúc của tệp Mach-O.

Có thể kiểm tra:

LC_SEGMENT_64
LC_LOAD_DYLIB
LC_MAIN
LC_BUILD_VERSION
LC_CODE_SIGNATURE

Danh sách thực tế thay đổi theo cách xây dựng chương trình.

13.5. Kiểm tra phụ thuộc thư viện

Sử dụng:

otool -L hello

Công cụ sẽ liệt kê những thư viện động liên quan được biểu diễn trong ảnh Mach-O.

Thông tin này hữu ích khi phân tích lỗi liên kết động hoặc khả năng triển khai chương trình.

13.6. Kiểm tra ký hiệu

Sử dụng:

nm hello

Có thể thêm những tùy chọn thích hợp để lọc ký hiệu.

Tuy nhiên, một tệp nhị phân đã bị loại bỏ ký hiệu (Stripped Binary) có thể không còn đầy đủ bảng ký hiệu truyền thống phục vụ việc kiểm tra.

13.7. Kiểm tra kiến trúc

Sử dụng:

lipo -info hello

hoặc:

lipo -archs hello

Những lệnh này giúp xác định tệp chứa một hay nhiều kiến trúc được hỗ trợ.

13.8. Đọc cấu trúc với LLVM

LLVM cung cấp những công cụ phân tích có thể xử lý Mach-O, tùy phiên bản và cấu hình:

llvm-objdump --macho --private-headers hello

Kiểm tra mã hợp ngữ:

llvm-objdump --disassemble hello

Kiểm tra nội dung section có thể thực hiện bằng những tùy chọn tương ứng của công cụ.

Khi nghiên cứu chương trình đa kiến trúc, cần bảo đảm đang phân tích đúng slice.


14. Những yêu cầu đối với trình đọc và trình sinh Mach-O

14.1. Trình đọc Mach-O

Một trình đọc Mach-O cần xử lý ít nhất các bước:

  1. Đọc magic number.
  2. Xác định tệp thin Mach-O hay fat binary.
  3. Xác định thứ tự byte và loại header.
  4. Kiểm tra kích thước tối thiểu.
  5. Đọc Mach header.
  6. Xác minh ncmds và sizeofcmds.
  7. Duyệt load commands.
  8. Kiểm tra offset và kích thước segment, section.
  9. Đọc những bảng ký hiệu hoặc dữ liệu bổ sung khi cần.
  10. Phát hiện cấu trúc không hợp lệ hoặc nằm ngoài giới hạn tệp.

Việc kiểm tra kích thước phải tránh tràn số nguyên.

Ví dụ, khi xác định một vùng tệp:

Trong triển khai an toàn, nên kiểm tra theo dạng không phát sinh tràn phép cộng, chẳng hạn xác minh offset không vượt fileSize, rồi kiểm tra size không lớn hơn fileSize - offset.

14.2. Trình sinh Mach-O

Một trình biên dịch hoặc linker có khả năng trực tiếp tạo Mach-O phải xây dựng đúng những cấu trúc cần thiết.

Đối với tệp đối tượng, những nhiệm vụ thường bao gồm:

  • Tạo Mach header.
  • Xác định kiến trúc CPU.
  • Tạo segment và section phù hợp.
  • Bố trí mã máy và dữ liệu.
  • Xây dựng ký hiệu.
  • Tạo bản ghi relocation.
  • Tính toán các offset và kích thước.

Đối với ảnh thực thi, công việc còn có thể bao gồm:

  • Thiết lập bố cục segment theo quy tắc nạp.
  • Tạo thông tin điểm vào.
  • Mô tả phụ thuộc thư viện động.
  • Tạo metadata cho dyld.
  • Đáp ứng yêu cầu phiên bản nền tảng.
  • Bố trí hoặc bổ sung chữ ký mã khi môi trường yêu cầu.

Cần phân định việc tạo tệp Mach-O đúng đặc tả và việc tạo một ứng dụng Apple có thể phân phối và thực thi thành công. Mục tiêu thứ hai còn liên quan đến SDK, ABI, runtime, chính sách bảo mật và công cụ nền tảng.

14.3. Kiểm thử tính tương thích

Những trường hợp kiểm thử quan trọng bao gồm:

Trường hợp Mục tiêu
Mach-O 64 bit hợp lệ Đọc đúng header và load commands
Tệp bị cắt ngắn Từ chối truy cập ngoài giới hạn
cmdsize bằng 0 Ngăn vòng lặp vô hạn hoặc xử lý sai
Load command sai căn chỉnh Phát hiện vi phạm quy tắc định dạng
Offset vượt kích thước tệp Phát hiện dữ liệu không hợp lệ
Fat binary nhiều kiến trúc Chọn đúng slice
Section không có nội dung vật lý Xử lý đúng loại section zerofill
Relocation khác kiến trúc Đọc đúng định dạng và loại relocation
Tệp có chained fixups Xác định đúng dữ liệu fixup
Tệp có chữ ký mã Đọc đúng vị trí và kích thước dữ liệu liên quan

15. Kết luận

Mach-O là một định dạng nhị phân quan trọng trong hệ sinh thái Apple, được sử dụng từ quá trình biên dịch và liên kết đến nạp và thực thi chương trình.

Định dạng này có nguồn gốc gắn với lịch sử hệ thống Mach và NeXT, sau đó tiếp tục phát triển trong Mac OS X, macOS và những nền tảng Apple khác.

Điểm đặc trưng nhất của Mach-O là hệ thống tổ chức dựa trên Mach header, load commands, segments và sections. Cách tổ chức này cho phép tệp mô tả không chỉ mã máy và dữ liệu, mà còn nhiều thông tin về liên kết động, nền tảng đích, điểm vào và những yêu cầu bảo mật.

Mach-O cũng hỗ trợ mô hình universal binary, trong đó nhiều ảnh nhị phân dành cho các kiến trúc CPU khác nhau được đóng gói trong cùng một tệp chứa.

Cùng với sự phát triển của dyld, các cấu trúc như chained fixups và export trie cho thấy định dạng Mach-O tiếp tục thích ứng với những yêu cầu mới của hệ thống nạp và liên kết.

Đối với nghiên cứu trình biên dịch, linker và hệ điều hành, hiểu Mach-O là cơ sở để giải thích cách mã máy được tổ chức thành một ảnh có thể được hệ thống tiếp nhận, ánh xạ và thực thi.

Tuy nhiên, Mach-O chỉ là một phần của giao diện nhị phân giữa chương trình và hệ điều hành. Việc thực thi còn phụ thuộc vào ABI, kiến trúc CPU, thư viện runtime và những chính sách của nền tảng.


Phụ lục A. Thuật ngữ kỹ thuật

Thuật ngữ tiếng Việt Thuật ngữ tiếng Anh Ý nghĩa
Định dạng Mach-O Mach Object Định dạng tệp đối tượng và ảnh nhị phân trong hệ sinh thái Apple
Header Mach Mach Header Cấu trúc thông tin tổng quát của tệp
Lệnh nạp Load Command Bản ghi mô tả thông tin phục vụ nạp, liên kết hoặc xử lý tệp
Vùng ánh xạ Segment Vùng tệp được mô tả để ánh xạ hoặc xử lý trong bộ nhớ
Mục dữ liệu Section Đơn vị tổ chức mã hoặc dữ liệu trong segment
Bảng ký hiệu Symbol Table Cấu trúc lưu thông tin về ký hiệu
Tái định vị Relocation Điều chỉnh các tham chiếu địa chỉ
Hiệu chỉnh tham chiếu Fixup Dữ liệu hoặc thao tác điều chỉnh tham chiếu nhị phân
Liên kết động Dynamic Linking Kết nối thư viện theo cơ chế nạp và thực thi
Bộ liên kết động Dynamic Linker Thành phần xử lý liên kết thư viện động
Tệp nhị phân đa kiến trúc Universal Binary Tệp chứa nhiều ảnh dành cho các kiến trúc khác nhau
Thành phần kiến trúc Architecture Slice Một ảnh Mach-O dành cho một kiến trúc trong fat binary
Điểm vào Entry Point Vị trí bắt đầu chu trình thực thi chương trình
Ngẫu nhiên hóa không gian địa chỉ Address Space Layout Randomization Cơ chế thay đổi vị trí nạp nhằm tăng cường bảo mật
Chữ ký mã Code Signing Dữ liệu và cơ chế xác minh mã theo chính sách nền tảng
Giao diện nhị phân ứng dụng Application Binary Interface Tập hợp quy tắc tương tác nhị phân giữa chương trình và môi trường thực thi

Phụ lục B. Tài liệu tham khảo

B.1. Đặc tả và mã nguồn chính thức của Apple

[1] Apple, mach-o/loader.h, mã nguồn XNU.

Nguồn định nghĩa trực tiếp các cấu trúc Mach header, segment command, section, load command và nhiều hằng số liên quan đến định dạng Mach-O.

https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h

[2] Apple, mach-o/fat.h.

Nguồn định nghĩa cấu trúc fat binary, bao gồm header và các bản ghi kiến trúc.

https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/fat.h

[3] Apple, mach-o/nlist.h.

Định nghĩa các bản ghi ký hiệu Mach-O và những thuộc tính liên quan.

https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/nlist.h

[4] Apple, Mach-O Documentation.

Các tài liệu kỹ thuật về định dạng Mach-O, cấu trúc ảnh nhị phân và cơ chế nạp.

https://developer.apple.com/documentation/kernel/mach-o

B.2. Liên kết động và fixup

[5] Apple, dyld, mã nguồn công khai.

Mã nguồn bộ liên kết động và các thành phần xử lý ảnh nhị phân thuộc hệ sinh thái Apple.

https://github.com/apple-oss-distributions/dyld

[6] Apple, MachOFile.cpp.

Mã nguồn xử lý và kiểm tra nhiều cấu trúc Mach-O, bao gồm thông tin liên kết và fixup.

https://github.com/apple-oss-distributions/dyld/blob/main/common/MachOFile.cpp

[7] Apple, fixup-chains.h.

Định nghĩa nhiều cấu trúc phục vụ chained fixups.

https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/fixup-chains.h

[8] Apple, Cache Builder.

Tài liệu mô tả những cơ chế liên quan đến xây dựng dyld shared cache và xử lý fixup.

https://github.com/apple-oss-distributions/dyld/blob/main/doc/CacheBuilder.md

B.3. Universal Binary

[9] Apple Developer Documentation, Building a universal macOS binary.

Tài liệu chính thức về cách xây dựng chương trình hỗ trợ cả Intel và Apple silicon, sử dụng các kiến trúc x86-64 và ARM64.

https://developer.apple.com/documentation/apple-silicon/building-a-universal-macos-binary

B.4. Công cụ và tài liệu bổ sung

[10] LLVM Project, LLVM Object File Formats.

Mã nguồn và công cụ liên quan đến việc đọc, ghi hoặc phân tích nhiều định dạng tệp đối tượng.

https://llvm.org/

[11] LLVM Project, Mach-O LLD Port.

Tài liệu về phần triển khai linker Mach-O trong LLVM.

https://lld.llvm.org/MachO/index.html

[12] John R. Levine, Linkers and Loaders, Morgan Kaufmann, 1999.

Công trình chuyên khảo về liên kết và nạp chương trình, cung cấp nền tảng để nghiên cứu các định dạng nhị phân.


Chú thích

  1. Apple, mach-o/loader.h, các định nghĩa mach_header, mach_header_64, load_command, segment_command_64, section_64 và các hằng số Mach-O. https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/loader.h ↩
  2. Apple, mach-o/fat.h, các định nghĩa cấu trúc fat binary và bản ghi kiến trúc. https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/fat.h ↩
  3. Apple, mach-o/nlist.h, định nghĩa bảng ký hiệu Mach-O. https://github.com/apple-oss-distributions/xnu/blob/main/EXTERNAL_HEADERS/mach-o/nlist.h ↩
  4. Apple, dyld, tài liệu và mã nguồn xử lý thông tin liên kết động. https://github.com/apple-oss-distributions/dyld ↩
  5. Apple, Building a universal macOS binary, tài liệu về các kiến trúc ARM64, x86-64 và công cụ lipo. https://developer.apple.com/documentation/apple-silicon/building-a-universal-macos-binary ↩
  6. Apple, fixup-chains.h, những định nghĩa phục vụ chained fixups. https://github.com/apple-oss-distributions/dyld/blob/main/include/mach-o/fixup-chains.h ↩
  7. Apple, Cache Builder, những cơ chế xử lý rebase, bind và shared cache. https://github.com/apple-oss-distributions/dyld/blob/main/doc/CacheBuilder.md ↩

Ghi chú về phạm vi đặc tả

Mach-O là định dạng tiếp tục được phát triển thông qua các phiên bản SDK, hệ điều hành và công cụ của Apple. Những cấu trúc được định nghĩa trong mã nguồn công khai có giá trị quan trọng để nghiên cứu, nhưng không có nghĩa mọi chi tiết triển khai nội bộ đều là một giao diện ổn định được cam kết cho phần mềm bên thứ ba.

Đặc biệt, những chương trình tự tạo tệp Mach-O cần đối chiếu quy định của SDK và hệ điều hành đích, thay vì giả định một cấu trúc hợp lệ trên phiên bản macOS nhất định sẽ luôn được chấp nhận trên mọi nền tảng Apple.