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;
}
rdiis the first parameter-passing register for the AMD/Linux 64-bit ABI.ediis being used in this code since your function takes a 32-bitintparameter.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.
Line 16 is an array indexing operation:
The AT&T syntax for memory addressing is a little strange looking. It breaks down as:
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
4and the index register being used israx. That breaks down to something like along the lines of this C-like pseudocode: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– sinceintis 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.