Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>To understand what <code>objc_msgSend_fixup</code> is and what it does it's necessary to know exactly how message sending is performed in Objective-C. All the ObjC programmers have heard one day that the compiler transforms <code>[obj message]</code> statements into <code>objc_msgSend(obj, sel_registerName("message"))</code> calls. However, that's not entirely accurate.</p> <p>To better ilustrate my explanation, consider the following ObjC snippet:</p> <pre><code>[obj mesgA]; [obj mesgB]; [obj mesgA]; [obj mesgB]; </code></pre> <p>In this snippet, two messages are sent to <code>obj</code>, each of which is sent twice. So, you might imagine that the following code is generated:</p> <pre><code>objc_msgSend(obj, sel_registerName("mesgA")); objc_msgSend(obj, sel_registerName("mesgB")); objc_msgSend(obj, sel_registerName("mesgA")); objc_msgSend(obj, sel_registerName("mesgB")); </code></pre> <p>However <code>sel_registerName</code> may be too costly and call it whenever a specific method is called is not a smart thing to do. Then, the compiler generates structures like this for each message to be sent:</p> <pre><code>typedef struct message_ref { id (*trampoline) (id obj, struct message_ref *ref, ...); union { const char *str; SEL sel; }; } message_ref; </code></pre> <p>So, in the example above, when the program starts, we have something like this:</p> <pre><code>message_ref l_objc_msgSend_fixup_mesgA = { &amp;objc_msgSend_fixup, "mesgA" }; message_ref l_objc_msgSend_fixup_mesgB = { &amp;objc_msgSend_fixup, "mesgB" }; </code></pre> <p>When these messages need to be sent to <code>obj</code>, the compiler generates code equivalent to the following:</p> <pre><code>l_objc_msgSend_fixup_mesgA.trampoline(obj, &amp;l_objc_msgSend_fixup_mesgA, ...); // [obj mesgA]; l_objc_msgSend_fixup_mesgB.trampoline(obj, &amp;l_objc_msgSend_fixup_mesgB, ...); // [obj mesgB]; </code></pre> <p>At the program startup, the message reference trampolines are pointers to the <code>objc_msgSend_fixup</code> function. For each <code>message_ref</code>, when its <code>trampoline</code> pointer is invoked for the first time, <code>objc_msgSend_fixup</code> gets called receiving the <code>obj</code> to which the message's got to be sent and the <code>message_ref</code> structure from which it was called. So, what <code>objc_msgSend_fixup</code> must do is get the selector for the message to be called. Since, this has to be done only once for each message reference, <code>objc_msgSend_fixup</code> must also replace the <code>trampoline</code> field of the ref by a pointer to another function that doesn't fix the message's selector. This function is called <code>objc_msgSend_fixedup</code> (the selector has been fixed up). Now that the message selector has been set and this doesn't have to be done again, <code>objc_msgSend_fixup</code> just calls <code>objc_msgSend_fixedup</code> and this just calls <code>objc_msgSend</code>. After that, if a message ref's <code>trampoline</code> is called again, its selector is already fixed, and <code>objc_msgSend_fixedup</code> is the one that gets called.</p> <p>In short, we could write <code>objc_msgSend_fixup</code> and <code>objc_msgSend_fixedup</code> like this:</p> <pre><code>id objc_msgSend_fixup(id obj, struct message_ref *ref, ...) { ref-&gt;sel = sel_registerName(ref-&gt;str); ref-&gt;trampoline = &amp;objc_msgSend_fixedup; objc_msgSend_fixedup(obj, ref, ...); } id objc_msgSend_fixedup(id obj, struct message_ref *ref, ...) { objc_msgSend(obj, ref-&gt;sel, ...); } </code></pre> <p>This makes message sending a lot faster, since the appropriate selector is discovered only at the first time the message is called (by <code>objc_msgSend_fixup</code>). On later calls, the selector will have been already found and the message is called directly with <code>objc_msgSend</code> (by <code>objc_msgSend_fixedup</code>).</p> <p>In the question's assembly code, <code>l_objc_msgSend_fixup_alloc</code> is the <code>alloc</code> method's <code>message_ref</code> structure and the segmentation fault may have been caused by a problem in its first field (maybe it's not pointing to <code>objc_msgSend_fixup</code>...)</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload