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
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