Skip to content

Latest commit

 

History

History
1007 lines (730 loc) · 36.9 KB

objective-c_abi.md

File metadata and controls

1007 lines (730 loc) · 36.9 KB

The Objective-C ABI

There are several Objective-C runtimes and ABIs available:

  • Apple/NeXT runtime
    • Legacy ABI, version 0 - The traditional 32-bit ABI without support for Objective-C 2.0 features. Used on the old PowerPC platform
    • Legacy ABI, version 1 - The traditional 32-bit ABI with support for Objective-C 2.0 features. Used on macOS 32-bit
    • Modern ABI, version 2 - The modern 64-bit ABI. Used on all other Apple platforms
  • GNU runtime - used on non-Apple platforms

This document describes the Apple runtime with the modern ABI on macOS x86-64, as implemented by the Apple LLVM compiler (11.0.3 (clang-1103.0.32.62)) shipped with Xcode 11.7. The information in this document has been obtained by reading the documentation provided by Apple, looking at assembly outputs and object dumps from the LLVM compiler.

Objective-C is a superset of C, therefore any of the language constructs that also exist in C, like functions, structs, and variables use the C ABI of the platform. This document only describes the ABI of the Objective-C specific language constructs.

Messages

The Objective-C model of object-oriented programming is based on message passing to object instances. Unlike D or C++ where a method is called. The difference from an implementation standpoint is that in D and C++ a vtable is used which is an array of function pointers and the compiler uses an index into that array to determine which method to call. In Objective-C, it's the runtime that is responsible for finding the correct implementation when a message is sent to an object. A method is identified by a selector, a null-terminated string representing its name, which maps to a C function pointer that implements the method.

Message Expression

In Objective-C, sending a message to an object looks like the following example:

int result = [receiver message];

In D it would look like:

int result = receiver.message();

The compiler implements this by making a regular C call to the objc_msgSend function in the Objective-C runtime. The signature of objc_msgSend looks something like this:

id objc_msgSend(id self, SEL op, ...);
  • The first parameter is the receiver (this/self pointer)
  • The second parameter is the name of the method mentioned in the message - that is, the method selector
  • The last parameter is for all the arguments that the implementation expects

The above example would be translated by the compiler to the following:

int result = objc_msgSend(receiver, selector);

If the method expects any arguments they're passed after the selector argument:

int result = objc_msgSend(receiver, selector, arg1, arg2);

The call to objc_msgSend should not be performed as a variadic call but instead, as if the objc_msgSend function had the same signature as the method that should be called but with the two additional parameters, self and op, added first. The implementation of objc_msgSend will jump to the method instead of calling it.

Because of the above, multiple versions of objc_msgSend exist. Depending on the return type of the method that is called, the correct version will be used. This depends on the platform C ABI. This is a list of functions for which return types they're used:

  • objc_msgSend_stret - Used for structs too large to be returned in registries
  • objc_msgSend_fpret - Used for long double
  • objc_msgSend_fp2ret - Used for _Complex long double
  • objc_msgSend - Used for everything else

Returning a Struct

If a struct is small enough to be returned in registers (according to the platform C ABI), the regular objc_msgSend function is used. If the struct will not fit in registers, the objc_msgSend_stret function is used. The signature of objc_msgSend_stret looks like this:

void objc_msgSend_stret(void * stretAddr, id self, SEL op, ...);

In the above signature, stretAddr is the address to a struct on the stack of the caller, which will be the returned value. The compiler calls this function like:

struct Foo foo;
objc_msgSend_stret(&foo, receiver, selector);

Super Calls

Making a super call is similar to making a regular call to an instance method. Instead of the objc_msgSend family of functions, the objc_msgSendSuper family is used. There are two functions available:

  • objc_msgSendSuper_stret - Used for structs too large to be returned in registries
  • objc_msgSendSuper - For everything else

The signature of objc_msgSendSuper is:

id objc_msgSend(struct objc_super* super, SEL op, ...);

And for objc_msgSendSuper_stret:

id objc_msgSend(void* stretAddr, struct objc_super* super, SEL op, ...);

The objc_super struct looks as follows:

struct objc_super
{
    id receiver;
    Class super_class;
}

Where receiver is the this pointer and super_class is the super class to call. super_class should be a L_OBJC_CLASSLIST_REFERENCES_$_ symbol.

Metaclass

All classes in Objective-C are themselves objects. A class object is an instance of the class' metaclass. Metaclasses follow their own inheritance chain. A metaclass inherits from the metaclass of the class' superclass. This continues all the way up to the root class (which in most cases is the NSObject class). The metaclass of the root class is an instance of itself.

Below is a diagram of the inheritance and instance relationships between classes and metaclasses:

┌──────────┬─────────────────────────┬─────────────────────────┐
│          │                         │                         │
│          │                         │                         │
│  ┌──────────────┐          ┌──────────────┐          ┌──────────────┐
│  │              │          │              │          │              │
│  │  NSObject's  │          │    Foo's     │          │    Bar's     │
├─▶│  metaclass   │◀─ ─ ─ ─ ─│  metaclass   │◀ ─ ─ ─ ─ │  metaclass   │
   │              │          │              │          │              │
│  └──────────────┘          └──────────────┘          └──────────────┘
           ▲                         ▲                         ▲
│          │                         │                         │
           │                         │                         │
│          │                         │                         │
           │                         │                         │
│  ┌──────────────┐          ┌──────────────┐          ┌──────────────┐
   │              │          │              │          │              │
│  │   NSObject   │          │     Foo      │          │     Bar      │
 ─▶│              │◀─ ─ ─ ─ ─│              │◀─ ─ ─ ─ ─│              │
   │              │          │              │          │              │
   └──────────────┘          └──────────────┘          └──────────────┘
           ▲                         ▲                         ▲
           │                         │                         │
           │                         │                         │
           │                         │                         │
   ┌──────────────┐          ┌──────────────┐          ┌──────────────┐
   │              │          │              │          │              │
   │ instance of  │          │ instance of  │          │ instance of  │
   │   NSObject   │          │     Foo      │          │     Bar      │
   │              │          │              │          │              │
   └──────────────┘          └──────────────┘          └──────────────┘


   an object ─────────▶ its class
   a class   ─ ─ ─ ─ ─▶ its superclass

Messaging a Class Method

Calling a class method, or a static method, in a language like D or C++ is basically the same as calling a free function. It's just scoped differently in the source code and might have a different mangled name.

Since Objective-C classes are themselves objects, messaging a class method is implemented exactly the same as messaging an instance method, it's just a different this pointer. The this pointer should be a L_OBJC_CLASSLIST_REFERENCES_$_ symbol.

Instance Variables

To solve the fragile base class problem instance variables are accessed with an offset through a symbol generated in the binary. The compiler outputs the symbol containing a static offset and, if there's a need, at load time the offset will be updated to reflect the new offset if a base class has a different layout at runtime.

The symbol has the name _OBJC_IVAR_$_<class_name>.<ivar_name> symbol, where <class_name> is the name of the class the instance variable belongs to and <ivar_name> is the name of the instance variable.

Protocols

Protocols in Objective-C corresponds to interfaces in a language like D or Java. Protocols support some features not available in these other languages:

  • Properties
  • Class Methods - Since class methods are virtual and overridable in Objective-C, it falls natural that protocols can have class methods that can be implemented.
  • Optional Methods - An optional method is a method that does not need to be implemented when the protocol is implemented. The class that implements the protocol is free to implement the optional method if it's suitable. When calling an optional method on a protocol, no compile time check will be performed to verify that the method is implemented. Instead, a runtime check is performed. If the method is not implemented an exception will be thrown. It's possible to check at runtime if a method is implemented by calling the respondsToSelector: method.

Section Data Types

This describes the various types that are store as data for various sections.

__method_list_t

This type is used to store a list of methods.

struct __method_list_t
{
  int entsize;
  int count;
  _objc_method first;
}

entsize

The size of _objc_method in bytes, always 24.

count

The number of methods in the list.

first

The first method.

_objc_method

This type is used to a single method.

struct _objc_method
{
  char* name;
  char* types;
  void* imp;
}

name

The name of the method. This is stored as a reference to the L_OBJC_METH_VAR_NAME_.<number> symbol, where <number> is an incrementing number.

types

The type encoding of the method. This is stored as a reference to the L_OBJC_METH_VAR_TYPE_.<number> symbol, where <number> is an incrementing number.

imp

The actual method implementation. The address to the function that is the method implementation.

_objc_protocol_list

This type is used to store a list of protocols.

struct _objc_protocol_list
{
    long count;
    _protocol_t*[count] list;
    _protocol_t* __unknown;
}

count

The number of protocols in the list.

list

The list of protocols. Each item in the list is store as a reference to a __OBJC_PROTOCOL_$_ symbol.

__unknown

Unknown. Seems to always be null.

_protocol_t

This type is used to store a protocol.

struct _protocol_t
{
    void* isa;
    char* name;
    _objc_protocol_list* protocols;
    __method_list_t* instanceMethods;
    __method_list_t* classMethods;
    __method_list_t* optionalInstanceMethods;
    __method_list_t* optionalClassMethods;
    _prop_list_t* instanceProperties;
    int size = _protocol_t.sizeof;
    int flags;
    char** extendedMethodTypes;
    char* demangledName;
    _prop_list_t* classProperties;
}

isa

Unknown. Seems to always be null.

name

The name of the protocol. This is stored as a reference to a L_OBJC_CLASS_NAME_ symbol.

protocols

A list of the protocols this protocols inherits from. This is stored as a reference to a __OBJC_$_PROTOCOL_REFS_. If the protocol doesn't inherit from any protocols, null is stored instead.

instanceMethods

A list of the instance methods this protocol contains. This is stored as a reference to a __OBJC_$_PROTOCOL_INSTANCE_METHODS_ symbol. If the protocol doesn't contain any instance methods, null is stored instead.

classMethods

A list of the class methods this protocol contains. This is stored as a reference to a __OBJC_$_PROTOCOL_CLASS_METHODS_ symbol. If the protocol doesn't contain any class methods, null is stored instead.

optionalInstanceMethods

A list of the optional instance methods this protocol contains. This is stored as a reference to a __OBJC_$_PROTOCOL_INSTANCE_METHODS_OPT_ symbol. If the protocol doesn't contain any optional instance methods, null is stored instead.

optionalClassMethods

A list of the optional class methods this protocol contains. This is stored as a reference to a __OBJC_$_PROTOCOL_CLASS_METHODS_OPT_ symbol. If the protocol doesn't contain any class methods, null is stored instead.

instanceProperties

A list of the instance properties this protocol contains.

size

The size of _protocol_t in bytes, always 96.

flags

Unknown. Seems to always be 0.

extendedMethodTypes

A list of the method types for the methods this protocol contains. This is stored as a reference to a __OBJC_$_PROTOCOL_METHOD_TYPES_ symbol. If the protocol doesn't contain any methods, null is stored instead.

demangledName

Unknown. Seems to always be null.

classProperties

A list of the class properties this protocol contains.

Symbols

Linkages

External Linkage

Externally visible function.

Internal Linkage

Rename collisions when linking (static functions).

Private Linkage

Like Internal, but omit from the symbol table.

Linkeonce Linkage

Globals with linkonce linkage are merged with other globals of the same name when linkage occurs. Unreferenced linkonce globals are allowed to be discarded.

Weak Linkage

weak linkage has the same merging semantics as Linkeonce linkage, except that unreferenced globals with weak linkage may not be discarded.

Visibility

Default

The default visibility style. This means that the declaration is visible to other modules.

Hidden

Two declarations of an object with hidden visibility refer to the same object if they are in the same shared object. Usually, hidden visibility indicates that the symbol will not be placed into the dynamic symbol table, so no other module (executable or shared library) can reference it directly.

L_OBJC_METH_VAR_NAME_

For each selector that is used, a symbol is generated in the resulting binary. The symbol has the name L_OBJC_METH_VAR_NAME_.<number>, where <number> is an incrementing number. The selector is stored as a null-terminated C string as the section data.

Section Linkage Alignment
__objc_methname Private 1

L_OBJC_METH_VAR_TYPE_

For each method that is defined, a symbol is generated in the resulting binary. The symbol has the name L_OBJC_METH_VAR_TYPE_.<number>, where <number> is an incrementing number. The section data contains the return type and the parameter types encoded as a null-terminated C string as according to the Type Encoding documentation provided by Apple.

Section Linkage Alignment
__objc_methtype Private 1

l_OBJC_$_INSTANCE_METHODS_/l_OBJC_$_CLASS_METHODS_

For each class that is defined and contains at least one class (static) method, a symbol is generated in the resulting binary. The symbol has the name l_OBJC_$_CLASS_METHODS_<class_name>, where <class_name> is the name of the class. For each class that is defined and contains at least one instance method, a symbol is generated with the name l_OBJC_$_INSTANCE_METHODS_<class_name>, where <class_name> is the name of the class. The section data that is stored corresponds to the __method_list_t type.

Section Linkage Alignment
__objc_const Private 8

L_OBJC_SELECTOR_REFERENCES_

For each L_OBJC_METH_VAR_NAME_ symbol that is generated, a corresponding symbol is generated as well. The symbol has the name L_OBJC_SELECTOR_REFERENCES_.<number>, where <number> is an incrementing number. The section data that is stored is a reference to the corresponding L_OBJC_METH_VAR_NAME_.

Section Linkage Alignment
__objc_selrefs Private 8

L_OBJC_CLASSLIST_REFERENCES_$_

For each externally defined class that is referenced, a symbol is generated in the resulting binary. The symbol has the name L_OBJC_CLASSLIST_REFERENCES_$_.<number>, where <number> is an incrementing number. The content of the symbol is a reference to an externally defined symbol with the name _OBJC_CLASS_$_<class_name>, where <class_name> is the name of the class.

Section Linkage Alignment
__objc_classrefs Private 8

L_OBJC_IMAGE_INFO

For any binary that is built, the L_OBJC_IMAGE_INFO symbols are generated. The section data that is stored corresponds to the following struct:

struct ObjcImageInfo
{
    int version_ = 0;
    int flags = 64;
}

version

Seems to always be fixed.

flags

Indicates if features like garbage collector, automatic reference counting (ARC) or class properties are supported. These features can be enabled/disabled in the Clang compiler using command line switches. The exact values used, or the features supported, are not known. The value of 64 is what Clang 9.0 outputs by default when no switches are specified.

Section Linkage Alignment
__objc_imageinfo Private 8

L_OBJC_CLASS_NAME_

For each class defined, a symbol is generated in the resulting binary. The symbol has the name L_OBJC_CLASS_NAME_.<number>, where <number> is an incrementing number. The name of the class is stored as a null-terminated C string as the section data.

Section Linkage Alignment
__objc_classname Private 8

l_OBJC_CLASS_RO_$_/l_OBJC_METACLASS_RO_$_

For each class defined, two symbols are generated in the resulting binary. One symbols with the name l_OBJC_CLASS_RO_$_<class_name> and one with the name l_OBJC_METACLASS_RO_$_<class_name>, where <class_name> is the name of the class. The first symbol is for the class and the second symbol is for the metaclass. The section data that is stored corresponds to the following struct:

struct _class_ro_t
{
    int flags;
    int instanceStart = 40;
    int instanceSize = 40;
    byte* reserved;
    byte* ivarLayout;
    char* name;
    __method_list_t* baseMethods;
    _objc_protocol_list* baseProtocols;
    _ivar_list_t* ivars;
    byte* weakIvarLayout;
    _prop_list_t* baseProperties;
}

flags

A bit field indicating if the class is a regular class, metaclass or root class. Possible flags:

  • regular class: 0
  • metaclass: 0x00001
  • root class: 0x00002

instanceStart

The start of the instance, in bytes. For a metaclass, this is always 40. For a class without instance variables it's the size of the class declaration. Otherwise, it's the offset of the first instance variable.

instanceSize

The size of an instance of this class, in bytes. For a metaclass, this is always 40.

reserved

Currently not used. Reserved for future use.

ivarLayout

Unknown. Seems to be null.

name

The name of the class. This is stored as a reference to the L_OBJC_CLASS_NAME_<class_name> symbol, where <class_name> is the name of the class.

baseMethods

A list of the class (static) methods this class contains. This is stored as a reference to the l_OBJC_$_CLASS_METHODS_<class_name> symbol, where <class_name> is the name of the class. If the class doesn't contain any class methods, null is stored instead.

baseProtocols

A list of the protocols this class implements. This is stored a references to the __OBJC_CLASS_PROTOCOLS_$_<class_name> symbol, where <class_name> is the name of the class. If the class doesn't implement any protocols, null is stored instead.

ivars

A list of the instance variables this class contains. This is stored as a reference to the l_OBJC_$_INSTANCE_VARIABLES_<class_name>, where <class_name> is the name of the class. For a metaclass or if the class doesn't have any instance variables, this will be null.

weakIvarLayout

Unknown. Seems to be null.

baseProperties

A list of the properties this class contains.

Section Linkage Alignment
__objc_const Private 8

_OBJC_CLASS_$_/_OBJC_METACLASS_$_

For each class defined, two symbols are generated in the resulting binary. One symbol with the name _OBJC_CLASS_$_<class_name> and one with the name _OBJC_METACLASS_$_<class_name>, where <class_name> is the name of the class. The first symbol is for the class and the second symbol is for the metaclass. The section data that is stored corresponds to the following struct:

struct _class_t
{
    _class_t* isa;
    _class_t* superclass;
    _objc_cache* cache;
    void* vtable;
    _class_ro_t* data;
}

isa

Pointer to the metaclass. This is stored as a reference to the _OBJC_METACLASS_$_<class_name> symbol, where <class_name> is the name of the class.

superclass

Pointer to the base class. This is stored as a reference to the _OBJC_CLASS_$_<class_name> symbol, where <class_name> is the name of the base class. Or a reference to the _OBJC_METACLASS_$_<class_name>, if this is a metaclass. If this class is a root class this will be null.

cache

Unknown. Usually a pointer to an empty cache object. This is stored as a reference to the externally defined __objc_empty_cache symbol.

vtable

Pointer to the vtable. For some selectors, as an optimization, a vtable can be used when calling the method, instead of the regular implementation. This applies to around 20 selectors that are very common to call but unlikely for these methods to be overridden.

data

A pointer to the class implementation. This is stored as a reference to the l_OBJC_CLASS_RO_$_<class_name> symbol, where <class_name> is the name of the class. Or a reference to the l_OBJC_METACLASS_RO_$_<class_name> symbol, if this class is metaclass.

Section Linkage Alignment
__objc_data External 8

L_OBJC_LABEL_CLASS_$

Contains a list of _class_t pointers for each class that is defined. This is stored as a reference to the _OBJC_CLASS_$_<class_name> symbol, where <class_name> is the name of the class.

Section Linkage Alignment
__objc_classlist Private 8

l_OBJC_$_INSTANCE_VARIABLES_

For each class that is defined and contains at least one instance variable, a symbol is generated in the resulting binary. The symbol has the name l_OBJC_$_INSTANCE_VARIABLES_<class_name> where <class_name> is the name of the class. The section data that is stored corresponds to the following struct:

struct _ivar_list_t
{
    int entsize;
    int count;
    _ivar_t[count] list;
}

struct _ivar_t
{
    long* offset;
    char* name;
    char* type;
    int alignment;
    int size;
}

_ivar_list_t

entsize

The size of _ivar_t in bytes, always 32.

count

The number of instance variables in the list.

list

The list of instance variables.

_ivar_t

offset

Offset to the instance variable. This is stored as a reference to the _OBJC_IVAR_$_<class_name>.<ivar_name> symbol, where <class_name> is the name of the class and <ivar_name> is the name of the instance variable.

name

The name of the instance variable. This is store as a reference to the L_OBJC_METH_VAR_NAME_.<number> symbol, where <number> is an incrementing number.

type

The type of the instance variable. This is store as a reference to the L_OBJC_METH_VAR_TYPE_.<number> symbol, where <number> is an incrementing number.

alignment

The alignment of the instance variable.

size

The size of the instance variable.

Section Linkage Alignment
__objc_const Private 8

__OBJC_CLASS_PROTOCOLS_$_

For each class that is defined and implements at least one protocol, a symbol is generated in the resulting binary. The symbol has the name __OBJC_CLASS_PROTOCOLS_$_<class_name> where <class_name> is the name of the class. The section data that is stored corresponds to the _objc_protocol_list type.

Section Linkage Global Alignment
__objc_const Private 8

__OBJC_PROTOCOL_$_

For each protocol that is defined or referenced, a symbol is generated in the resulting binary. The symbol has the name __OBJC_PROTOCOL_$_<protocol_name>, where <protocol_name> is the name of the protocol. The section data that is stored corresponds to the _protocol_t type.

Section Linkage Visibility Global Alignment
__data Weak Hidden 8

__OBJC_LABEL_PROTOCOL_$_

For each protocol that is defined or referenced, a symbol is generated in the resulting binary. The symbol has the name __OBJC_LABEL_PROTOCOL_$_<protocol_name>, where <protocol_name> is the name of the protocol. The section data that is stored corresponds to the _protocol_t* type. This is stored as a reference to the __OBJC_PROTOCOL_$_<protocol_name> symbol, where <protocol_name> is the name of the protocol.

Section Linkage Visibility Global Alignment
__objc_protolist Weak Hidden 8

__OBJC_$_PROTOCOL_REFS_

For each protocol that inherits from other protocols, a symbol is generated in the resulting binary. The symbol has the name __OBJC_$_PROTOCOL_REFS_<protocol_name> symbol, where <protocol_name> is the name of the protocol. The section data contains a list of protocols that the protocol inherits from and is stored as the _objc_protocol_list type.

Section Linkage Global Alignment
__objc_const Private 8

__OBJC_$_PROTOCOL_INSTANCE_METHODS_

For each protocol that is defined or referenced and contains at least one instance method, a symbol is generated in the resulting binary. The symbol has the name __OBJC_$_PROTOCOL_INSTANCE_METHODS_<protocol_name>, where <protocol_name> is the name of the protocol. The section data that is stored corresponds to the __method_list_t type.

Section Linkage Global Alignment
__objc_const Private 8

__OBJC_$_PROTOCOL_CLASS_METHODS_

For each protocol that is defined or referenced and contains at least one class method, a symbol is generated in the resulting binary. The symbol has the name __OBJC_$_PROTOCOL_CLASS_METHODS_<protocol_name>, where <protocol_name> is the name of the protocol. The section data that is stored corresponds to the __method_list_t type.

Section Linkage Global Alignment
__objc_const Private 8

__OBJC_$_PROTOCOL_INSTANCE_METHODS_OPT_

For each protocol that is defined or referenced and contains at least one optional instance method, a symbol is generated in the resulting binary. The symbol has the name __OBJC_$_PROTOCOL_INSTANCE_METHODS_OPT_<protocol_name>, where <protocol_name> is the name of the protocol. The section data that is stored corresponds to the __method_list_t type.

Section Linkage Global Alignment
__objc_const Private 8

__OBJC_$_PROTOCOL_CLASS_METHODS_OPT_

For each protocol that is defined or referenced and contains at least one optional class method, a symbol is generated in the resulting binary. The symbol has the name __OBJC_$_PROTOCOL_CLASS_METHODS_OPT_<protocol_name>, where <protocol_name> is the name of the protocol. The section data that is stored corresponds to the __method_list_t type.

Section Linkage Global Alignment
__objc_const Private 8

__OBJC_$_PROTOCOL_METHOD_TYPES_

For each protocol that is defined or referenced and contains at least one method, a symbol is generated in the resulting binary. The symbol has the name __OBJC_$_PROTOCOL_METHOD_TYPES_<protocol_name>, where <protocol_name> is the name of the protocol. The section data that is stored is a list of symbols, where each element in the list is a reference to a L_OBJC_METH_VAR_TYPE_ symbol.

Section Linkage Global Alignment
__objc_const Private 8

Segments and Sections

The following segments and sections are used to store data in the binary. This table also includes properties of these sections:

Section Segment Type Attribute Alignment
__objc_imageinfo __DATA regular no_dead_strip 0
__objc_methname __TEXT cstring_literals 0
__objc_classlist __DATA regular no_dead_strip 8
__objc_selrefs __DATA literal_pointers no_dead_strip 8
__objc_classrefs __DATA regular no_dead_strip 8
__objc_classname __TEXT cstring_literals 0
__objc_const __DATA regular 8
__objc_data __DATA regular 8
__objc_methtype __TEXT cstring_literals 0
__objc_protolist __DATA regular no_dead_strip 8
__data __DATA regular 8

For more information about the different section types and attributes, see the documentation for Assembler Directives from Apple.

Tools

Here follows a list of useful tools that can/have been used to get the information available in this document.

Clang

Shipped with Apple's developer tools, Xcode.

Assembly Output

Outputs the assembly code, symbols, and their data. Invoke Clang with the -S flag:

$ ls
main.m
$ clang -S main.m
$ ls
main.m main.s

LLVM IR Output

Outputs the LLVM IR code, symbols, and their data. Invoke Clang with the -emit-llvm -S flags:

$ ls
main.m
$ clang -emit-llvm -S main.m
$ ls
main.m main.ll

otool

Apple's disassembly and object dump tool. Can pretty print the Objective-C sections, including visualizing the sections as structs including names of the fields. Recommended flags: -rVotv.

$ clang -c main.m -o main.o
$ otool -rVotv main.o

Shipped with Apple's developer tools, Xcode.

LLVM Object Reader - llvm-readobj

Object reader/dumper from LLVM.

$ clang -c main.m -o main.o
$ llvm-readobj -file-headers -s -sd -r -t -macho-segment -macho-dysymtab -macho-indirect-symbols main.o

Shipped with the official LLVM/Clang distributions, i.e. https://releases.llvm.org.

dumpobj

DigitalMars object dumper.

$ clang -c main.m -o main.o
$ dumpobj main.o

Shipped with DMD.

Hopper Disassembler

Interactive disassembler for macOS and Linux with a GUI. Can pretty print the Objective-C sections, including visualizing the sections as structs including names of the fields.

A third-party tool that costs money. A 30 minutes demo session is available but it can be restarted indefinitely. Available at https://www.hopperapp.com.