Live data from Hacker News

Reading iOS app binary files

blog.smartdec.net

11–20 of 20 posts

Re: Reading iOS app binary files

#11

Objective-C was the first language I used where I looked under the covers and tried to understand the machinery of the language, and its extremely dynamic nature makes it a great place to start to understand language runtimes. It's so conceptually simple, and (aside from objc_msgSend) you can implement the whole thing in C. libobjc2 has (if I'm counting correctly) 23 .c files, and it includes things you can totally i…

> The only tricky part is the message-sending routines, since they have to be written in assembly Why? (context: never touched Objective-C)

objc_msgSend accepts a variable number of arguments, and it needs to forward those to the method implementation. This is not possible to do in pure C.

Re: Reading iOS app binary files

#12
post #10

Earlier quoted context omitted.

> The only tricky part is the message-sending routines, since they have to be written in assembly Why? (context: never touched Objective-C)

Disclaimer: I may be completely wrong, but I don't think OP is saying that while writing normal ObjC that you need to write the message passing in assembly. Instead, that you could recreate ObjC in regular C but you would have to use assembly to construct the message passing portion of the language.

Sure, but what's the property of ObjC-style message passing that makes it hard to implement in C?

Like when you implement coroutines/threads in your language runtime, you're going to implement the context switching part in assembly because you just don't have access to the relevant information (registers/stack/...) from portable C (aside from using setjmp/longjmp maybe).

Re: Reading iOS app binary files

#13
post #12
post #10

Earlier quoted context omitted.

Disclaimer: I may be completely wrong, but I don't think OP is saying that while writing normal ObjC that you need to write the message passing in assembly. Instead, that you could recreate ObjC in regular C but you would have to use assembly to construct the message passing portion of the language.

Sure, but what's the property of ObjC-style message passing that makes it hard to implement in C? Like when you implement coroutines/threads in your language runtime, you're going to implement the context switching part in assembly because you just don't have access to the relevant information (registers/stack/...) from portable C (aside from using setjmp/longjmp maybe).

A parent comment says it's due to variable number of arguments.

I thought it was about speed, heh.

Re: Reading iOS app binary files

#14

Earlier quoted context omitted.

> The only tricky part is the message-sending routines, since they have to be written in assembly Why? (context: never touched Objective-C)

objc_msgSend accepts a variable number of arguments, and it needs to forward those to the method implementation. This is not possible to do in pure C.

What about just forwarding the var_args variable?

Re: Reading iOS app binary files

#15

Earlier quoted context omitted.

objc_msgSend accepts a variable number of arguments, and it needs to forward those to the method implementation. This is not possible to do in pure C.

What about just forwarding the var_args variable?

You'd have to pass around a va_list everywhere and parse it at the call site. This adds overhead that you probably don't want to deal with, especially since objc_msgSend is probably the hottest code path in any Objective-C program.

Re: Reading iOS app binary files

#16
post #13
post #12

Earlier quoted context omitted.

Sure, but what's the property of ObjC-style message passing that makes it hard to implement in C? Like when you implement coroutines/threads in your language runtime, you're going to implement the context switching part in assembly because you just don't have access to the relevant information (registers/stack/...) from portable C (aside from using setjmp/longjmp maybe).

A parent comment says it's due to variable number of arguments. I thought it was about speed, heh.

To be honest, it's probably both. The runtime gurus at Apple do a great job hand-optimizing objc_msgSend for each platform since it's such an important factor in the overall speed of an Objective-C program.

Re: Reading iOS app binary files

#17

Objective-C was the first language I used where I looked under the covers and tried to understand the machinery of the language, and its extremely dynamic nature makes it a great place to start to understand language runtimes. It's so conceptually simple, and (aside from objc_msgSend) you can implement the whole thing in C. libobjc2 has (if I'm counting correctly) 23 .c files, and it includes things you can totally i…

Objective-C is two parts, a compiler and a runtime. Both are reasonably simple but there are many details that are important.

Check out Mike Ashes excellent blog about Objective-C, the runtime and many other things:

https://mikeash.com/pyblog/

Re: Reading iOS app binary files

#18
post #12
post #10

Earlier quoted context omitted.

Disclaimer: I may be completely wrong, but I don't think OP is saying that while writing normal ObjC that you need to write the message passing in assembly. Instead, that you could recreate ObjC in regular C but you would have to use assembly to construct the message passing portion of the language.

Sure, but what's the property of ObjC-style message passing that makes it hard to implement in C? Like when you implement coroutines/threads in your language runtime, you're going to implement the context switching part in assembly because you just don't have access to the relevant information (registers/stack/...) from portable C (aside from using setjmp/longjmp maybe).

It's really the functionality of a method taking an unspecified number of arguments and jumping directly to the implementation's function pointer. Though, now that you mention it, there's really no reason you need to do that.

You could have your own calling convention where arguments aren't passed in registers or on the stack, but are boxed into some container. That way every method's implementation function could have the same signature, taking a pointer to the receiver ("self"), the method name, a box of arguments, and a place to pass the return value back out:

    typedef void (*IMP)(id, SEL, struct context *, void **); // arguments are `self`, the method name (`const char *`), a pointer to a structure containing the arguments, and a place to put your return value
I know of at least one Objective-C runtime implementation that does this. It won't be nearly as efficient – you have to pack/unpack the arguments, it pushes a stack frame instead of just jumping to the implementation, etc. – but it would certainly be portable.

Re: Reading iOS app binary files

#19
post #9

Objective-C was the first language I used where I looked under the covers and tried to understand the machinery of the language, and its extremely dynamic nature makes it a great place to start to understand language runtimes. It's so conceptually simple, and (aside from objc_msgSend) you can implement the whole thing in C. libobjc2 has (if I'm counting correctly) 23 .c files, and it includes things you can totally i…

> (aside from objc_msgSend) you can implement the whole thing in C And if you're willing to impose some limitations (maximum number of arguments, no floating-point arguments or return value), it's quite easy to implement a "toy" version of objc_msgSend in pure C.

I remembered after writing this that there's an implementation[0] that boxes up method arguments, giving everything a signature of `void objc_msgSend(void self, SEL _cmd, void *_param)`.

[0]https://www.mulle-kybernetik.com/weblog/2015/mulle_objc_meta...

Re: Reading iOS app binary files

#20
post #13
post #12

Earlier quoted context omitted.

Sure, but what's the property of ObjC-style message passing that makes it hard to implement in C? Like when you implement coroutines/threads in your language runtime, you're going to implement the context switching part in assembly because you just don't have access to the relevant information (registers/stack/...) from portable C (aside from using setjmp/longjmp maybe).

A parent comment says it's due to variable number of arguments. I thought it was about speed, heh.

It's (if not mostly, these days) about speed, but it is also to retain the notion that Objective-C methods are just C functions with 2 extra parameters, `self` and `_cmd`.

But yes – when objc_msgSend is invoked tens of thousands of times/second, you'll write it in ASM to get the performance boost anyway. When you're a compiler or runtime engineer working in a language with as few opportunities for static optimization as Objective-C, you bet your ass you'll squeeze every drop possible from message dispatch.

Post reply on HN