0

Can anyone tell me what the following code in x86 ASM does? It's only part of a larger file, but it's just this bit that's getting me down.

find_max: 6 .LFB0: 7 .cfi_startproc 8 pushq %rbp 9 .cfi_def_cfa_offset 16 10 movq %rsp, %rbp 11 .cfi_offset 6, -16 12 .cfi_def_cfa_register 6 13 movl %edi, -20(%rbp) 14 movl -20(%rbp), %eax 15 cltq 16 movl a(,%rax,4), %eax 17 movl %eax, -4(%rbp) 18 movl -20(%rbp), %eax 19 movl %eax, -8(%rbp) 

Specifically,

  • What's initially in %edi on line 13?
  • Why is the code referencing -20(%rbp)?
  • And what exactly does line 16 do?
  • What's the wisdom behind switching behind the 32-bit registers and the 64-bit registers (for instance in the case of line 15)?

The C code I disassembled to get this goes something like the following:

extern int a[]; int find_max(int n) { int max = a[n]; int pos = n; int x; while (n > 0) { n--; x = a[n]; if (x > max) { max = x; pos = n; } } return pos; } 
1
  • If you have the C code, don't you already know what it's doing? What exactly are you trying to ask? Commented Jun 22, 2011 at 17:17

1 Answer 1

7

What's initially in %edi on line 13?

rdi is the first parameter-passing register for the AMD/Linux 64-bit ABI. edi is being used in this code since your function takes a 32-bit int parameter.


Why is the code referencing -20(%rbp)?

It's saving the passed-in-parameter to the stack; presumably you are compiling with low or no optimization, so every variable is getting a real memory address. If you turn up the optimizations, you'll probably see these operations disappear.


And what exactly does line 16 do?

Line 16 is an array indexing operation:

movl a(,%rax,4), %eax 

The AT&T syntax for memory addressing is a little strange looking. It breaks down as:

segment-override:signed-offset(base,index,scale)

In your case, the array's address is being used as the offset field, you have no base register or segment override, the scale is 4 and the index register being used is rax. That breaks down to something like along the lines of this C-like pseudocode:

eax = *(int *)((char *)a + (rax * 4)) 

What's the wisdom behind switching behind the 32-bit registers and the 64-bit registers (for instance in the case of line 15)?

I don't see anything like that on line 15, but the reason it's done is because your function uses a lot of int - since int is a 32-bit type, the compiler is using 32-bit registers. Where it doesn't matter or the compiler is using temporary registers, it's choosing the native 64-bit size.

Sign up to request clarification or add additional context in comments.

3 Comments

The last line is more like eax = *((int*)((char*) a + rax*4));. The code is taking into account the size of an int.
@cHao, yeah, that's a more obvious description. I compressed some of the redundancy out of it in my example in an effort to make it match some semblance of the original code. I'll update that.
Thanks a lot. That cleared things up a lot. :) @cHao, thanks to you, too :)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.