Search code examples
cassemblygnu-assembler

Accessing calloced array in GAS assembly


I have a C function which allocated some memory to an array that is going to be filled with natural numbers up to a certain N.

Lets say,

N = 10;
array = calloc(N, sizeof(int));

I then call upon an assembly function that I have written, however I don't seem to be able to access the array fields. I manage to find the value of N which is located at 8(%ebp), and I have checked with GDB that it really equals to the N set in the C code.

However, when I try to access the first element in the array, and move it to, for example %esi, the value is not zero as it should be.

That I do by using the following code

movl 12(%ebp), %esi

EDIT; I do of course fill the array with natural numbers before calling the assembly function. I just did not want to type in the for loop here.

As I understands it, the parentheses de-refrences the first element of the array, and copies that to esi, however, esi contains only a huge negative number when I use info registers on a breakpoint set after this code in GDB.

So, How do I access arrays that is calloced beforehand, and passed into an assembly function? Is it not possible to derefrence, and copy that single element?

Here is the C function that calls upon the assembly function

int main(int argc, char *argv[]){

    int n = 10;

    int *array = calloc(n, sizeof(int));
    int i, j;

    // Populate array up to N
    for(i = 0; i < n; i++){
        array[i] = 2 + i;
    }

    printf("Array: %d \n", sizeof(array));

    // Run sievs
    sievs_assembly(n, array);

    // print prime
    print_prime(array, n);

    // Free mem
    free(array);

    return EXIT_SUCCESS;
}

I dont want to post the assembly file as a whole, since it is a school project, and I'm not asking for help solving the assessment, only the specific problem. How to derefrence an array item.

The function prototype is

extern void sievs_assembly(int n, int *a);

I thought that since the pointer *a is an int array, and the first argument N is located at 8(%ebp), that the first array element would be 12(%ebp).

How do I actually get to the value if its not enough to just do movl 12(%ebp), %esi


Solution

  • When you do:

    movl 12(%ebp), %esi
    

    you have moved the memory adress of your array into %esi. The value of the first element is what this adress is pointing to. To get that you can use:

    movl (%esi), %eax
    

    This moves the first element into %eax. The brackets basicly mean "what %esi is pointing to". The size of an int is probably 4 bytes for you (you could check with 'sizeof(int)'). So to acces the next element you could use:

    movl 4(%esi), %eax
    

    Which moves the next element into %eax.

    I've also made an example program which prints 2 values from an array. Note: I made it for windows.

    .macro print str         #macro name is 'print'. 1 argument: 'str'
        pushl \str           #argument names are escaped
        call _printf
        addl $4, %esp        #pop the arguments
    .endm
    
    .macro printf str fs     #can't overload macro names, so let's call this one 'printf'
        pushl \str
        pushl \fs            #printing numbers requires a format srting
        call _printf
        addl $8, %esp
    .endm
    
    .text
    .global _main
    
    _main:                  #actual program, '_main' becomes 'WinMain@16'
        pushl %ebp          #push frame
        movl %esp, %ebp
    
        movl $array, %esi   #Move array pointer to $esi.
    
        #print what %esi is pointing to
        printf (%esi), $fs
    
        #print a newline
        print $nl
    
        #print what %esi+4 is pointing to. Since a long is 4 bytes
        #The next element of the array is 4 bytes further than the first
        printf 4(%esi), $fs
    
        movl $0, %eax       #move 0 to return register
        leave               #pop frame
        ret                 #return
    
    .data
    
    fs: .string "%i"    #Format string
    nl: .string "\n"    #New Line
    
    array:              #Some array
        .long 1,2
    

    This program prints the output:

    1
    2
    

    Edit: Since this got some attention, I thought I'd update the answer with some macros.

    And explain the _ prefixes on c library calls and main; I'm compiling on windows with MinGW, which requires those prefixes to avoid getting undefined reference errors. On linux they're not needed.

    For further documentation about macros and GAS see: using as