user11764168
user11764168

Reputation:

Assembly instruction reading, leaq

So I'm trying to compute the values of M and N in the following code with the assembly code given.

int array1[M][N];
int array2[N][M];

void copyelement(int i, int j) {
    array1[i][j] = array2[j][i];
}

Assembly:


copyelement:
    movslq      %esi, %rsi
    movslq      %edi, %rdi
    leaq        (%rdi,%rdi,8), %rax
    addq        %rsi, %rax
    leaq        (%rsi,%rsi,2), %rdx
    leaq        (%rsi,%rdx,4), %rdx
    addq        %rdx, %rdi
    leaq        array2(%rip), %rdx
    movl        (%rdx,%rdi,4), %ecx
    leaq        array1(%rip), %rdx
    movl        %ecx, (%rdx,%rax,4)
    ret

While reading through the assembly code, I got through till array2(%rip) and then I didn't know how to move forward.

At this point, according to my calculations I should have
%rdx = %rdi + (%rsi + %rax) + 4*((%rsi+%rax) + 2*(%rsi + %rax)).

Also I'm not quite sure how I would be able to get the array size from this.

Upvotes: 2

Views: 2923

Answers (2)

Eric Postpischil
Eric Postpischil

Reputation: 222669

Here are the instructions with annotations saying what they do.

// Initially, edi contains i and esi contains j.

movslq %esi, %rsi          // Sign-extend 32-bit j to 64 bits.
movslq %edi, %rdi          // Sign-extend 32-bit i to 64 bits.
leaq   (%rdi,%rdi,8), %rax // rax = rdi + rdi*8 = 9*rdi = 9*i.
addq   %rsi, %rax          // rax = rax + rsi = 9*i + j.
leaq   (%rsi,%rsi,2), %rdx // rdx = rsi + rsi*2 = 3*rsi = 3*j.
leaq   (%rsi,%rdx,4), %rdx // rdx = rsi + rdx*4 = j + (3*j)*4 = 13*j.
addq   %rdx, %rdi          // rdi = rdi + rdx = i + 13*j = i + 13*j.
leaq   array2(%rip), %rdx  // rdx = array2 (address of first element).
movl   (%rdx,%rdi,4), %ecx // Load *(rdx + rdi*4) = array2[rdi] = array2[i + 13*j] into ecx.
leaq   array1(%rip), %rdx  // rdx = array1 (address of first element).
movl   %ecx, (%rdx,%rax,4) // Store ecx into (rdx + rax*4) = array1[rax] = array1[9*i + j].

Thus array2[j][i] in the C code is array2[i + 13*j] in the assembly code (making allowances for two-dimensional addressing versus one-dimensional addressing). The latter should be array2[i + M*j], so we can conclude M is 13.

Similarly, array1[i][j] in the C code is array1[9*i + j] in the assembly code. The latter should be array1[N*i + j], so we can conclude N is 9.

Upvotes: 4

Martin Rosenau
Martin Rosenau

Reputation: 18493

I got through till array2(%rip) and then I didn't know how to move forward.

Using that instruction, the address of array2 (or array2[0][0]) is written to the rdx register. Forget about the rip register here.

The combination of that instruction plus the following one (movl) will read the array element ((int *)array2)[rdi]. The two instructions following will write the array element ((int *)array1)[rax].

This means that rdi contains the value M*j+i and rax contains the value N*i+j.

If the code has been compiled for System-V, rdi initally contained the value of i and rsi initially contained the value of j.

EDIT

okay I tried again, but I can't retrieve the exact value of M and N because the registers don't have any values loaded :/ am I missing something?

First we check with i=0, j=1:

This means that edi is initially 0 and esi is initially 1.

If I did not make a mistake, rdi is 13 before the leaq array2 ... instruction.

This means that M*j+i = M*1+0 = M = 13.

Then we check with i=1, j=0.

If I did not make a mistake, rax is 9 before the leaq array2 ... instruction.

This means that N*i+j = N*1+0 = N = 9.

Upvotes: 1

Related Questions