why we need to push the stack pointer (rbp) before calling an extern C function in assembly on MacOs?
08:35 23 Nov 2020

I am new to assembly and I was trying to call an extern function of C within assembly code, I tried to call strlen function as shown in the below code:

global _my_strlen
section .text
extern _strlen

_my_strlen:               ;rdi register has the address of the string that is passed within the main function
    call    _strlen       ;call strlen which is a C function and pass to it rdi
    ret                   ;the return value of strlen is stored in rax and it will be returned to our main

this is my main function:

#include 

int     my_strlen(char *str);

int     main()
{
    printf("len = %d\n",my_strlen("this len must be 19"));
    return (0);
}

however when I compile and run it with nasm, it gives me a segmentation fault as shown below :

[1]    58770 segmentation fault  ./a.out

I searched a little bit, and I found that you should push the stack before calling an extern function and pop it later, so I changed the code like this:

global _my_strlen
section .text
extern _strlen

_my_strlen:
    push    rbp            ;Push stack
    call    _strlen        ;call strlen which is a C function and pass to it rdi
    pop     rbp            ;Pop stack
    ret                    ;the return value of strlen is stored in rax and it will be

and it worked perfectly as shown in the result:

len = 19

I don't know why we need to push the stack, and why it segfaults if you didn't so, what's happening in the background and what has got changed after calling strlen, does calling strlen affect the stack and how?!

Btw I tried to push other registers instead of rbp for example push rdx pop rdx and it worked, and this is making me more confused than before, hope you explain it in a good way, and thanks in advance.

c assembly stack kernel nasm