DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Objective-C Method Definition Internals

In a previous article we looked at class definitions and Objective C-class definition structures. Now let's look at how to use them together.

Christopher Lamb user avatar by
Christopher Lamb
CORE ·
Apr. 24, 19 · Analysis
Like (1)
Save
Tweet
Share
6.66K Views

Join the DZone community and get the full member experience.

Join For Free

We've talked in a previous article about class definitions and we've looked at Objective C-class definition structures. They use an __objc_class structure which contains information with respect to the class's super class, something called a meta class, a cache, a vTable, and a pointer to class data. We were working with a simple Printer class:

#import <Foundation/Foundation.h>

@interface Printer : NSObject

@property NSString *str_to_print;

- (void) printMsg;
- (void) printString: (NSString*) message;

@end

@implementation Printer

- (void) printMsg {
printf("%s\n", [self.str_to_print UTF8String]);
}

- (void) printString: (NSString*) message {
self.str_to_print = message;
[self printMsg];
}

@end



int main(int argc, const char * argv[]) {
  @autoreleasepool {
  Printer *printer = [[Printer alloc] init];
  [printer printString: @"Hello World!"];
  }
  return 0;
}

Now a metaclass in Objective-C allows you to treat a class as an object, essentially. You can create static methods in Objective C, and the meta class is what allows you to do it. Class definitions can have associated methods and data elements, just like a class instance, and need are implememented in the same way as a result.

Coincidentally, it seems that the objc_class structure in runtime.h looks like this:

struct objc_class {
  Class _Nonnull isa OBJC_ISA_AVAILABILITY;
  #if !__OBJC2__
  Class _Nullable super_class OBJC2_UNAVAILABLE;
  const char * _Nonnull name OBJC2_UNAVAILABLE;
  long version OBJC2_UNAVAILABLE;
  long info OBJC2_UNAVAILABLE;
  long instance_size OBJC2_UNAVAILABLE;
  struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
  struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
  struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
  struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
  #endif
}

Which is not what we see when we disassemble the binary. Anyway, let's start looking through class definition we do have, we'll return to this discrepancy later.

The last element in the structure extracted from the executable was an __objc_class_Printer_data type. The other elements in the disassembled class definition ( _OBJC_METACLASS_$_PRINTER, _OBJC_CLASS_s_NSObject, and __objc_empty_cache) we've either covered or they refer to data structures within the Objective-C runtime. So let's take a look at __objc_class_Printer_data:

__objc_class_Printer_data:
0000000100001198 struct __objc_data { 
  0x184, // flags
  8, // instance start
  16, // instance size
  0x0,
  aX01, // ivar layout
  aPrinter, // name
  __objc_class_Printer_methods, // base methods
  0x0, // base protocols
  __objc_class_Printer_ivars, // ivars
  0x0, // weak ivar layout
  __objc_class_Printer_properties // base properties
}

This looks promising! Here, we seem to have references to methods, the class name, variables, and properties. We have other missing elements too, like the class name. This seems to contain the missing data from the original defined structure, too. We'll take a look at why these seem to differ in the future, right now we're looking at method definitions. Let's take a look at the __objc_class_Printer_methods structure:

__objc_class_Printer_methods:
00000001000010d8 struct __objc_method_list {
  0x18, // flags
  5 // method count
}
00000001000010e0 struct __objc_method {
  aPrintmsg, // name
  aV1608, // signature
  -[Printer printMsg] // implementation
}

00000001000010f8 struct __objc_method {
  aPrintstring, // name
  aV240816, // signature
  -[Printer printString:] // implementation
}

0000000100001110 struct __objc_method {
  aCxxdestruct, // name
  aV1608, // signature
  -[Printer .cxx_destruct] // implementation
}

0000000100001128 struct __objc_method {
  aStrtoprint_100000f18, // name
  a1608, // signature
  -[Printer str_to_print] // implementation
}

0000000100001140 struct __objc_method {
  aSetstrtoprint, // name
  aV240816, // signature
  -[Printer setStr_to_print:] // implementation
}

This is what we're looking for — let's take a closer look. This is a list of methods, defined by the __objc_method_list structure. We have a list of five methods here, some of which we defined (e.g. printString) and some we didn't (e.g. cxx_destruct). Each of these entries have pointers to the implementation functions too (I'm using Hopper here, which is very friendly to Objective-C disassembly and function demangling, which is why this section of the disassembly is so easy to read).

Each of the method structures define the method name, signature, and a pointer to an implementation function. Let's take a look at the decompiled printString method implementation:

-(void)printString:(void *)arg2 {
  var_18 = 0x0;
  objc_storeStrong(&var_18, arg2);
  [self setStr_to_print:var_18];
  [self printMsg];
  objc_storeStrong(&var_18, 0x0);
  return;
}

And here's our original:

- (void) printString: (NSString*) message {
  self.str_to_print = message;
  [self printMsg];
}

Pretty close! We have a few extra things in the decompiled method related to reference counting, but the code is pretty much what we'd expect.

So now we see how classes are defined, or at least some of the major elements (we haven't discussed Protocols or Properties, for example, but you can see how properties are supported in the disassembly here, specifically via the setStr_to_print method).

There's lots of interesting stuff to continue to unravel here — how these methods are actually called, for example, or how Protocols are supported, or why we see the data stored in the executable that seems a bit off from header file definitions. We'll continue to explore some of this later, but it's time we took a look at how this kind of thing is implemented in Swift.

Objective C

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Problems of Cloud Cost Management: A Socio-Technical Analysis
  • Learning by Doing: An HTTP API With Rust
  • Securing VMs, Hosts, Kubernetes, and Cloud Services
  • How To Get Page Source in Selenium Using Python

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: