Skip to content

Instantly share code, notes, and snippets.

@atommclain
Last active December 16, 2015 00:29
Show Gist options
  • Save atommclain/a957e39525209a3051d3 to your computer and use it in GitHub Desktop.
Save atommclain/a957e39525209a3051d3 to your computer and use it in GitHub Desktop.
Objective-C method reflection question
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#define varString(varname) #varname
#define logPointerInfo(ptr1, ptr2) \
NSLog(@"%s: %p, %s: %p equal: %@", varString(ptr1), ptr1, varString(ptr2), ptr2, (ptr1 - (intptr_t *)ptr2 == 0 ? @"YES" : @"NO"))
@interface ADTestObject : NSObject
@end
@implementation ADTestObject
- (void)test:(NSString *)stringOne secondString:(NSString *)stringTwo
thridString:(NSString *)stringThree
fourthString:(NSString *)stringFour
fifthString:(NSString *)stringFive
sixthString:(NSString *)stringSix
{
// I am an expanded macro inside an unknown instance method
// NSLog(@"some how uncommenting this breaks the following code. Why come?");
intptr_t *arg0;
__asm__ __volatile__(
"mov %%rdi,%0\n\t"
: "=r" (arg0));
intptr_t *arg1;
__asm__ __volatile__(
"mov %%rsi,%0\n\t"
: "=r" (arg1));
intptr_t *arg2;
__asm__ __volatile__(
"mov %%rdx,%0\n\t"
: "=r" (arg2));
intptr_t *arg3;
__asm__ __volatile__(
"mov %%rcx,%0\n\t"
: "=r" (arg3));
intptr_t *arg4;
__asm__ __volatile__(
"mov %%r8,%0\n\t"
: "=r" (arg4));
intptr_t *arg5;
__asm__ __volatile__(
"mov %%r9,%0\n\t"
: "=r" (arg5));
intptr_t *arg6;
__asm__ __volatile__(
"mov -(96)(%%rbp),%0\n\t" // I think I should be using RSI for this...
: "=r" (arg6));
intptr_t *arg7;
__asm__ __volatile__(
"mov -(96+48)(%%rbp),%0\n\t"
: "=r" (arg7));
NSLog(@"%s", __PRETTY_FUNCTION__);
logPointerInfo(arg0, self);
logPointerInfo(arg1, (void *)_cmd); // why does this need to be cast to void *?
logPointerInfo(arg2, stringOne);
logPointerInfo(arg3, stringTwo);
logPointerInfo(arg4, stringThree);
logPointerInfo(arg5, stringFour);
logPointerInfo(arg6, stringFive);
logPointerInfo(arg7, stringSix);
NSMethodSignature *sig = [[[(id)arg0 class] alloc] methodSignatureForSelector:(SEL)arg1];
NSLog(@"frameLength : %lx", sig.frameLength);
NSLog(@"numberOfArgs: %lx", sig.numberOfArguments);
Method method = class_getInstanceMethod([self class], _cmd);
unsigned int numberOfArgs = method_getNumberOfArguments(method);
NSLog(@"Number of arguments %i", numberOfArgs);
if (numberOfArgs < 3)
{
return; // method has no parameters ('self' and '_cmd' are sent to all methods)
}
for (unsigned int i = 2; i <= numberOfArgs; i++)
{
char argType[256];
method_getArgumentType(method, i, argType, 256);
NSString *argumentType = [NSString stringWithUTF8String:argType];
if ([argumentType isEqualToString:@"@"])
{
// argument is object, do fancy printing here
}
}
}
- (void)test:(NSString *)stringOne secondString:(NSString *)stringTwo
thridString:(NSString *)stringThree
fourthString:(NSString *)stringFour
fifthString:(NSString *)stringFive
sixthString:(NSString *)stringSix
seventhString:(NSString *)stringSeven
{
// I am an expanded macro inside an unknown instance method but now I'm broken just because this method takes an additional parameter
intptr_t *arg0;
__asm__ __volatile__(
"mov %%rdi,%0\n\t"
: "=r" (arg0));
intptr_t *arg1;
__asm__ __volatile__(
"mov %%rsi,%0\n\t"
: "=r" (arg1));
intptr_t *arg2;
__asm__ __volatile__(
"mov %%rdx,%0\n\t"
: "=r" (arg2));
intptr_t *arg3;
__asm__ __volatile__(
"mov %%rcx,%0\n\t"
: "=r" (arg3));
intptr_t *arg4;
__asm__ __volatile__(
"mov %%r8,%0\n\t"
: "=r" (arg4));
intptr_t *arg5;
__asm__ __volatile__(
"mov %%r9,%0\n\t"
: "=r" (arg5));
intptr_t *arg6;
__asm__ __volatile__(
"mov -(96)(%%rbp),%0\n\t"
: "=r" (arg6));
intptr_t *arg7;
__asm__ __volatile__(
"mov -(96+48)(%%rbp),%0\n\t"
: "=r" (arg7));
intptr_t *arg8;
__asm__ __volatile__(
"mov -(96+48)(%%rbp),%0\n\t"
: "=r" (arg8));
NSLog(@"%s", __PRETTY_FUNCTION__);
logPointerInfo(arg0, self);
logPointerInfo(arg1, (void *)_cmd); // why does this need to be cast to void *?
logPointerInfo(arg2, stringOne);
logPointerInfo(arg3, stringTwo);
logPointerInfo(arg4, stringThree);
logPointerInfo(arg5, stringFour);
logPointerInfo(arg6, stringFive);
logPointerInfo(arg7, stringSix);
logPointerInfo(arg8, stringSeven);
// ...the rest of the code from above
}
@end
int main(int argc, char *argv[]) {
@autoreleasepool {
NSString *string = @"Hello world. The quick brown fox jumped over the lazy brown dog.";
NSArray *words = [string componentsSeparatedByString:@" "];
ADTestObject *testObj = [[ADTestObject alloc] init];
// This *brittle* method works as intended
[testObj test:words[0] secondString:words[1] thridString:words[2] fourthString:words[3] fifthString:words[4] sixthString:words[5]];
// Adding an additional parameter breaks previous working code... :(
[testObj test:words[0] secondString:words[1] thridString:words[2] fourthString:words[3] fifthString:words[4] sixthString:words[5] seventhString:words[6]];
}
}
// http://quickies.seriot.ch/?id=451
// http://0xax.blogspot.com/2014/12/say-hello-to-x8664-assembly-part-7.html
// https://www.clarkcox.com/blog/2009/02/04/inspecting-obj-c-parameters-in-gdb/
// http://www.raywenderlich.com/37181/ios-assembly-tutorial
// TODO: get extra values from $bp // sorta
//http://stackoverflow.com/questions/10890648/add-a-variable-to-the-stack-in-x86-assembly
//http://zenit.senecac.on.ca/wiki/index.php/X86_64_Register_and_Instruction_Quick_Start
//http://stackoverflow.com/questions/21030898/xcode-running-asm
//http://asm.sourceforge.net/articles/rmiyagi-inline-asm.txt
//https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
//http://0xax.blogspot.com/2014/12/say-hello-to-x8664-assembly-part-7.html
@atommclain
Copy link
Author

compilation flags: -std=c99 -framework Foundation

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment