views:

62

answers:

1

I am experiencing a crash, and while investigating I found myself totally blocked by the following code:

0000000000000a00 <_IO_vfprintf>:
a00:       55                      push   %rbp
a01:       48 89 e5                mov    %rsp,%rbp
a04:       41 57                   push   %r15
a06:       41 56                   push   %r14
a08:       41 55                   push   %r13
a0a:       41 54                   push   %r12
a0c:       53                      push   %rbx
a0d:       48 81 ec 48 06 00 00    sub    $0x648,%rsp
a14:       48 89 95 98 f9 ff ff    mov    %rdx,0xfffffffffffff998(%rbp)

This is generated by running objdump --disassemble /usr/lib64/libc.a on a 64-bit x86 system, and then searching through the output. This is AT&T syntax, so destinations are on the right.

Specifically, I don't understand the last instruction. It seems to be writing the value of the rdx register into memory somewhere on the stack (far, far away), before the function has touched that register. To me, this doesn't make any sense.

I tried reading up on the calling conventions, and my best theory now is that rdx is used for a parameter, so the code is basically "returning" the parameter value directly. This is not the end of the function, so it's not really returning, of course.

+4  A: 

Yes, it's a parameter. The ABI used by Linux assigns up to 6 "INTEGER" (<= 64-bit integer, or pointer) type parameters to registers, in the obvious and easy-to-remember order %rdi, %rsi, %rdx, %rcx, %r8, %r9.

The stack frame is 1648 bytes (sub $0x648,%rsp claims 1608 bytes, plus 5 64-bit registers have been pushed before that), and 0xfffffffffffff998 is -1640.

So the code is storing the 3rd parameter near the bottom of the stack frame.

(Note: the Windows 64-bit ABI is different to the Linux one.)

Matthew Slattery
Awesome, thanks. I really should take some time (5-10 years or so) and get back into the groove with assembly programming.
unwind