Search code examples
assemblyx86gnu-assemblercalling-conventionatt

How do I acess the value of the last parameter of a function, given that the first two parameters are dynamic arrays?


The function in C is

void f(int* out, int* in, int nbElements){
    // do stuff
}

Since int nbElements is the first to be pushed on the stack and in and out have variable sizes, how can I access the value of nbElements? As far as I understand, the stack looks something like this:

          esp
          ebp
     return address         # -4(%ebp) 
1st element of int* out     # -8(%ebp)
1st element of int* in      # (%ebp - 8 - 4*nbElements)
      nbElements            # not sure how I can access the value of this

So how can I access the value of nbElements without knowing its address?


Solution

  • The stack frame is somewhat different.

    The caller does not set up %ebp. That is up to the called function, if it choses to use %ebp at all.

    Notice that in your function below, it does not use %ebp at all. All references to arguments are relative to the stack pointer (%esp).

    This gives the stack frame:

    1000: nbElements
    0FFE: in
    0FFC: out
    0FFA: return address
    0FF6: <---------------------- %esp points here
    

    So, as below to access nbElements, you want 12(%esp)

    If your function sets up %ebp, the offsets will change by approx. 4:

        .text
        .globl  f
    f:
        pushl   %ebp
        movl    %esp,%ebp
    
        movl    8(%ebp), %eax
        movl    %eax, outsave
    
        movl    12(%ebp), %eax
        movl    %eax, insave
    
        movl    16(%ebp), %eax
        movl    %eax, cntsave
    
        pop     %ebp
        ret
    

    Here is something similar to your function:

    int *outsave;
    int *insave;
    int cntsave;
    
    void
    f(int *out, int *in, int nbElements)
    {
    
        // do stuff
        outsave = out;
        insave = in;
        cntsave = nbElements;
    }
    

    This is the assembly output:

        .text
        .globl  f
    f:
        movl    4(%esp), %eax
        movl    %eax, outsave
    
        movl    8(%esp), %eax
        movl    %eax, insave
    
        movl    12(%esp), %eax
        movl    %eax, cntsave
    
        ret
    

    This is a sample caller of f:

    void
    f(int *out, int *in, int nbElements);
    
    int outbuf[100];
    int inbuf[100];
    int bufcnt;
    
    void
    g(void)
    {
    
        f(outbuf,inbuf,bufcnt);
    }
    

    This is the assembly for that:

        .text
        .globl  g
    g:
        subl    $16, %esp
    
        pushl   bufcnt
        pushl   $inbuf
        pushl   $outbuf
    
        call    f
        addl    $28, %esp
    
        ret