I assembled a simple objective-c file that prints hello to the screen. this is the code:

#import <Foundation/Foundation.h>
int main() {
    NSString* a = [NSString stringWithUTF8String: "hi"];
    return 0;

When I assembled it and converted it into Nasm syntax, this is the output:

section .text
default rel
extern _OBJC_CLASS_$_NSString
extern _NSLog
extern _objc_msgSend   
global _main 
    push rbp 
    mov rbp, rsp 
    sub rsp, 16 
    lea rdx, [ L_.str] 
    mov dword [rbp - 4], 0
    mov rax, qword [ L_OBJC_CLASSLIST_REFERENCES_$_] 
    mov rsi, qword [ L_OBJC_SELECTOR_REFERENCES_]
    mov rdi, rax 
    call    _objc_msgSend 
    mov qword [rbp - 16], rax 
    mov rax, qword [rbp - 16] 
    mov rdi, rax ; rdi has rax
    mov al, 0 
    call    _NSLog 
    xor eax, eax 
    add rsp, 16 
    pop rbp 

segment __DATA,__objc_classrefs

    segment __TEXT,__cstring
L_.str: db  "hi"

    segment .__TEXT,.__objc_methname
L_OBJC_METH_VAR_NAME_:   db "stringWithUTF8String:"

    segment __DATA,__objc_selrefs

    segment __DATA,__objc_imageinfo
    dd  0
    dd  64

I understand most of it, like the different objc segments, but I dont understand things like mov rax, qword [rbp - 16] or even mov al, 0. This is 64 bit assembly code so why is the register al referenced? and why is [rbp-16] stored into rax?


The instructions

mov qword [rbp - 16], rax 
mov rax, qword [rbp - 16] 

are created by the compiler which is using stack based memory allocation to store the result from the NSString objc call. If you compile with optimizations, the compiler should eliminate the need to store the value in stack altogether.


mov al, 0

is set as an input to the NSLog function which is a variadic function so it needs a way to determine how many variables are stored in vector registers (xmm/ymm) vs general purpose ones (e.g. rdi, rsi, etc.) when processing the input arguments. Since the number of vector registers is far less than 256, it only needs to use 8-bits and will only look at al. This saves a bit of space in code utilization as the mov al, xx operation only takes 2 bytes.

  • So mov qword [rbp - 16], rax moves the NSString into rax? – Camden Jan 8 '18 at 14:44
  • It's the other way around. mov qword [rbp - 16], rax moves the value in rax into the stack memory. rax holds the value returned from the objc call which is a pointer to a NSString instance – cimarron Jan 8 '18 at 17:59
  • so why is there a mov rax, qword [ rbp - 16 ]? wouldnt that be the opposite? – Camden Jan 9 '18 at 4:39
  • Yes, first it saves the return value to memory and then loads it back up into rax. The compiler is just basically translating operations it has identified without trying to optimize anything which is why it is so inefficient. – cimarron Jan 9 '18 at 5:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.